CTF Writeup for World Peace - A challenge in IITB Trust Lab CTF Round 2 2023
This challenge was created by me for Trust Lab CTF Round 2 held in October 2023
Challenge Description
In the not-so-distant future, the world has finally achieved a state of unprecedented global harmony. Cats, once believed to be mere pets, have risen to prominence as ambassadors of peace and unity. The world has come to cherish the soothing sound of cats’ meows as a symbol of world peace. However, a sinister plot threatens to disrupt this tranquility. Can you help the felines figure out the key to world peace?
Here are the challenge files.
Solution
0040135b int32_t size
0040135b __isoc99_scanf(&data_4020c3, &size)
00401365 meow()
0040136a int32_t rax_4 = size
00401377 int64_t var_b8 = sx.q(rax_4) - 1
004013b1 int64_t rax_8 = divu.dp.q(0:(sx.q(rax_4) + 0xf), 0x10) * 0x10
❓️004013c8 while (rsp != &var_c8 - (rax_8 & 0xfffffffffffff000))
004013ca rsp = rsp - 0x1000
004013d1 *(rsp + 0xff8) = *(rsp + 0xff8)
004013e5 void* rsp_1 = rsp - zx.q(rax_8.d & 0xfff)
004013f4 if (zx.q(rax_8.d & 0xfff) != 0)
004013ff void* rax_11 = zx.q(rax_8.d & 0xfff) - 8 + rsp_1
00401402 *rax_11 = *rax_11
00401423 *(rsp_1 + sx.q(size)) = 0
00401436 printf("Say Something: ")
00401445 fflush(stdout)
00401462 read(0, rsp_1, sx.q(var_bc))
0040146c meow()
0040147b puts(rsp_1)
0040148a fflush(stdout)
00401494 meow()
004014a3 puts("Consuming consumerism: ")
004014b2 fflush(stdout)
004014cb void var_a8
004014cb read(0, &var_a8, 0x190)
004014d0 int64_t rax_22 = 0
004014e5 if (rax != *(fsbase + 0x28))
004014e7 rax_22 = __stack_chk_fail()
004014fa return rax_22
We see that the program has stack canary enabled for all the functions. The last read is of size 0x190 but the buffer at which it is storing is smaller in size. After 0xa8 bytes, that would overwrite the return address and there is a win function. Moreover, as the binary is not pie, the address of win function is always same.
Now we need to leak the canary in order to overwrite the return address.
After getting the size of the input from the user, the program allocates a space for the buffer.
The size of this buffer is decided at runtime. This buffer is being stored on stack.
Thus, this buffer contains part of the stack used by other function calls before the allocation.
meow
function is called just before buffer allocation, therefore, the buffer contains the canary.
The buffer is being printed as a string. If we fill the buffer till the canary, we can leak the canary.
Using gdb, we can find out that if we allocate 300 bytes of buffer, after entering 280 bytes, the canary is there. As last byte of canary is null, we need to write 281 bytes in the buffer. When the buffer is printed, the 7 bytes after 281 bytes are bytes of canary.
p.sendline(b'300')
p.sendline(b'a'*280)
p.recvuntil(b'aaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n')
canary = b'\x00' + p.recv(7)
Now, we have the canary and we can use it to overwrite the return address and print the flag. Here is the exploit for the challenge.