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

Add new Ldap session type #19058

Merged
9 commits merged into from May 15, 2024
Merged

Add new Ldap session type #19058

9 commits merged into from May 15, 2024

Conversation

dwelch-r7
Copy link
Contributor

@dwelch-r7 dwelch-r7 commented Apr 5, 2024

Similar to adding the SMB session type here #18539 and here #18596 but for LDAP sessions/modules that can take advantage of re-using an ldap session

This PR adds in a new session type for LDAP following on from the recently added SQL and SMB sessions

Verification Steps:

  • Enable the new LDAP session feature features set ldap_session_type true

  • Run auxiliary/scanner/ldap/ldap_login against an ldap server to get a session (an example of running an ldap container can be found in the ldap acceptance tests here

    - name: Run samba/ldap docker container
    working-directory: 'test/ldap'
    run: |
    docker compose build
    docker compose up --wait -d
    )

  • Interact with the session with sessions -i <session_id> and with sessions -i -1

  • Run the query command (example queries used by the ldap_query module found here https://github.com/rapid7/metasploit-framework/blob/97f75c19e43bff214ec408854f30b0144a0a2347/data/auxiliary/gather/ldap_query/ldap_queries_default.yaml )

  • Run bg to background the session

  • use auxiliary/gather/ldap_query and then set SESSION <session_id> run the module and you should get successful results back

  • Exit the session with exit from within the session context and via sessions -K/sessions -k <session_id>

  • make sure the feature is off first features set ldap_session_type false

  • Run through the standard usage of the modules, ensure the SESSION datastore option is not visible and the modules succeed

  • Turn the feature on features set ldap_session_type true

  • Run through the modules again creating or using an LDAP session type where applicable, the results should be identical to the modules standard usage

  • Ensure authentication with LDAP::Auth=kerberos works with the ldap_login module and that that session works with another module e.g. ldap_query

@smcintyre-r7
Copy link
Contributor

We recently added the Shadow Credentials module in #19051 and I think that was after this branch was created. Would you mind pulling in those changes and adding LDAP session support to that module when the time comes?

@bwatters-r7 bwatters-r7 self-assigned this Apr 11, 2024
@dwelch-r7 dwelch-r7 force-pushed the ldap-session-type branch 4 times, most recently from 16e969d to cd4b2ca Compare April 25, 2024 17:08
@dwelch-r7 dwelch-r7 force-pushed the ldap-session-type branch 4 times, most recently from 9827e4a to 03f4ce7 Compare May 2, 2024 14:53
@dwelch-r7 dwelch-r7 marked this pull request as ready for review May 3, 2024 09:03
# Runs the specified command wrapper in something to catch exceptions.
#
def run_command(dispatcher, method, arguments)
# TODO: double check these are the correct errors to handle
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👀

module Ui
###
#
# Core SMB client commands
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Core SMB client commands
# Core LDAP client commands

#
# Shares
#
def name
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix please

@@ -45,7 +45,7 @@ def initialize(opts = {})
# @raise [RuntimeError] if the connection can not be created
def connect
return connection if connection

raise ArgumentError, 'Missing remote address' unless self.host && self.port
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: Maybe a better fix in Rex is needed here

if datastore['CreateSession']
print_status("#{sessions.size} LDAP #{sessions.size == 1 ? 'session was' : 'sessions were'} opened successfully.")
else
print_status('You can open an LDAP session with these credentials and %grnCreateSession%clr set to true')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
print_status('You can open an LDAP session with these credentials and %grnCreateSession%clr set to true')
print_status('You can open an LDAP session with these credentials and %grnCreateSession%clr set to true') if framework.features.enabled?(Msf::FeatureManager::LDAP_SESSION_TYPE)

@bwatters-r7
Copy link
Contributor

I'm confused by Run through the modules again creating or using an SMB session type where applicable, the results should be identical to the modules standard usage

I can readily create an smb session, but it fails when I give it to the ldap_query module, which makes sense?

Am I missing something?

@smcintyre-r7
Copy link
Contributor

I think either he's saying to test that SMB sessions still work with SMB modules, or it's a typo and it should have been LDAP and not SMB. Either way, an SMB session isn't compatible with the ldap_query module so receiving an error message sounds correct.

@dwelch-r7
Copy link
Contributor Author

Apologies I lifted the testing steps from the SMB PR to make sure we were testing these new sessions in all the same ways, I've updated the verification steps now to read LDAP instead of SMB

@bwatters-r7
Copy link
Contributor

When I use admin/ldap/rbcd, it succeeds when I give it the Domain Administrator account, but not when I give it an LDAP session with the Administrator account:

msf6 auxiliary(admin/ldap/rbcd) > show options

Module options (auxiliary/admin/ldap/rbcd):

   Name           Current Setting  Required  Description
   ----           ---------------  --------  -----------
   DELEGATE_FROM                   no        The delegation source
   DELEGATE_TO    WS01             yes       The delegation target
   SSL            false            no        Enable SSL on the LDAP connection


   Used when making a new connection via RHOSTS:

   Name      Current Setting  Required  Description
   ----      ---------------  --------  -----------
   DOMAIN    example          no        The domain to authenticate to
   PASSWORD  v3Mpassword      no        The password to authenticate with
   RHOSTS    10.5.132.252     no        The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-meta
                                        sploit.html
   RPORT     389              no        The target port
   USERNAME  Administrator    no        The username to authenticate with


   Used when connecting via an existing SESSION:

   Name     Current Setting  Required  Description
   ----     ---------------  --------  -----------
   SESSION                   no        The session to run this module on


Auxiliary action:

   Name  Description
   ----  -----------
   READ  Read the security descriptor



View the full module info with the info, or info -d command.

msf6 auxiliary(admin/ldap/rbcd) > run
[*] Running module against 10.5.132.252

[*] Discovering base DN automatically
[*] The msDS-AllowedToActOnBehalfOfOtherIdentity field is empty.
[*] Auxiliary module execution completed
msf6 auxiliary(admin/ldap/rbcd) > sessions

Active sessions
===============

  Id  Name  Type  Information                            Connection
  --  ----  ----  -----------                            ----------
  1         ldap  LDAP Administrator @ 10.5.132.252:389  10.5.135.201:36831 -> 10.5.132.252:389 (10.5.132.252)
  2         ldap  LDAP sandy @ 10.5.132.252:389          10.5.135.201:36723 -> 10.5.132.252:389 (10.5.132.252)

msf6 auxiliary(admin/ldap/rbcd) > set session 1
session => 1
msf6 auxiliary(admin/ldap/rbcd) > run
[*] Running module against 10.5.132.252

[*] Discovering base DN automatically
[-] Auxiliary failed: NoMethodError undefined method `unpack' for nil:NilClass
[-] Call stack:
[-]   /home/tmoose/rapid7/metasploit-framework/lib/rex/proto/ldap.rb:110:in `read_ber'
[-]   /home/tmoose/.rvm/gems/ruby-3.1.0/gems/net-ldap-0.19.0/lib/net/ldap/connection.rb:236:in `block in read'
[-]   /home/tmoose/.rvm/gems/ruby-3.1.0/gems/net-ldap-0.19.0/lib/net/ldap/instrumentation.rb:19:in `instrument'
[-]   /home/tmoose/.rvm/gems/ruby-3.1.0/gems/net-ldap-0.19.0/lib/net/ldap/connection.rb:235:in `read'
[-]   /home/tmoose/.rvm/gems/ruby-3.1.0/gems/net-ldap-0.19.0/lib/net/ldap/connection.rb:203:in `queued_read'
[-]   /home/tmoose/rapid7/metasploit-framework/lib/rex/proto/ldap.rb:357:in `block (2 levels) in search'
[-]   /home/tmoose/rapid7/metasploit-framework/lib/rex/proto/ldap.rb:309:in `loop'
[-]   /home/tmoose/rapid7/metasploit-framework/lib/rex/proto/ldap.rb:309:in `block in search'
[-]   /home/tmoose/.rvm/gems/ruby-3.1.0/gems/net-ldap-0.19.0/lib/net/ldap/instrumentation.rb:19:in `instrument'
[-]   /home/tmoose/rapid7/metasploit-framework/lib/rex/proto/ldap.rb:298:in `search'
[-]   /home/tmoose/.rvm/gems/ruby-3.1.0/gems/net-ldap-0.19.0/lib/net/ldap.rb:786:in `block (2 levels) in search'
[-]   /home/tmoose/.rvm/gems/ruby-3.1.0/gems/net-ldap-0.19.0/lib/net/ldap.rb:1307:in `use_connection'
[-]   /home/tmoose/.rvm/gems/ruby-3.1.0/gems/net-ldap-0.19.0/lib/net/ldap.rb:785:in `block in search'
[-]   /home/tmoose/.rvm/gems/ruby-3.1.0/gems/net-ldap-0.19.0/lib/net/ldap/instrumentation.rb:19:in `instrument'
[-]   /home/tmoose/.rvm/gems/ruby-3.1.0/gems/net-ldap-0.19.0/lib/net/ldap.rb:784:in `search'
[-]   /home/tmoose/rapid7/metasploit-framework/modules/auxiliary/admin/ldap/rbcd.rb:112:in `ldap_get'
[-]   /home/tmoose/rapid7/metasploit-framework/modules/auxiliary/admin/ldap/rbcd.rb:149:in `block in run'
[-]   /home/tmoose/rapid7/metasploit-framework/lib/msf/core/optional_session/ldap.rb:51:in `ldap_connect'
[-]   /home/tmoose/rapid7/metasploit-framework/modules/auxiliary/admin/ldap/rbcd.rb:134:in `run'
[*] Auxiliary module execution completed
msf6 auxiliary(admin/ldap/rbcd) > 

@bwatters-r7
Copy link
Contributor

Same result for auxiliary/gather/asrep

msf6 auxiliary(gather/asrep) > show options

Module options (auxiliary/gather/asrep):

   Name          Current Setting  Required  Description
   ----          ---------------  --------  -----------
   Rhostname     WIN-JGPU2LIT1DJ  yes       The domain controller's hostname
   SSL           false            no        Enable SSL on the LDAP connection
   Timeout       10               yes       The TCP timeout to establish Kerberos connection and read data
   USE_RC4_HMAC  true             yes       Request using RC4 hash instead of default encryption types (faster to crack)


   When ACTION is BRUTE_FORCE:

   Name       Current Setting  Required  Description
   ----       ---------------  --------  -----------
   USER_FILE                   no        File containing usernames, one per line


   Used when making a new connection via RHOSTS:

   Name      Current Setting  Required  Description
   ----      ---------------  --------  -----------
   DOMAIN    example          no        The domain to authenticate to
   PASSWORD  v3Mpassword      no        The password to authenticate with
   RHOSTS    10.5.132.252     yes       The target KDC, see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasplo
                                        it.html
   RPORT     389              no        The target port
   USERNAME  Administrator    no        The username to authenticate with


   Used when connecting to LDAP over an existing SESSION:

   Name     Current Setting  Required  Description
   ----     ---------------  --------  -----------
   RHOSTS   10.5.132.252     yes       The target KDC, see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploi
                                       t.html
   SESSION                   no        The session to run this module on


Auxiliary action:

   Name  Description
   ----  -----------
   LDAP  Ask a domain controller directly for the susceptible user accounts



View the full module info with the info, or info -d command.

msf6 auxiliary(gather/asrep) > run
[*] Running module against 10.5.132.252


[-] No entries could be found for (&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=4194304))!
[*] Auxiliary module execution completed
msf6 auxiliary(gather/asrep) > set session 1
session => 1
msf6 auxiliary(gather/asrep) > run
[*] Running module against 10.5.132.252

[-] Auxiliary failed: NoMethodError undefined method `unpack' for nil:NilClass
[-] Call stack:
[-]   /home/tmoose/rapid7/metasploit-framework/lib/rex/proto/ldap.rb:110:in `read_ber'
[-]   /home/tmoose/.rvm/gems/ruby-3.1.0/gems/net-ldap-0.19.0/lib/net/ldap/connection.rb:236:in `block in read'
[-]   /home/tmoose/.rvm/gems/ruby-3.1.0/gems/net-ldap-0.19.0/lib/net/ldap/instrumentation.rb:19:in `instrument'
[-]   /home/tmoose/.rvm/gems/ruby-3.1.0/gems/net-ldap-0.19.0/lib/net/ldap/connection.rb:235:in `read'
[-]   /home/tmoose/.rvm/gems/ruby-3.1.0/gems/net-ldap-0.19.0/lib/net/ldap/connection.rb:203:in `queued_read'
[-]   /home/tmoose/rapid7/metasploit-framework/lib/rex/proto/ldap.rb:357:in `block (2 levels) in search'
[-]   /home/tmoose/rapid7/metasploit-framework/lib/rex/proto/ldap.rb:309:in `loop'
[-]   /home/tmoose/rapid7/metasploit-framework/lib/rex/proto/ldap.rb:309:in `block in search'
[-]   /home/tmoose/.rvm/gems/ruby-3.1.0/gems/net-ldap-0.19.0/lib/net/ldap/instrumentation.rb:19:in `instrument'
[-]   /home/tmoose/rapid7/metasploit-framework/lib/rex/proto/ldap.rb:298:in `search'
[-]   /home/tmoose/.rvm/gems/ruby-3.1.0/gems/net-ldap-0.19.0/lib/net/ldap.rb:786:in `block (2 levels) in search'
[-]   /home/tmoose/.rvm/gems/ruby-3.1.0/gems/net-ldap-0.19.0/lib/net/ldap.rb:1307:in `use_connection'
[-]   /home/tmoose/.rvm/gems/ruby-3.1.0/gems/net-ldap-0.19.0/lib/net/ldap.rb:785:in `block in search'
[-]   /home/tmoose/.rvm/gems/ruby-3.1.0/gems/net-ldap-0.19.0/lib/net/ldap/instrumentation.rb:19:in `instrument'
[-]   /home/tmoose/.rvm/gems/ruby-3.1.0/gems/net-ldap-0.19.0/lib/net/ldap.rb:784:in `search'
[-]   /home/tmoose/rapid7/metasploit-framework/lib/rex/proto/ldap/client.rb:73:in `discover_schema_naming_context'
[-]   /home/tmoose/rapid7/metasploit-framework/lib/rex/proto/ldap/client.rb:31:in `schema_dn'
[-]   /home/tmoose/rapid7/metasploit-framework/modules/auxiliary/gather/asrep.rb:112:in `block in run_ldap'
[-]   /home/tmoose/rapid7/metasploit-framework/lib/msf/core/optional_session/ldap.rb:51:in `ldap_connect'
[-]   /home/tmoose/rapid7/metasploit-framework/modules/auxiliary/gather/asrep.rb:106:in `run_ldap'
[-]   /home/tmoose/rapid7/metasploit-framework/modules/auxiliary/gather/asrep.rb:73:in `run'
[*] Auxiliary module execution completed
msf6 auxiliary(gather/asrep) > 

@bwatters-r7
Copy link
Contributor

I was unable to replicate these errors in the light of day; we think it might be because the session timed out and then silently failed.

@dwelch-r7
Copy link
Contributor Author

I was unable to replicate these errors in the light of day; we think it might be because the session timed out and then silently failed.

Did some poking arpund on this, seems that the default idle timeout for ldap connections is 15 minutes, after leaving a session idle for 15+ minutes I was able to replicate the issue you reported and I've added in some extra handling for inactive sessions and killing them when they are next interacted with

At some point we'll probably want some sort of keep alive function so the sessions can stay around longer but I think we don't need it for MVP
We have something similar already implemented for winrm which might be a good starting point for adding it here

def start_keep_alive_loop(framework)

@bwatters-r7 bwatters-r7 closed this pull request by merging all changes into rapid7:master in f3a8b35 May 15, 2024
@bwatters-r7
Copy link
Contributor

Release notes

This adds an LDAP session type allowing users and modules to interact directly with LDAP servers without uploading a payload.

@smcintyre-r7 smcintyre-r7 added the rn-enhancement release notes enhancement label May 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
rn-enhancement release notes enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants