The challenge took place during Northsec 2023, an annual cybersecurity event held in Montreal. I was lucky enough to take part in this event thanks to École 2600. For a bit of context, in the Northsec CTF we all embodied employees of the corporation and in this challenge we were one employee in charge of an investigation. In addition to this scenario all the CTF and the Windows track were in IPv6, which posed some problems with some tools. The domains
www.bank.ctf
andatm01.bank.ctf
were given to us as entry points.
First, we can do an nmap scan of the two domains to see what services are available :
Flag Bonus 1
On the first domain (www.bank.ctf
) we find a single HTTP service exposed on port 80.When we go to the HTTP service, we discover an application that lets us observe money transactions and the amount each account holds.Looking at the source code of each page we find a bonus flag :
Flag 1
On the second domain (atm01.bank.ctf
) we saw earlier that there was a VNC service available and we can see that it can be accessed anonymously without credentials :
Once connected in vnc on the desktop, you can retrieve the first flag of the track :
Flag 2
By listing the files and folders on the machine in the C:\Packages
directory, we find a README.txt
file in which it is explained to us that the updates have been disabled because they failed :
When we push the enumeration of these folders we find a RunUpdate.bat
script which echoes what we saw previously in the README.txt
file :
The script contains credentials for the ATMService
domain account as well as an encoded string :
When we try to look with CyberChef at different rotations to decode the string, we realize that it is ROT47 and we get the second flag of the track :
Flag 3
We can try to connect with the account we recovered previously :
crackmapexec smb atm01.bank.ctf -u ATMService -p 'qb@ZWFVF2$1w$[*='
But we get the error STATUS_PASSWORD_EXPIRED
which means that the user’s password has expired, but if we refer to the article that n00py wrote . There are different ways to reset the user’s password. Thanks to the VNC access that we have, we can use it to interactively reset the password of the ATMService
user :
Once the password has been reset we can try to spray it on the domain machines to see if we are not the local administrator of one of them but this is not the case :
Now that we have compromised a domain account we will be able to enumerate the rights we have in the domain with SharpHound
in order to be able to try to elevate our privileges within the domain :
I used Sharphound instead of Rusthound and Bloodhound.py because the latter had issues when used on IPv6 networks.
Once the data has been retrieved and injected into Bloodhound, we see that the ATMService
user who was previously compromised is a member of the ATMAccounts
group which has GenericAll
rights on the ATM01
machine. This right can allow us to compromise the machine in several ways as can be seen on TheHackerRecipes :
First way
By listing the SMB file shares one can observe that LAPS (Local Administrator Password Solution) is deployed on the Active Directory domain :
If we refer to our favorite bible TheHackerRecipes, we see that with GenericAll rights on a machine we can read the ms-mcs-admpwd attribute which contains the LAPS password, that of the RID 500 Administrator by default . To achieve this we have several possible choices either to use LAPSDumper or CrackMapExec :
Here’s the command that dumps LAPS with CME: crackmapexec smb atm01.bank.ctf -u 'ATMService' -p 'qb@ZWFVF2$1w$[*=1337' --laps'
We check using CME that we are local Administrator with the mention (Pwn3d!)
:
Second way
Looking again at TheHackerRecipes we see that with GenericAll rights on a machine we can also perform an RBCD (Resource Based Constrained Delegation), the objective is to rewrite the msDS-AllowedToActOnBehalfOfOtherIdentity attribute of the target machine with an account having an SPN (Service Principal Name) that we control to be able to impersonate a user on the target machine. We could also exploit an RBCD SPN less but we have to sacrifice an account to do that and currently we only have one account so it would be a bit silly to make it unusable.
When we look at the prerequisites to be able to operate an RBCD we see that we must at some point have an account with an SPN, in general what we do is that we create a machine account joined to the domain because this machine account has multiple default SPNs. To be able to join a machine to the domain, the MAQ (Machine Account Quota) must not be at 0. The problem here is that it is precisely at 0 :
Currently we have none of the prerequisites to do either a classic RBCD or an SPN-less RBCD. So we have to find a way to compromise an account with an SPN.
Still digging, I find a possibility. If a machine account is configured as Pre-Windows 2000, its password is based on its name. Looking at Bloodhound, we see that indeed a machine is configured in this way :
First we will retrieve the list of machines that are configured in this way and we generate the associated password (in reality we could have just done it by hand because we already knew a machine that was usable but it’s for fun) :
We test to connect with the combination we generated and we get the error STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT
:
But good news it means that we have the right password and that we can exploit this account to be able to reset the password of the machine account with an arbitrary password :
Using rpcchangepwd from the impacket suite, we will reset the machine account password :
Now we have the requirements to perform an RBCD :
First we will rewrite the attribute msDS-AllowedToActOnBehalfOfOtherIdentity
with the machine account we control :
rbcd.py -action write -delegate-from 'webdev-old$' -delegate-to 'ATM01$' 'bank.ctf/ATMService:qb@ZWFVF2$1w$[*=1337'`
Now that it’s done, the ATM01 machine authorizes the machine we control (webdev-old$) to delegate for any user (except Protected Users or Account is sensitive and cannot be delegated) to any she ATM01 service :
getST.py -spn 'cifs/atm01.bank.ctf' -impersonate administrator -dc-ip 9000:c1f3:fea4:dec1:216:3eff:fea2:3b2d 'bank.ctf/webdev-old$:Emzmw^wimqRKy!bs#m5'`
Now that we have succeeded in compromising the first machine we can carry out post-exploitation in order to recover the various secrets and passwords that are stored on the machine, using DonPAPI we can dump all the secrets stored in LSA, DPAPI, etc. This allows us to retrieve the third flag as well as a new domain account :
We could also have dumped the LSA and DPAPI secrets using CME : crackmapexec smb atm01.bank.ctf -u 'Administrator' -p 'W8Jy&lh5)601ud$' --dpapi --lsa
Flag 4
We find ourselves in the same situation as earlier with the password of the BankService
account which has expired :
You can reset the BankService
account password in the same way as before. By spraying the credentials of this account on the machines of the domain, we realize that the account is Local administrator of the ITOPS01
machine :
Now that you are a local administrator, same post-exploitation process as before, but you can’t find much. So I decide to dump lsass using the CME lsassy module but I can’t. So I decide to look if RunAsPPL
is configured on the lsass process and I see that it is indeed the case :
We will therefore not be able to dump LSASS so simply. With the help of a very good article from itm4n on RunAsPPL protection I saw that there was the possibility of disabling the protection with digitally signed driver to remove the protection flag of the Process object in the Kernel. We can use the mimidrv.sys driver to do this, the driver must be present in the current folder to be loaded :
And now we can use CME’s lsassy module to dump LSASS. We can thanks to that recover a new domain account as well as the fourth flag of the track :
Flag 5
After getting the fourth flag I got stuck for a while because I have too much tunnel vision. But at some point I decided to try using the ESC8 again which I had thought of at the beginning of the track (which would have allowed me to bypass many previous steps). I had been blocked at the beginning because I did not know that we had a machine available that allowed us to receive connections from other machines in the lab because the outgoing flows to our machines were blocked (a restriction of the below from Northsec). Once I learned I was able to use the machine provided to operate the ESC8.
Before showing you how this vulnerability can be exploited, I will quickly remind you how the ESC8 works. The idea is to exploit the fact that web enrollment is enabled on the server that acts as the certificate authority, in this case it is adcs01.bank.ctf
. The fact that web enrollment is enabled will allow us to exploit an NTLM relay attack to be able to request a certificate and authenticate with it afterwards.
The first step is to set up an ntlmrelayx in order to be able to receive NTLM authentications and relay them to the ADCS :
Then we will try to recover an authentication, for that we can use Coercer which will force machine accounts to authenticate to the machine of our choice :
We receive the authentication and just after we receive a certificate for the DC01$
account :
Now that we have retrieved our certificate for the DC01$ account, we will be able to authenticate with it. We have several possibilities either we authenticate with PKINIT or with Schannel (Secure Channel). To make my life easier I would have liked to use certipy but it does not support IPv6 well. But suddenly we will do it on Windows using Rubeus and mimikatz.
First we will retrieve a TGT as DC01$ using PKINIT :
Now we will be able to use mimikatz to make PassTheTicket :
And now we will be able to DCSync and recover the credentials of the Domain Administrator because indeed the machines do not have default rights in the Active Directory except domain controller which have the privileges DS-Replication-Get-Changes and the DS-Replication-Get-Changes-All on the domain :
We could have used the user’s NT hash to authenticate with the NTLM protocol, but the Domain Administrator cannot authenticate only via the Kerberos protocol. So first we make a TGT request that we can reuse after :
Now that we have been able to recover a TGT as domain administrator we will be able to connect to the machine and recover the fifth flag of the track :
Small bonus for those who want to know how we could have done with certipy and CME :
certipy auth -pfx DC01.pfx -dc-ip 9000:c1f3:fea4:dec1:216:3eff:fea2:3b2d -domain bank.ctf -username 'DC01$'
crackmapexec smb dc01.bank.ctf -u 'DC01$' -H 'hash_nt_dc01' --ntds
Flag 6
Once we are Domain Admin, we see a message appear on the CTF platform, we see that we are told about a jump machine which is used to access the payment service :
By doing post exploitation we find a machine called jump01.bank.ctf
which could correspond to this description. When we scan the machine jump01.bank.ctf
we find no open port that would allow us to gain access to it. This is due to the machine’s local firewall which blocks all incoming flows. To work around this problem, we can deploy a firewall rule via a GPO
that will allow us to deactivate these restrictions and communicate with the machine. After some waiting time, new services appear and allow us to obtain access to the machine (normally we should have waited 60 minutes for the GPO to be deployed, but the creator of the challenge had put a scheduled task to update the GPOs of the machine in order to reduce this waiting time) :
Now that we have access to the machine and that we are Domain Admin we can simply retrieve the sixth flag of the track :
Flag 7
Once we submit the sixth flag of the track, we are given the FQDN (Fully Qualified Domain Name) of a new machine rabbitmq.bank.ctf
as well as the authentication to access the payment process by certificates :
First we can scan the rabbitmq.bank.ctf
machine to see the services we can access on this machine and we see that we have access to a queue message service :
By doing post exploitation on the jump01.bank.ctf
machine, we find at the root of it a Certs
folder which contains all the information that allows us to authenticate ourselves to the message queue server :
Because of a time constraint imposed with the CTF I could not finish the last part of the track but I provide you with the little script with which I was able to connect to the message queue server using the certificates that ‘we retrieved previously (I used a lot the documentation of the Pika library ) :
Credits
Thanks to Maxime Nadeau for carrying out this challenge which was really interesting and fun to do, if you want to know what the official path of compromise of the track looks like :
He also wrote a writeup : https://blog.evl.red/northsec/ctf/writeup/2023/04/24/nsec-2023-atm.html
Ressources :
- https://github.com/mpgn/CrackMapExec
- https://github.com/ThePorgs/impacket
- https://github.com/GhostPack/Rubeus
- https://github.com/ParrotSec/mimikatz
- https://github.com/BloodHoundAD/BloodHound
- https://github.com/p0dalirius/Coercer
- https://github.com/n00py/LAPSDumper
- https://pika.readthedocs.io/
- https://github.com/login-securite/DonPAPI
- https://www.thehacker.recipes
- https://www.n00py.io/2021/09/resetting-expired-passwords-remotely/
- https://itm4n.github.io/lsass-runasppl
- https://github.com/p0dalirius/Coercer
- https://offsec.almond.consulting/authenticating-with-certificates-when-pkinit-is-not-supported.html
- https://posts.specterops.io/certified-pre-owned-d95910965cd2
原文始发于BOUYAICHE RAYAN:Windows Track Northsec 2023 Writeup