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

ntlmrelayx.py LDAP socksserver: Support for multiple simultaneous LDAP connections #1877

Open
rtpt-romankarwacik opened this issue Jan 23, 2025 · 2 comments

Comments

@rtpt-romankarwacik
Copy link
Contributor

rtpt-romankarwacik commented Jan 23, 2025

Apps using mutliple simultaneous LDAP connections do not work with the new LDAP socks proxy, as only one connection per user/target is supported. Using the message IDs of the LDAP requests it should be possible to handle multiple simultanoeus connections.

One example of this using bloodhound-python:

$ ntlmrelayx.py -t 'ldap://DCIP' -6 --no-smb --no-dump --no-da --no-acl --no-validate-privs -socks --keep-relaying --no-wcf-server --no-raw-server
Impacket v0.13.0.dev0+20250106.113739.9e3f4d8b - Copyright Fortra, LLC and its affiliated companies 

[*] Protocol Client IMAP loaded..
[*] Protocol Client IMAPS loaded..
[*] Protocol Client MSSQL loaded..
[*] Protocol Client HTTP loaded..
[*] Protocol Client HTTPS loaded..
[*] Protocol Client DCSYNC loaded..
[*] Protocol Client SMB loaded..
[*] Protocol Client RPC loaded..
[*] Protocol Client LDAP loaded..
[*] Protocol Client LDAPS loaded..
[*] Protocol Client SMTP loaded..
[*] Running in relay mode to single host
[*] SOCKS proxy started. Listening on 127.0.0.1:1080
[*] IMAPS Socks Plugin loaded..
[*] LDAP Socks Plugin loaded..
[*] HTTP Socks Plugin loaded..
[*] SMTP Socks Plugin loaded..
[*] SMB Socks Plugin loaded..
[*] LDAPS Socks Plugin loaded..
[*] IMAP Socks Plugin loaded..
[*] HTTPS Socks Plugin loaded..
[*] MSSQL Socks Plugin loaded..
[*] Setting up HTTP Server on port 80
 * Serving Flask app 'impacket.examples.ntlmrelayx.servers.socksserver'
 * Debug mode: off
[*] Multirelay disabled

[*] Servers started, waiting for connections
Type help for list of commands
ntlmrelayx> [*] HTTPD(80): Client requested path: /
[*] HTTPD(80): Connection from ::1 controlled, attacking target ldap://DCIP
[*] HTTPD(80): Client requested path: /
[*] HTTPD(80): Authenticating against ldap://DCIP as DOMAIN/USER SUCCEED
[*] SOCKS: Adding DOMAIN/USER@DCIP(389) to active SOCKS connection. Enjoy
----------------------------------------
Exception occurred during processing of request from ('127.0.0.1', 60388)
Traceback (most recent call last):
  File "/usr/lib/python3.11/socketserver.py", line 691, in process_request_thread
    self.finish_request(request, client_address)
  File "/usr/lib/python3.11/socketserver.py", line 361, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/usr/share/redteam-python-attacktools/python-lib/impacket/examples/ntlmrelayx/servers/socksserver.py", line 292, in __init__
    socketserver.BaseRequestHandler.__init__(self, request, client_address, server)
  File "/usr/lib/python3.11/socketserver.py", line 755, in __init__
    self.handle()
  File "/usr/share/redteam-python-attacktools/python-lib/impacket/examples/ntlmrelayx/servers/socksserver.py", line 328, in handle
    hostLength = unpack('!B',request['PAYLOAD'][0])[0]
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: a bytes-like object is required, not 'int'
----------------------------------------
[*] LDAP: Proxying client session for DOMAIN/USER@10.8.1.4(389)
[-] LDAP: Connection for DOMAIN/USER@DCIP(389) is being used at the moment!
[-] LDAP: Connection for DOMAIN/USER@DCIP(389) is being used at the moment!
----------------------------------------
Exception occurred during processing of request from ('127.0.0.1', 39296)
Traceback (most recent call last):
  File "/usr/lib/python3.11/socketserver.py", line 691, in process_request_thread
    self.finish_request(request, client_address)
  File "/usr/lib/python3.11/socketserver.py", line 361, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/usr/share/redteam-python-attacktools/python-lib/impacket/examples/ntlmrelayx/servers/socksserver.py", line 292, in __init__
    socketserver.BaseRequestHandler.__init__(self, request, client_address, server)
  File "/usr/lib/python3.11/socketserver.py", line 755, in __init__
    self.handle()
  File "/usr/share/redteam-python-attacktools/python-lib/impacket/examples/ntlmrelayx/servers/socksserver.py", line 328, in handle
    hostLength = unpack('!B',request['PAYLOAD'][0])[0]
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: a bytes-like object is required, not 'int'
----------------------------------------

$ proxychains bloodhound-python -u "USER" -d "DOMAIN" -p " " -c DCOnly
[proxychains] config file found: /etc/proxychains4.conf
[proxychains] preloading /usr/lib/x86_64-linux-gnu/libproxychains.so.4
[proxychains] DLL init: proxychains-ng 4.16
[proxychains] DLL init: proxychains-ng 4.16
INFO: BloodHound.py for BloodHound Community Edition
INFO: Found AD domain: DOMAIN
INFO: Getting TGT for user
[proxychains] Strict chain  ...  127.0.0.1:1080  ...  DCIP:88 <--socket error or timeout!
WARNING: Failed to get Kerberos TGT. Falling back to NTLM authentication. Error: [Errno Connection error (DCIP:88)] [Errno 111] Connection refused
INFO: Connecting to LDAP server: DCIP
[proxychains] Strict chain  ...  127.0.0.1:1080  ...  DCIP:389  ...  OK
INFO: Found 1 domains
INFO: Found 1 domains in the forest
INFO: Connecting to LDAP server: DCIP
[proxychains] Strict chain  ...  127.0.0.1:1080  ...  DCIP:389  ...  OK
Exception in thread Thread-4 (_handle_results):
Traceback (most recent call last):
  File "/usr/share/redteam-python-attacktools/python-lib/bloodhound/ad/utils.py", line 474, in resolve_aces
    linkitem = self.addomain.newsidcache.get(ace['sid'])
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/share/redteam-python-attacktools/python-lib/bloodhound/ad/utils.py", line 576, in get
    return self._cache[entry]
           ~~~~~~~~~~~^^^^^^^
KeyError: 'S-1-5-21-[...]-512'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3.11/threading.py", line 1038, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.11/threading.py", line 975, in run
    self._target(*self._args, **self._kwargs)
  File "/usr/lib/python3.11/multiprocessing/pool.py", line 595, in _handle_results
    cache[job]._set(i, obj)
  File "/usr/lib/python3.11/multiprocessing/pool.py", line 779, in _set
    self._callback(self._value)
  File "/usr/share/redteam-python-attacktools/python-lib/bloodhound/enumeration/memberships.py", line 733, in process_acldata
    data['Aces'] += self.aceresolver.resolve_aces(aces)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/share/redteam-python-attacktools/python-lib/bloodhound/ad/utils.py", line 479, in resolve_aces
    ldapentry = self.resolver.resolve_sid(ace['sid'], use_gc)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/share/redteam-python-attacktools/python-lib/bloodhound/enumeration/objectresolver.py", line 123, in resolve_sid
    if not self.addc.ldap_connect(resolver=True):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/share/redteam-python-attacktools/python-lib/bloodhound/ad/domain.py", line 70, in ldap_connect
    ldap = self.ad.auth.getLDAPConnection(hostname=self.hostname, ip=ip,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/share/redteam-python-attacktools/python-lib/bloodhound/ad/authentication.py", line 164, in getLDAPConnection
    bound = conn.bind()
            ^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/ldap3/core/connection.py", line 628, in bind
    response = self.do_ntlm_bind(controls)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/ldap3/core/connection.py", line 1398, in do_ntlm_bind
    response = self.post_send_single_response(self.send('bindRequest', request, controls))
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/ldap3/strategy/sync.py", line 160, in post_send_single_response
    responses, result = self.get_response(message_id)
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/ldap3/strategy/base.py", line 370, in get_response
    raise LDAPSessionTerminatedByServerError(self.connection.last_error)
ldap3.core.exceptions.LDAPSessionTerminatedByServerError: session terminated by server
INFO: Connecting to LDAP server: DCIP
[proxychains] Strict chain  ...  127.0.0.1:1080  ...  DCIP:389  ...  OK
Traceback (most recent call last):
  File "/usr/share/redteam-python-attacktools/python-lib/bloodhound/ad/utils.py", line 474, in resolve_aces
    linkitem = self.addomain.newsidcache.get(ace['sid'])
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/share/redteam-python-attacktools/python-lib/bloodhound/ad/utils.py", line 576, in get
    return self._cache[entry]
           ~~~~~~~~~~~^^^^^^^
KeyError: 'S-1-5-21-[...]-1220'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/share/redteam-python-attacktools/bin/bloodhound-python", line 8, in <module>
    sys.exit(main())
             ^^^^^^
  File "/usr/share/redteam-python-attacktools/python-lib/bloodhound/__init__.py", line 347, in main
    bloodhound.run(collect=collect,
  File "/usr/share/redteam-python-attacktools/python-lib/bloodhound/__init__.py", line 81, in run
    membership_enum.enumerate_memberships(timestamp=timestamp, fileNamePrefix=fileNamePrefix)
  File "/usr/share/redteam-python-attacktools/python-lib/bloodhound/enumeration/memberships.py", line 854, in enumerate_memberships
    self.enumerate_users(timestamp, fileNamePrefix)
  File "/usr/share/redteam-python-attacktools/python-lib/bloodhound/enumeration/memberships.py", line 209, in enumerate_users
    self.parse_gmsa(user, entry)
  File "/usr/share/redteam-python-attacktools/python-lib/bloodhound/enumeration/memberships.py", line 720, in parse_gmsa
    processed_aces = self.aceresolver.resolve_aces(aces)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/share/redteam-python-attacktools/python-lib/bloodhound/ad/utils.py", line 479, in resolve_aces
    ldapentry = self.resolver.resolve_sid(ace['sid'], use_gc)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/share/redteam-python-attacktools/python-lib/bloodhound/enumeration/objectresolver.py", line 123, in resolve_sid
    if not self.addc.ldap_connect(resolver=True):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/share/redteam-python-attacktools/python-lib/bloodhound/ad/domain.py", line 70, in ldap_connect
    ldap = self.ad.auth.getLDAPConnection(hostname=self.hostname, ip=ip,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/share/redteam-python-attacktools/python-lib/bloodhound/ad/authentication.py", line 164, in getLDAPConnection
    bound = conn.bind()
            ^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/ldap3/core/connection.py", line 628, in bind
    response = self.do_ntlm_bind(controls)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/ldap3/core/connection.py", line 1398, in do_ntlm_bind
    response = self.post_send_single_response(self.send('bindRequest', request, controls))
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/ldap3/strategy/sync.py", line 160, in post_send_single_response
    responses, result = self.get_response(message_id)
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/ldap3/strategy/base.py", line 370, in get_response
    raise LDAPSessionTerminatedByServerError(self.connection.last_error)
ldap3.core.exceptions.LDAPSessionTerminatedByServerError: session terminated by server
Traceback (most recent call last):
  File "/usr/lib/python3.11/multiprocessing/util.py", line 300, in _run_finalizers
    finalizer()
  File "/usr/lib/python3.11/multiprocessing/util.py", line 224, in __call__
    res = self._callback(*self._args, **self._kwargs)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/multiprocessing/pool.py", line 698, in _terminate_pool
    raise AssertionError(
AssertionError: Cannot have cache with result_hander not alive
@anadrianmanrique
Copy link
Contributor

Hi @rtpt-romankarwacik. As @b1two pointed out in the original PR (#1825) #1825 (comment) there are some issues related to bloodhound issuing simultaneous connections. @b1two suggested a workaround to be applied on the bloodhound side. From the impacket side, I don't think there's much to do, as we are reusing a fixed authenticated connection. Maybe in a scenario with a pool of connections to the same target would work, but that depends on externals factors, like if the operator is able to coerce several connections to the relay or not.

@rtpt-romankarwacik
Copy link
Contributor Author

@anadrianmanrique Thank you, I missed that comment. My idea was, that per socks LDAP client the LDAP requests' message IDs could be rewritten and sent via one outgoing LDAP connection. This way, only one authenticated connection per target is needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants