ROPgadget题型——ret2syscall

    科技2026-02-07  3

    查看条件

    这道题没有后门函数,也不能在栈上写shellcode,拖入IDA中发现有大量的函数,说明是静态链接的文件。那么可以考虑ROPgadget。

    于是,考虑如下系统调用获取shell: execve("/bin/sh",NULL,NULL) 在32位程序中,参数一般是放在栈中的,但系统调用例外,参数是放在通用寄存器中的。即eax,ebx,ecx,edx。 eax:存放系统调用号,0xb ebx:存放第一个参数/bin/sh地址 ecx:存放第二个参数0 edx:存放第三个参数0

    下面就是想办法把几个参数和调用号“弹到”寄存器上:

    找到pop edx;pop ecx;pop ebx; ret

    找到pop eax; ret

    找到0x80

    找到/bin/sh的地址

    栈图

    此图中的rbp改为ebp,忘记原题是32位的了=。= 查看程序的汇编代码:disass main,会发现最后两条是leave和ret。 leave又包含两部分:mov esp,ebp和pop ebp ret包含:pop eip 分析上图,执行到mov esp,ebp时,esp和ebp指针同时指向保存ebp的空间,执行到pop ebp时,esp指向pop eax;ret那一格,ebp退回到原来的地方。 接着要执行leave的最后一条ret,esp把指向空间的值弹到eip上,esp再下降一格,那么此时,eip指向pop eax;ret,esp指向0xb。 接下来,就要执行pop eax;ret了,先看pop eax:esp会把值0xb弹到eax上,esp再下降一格,执行ret后esp会把pop edx;pop ecx;pop ebx;ret弹到eip上,随后再下降一格… 之后的分析和上面类似。

    payload也要按照上面顺序拼凑,触发0x80后会产生中断,根据系统调用号0xb会自动调用execve()函数。 32位中,execve()函数对应的系统调用号是0xb (11) 64位中,execve()函数对应的系统调用号是0xdd (221)

    from pwn import * p=process("./ret") pop_eax=0x080bb196 pop_edx_ecx_ebx=0x0806eb90 binsh_addr=0x080be408 addr_0x80=0x08049421 payload=flat(["A"*112,pop_eax,0xb,pop_edx_ecx_ebx,0,0,binsh_addr,addr_0x80]) p.sendline(payload) p.interactive()

    大功告成

    Processed: 0.014, SQL: 9