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

New LDAP Flag Find Delegation #381

Merged
merged 19 commits into from
Nov 14, 2024
Merged

Conversation

termanix
Copy link
Contributor

Added the --find-delegation LDAP flag, implemented from the impacket-findDelegation tool.

image

@NeffIsBack NeffIsBack added the enhancement New feature or request label Jul 26, 2024
Added try except on header

Signed-off-by: termanix <[email protected]>
Signed-off-by: termanix <[email protected]>
mpgn
mpgn previously approved these changes Sep 29, 2024
@mpgn mpgn added this to the v1.3.0 milestone Sep 29, 2024
@NeffIsBack NeffIsBack modified the milestones: v1.3.0, v1.4.0 Oct 6, 2024
@NeffIsBack
Copy link
Contributor

Getting some weird exceptions from impacket here:

┌──(kalikali)-[~/Git/NetExec]  (find-delegate)
└─$ poetry run nxc ldap 192.168.56.11 -u 'eddard.stark' -p 'FightP3aceAndHonor!' --find-delegation
SMB         192.168.56.11   445    WINTERFELL       [*] Windows 10 / Server 2019 Build 17763 x64 (name:WINTERFELL) (domain:north.sevenkingdoms.local) (signing:True) (SMBv1:False)
LDAP        192.168.56.11   389    WINTERFELL       [+] north.sevenkingdoms.local\eddard.stark:FightP3aceAndHonor! (Pwn3d!)
[{'objectCategory': 'CN=Person,CN=Schema,CN=Configuration,DC=sevenkingdoms,DC=local',
  'pwdLastSet': '133562920842332063',
  'sAMAccountName': 'sansa.stark',
  'userAccountControl': '590336'},
 {'msDS-AllowedToDelegateTo': 'CIFS/winterfell',
  'objectCategory': 'CN=Person,CN=Schema,CN=Configuration,DC=sevenkingdoms,DC=local',
  'pwdLastSet': '133562920968709384',
  'sAMAccountName': 'jon.snow',
  'userAccountControl': '16843264'},
 {'msDS-AllowedToActOnBehalfOfOtherIdentity': '\x01\x00\x04\x80\x1c'
                                              '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x04\x00\x08\x00\x00\x00\x00\x00\x01\x02\x00\x00\x00\x00\x00\x05 '
                                              '\x00\x00\x00 \x02\x00\x00',
  'objectCategory': 'CN=Computer,CN=Schema,CN=Configuration,DC=sevenkingdoms,DC=local',
  'pwdLastSet': '133711683096745392',
  'sAMAccountName': 'RBCD-COMPUTER$',
  'userAccountControl': '4128'},
 {'msDS-AllowedToDelegateTo': 'HTTP/winterfell',
  'objectCategory': 'CN=Computer,CN=Schema,CN=Configuration,DC=sevenkingdoms,DC=local',
  'pwdLastSet': '133712520277077207',
  'sAMAccountName': 'CASTELBLACK$',
  'userAccountControl': '4096'}]
[16:16:52] ERROR    Skipping item, cannot process due to error 'or' filter must have at least one element                                                                           ldap.py:1193
                    ╭───────────────────────────────────────────────────────────── Traceback (most recent call last) ─────────────────────────────────────────────────────────────╮             
                    │ /home/kali/Git/NetExec/nxc/protocols/ldap.py:1171 in find_delegation                                                                                        │             
                    │                                                                                                                                                             │             
                    │   1168 │   │   │   │   │   │   for ace in sd["Dacl"].aces:                                                                                                  │             
                    │   1169 │   │   │   │   │   │   │   search_filter = search_filter + "(objectSid=" +                                                                          │             
                    │        ace["Ace"]["Sid"].formatCanonical() + ")"                                                                                                            │             
                    │   1170 │   │   │   │   │   │   search_filter = search_filter +                                                                                              │             
                    │        ")(!(UserAccountControl:1.2.840.113556.1.4.803:=2)))"                                                                                                │             
                    │ ❱ 1171 │   │   │   │   │   │   delegUserResp = self.search(search_filter,                                                                                   │             
                    │        attributes=["sAMAccountName", "objectCategory"], sizeLimit=999)                                                                                      │             
                    │   1172 │   │   │   │   │   │   for item2 in delegUserResp:                                                                                                  │             
                    │   1173 │   │   │   │   │   │   │   if isinstance(item2, ldapasn1_impacket.SearchResultEntry) is
not True:                                                                                                                                            │             
                    │   1174 │   │   │   │   │   │   │   │   continue                                                                                                             │             
                    │                                                                                                                                                             │             
                    │ /home/kali/Git/NetExec/nxc/protocols/ldap.py:705 in search                                                                                                  │             
                    │                                                                                                                                                             │             
                    │    702 │   │   │   │                                                                                                                                        │             
                    │    703 │   │   │   │   # Microsoft Active Directory set an hard limit of 1000 entries returned                                                              │             by any search                                                                                                                                        │             
                    │    704 │   │   │   │   paged_search_control =                                                                                                               │             
                    │        ldapasn1_impacket.SimplePagedResultsControl(criticality=True, size=1000)                                                                             │             
                    │ ❱  705 │   │   │   │   return self.ldapConnection.search(                                                                                                   │             
                    │    706 │   │   │   │   │   searchFilter=searchFilter,                                                                                                       │             
                    │    707 │   │   │   │   │   attributes=attributes,                                                                                                           │             
                    │    708 │   │   │   │   │   sizeLimit=sizeLimit,                                                                                                             │             
                    │                                                                                                                                                             │             
                    │ /home/kali/.cache/pypoetry/virtualenvs/netexec-RzaU0oFN-py3.12/lib/python3.12/site-packages/impacket/ldap/ldap.py:388 in search                             │             
                    │                                                                                                                                                             │             
                    │   385 │   │   searchRequest['sizeLimit'] = sizeLimit                                                                                                        │             
                    │   386 │   │   searchRequest['timeLimit'] = timeLimit                                                                                                        │             
                    │   387 │   │   searchRequest['typesOnly'] = typesOnly                                                                                                        │             
                    │ ❱ 388 │   │   searchRequest['filter'] = self._parseFilter(searchFilter)                                                                                     │             
                    │   389 │   │   searchRequest['attributes'].setComponents(*attributes)                                                                                        │             
                    │   390 │   │                                                                                                                                                 │             
                    │   391 │   │   done = False                                                                                                                                  │             
                    │                                                                                                                                                             │             
                    │ /home/kali/.cache/pypoetry/virtualenvs/netexec-RzaU0oFN-py3.12/lib/python3.12/site-packages/impacket/ldap/ldap.py:495 in _parseFilter                       │             
                    │                                                                                                                                                             │             
                    │   492 │   │   except AttributeError:                                                                                                                        │             
                    │   493 │   │   │   pass                                                                                                                                      │             
                    │   494 │   │   filterList = list(reversed(filterStr))                                                                                                        │             
                    │ ❱ 495 │   │   searchFilter = self._consumeCompositeFilter(filterList)                                                                                       │             
                    │   496 │   │   if filterList:  # we have not consumed the whole filter string                                                                                │             497 │   │   │   raise LDAPFilterSyntaxError("unexpected token: '%s'" % filterList[-1])                                                                    │             
                    │   498 │   │   return searchFilter                                                                                                                           │             
                    │                                                                                                                                                             │             
                    │ /home/kali/.cache/pypoetry/virtualenvs/netexec-RzaU0oFN-py3.12/lib/python3.12/site-packages/impacket/ldap/ldap.py:520 in _consumeCompositeFilter            │             
                    │                                                                                                                                                             │             
                    │   517 │   │   filters = []                                                                                                                                  │             
                    │   518 │   │   while True:                                                                                                                                   │             
                    │   519 │   │   │   try:                                                                                                                                      │             
                    │ ❱ 520 │   │   │   │   filters.append(self._consumeCompositeFilter(filterList))                                                                              │             
                    │   521 │   │   │   except LDAPFilterSyntaxError:                                                                                                             │             
                    │   522 │   │   │   │   break                                                                                                                                 │             
                    │   523                                                                                                                                                       │             
                    │                                                                                                                                                             │             
                    │ /home/kali/.cache/pypoetry/virtualenvs/netexec-RzaU0oFN-py3.12/lib/python3.12/site-packages/impacket/ldap/ldap.py:532 in _consumeCompositeFilter            │             
                    │                                                                                                                                                             │             
                    │   529 │   │   │   filterList.append(c)                                                                                                                      │             
                    │   530 │   │   │   raise LDAPFilterSyntaxError("unexpected token: '%s'" % c)                                                                                 │             
                    │   531 │   │                                                                                                                                                 │             
                    │ ❱ 532 │   │   return self._compileCompositeFilter(operator, filters)                                                                                        │             
                    │   533 │                                                                                                                                                     │             
                    │   534def _consumeSimpleFilter(self, filterList):                                                                                                       │             
                    │   535 │   │   try:                                                                                                                                          │             
                    │                                                                                                                                                             │             
                    │ /home/kali/.cache/pypoetry/virtualenvs/netexec-RzaU0oFN-py3.12/lib/python3.12/site-packages/impacket/ldap/ldap.py:579 in _compileCompositeFilter            │             
                    │                                                                                                                                                             │             
                    │   576 │   │   │   searchFilter['and'].setComponents(*filters)                                                                                               │             
                    │   577 │   │   elif operator == '|':                                                                                                                         │             
                    │   578 │   │   │   if len(filters) == 0:                                                                                                                     │             
                    │ ❱ 579 │   │   │   │   raise LDAPFilterInvalidException("'or' filter must have at least one                                                                  │             
                    │       element")                                                                                                                                             │             
                    │   580 │   │   │   searchFilter['or'].setComponents(*filters)                                                                                                │             
                    │   581 │   │                                                                                                                                                 │             
                    │   582 │   │   return searchFilter                                                                                                                           │             
                    ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯             
                    LDAPFilterInvalidException: 'or' filter must have at least one element                                                                                                      
LDAP        192.168.56.11   389    WINTERFELL       [-] Header Index error list index out of range

Added processAttributeValue Function
A new helper function was introduced to process the content of LDAP AttributeValue objects.

Updated printTable Function

Resource-Based Constrained Delegation Processing

Added Constant Variables
Constant variables were defined for userAccountControl values.

Modular Code Structure
The overall structure was made more modular; functions were clearly separated for better readability.

Signed-off-by: termanix <[email protected]>
@termanix
Copy link
Contributor Author

termanix commented Oct 7, 2024

After updates
image

mpgn
mpgn previously approved these changes Oct 7, 2024
Copy link
Contributor

@NeffIsBack NeffIsBack left a comment

Choose a reason for hiding this comment

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

Some small changes are left.
I also thought about we check for accounts that are sensitive for delegation. Any idea where that could be integrated well? Perhaps a new column? As we already query the UserAccountControl this should easily doable.

nxc/protocols/ldap.py Outdated Show resolved Hide resolved
nxc/protocols/ldap.py Outdated Show resolved Hide resolved
@termanix
Copy link
Contributor Author

Some small changes are left.

I also thought about we check for accounts that are sensitive for delegation. Any idea where that could be integrated well? Perhaps a new column? As we already query the UserAccountControl this should easily doable.

Probabyly new column could be better. It also makes reading easier.

Copy link
Contributor

@NeffIsBack NeffIsBack left a comment

Choose a reason for hiding this comment

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

LGTM 👍
image

@NeffIsBack NeffIsBack merged commit 0da04dd into Pennyw0rth:main Nov 14, 2024
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants