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
(Log4Shell playthings) Initial implementation of Rex LDAP Server #15961
(Log4Shell playthings) Initial implementation of Rex LDAP Server #15961
Conversation
Ping @smcintyre-r7/@zeroSteiner & @timwr |
I forget how lively the PR page gets when apocalyptic stuff is afoot . Thanks for checking @bcoles @gwillcox-r7 - could you guys please peek the code and kick me to fix any mistakes? I've been writing Rust and languages which i'm too embarrassed to mention in hacker company for the last few months so please don't assume any proficiency on my end :). |
Yup, my stuff would fail sanity tests. |
We've had the same failure on a few other PRs, so it looks like it's an issue on our side. |
Thanks @space-r7. |
This merges rapid7#15961 into the log4shell branch to test the new LDAP server.
a71b8e6
to
5ca8bc2
Compare
dd69f2e
to
78a3e1b
Compare
Weird this is now trying to pull in files that were landed earlier today. Are you sure your branch is synced correctly with Edit: If needed I'm happy to rebase this if you would like and see if that fixes things if your having issues, otherwise feel free to try rebase against |
ab0ad80
to
6af100f
Compare
Rebased on master. |
9fc6e40
to
af1cbd9
Compare
Looks like the PDU parsing for the authenticated search request is failing: [12/15/2021 03:59:30] [i(0)] core: Error in stream server client monitor: LDAP PDU Format Error: undefined method `[]' for nil:NilClass
[12/15/2021 03:59:30] [i(0)] core:
Call stack:
.../gems/net-ldap-0.17.0/lib/net/ldap/pdu.rb:97:in `rescue in initialize'
.../gems/net-ldap-0.17.0/lib/net/ldap/pdu.rb:86:in `initialize'
/opt/metasploit4/msf4/lib/rex/proto/ldap/server.rb:149:in `new'
/opt/metasploit4/msf4/lib/rex/proto/ldap/server.rb:149:in `default_dispatch_request'
/opt/metasploit4/msf4/lib/rex/proto/ldap/server.rb:137:in `dispatch_request'
/opt/metasploit4/msf4/lib/rex/proto/ldap/server.rb:273:in `on_client_data'
/opt/metasploit4/msf4/lib/rex/proto/ldap/server.rb:103:in `block in start' which is |
lib/rex/proto/ldap/server.rb
Outdated
def default_dispatch_request(cli, data) | ||
return if data.strip.empty? | ||
data.extend(Net::BER::Extensions::String) | ||
while pdu = Net::LDAP::PDU.new(data.read_ber!(Net::LDAP::AsnSyntax)) |
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.
So it looks like this is intending to handle an encoded stream of requests. It'd be really nice if each PDU was handled individually as an option when using the library. Something like an on_request_pdu
callback that would handle exactly one PDU request that could then dispatch to the services default handler. That would enable modules to catch the request types they want to handle themselves and forward the rest to the default without needing all the error handling and looping logic.
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.
Also I was encountering an exception here when the stream was depleted.
def default_dispatch_request(cli, data) | |
return if data.strip.empty? | |
data.extend(Net::BER::Extensions::String) | |
while pdu = Net::LDAP::PDU.new(data.read_ber!(Net::LDAP::AsnSyntax)) | |
while !data.empty? && pdu = Net::LDAP::PDU.new(data.read_ber!(Net::LDAP::AsnSyntax)) |
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.
For now i am logging these, but yeah, we should revise as suggested (adding as a TODO)
af1cbd9
to
4210b33
Compare
I think we're roughly "testable" now - could folks using this rebase/merge-up and kick me with any new or unresolved issues? |
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 tested this out a bit and didn't find an real issues. Part of the testing was with the Log4Shell scanner.
@zeroSteiner - could you please suggest a merge fix against your code? |
Sure, if you apply the following patch, the conflict can be resolved by just accepting all the changes within this PR. log4shell_scanner.patch
diff upstream/master..HEADFor context, these should then be the changes once the patch has been applied against the current revision on master.It's pretty much just the service code.
|
hmm, that dog won't hunt exactly - going to apply the diff and make some changes as this breaks stuff |
@zeroSteiner - done. However this drops my ref/dup thing so i haven't tested whether it actually works. |
New PR incoming with module - had to drop to avoid conflict |
In order to detect scan callbacks, serve payloads, and otherwise interact with the LDAP protocol handler in JNDI, Metasploit needs a native LDAP service properly exposed to various parts of the Framework and users/consumers. Implement Rex::Protocol::LDAP::Server with TCP and UDP socket handlers abstracted to a common access pattern between L4 stacks. Extend the socket clients to hold a state attibute for LDAP bind authentication, and use the UDP client abstraction to implement consistent callback semantics for data receipt from a client and handling response on the other side. The server utilizes Rex' native sockets, permitting full pivot and proxy support over the Switchboard. Implement the Msf::Exploit::Remote::LDAP::Server mixin to manage service abstraction and shared methods exposed to Metasploit modules. Note: during implementation of this functionality, it was discovered that the Scanner mixin's :replicant method resulted in :dup calls to the Rex::ServiceManager service created by this new mixin (and any others leveraging ServiceManager). As a result, double-bind attempts created failures in service instantiation from the duplicated MetasploitModules which also dropped the @service instance variable reference to the actual running service; leaving the socket inexorably bound until Framework was halted and Ruby released the FDs. See rapid7/rex-core#19 and the Issues/Pull Requests sections of R7's MSF GitHub. Expose the new LDAP infrastructure to users by way of a basic LDAP server MetasploitModule which consumes a tiny sample LDIF (provided) and performs queries against it. This is intended to be a template for future work such as LDAP authentication capture, protocol proxy for MITM and intercept, and other more specific implementations for exploits and auxiliary modules. For feature completeness, provide a Rex::Socket override for Net::LDAP::Connection until we have a proper, native to Rex, LDAP client class implemented. Testing: Basic functionality only, this is an early effort which will be extended for feature-completeness over time
a8a4d83
to
db8f4ff
Compare
Implement the new Rex::Protocol::LDAP::Server to handle log4shell callbacks from vulnerable hosts.
The previous module still works for me against solr 🎉
Although we seem to have lost this helpful debug line from the old implementation, which was previously handy for spotting when I was listening on the wrong interface 😄
Not a massive issue, but it may not handle the srvhost being scanned:
|
Ah, I realize that in addition to losing the helpful startup message:
We also lose the helpful bind error message EACCES error handling Master: metasploit-framework/lib/msf/core/exploit/remote/tcp_server.rb Lines 90 to 105 in 69e67db
This branch:
Might be good shuffling things around to get a consistent error message here |
Due to how this stack is being broken up into LDAP core, scanner update, and exploit work, changes requested in rapid7#15972 actually apply in this branch and get rebased to the remaining ones. Address requests to clean up the textual messages, LDIF file read, sourcing of LDAP methods from net-ldap, and YARD-related placement of attr_* annotations.
Thanks for digging into this @adfoster-r7. Regarding |
aa2c821
to
25e2fbd
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 test the client changes using the auxiliary/gather/ldap_hashdump
module and the test server from it's module docs. I tested both with and without an SSL socket (SSL provided by ncat) and everything worked as intended once the options were set correctly.
I also retested the Log4Shell scanner which is still functioning correctly.
Finally I tested the ldap server module once more and wrote up the module docs which I pushed up in d82b9ec. I did rename it to simply ldap
to match the other modules. When we get around to having a proxy we can name it ldap_proxy
which should still be intuitive given that an LDAP's typical function is not to proxy.
Once the unit tests pass, I'll get this landed. Thanks for all of your work on this @sempervictus!
Release NotesThis adds the initial implementation of an LDAP server implemented in Rex and updates the existing log4shell scanner module to use it as well as provides a new example module. |
Thanks for testing, completing, and landing thins @smcintyre-r7. All good with the name change on this end, will rebase the other two branches atop master now. |
In order to support efforts around CVE-2021-44228, an LDAP server
is needed to service JNDI LDAP URLs with properly encoded response
data. Rex provides native service infrastructure defining patterns
to provide callbacks to higher-level consumers for incoming and
outgoing data actions, and is designed for integration into higher
level namespaces within Msf::.
This commit stubs out the required LDAP service, borrowing the meat
of LDAP interaction from the
ldapserver.rb
file in net-ldap'stestserver
directory. The rest of the service is boilerplate Rexcode supporting both UDP and TCP layer 4 protocols with all the
monitor thread management needed to handle stateless transport.
Default LDAP request handling is taken ~ verbatim from upstream to
show how an Msf or MetasploitModule level callback could interact
with the data.
Testing: none, this is an ugly hack by a grumpy old man.
TODO:
Test the code...
Provide Msf::Exploit namespace with relevant interfaces
For now, this can be used raw in modules - well make it pretty
later.
Narrow down use-cases/interactions and extend convenience methods
to better service consumers.