NX-ROP

本文最后更新于:2022年3月6日 晚上

什么是NX与ROP

NX即为no execute bit,即禁止执行位

以下是wiki中文的解释

支持NX技术的系统会把内存中的区域分类为只供存储处理器指令集与只供存储数据使用的两种。任何标记了NX位的区块代表仅供存储数据使用而不是存储处理器的指令集,处理器将不会将此处的数据作为代码执行,以此这种技术可防止多数的缓存溢出式攻ji(即一些恶意程序把自身的恶意指令集通过特殊手段放在其他程序的存储区并被执行,从而攻ji甚至控制整台电脑系统)。

个人理解就是不能用常规的最简单的栈溢出手段,来直接修改返回地址为目标函数地址。

ROP即返回导向编程(英语:Return-Oriented Programming,缩写:ROP)
其核心思想是通过栈溢出等方式控制堆栈调用以劫持程序控制流并执行针对性的机器语言指令序列(称为Gadgets)。所谓 gadgets 就是以 ret 结尾的指令序列,通过这些指令序列,我们可以修改某些地址的内容,方便控制程序的执行流程。

因为开启了NX 保护,我们不可以把shellcode放到栈上来执行了,因此我们就需用用到ROP技术来迂回获得SHELL。


++本文是学习笔记形式,许多内容与原文章相同,但会加入部分个人理解。因为自学ctf确实费劲,一个地方搞不懂会困扰几天,希望我个人对样例的复现过程,和我的经验能帮助到后来者,少走弯路。++

原文地址

https://bbs.pediy.com/thread-221041.htm

再次感谢原文大佬作者!

win的IDA pro与虚拟机中的linux联合调试方法

1.在IDA中选中remote linux debugger

2.在菜单debugger下拉菜单里选择process option选项,设置如下:
test-png
其中目录就选择rop所在目录,hostname填上linux虚拟机的ip,端口默认选择23946

3.然后打开linux虚拟机,并把ida目录下的linxu_serverX64拷贝到虚拟机里并执行
image.png


4.用py编写调试代码rexp.py如下:


#! /usr/bin/python
from pwn import *
import pdb
context.log_level = ‘debug’
target = process(‘./rop’)
elf=ELF(‘./rop’) #这个会显示rop用了哪些保护技术
pdb.set_trace()#这里设置一个pdb断点,可以让ida附加rop进程


target.sendline(‘a’64+’b’8+’c’*8)
target.interactive()
5.然后在linux系统上新开一个终端,执行rexp.py如下
image.png

6.在ida vuln函数里的gets函数后面下好断点

7.然后点击debugger,附加远程进程,找到./rop打开
image.png
并按F9执行

8.回到linux中,在Pdb终端里面输入n并回车(即next,下一步的意思)

9.可以看见IDA中出现同步的动态调试信息。

以上便是IDA与linux的联合调试过程

\

开启NX保护与不开启时,做题时的不同感受

1.开启NX以后,最直接的效果就是不能在栈上执行shellcode,也就是不能直接通过溢出,修改返回地址为shellcode,来获得shell。
2.但是开启NX以后,可以修改返回地址为已有的backdoor函数得到shell。
3.如果没有现成的backdoor函数,则需要我们想办法转移到其他空间,执行shellcode。

64位与32位下,简单的应对NX保护的方式

即构造ROP链
1.64位环境下,一般先搜索有类似“pop rdi ; ret;”形式的代码段
命令:

ROPgadget –binary 文件名 | grep “pop rdi”

找到相关代码段后,payload第一部分覆盖缓冲区和rbp(ebp)后,便接上ROPgadget找到的gadget地址。
为什么要寻找pop rdi呢?
因为函数第一个参数一般都存在rdi中,这样可以达到传参的目的。
再寻找”/bin/sh”字符串地址,链接在rop链后。
随后传入_system函数地址,作用是,通过ret指令,跳转至该地址,执行system()
此时rdi已经被设置好为”/bin/sh”,即会执行system(“/bin/sh”)
获得系统权限。
payload一般如下:

payload = b’A’*(缓冲区长度) + b’B’*8 + p64(pop_rdi_addr) + p64(/bin/sh_addr) + p64(_system_addr)

2.32位环境下一般采用布置栈帧,达到调用函数、传递参数的目的
payload一般如下:

payload = b’A’*(缓冲区长度) + b’B’*4 + p32(_system_addr) + p32(0x0) + p32(/bin/sh_addr)

首先,覆盖完缓冲区后,为了达到返回地址处,要覆盖ebp,ebp的大小是4个字节。
然后通过修改返回地址,进入system函数,此时我们位于system函数栈帧中的ebp处,我们需要填充一下ebp下面的返回地址,随便设置为0x0.
紧接着导入/bin/sh字符串,达到传参的目的。


以上便是本人对NX及ROP技术初次认识的浅显简介,让各位见笑了。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!