缓冲区溢出实验

一、实验说明

1.1实验环境:

【操作系统】

 Ubuntu16.04.07 LTS 32bit

 内核:4.15.0-112-generic

【软件版本】

gcc:  5.4.0

make: 4.1

1.2 重要说明

本次实验参考了

https://www.cnblogs.com/lqerio/p/12870943.html

【6】 缓冲区溢出 一个字节溢出 指针修改内存_xbffoo-CSDN博客

 建议了解:【C语言】你必须知道的栈区细节—函数栈帧(动态详解)_标识出此时栈底(ebp)和栈顶(esp)的位置及对应取值-CSDN博客

二 实验内容

2.1 实验准备

2.1.1 下载安装gdb-peda,prelink

2.1.2 关闭保护机制

取消地址随机化:

同时在编译时设置相应参数:

-fno-stack-protector:禁用堆栈溢出保护

-z execstack:关闭数据溢出保护

2.1.3 安装漏洞程序

1.make

2.sudo make install

2.1.3 分析shellcode构造

编写shellcode C代码如下:

gcc编译后成功弹出shell:

对编译的二进制程序使用objdump反汇编

objdump -d shellcode > shellcode.S

可见汇编代码

由此编写汇编代码如下:

编译链接运行如下:

使用如下命令获取shellcode对应机器码

\x31\xc9\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x31\xc0\xb0\x0b\xcd\x80

构造如下C程序验证机器码:

编译时关闭数据溢出保护和堆栈溢出保护

执行:

说明机器码正确。

同时,查询到构造shell还有另一方法

static const char shellcode[] =

 "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"

"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"

"\x80\xe8\xdc\xff\xff\xff/bin/sh";

同样编写程序验证,可成功引发shell。

第一种方法使用了execve("/bin/sh", ["/bin/sh", NULL], NULL) 调用来执行 /bin/sh,通过栈来设置参数,实验过程中发现在构造vul2的exploit2时,会导致vul2的buf数组起始位置发生变化,而第二种方法通过寄存器设置参数,可以避免此问题,两种构造shell的机器码均记录下来,分别存储为

shllcode1.h(第一种方法),shellcode.h(第二种方法)

2.2 漏洞程序一

2.2.1 漏洞分析

分析:

bar 函数中使用 strcpy 函数将 arg 拷贝到 out 中,这里的 out 是一个局部数组,大小为 256 字节。但strcpy 函数不会检查目标数组的大小,而是简单地将源字符串复制到目标地址,这可能导致缓冲区溢出:如果参数 arg 的长度超过了 out 的大小(256 字节),strcpy 将继续写入超出缓冲区 out 的部分,导致栈上的其他数据被覆盖。这种情况就是经典的栈溢出漏洞,因为溢出的数据会覆盖函数调用栈中重要的数据,如返回地址和函数参数,从而可能影响程序的控制流程和执行。同时,调用bar函数的foo 函数接受命令行参数 argv,并将 argv[1] 作为参数传递给 bar 函数,其中 argv[1] 是 main 函数中的命令行参数 argv 的第二个元素。这意味着,如果在命令行中提供的参数超过了程序预期的范围,就会导致 bar 函数试图将过长的字符串复制到 buf 中,从而造成缓冲区溢出。

foo函数栈帧如下,当写入264字节时第261-264字节会覆盖原有返回地址。

2.2.2 构造payload

根据上述漏洞原理,构造payload,向buf中写入264字节的数据引起溢出,其中260~263为新的返回地址,即为写入shellcode机器码的开始地址,如下构造程序:

编译:gcc exploit1.c -o exploit1 -fno-stack-protector -z execstack

调试:gdb -e ./exploiy1 -s /tmp/vul1 –directory=../vulnerables

进入调试后,使用catch exec命令,是程序由exploit1通过execve执行vul1时中断,便于调试:

执行vul1后,在foo函数下断点,以便找到buf数组起始位置从而判断返回地址:

使用指令x/1xw buf可见buf起始地址,使用此地址替换上述的0x00000000

再次编译,重复上述操作,确认buf起始地址没有发生改变,由此payload构造成功。

使用gcc exploit1.c -o exploit1 -fno-stack-protector -z execstack编译后执行,成功获取具有root权限的shell:

2.3 漏洞程序二

2.3.1 漏洞分析

程序vul2与vul1非常相似,但限制了拷贝的字符串的长度,使得不会出现通过缓冲区溢出直接覆盖返回地址的情况,但其在确认字符串长度时使用了<=符号,导致字符串拷贝时可能多复制一个字节,这样我们就可以修改bar栈帧中的old ebp,也就是调用它的foo函数的ebp的最后一个字节。回到foo函数后执行leave指令(相当于mov esp,ebp pop ebp两条指令)时将被修改后的ebp传给esp,若此时esp+4指向shellcode的地址,那么执行ret指令时我们就能成功跳转至shellcode机器码所在位置从而获取shell.

总体过程描述大致如下图

2.3.2 构造payload

根据上述原理,首先在gdb中调试获取buf的地址:

调试vul2,反汇编foo函数,获取bar函数地址为0x804851a

构造一个200字节的payload并编译exploit2.c。使用gdb -e exploit2 -s /tmp/vul2联合调试,在bar函数处下断点,打印ebp和buf值

catch exec

r

b *0x0804851a

c

p $edp

p &buf

获取到buf范围是0xbffffcb8-0xbffffd80共200字节, ebp为0xbffffd8c, 如果覆盖掉ebp最后一字节为00,改变ebp为0xbffffd00,那么ret存放地址应当为0xbffffd04-0xbffffd08,注意是小端存储。D04-cb8=4c=76字节。

编写程序,构造数组:

在此过程中曾使用第一种shell构造方法,但实验过程中发现buf数组地址总是发生变化,经查询发现第一种方法通过栈来设置参数,推测可能是使用的栈导致了vul2的内存空间被占用,网上查询到第二种方法,如上文所述存在shellcode.h中,最终程序编写如下

编译运行:

成功获取具有root的权限的shell

2.4 漏洞程序三

2.4.1 漏洞分析

                     
程序输入为整数count和字符串in。采用了if判断语句来防止溢出,存在的漏洞主要是当count为一个足够小的负数时,可以满足 if 的条件进入memcpy函数,而memcpy接受的内存长度类型为size_t,在32位中即为unsigned int,共计4字节(32位),可以表示的最大值是 2^32 – 1=4,294,967,295,其函数原型如下:

当负数足够小时,负数*sizeof(widget_t)可能溢出产生正数。故要对vul3栈溢出攻击只需要构造合适的负数count产生溢出和字符串in覆盖buf,然后覆盖ebp,ret即可。由程序代码可知widget_t结构体占4字节,buf数组占用20*1000=20000字节,若count*20>20000即可导致数组越界,因此count的4字节32位二进制中除去第一位符号位为1外剩余位应当>=1001=0b001111101001,因此传入的count的二进制可为0b 1000 0000 0000 0000 0000 0011 1110 1001,计算机中负数以补码存储,对应为0b 0111 1111 1111 1111 1111 1100 0001 0111,其对应十进制为-2,147,484,649。buf大小为20000字节,故返回地址在20004~20008字节处。覆盖该地址内存为buf的起始地址,然后buf覆盖为shellcode即可。

2.4.2 构造payload

类似方法获取buf起始地址:

得到buf基址 0xbfffa220

编写程序,构造数组:

使用命令gcc -o exploit3 exploit3.c -z execstack -fno-stack-protector编译运行

  • 7
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值