Skip to content

Commit 4bcd2ee

Browse files
committed
Part #81 : Basic auth support (not --authorization-injection)
1 parent c68641a commit 4bcd2ee

3 files changed

Lines changed: 42 additions & 3 deletions

File tree

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ $ python3 log4j-scan.py -h
4040
[•] Secure your External Attack Surface with FullHunt.io.
4141
usage: log4j-scan.py [-h] [-u URL] [-l USEDLIST] [--request-type REQUEST_TYPE] [--headers-file HEADERS_FILE] [--run-all-tests] [--exclude-user-agent-fuzzing]
4242
[--wait-time WAIT_TIME] [--waf-bypass] [--dns-callback-provider DNS_CALLBACK_PROVIDER] [--custom-dns-callback-host CUSTOM_DNS_CALLBACK_HOST]
43+
[--basic-auth-user USER] [--basic-auth-password PASSWORD] [--disable-http-redirects]
4344

4445
optional arguments:
4546
-h, --help show this help message and exit
@@ -65,6 +66,10 @@ optional arguments:
6566
DNS Callback provider (Options: dnslog.cn, interact.sh) - [Default: interact.sh].
6667
--custom-dns-callback-host CUSTOM_DNS_CALLBACK_HOST
6768
Custom DNS Callback Host.
69+
--basic-auth-user USER
70+
Preemptive basic authentication user.
71+
--basic-auth-password PASSWORD
72+
Preemptive basic authentication password.
6873
--disable-http-redirects
6974
Disable HTTP redirects. Note: HTTP redirects are useful as it allows the payloads to have higher chance of reaching vulnerable systems.
7075
```

log4j-scan.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from Crypto.PublicKey import RSA
2424
from Crypto.Hash import SHA256
2525
from termcolor import cprint
26+
from requests.auth import HTTPBasicAuth
2627

2728
# Disable SSL warnings
2829
try:
@@ -115,6 +116,14 @@ def parse_args(args_input):
115116
dest="disable_redirects",
116117
help="Disable HTTP redirects. Note: HTTP redirects are useful as it allows the payloads to have higher chance of reaching vulnerable systems.",
117118
action='store_true')
119+
parser.add_argument("--basic-auth-user",
120+
dest="basic_auth_user",
121+
help="Preemptive basic authentication user.",
122+
action='store')
123+
parser.add_argument("--basic-auth-password",
124+
dest="basic_auth_password",
125+
help="Preemptive basic authentication password.",
126+
action='store')
118127

119128
return parser.parse_args(args_input)
120129

@@ -279,12 +288,17 @@ def scan_url(url, callback_host, proxies, args):
279288
cprint(f"[•] Scanning for CVE-2021-45046 (Log4j v2.15.0 Patch Bypass - RCE)", "yellow")
280289
payloads = get_cve_2021_45046_payloads(f'{parsed_url["host"]}.{callback_host}', random_string)
281290

291+
auth = None
292+
if args.basic_auth_user:
293+
auth = HTTPBasicAuth(args.basic_auth_user, args.basic_auth_password)
294+
282295
for payload in payloads:
283296
cprint(f"[•] URL: {url} | PAYLOAD: {payload}", "cyan")
284297
if args.request_type.upper() == "GET" or args.run_all_tests:
285298
try:
286299
requests.request(url=url,
287300
method="GET",
301+
auth=auth,
288302
params={"v": payload},
289303
headers=get_fuzzing_headers(payload, args.headers_file, args.exclude_user_agent_fuzzing),
290304
verify=False,
@@ -299,6 +313,7 @@ def scan_url(url, callback_host, proxies, args):
299313
# Post body
300314
requests.request(url=url,
301315
method="POST",
316+
auth=auth,
302317
params={"v": payload},
303318
headers=get_fuzzing_headers(payload, args.headers_file, args.exclude_user_agent_fuzzing),
304319
data=get_fuzzing_post_data(payload),
@@ -313,6 +328,7 @@ def scan_url(url, callback_host, proxies, args):
313328
# JSON body
314329
requests.request(url=url,
315330
method="POST",
331+
auth=auth,
316332
params={"v": payload},
317333
headers=get_fuzzing_headers(payload, args.headers_file, args.exclude_user_agent_fuzzing),
318334
json=get_fuzzing_post_data(payload),

tests/test_log4j_scan.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import re
2-
import importlib
2+
import requests_mock
3+
import importlib
34
log4j_scan = importlib.import_module("log4j-scan", package='..')
45

6+
LOCALHOST = 'https://localhost/'
7+
58

69
def test_args_required(capsys):
710
log4j_scan.main([])
@@ -12,9 +15,9 @@ def test_args_required(capsys):
1215
def test_default(requests_mock, capsys):
1316
adapter_dns_register = requests_mock.post('https://interact.sh/register', text='success')
1417
adapter_dns_save = requests_mock.get('https://interact.sh/poll', json={'data': [], 'extra': None, 'aes_key': 'FAKE'})
15-
adapter_endpoint = requests_mock.get('https://localhost/')
18+
adapter_endpoint = requests_mock.get(LOCALHOST)
1619

17-
log4j_scan.main(['-u', 'https://localhost/'])
20+
log4j_scan.main(['-u', LOCALHOST])
1821

1922
captured = capsys.readouterr()
2023

@@ -25,4 +28,19 @@ def test_default(requests_mock, capsys):
2528
assert 'Targets does not seem to be vulnerable' in captured.out
2629
assert 'jndi' in adapter_endpoint.last_request.url
2730
assert re.match(r'\${jndi:ldap://localhost\..*.interact\.sh/.*}', adapter_endpoint.last_request.headers['User-Agent'])
31+
assert 'Authorization' not in adapter_endpoint.last_request.headers
32+
33+
34+
def test_authentication_basic(requests_mock):
35+
adapter_endpoint_get = requests_mock.get(LOCALHOST)
36+
adapter_endpoint_post = requests_mock.post(LOCALHOST)
37+
38+
log4j_scan.main(['-u', LOCALHOST, '--custom-dns-callback-host', 'http://custom.dns.callback', '--basic-auth-user', 'foo', '--basic-auth-password', 'bar', '--run-all-tests'])
39+
40+
assert adapter_endpoint_get.call_count == 1
41+
assert adapter_endpoint_post.call_count == 2
2842

43+
_basic_auth_encoded = 'Basic Zm9vOmJhcg=='
44+
assert _basic_auth_encoded == adapter_endpoint_get.last_request.headers['Authorization']
45+
assert _basic_auth_encoded == adapter_endpoint_post.request_history[0].headers['Authorization']
46+
assert _basic_auth_encoded == adapter_endpoint_post.request_history[1].headers['Authorization']

0 commit comments

Comments
 (0)