66class NXCModule :
77 """
88 Module for changing or resetting user passwords
9- Module by Fagan Afandiyev and termanix
9+ Module by Fagan Afandiyev, termanix and NeffIsBack
1010 """
1111
1212 name = "change-password"
@@ -22,15 +22,13 @@ def options(self, context, module_options):
2222 NEWNTHASH The new NT hash of the user.
2323
2424 Optional:
25- OLDPASS The old password of the user (if not specified, the current password will be used)
26- OLDNTHASH The old NT hash of the user (if not specified, the current password will be used)
2725 USER The user account if the target is not the current user.
2826
2927 Examples
3028 --------
3129 If STATUS_PASSWORD_MUST_CHANGE or STATUS_PASSWORD_EXPIRED (Change password for current user)
32- netexec smb <DC_IP> -u username -p oldpass -M change-password -o OLDPASS='oldpass' NEWPASS='newpass'
33- netexec smb <DC_IP> -u username -H oldnthash -M change-password -o OLDNTHASH='oldnthash' NEWPASS='newpass'
30+ netexec smb <DC_IP> -u username -p oldpass -M change-password -o NEWPASS='newpass'
31+ netexec smb <DC_IP> -u username -H oldnthash -M change-password -o NEWPASS='newpass'
3432
3533 If want to change other user's password (with forcechangepassword priv or admin rights)
3634 netexec smb <DC_IP> -u username -p password -M change-password -o USER='target_user' NEWPASS='target_user_newpass'
@@ -39,10 +37,7 @@ def options(self, context, module_options):
3937 self .context = context
4038 self .newpass = module_options .get ("NEWPASS" )
4139 self .newhash = module_options .get ("NEWNTHASH" )
42- self .oldpass = module_options .get ("OLDPASS" )
43- self .oldhash = module_options .get ("OLDNTHASH" )
4440 self .target_user = module_options .get ("USER" )
45- self .reset = module_options .get ("RESET" , True )
4641
4742 if not self .newpass and not self .newhash :
4843 context .log .fail ("Either NEWPASS or NEWNTHASH is required!" )
@@ -87,11 +82,9 @@ def on_login(self, context, connection):
8782 target_username = self .target_user or connection .username
8883 target_domain = connection .domain
8984
90- # If OLDPASS or OLDHASH are not specified, default to the credentials used for authentication.
91- if not self .oldpass :
92- self .oldpass = connection .password
93- if not self .oldhash :
94- self .oldhash = connection .nthash
85+ # Grab all creds from the connection to use for authentication
86+ self .oldpass = connection .password
87+ self .oldhash = connection .nthash
9588
9689 new_lmhash , new_nthash = "" , ""
9790
@@ -125,42 +118,35 @@ def on_login(self, context, connection):
125118
126119 def _smb_samr_change (self , context , connection , target_username , target_domain , oldHash , newPassword , newHash ):
127120 try :
128- if not self .anonymous :
129- # Connect to the target server and retrieve handles
130- server_handle = samr .hSamrConnect (self .dce , connection .host + "\x00 " )["ServerHandle" ] # Does not work for null session auth.
131- domain_sid = samr .hSamrLookupDomainInSamServer (self .dce , server_handle , target_domain )["DomainId" ]
132- domain_handle = samr .hSamrOpenDomain (self .dce , server_handle , domainId = domain_sid )["DomainHandle" ]
133- user_rid = samr .hSamrLookupNamesInDomain (self .dce , domain_handle , (target_username ,))["RelativeIds" ]["Element" ][0 ]
134- user_handle = samr .hSamrOpenUser (self .dce , domain_handle , userId = user_rid )["UserHandle" ]
135-
136- if self .reset :
137- # Change the password with new password hash
138- samr .hSamrSetNTInternal1 (self .dce , user_handle , newPassword , newHash )
139- context .log .success (f"Successfully changed password for { target_username } " )
140- else :
141- # Change the password with new password
142- samr .hSamrUnicodeChangePasswordUser2 (self .dce , "\x00 " , target_username , self .oldpass , newPassword , "" , "" )
143- context .log .success (f"Successfully changed password for { target_username } " )
121+ # Reset the password for a different user
122+ if target_username != connection .username :
123+ user_handle = self .hSamrOpenUser (connection , target_username )
124+ samr .hSamrSetNTInternal1 (self .dce , user_handle , newPassword , newHash )
125+ context .log .success (f"Successfully changed password for { target_username } " )
144126 else :
145- # Handle anonymous/null session password change
146- self .mustchangePassword (target_username , target_domain , self .oldpass , newPassword , "" , oldHash , "" , newHash )
147- except AttributeError :
148- context .log .fail ("SMB-SAMR password change failed: Ensure that either the OLDPASS or OLDNTHASH option is provided and attempt again." )
127+ # Change password for the current user
128+ if newPassword :
129+ # Change the password with new password
130+ samr .hSamrUnicodeChangePasswordUser2 (self .dce , "\x00 " , target_username , self .oldpass , newPassword , "" , oldHash )
131+ else :
132+ # Change the password with new hash
133+ user_handle = self .hSamrOpenUser (connection , target_username )
134+ samr .hSamrChangePasswordUser (self .dce , user_handle , self .oldpass , "" , oldHash , "aad3b435b51404eeaad3b435b51404ee" , newHash )
135+ context .log .highlight ("Note: Target user must change password at next logon." )
136+ context .log .success (f"Successfully changed password for { target_username } " )
149137 except Exception as e :
150138 context .log .fail (f"SMB-SAMR password change failed: { e } " )
151139 finally :
152140 self .dce .disconnect ()
153141
154- def mustchangePassword (self , target_username , targetDomain , oldPassword , newPassword , oldPwdHashLM , oldPwdHashNT , newPwdHashLM , newPwdHashNT ):
155- if newPassword and oldPassword :
156- # Change password using old and new plaintext passwords
157- samr .hSamrUnicodeChangePasswordUser2 (self .dce , "\x00 " , target_username , oldPassword , newPassword , "" , "" )
158- self .context .log .success (f"Successfully changed password for { target_username } " )
159- elif newPassword and oldPwdHashNT :
160- # Change password using hash for authentication
161- samr .hSamrUnicodeChangePasswordUser2 (self .dce , "\x00 " , target_username , oldPassword , newPassword , "" , oldPwdHashNT )
162- self .context .log .success (f"Successfully changed password for { target_username } " )
163- else :
164- # Use NT internal function to set new password or hash
165- samr .hSamrSetNTInternal1 (self .dce , target_username , newPassword , newPwdHashNT )
166- self .context .log .success (f"Successfully changed password for { target_username } " )
142+ def hSamrOpenUser (self , connection , username ):
143+ """Get handle to the user object"""
144+ try :
145+ # Connect to the target server and retrieve handles
146+ server_handle = samr .hSamrConnect (self .dce , connection .host + "\x00 " )["ServerHandle" ]
147+ domain_sid = samr .hSamrLookupDomainInSamServer (self .dce , server_handle , connection .domain )["DomainId" ]
148+ domain_handle = samr .hSamrOpenDomain (self .dce , server_handle , domainId = domain_sid )["DomainHandle" ]
149+ user_rid = samr .hSamrLookupNamesInDomain (self .dce , domain_handle , (username ,))["RelativeIds" ]["Element" ][0 ]
150+ return samr .hSamrOpenUser (self .dce , domain_handle , userId = user_rid )["UserHandle" ]
151+ except Exception as e :
152+ self .context .log .fail (f"Failed to open user: { e } " )
0 commit comments