Skip to content

Commit 29de0cc

Browse files
authored
Used parse_result_attributes for parsing
Signed-off-by: termanix <50464194+termanix@users.noreply.github.com>
1 parent 7db7de4 commit 29de0cc

1 file changed

Lines changed: 58 additions & 52 deletions

File tree

nxc/protocols/ldap.py

Lines changed: 58 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
from impacket.ldap import ldap as ldap_impacket
3030
from impacket.ldap import ldaptypes
3131
from impacket.ldap import ldapasn1 as ldapasn1_impacket
32+
from impacket.ldap.ldapasn1 import AttributeValue
3233
from impacket.ldap.ldap import LDAPFilterSyntaxError
3334
from impacket.smb import SMB_DIALECT
3435
from impacket.smbconnection import SMBConnection, SessionError
@@ -1100,92 +1101,97 @@ def processAttributeValue(attribute):
11001101

11011102
def printTable(items, header):
11021103
colLen = []
1104+
1105+
# Calculating maximum lenght before parsing CN.
11031106
for i, col in enumerate(header):
1104-
rowMaxLen = max(len(str(row[i])) for row in items)
1107+
rowMaxLen = max(len(row[1].split(",")[0].split("CN=")[-1]) for row in items) if i == 1 else max(len(str(row[i])) for row in items)
11051108
colLen.append(max(rowMaxLen, len(col)))
11061109

11071110
# Create the format string for each row
11081111
outputFormat = " ".join([f"{{{num}:{width}s}}" for num, width in enumerate(colLen)])
11091112

1113+
# Print header
11101114
self.logger.highlight(outputFormat.format(*header))
11111115
self.logger.highlight(" ".join(["-" * itemLen for itemLen in colLen]))
11121116

11131117
# Print rows
11141118
for row in items:
1115-
# Burada DelegationRightsTo'yu düzeltmek için join() ekleyin
1119+
# Get first CN value.
1120+
if "CN=" in row[1]:
1121+
row[1] = row[1].split(",")[0].split("CN=")[-1]
1122+
1123+
# Added join for DelegationRightsTo
11161124
row[3] = ", ".join(str(x) for x in row[3]) if isinstance(row[3], list) else row[3]
1125+
11171126
self.logger.highlight(outputFormat.format(*row))
1118-
1127+
11191128
# Building the search filter
11201129
search_filter = ("(&(|(UserAccountControl:1.2.840.113556.1.4.803:=16777216)"
11211130
"(UserAccountControl:1.2.840.113556.1.4.803:=524288)"
11221131
"(msDS-AllowedToDelegateTo=*)(msDS-AllowedToActOnBehalfOfOtherIdentity=*))"
11231132
"(!(UserAccountControl:1.2.840.113556.1.4.803:=2))"
11241133
"(!(UserAccountControl:1.2.840.113556.1.4.803:=8192)))")
1125-
1134+
11261135
attributes = ["sAMAccountName", "pwdLastSet", "userAccountControl", "objectCategory",
11271136
"msDS-AllowedToActOnBehalfOfOtherIdentity", "msDS-AllowedToDelegateTo"]
11281137

11291138
resp = self.search(search_filter, attributes, 0)
1130-
11311139
answers = []
11321140
self.logger.debug(f"Total of records returned {len(resp):d}")
1141+
resp_parse = parse_result_attributes(resp)
11331142

1134-
for item in resp:
1135-
if not isinstance(item, ldapasn1_impacket.SearchResultEntry):
1136-
continue
1137-
1143+
for item in resp_parse:
11381144
mustCommit = False
11391145
sAMAccountName = ""
11401146
userAccountControl = 0
11411147
delegation = ""
11421148
objectType = ""
11431149
rightsTo = []
11441150
protocolTransition = 0
1145-
1151+
11461152
try:
1147-
for attribute in item["attributes"]:
1148-
if str(attribute["type"]) == "sAMAccountName":
1149-
sAMAccountName = str(attribute["vals"][0])
1150-
mustCommit = True
1151-
elif str(attribute["type"]) == "userAccountControl":
1152-
userAccountControl = str(attribute["vals"][0])
1153-
if int(userAccountControl) & UF_TRUSTED_FOR_DELEGATION:
1154-
delegation = "Unconstrained"
1155-
rightsTo.append("N/A")
1156-
elif int(userAccountControl) & UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION:
1157-
delegation = "Constrained w/ Protocol Transition"
1158-
protocolTransition = 1
1159-
elif str(attribute["type"]) == "objectCategory":
1160-
objectType = str(attribute["vals"][0]).split("=")[1].split(",")[0]
1161-
elif str(attribute["type"]) == "msDS-AllowedToDelegateTo":
1162-
if protocolTransition == 0:
1163-
delegation = "Constrained"
1164-
rightsTo = [processAttributeValue(val) for val in attribute["vals"]]
1165-
1166-
# Not an elif as an object could both have RBCD and another type of delegation
1167-
if str(attribute["type"]) == "msDS-AllowedToActOnBehalfOfOtherIdentity":
1168-
rbcdRights = []
1169-
rbcdObjType = []
1170-
sd = ldaptypes.SR_SECURITY_DESCRIPTOR(data=bytes(attribute["vals"][0]))
1171-
search_filter = "(&(|"
1172-
for ace in sd["Dacl"].aces:
1173-
search_filter += "(objectSid=" + ace["Ace"]["Sid"].formatCanonical() + ")"
1174-
search_filter += ")(!(UserAccountControl:1.2.840.113556.1.4.803:=2)))"
1175-
delegUserResp = self.search(search_filter, attributes=["sAMAccountName", "objectCategory"], sizeLimit=999)
1176-
1177-
for item2 in delegUserResp:
1178-
if not isinstance(item2, ldapasn1_impacket.SearchResultEntry):
1179-
continue
1180-
rbcdRights.append(str(item2["attributes"][0]["vals"][0]))
1181-
rbcdObjType.append(str(item2["attributes"][1]["vals"][0]).split("=")[1].split(",")[0])
1182-
1183-
if mustCommit:
1184-
if int(userAccountControl) & UF_ACCOUNTDISABLE:
1185-
self.logger.debug(f"Bypassing disabled account {sAMAccountName}")
1186-
else:
1187-
for rights, objType in zip(rbcdRights, rbcdObjType):
1188-
answers.append([rights, objType, "Resource-Based Constrained", sAMAccountName])
1153+
sAMAccountName = item.get("sAMAccountName")
1154+
mustCommit = sAMAccountName is not None
1155+
1156+
userAccountControl = int(item.get("userAccountControl", 0))
1157+
objectType = item.get("objectCategory")
1158+
1159+
if userAccountControl & UF_TRUSTED_FOR_DELEGATION:
1160+
delegation = "Unconstrained"
1161+
rightsTo.append("N/A")
1162+
elif userAccountControl & UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION:
1163+
delegation = "Constrained w/ Protocol Transition"
1164+
protocolTransition = 1
1165+
1166+
if item.get("msDS-AllowedToDelegateTo") is not None:
1167+
if protocolTransition == 0:
1168+
delegation = "Constrained"
1169+
rightsTo = item.get("msDS-AllowedToDelegateTo")
1170+
1171+
# Not an elif as an object could both have RBCD and another type of delegation
1172+
if item.get("msDS-AllowedToActOnBehalfOfOtherIdentity") is not None:
1173+
databyte = AttributeValue(item.get("msDS-AllowedToActOnBehalfOfOtherIdentity")) # STR to impacket.ldap.ldapasn1.AttributeValue
1174+
rbcdRights = []
1175+
rbcdObjType = []
1176+
sd = ldaptypes.SR_SECURITY_DESCRIPTOR(data=bytes(databyte))
1177+
search_filter = "(&(|"
1178+
for ace in sd["Dacl"].aces:
1179+
search_filter += "(objectSid=" + ace["Ace"]["Sid"].formatCanonical() + ")"
1180+
search_filter += ")(!(UserAccountControl:1.2.840.113556.1.4.803:=2)))"
1181+
delegUserResp = self.search(search_filter, attributes=["sAMAccountName", "objectCategory"], sizeLimit=999)
1182+
1183+
for item2 in delegUserResp:
1184+
if not isinstance(item2, ldapasn1_impacket.SearchResultEntry):
1185+
continue
1186+
rbcdRights.append(str(item2["attributes"][0]["vals"][0]))
1187+
rbcdObjType.append(str(item2["attributes"][1]["vals"][0]).split("=")[1].split(",")[0])
1188+
1189+
if mustCommit:
1190+
if int(userAccountControl) & UF_ACCOUNTDISABLE:
1191+
self.logger.debug(f"Bypassing disabled account {sAMAccountName}")
1192+
else:
1193+
for rights, objType in zip(rbcdRights, rbcdObjType):
1194+
answers.append([rights, objType, "Resource-Based Constrained", sAMAccountName])
11891195

11901196
if delegation in ["Unconstrained", "Constrained", "Constrained w/ Protocol Transition"] and mustCommit:
11911197
if int(userAccountControl) & UF_ACCOUNTDISABLE:

0 commit comments

Comments
 (0)