@@ -42,7 +42,9 @@ def options(self, context, module_options):
4242 sys .exit (1 )
4343
4444 def authenticate (self , context , connection , protocol , anonymous = False ):
45+ # Authenticate to the target using DCE/RPC with either user credentials or a null session. Establishes a connection and binds to the SAMR service.
4546 try :
47+ # Map to the SAMR endpoint on the target
4648 string_binding = epm .hept_map (connection .host , samr .MSRPC_UUID_SAMR , protocol = protocol )
4749 rpctransport = transport .DCERPCTransportFactory (string_binding )
4850 rpctransport .setRemoteHost (connection .host )
@@ -62,6 +64,7 @@ def authenticate(self, context, connection, protocol, anonymous=False):
6264 )
6365 context .log .info (f"Connecting as { connection .domain } \\ { connection .username } " )
6466
67+ # Connect to the DCE/RPC endpoint and bind to the SAMR service
6568 dce = rpctransport .get_dce_rpc ()
6669 dce .connect ()
6770 context .log .info ("[+] Successfully connected to DCE/RPC" )
@@ -79,6 +82,7 @@ def on_login(self, context, connection):
7982
8083 new_lmhash , new_nthash = "" , ""
8184
85+ # Parse new hash values if provided
8286 if self .newhash :
8387 try :
8488 new_lmhash , new_nthash = self .newhash .split (":" )
@@ -89,6 +93,7 @@ def on_login(self, context, connection):
8993 self .anonymous = False
9094 self .dce = self .authenticate (context , connection , protocol = "ncacn_np" , anonymous = self .anonymous )
9195 except Exception as e :
96+ # Handle specific errors like password expiration or must be change
9297 if "STATUS_PASSWORD_MUST_CHANGE" in str (e ) or "STATUS_PASSWORD_EXPIRED" in str (e ):
9398 context .log .warning ("Password must be changed. Trying with null session." )
9499 self .anonymous = True
@@ -100,29 +105,33 @@ def on_login(self, context, connection):
100105 raise
101106
102107 try :
108+ # Perform the SMB SAMR password change
103109 self ._smb_samr_change (context , connection , target_username , target_domain , self .oldhash , self .newpass , new_nthash )
104110 except Exception as e :
105111 context .log .error (f"Password change failed: { e } " )
106112
107113 def _smb_samr_change (self , context , connection , target_username , target_domain , oldHash , newPassword , newHash ):
108114 try :
109115 if not self .anonymous :
110- server_handle = samr .hSamrConnect (self .dce , connection .host + "\x00 " )["ServerHandle" ]
116+ # Connect to the target server and retrieve handles
117+ server_handle = samr .hSamrConnect (self .dce , connection .host + "\x00 " )["ServerHandle" ] # Does not work for null session auth.
111118 domain_sid = samr .hSamrLookupDomainInSamServer (self .dce , server_handle , target_domain )["DomainId" ]
112119 domain_handle = samr .hSamrOpenDomain (self .dce , server_handle , domainId = domain_sid )["DomainHandle" ]
113120 user_rid = samr .hSamrLookupNamesInDomain (self .dce , domain_handle , (target_username ,))["RelativeIds" ]["Element" ][0 ]
114121 user_handle = samr .hSamrOpenUser (self .dce , domain_handle , userId = user_rid )["UserHandle" ]
115122
116123 if self .reset :
124+ # Change the password with new password hash
117125 samr .hSamrSetNTInternal1 (self .dce , user_handle , newPassword , newHash )
118126 context .log .success (f"Successfully changed password for { target_username } " )
119127 else :
120-
128+ # Change the password with new password
121129 samr .hSamrUnicodeChangePasswordUser2 (
122130 self .dce , "\x00 " , target_username , self .oldpass , newPassword , "" , ""
123131 )
124132 context .log .success (f"Successfully changed password for { target_username } " )
125133 else :
134+ # Handle anonymous/null session password change
126135 self .mustchangePassword (target_username , target_domain , self .oldpass , newPassword , "" , oldHash , "" , newHash )
127136 except Exception as e :
128137 context .log .fail (f"SMB-SAMR password change failed: { e } " )
@@ -131,11 +140,14 @@ def _smb_samr_change(self, context, connection, target_username, target_domain,
131140
132141 def mustchangePassword (self , target_username , targetDomain , oldPassword , newPassword , oldPwdHashLM , oldPwdHashNT , newPwdHashLM , newPwdHashNT ):
133142 if newPassword and oldPassword :
143+ # Change password using old and new plaintext passwords
134144 samr .hSamrUnicodeChangePasswordUser2 (self .dce , "\x00 " , target_username , oldPassword , newPassword , "" , "" )
135145 self .context .log .success (f"Successfully changed password for { target_username } " )
136146 elif newPassword and oldPwdHashNT :
147+ # Change password using hash for authentication
137148 samr .hSamrUnicodeChangePasswordUser2 (self .dce , "\x00 " , target_username , oldPassword , newPassword , "" , oldPwdHashNT )
138149 self .context .log .success (f"Successfully changed password for { target_username } " )
139150 else :
151+ # Use NT internal function to set new password or hash
140152 samr .hSamrSetNTInternal1 (self .dce , target_username , newPassword , newPwdHashNT )
141153 self .context .log .success (f"Successfully changed password for { target_username } " )
0 commit comments