0x01 代码植入原理:
通过栈溢出让程序执行输入数据中植入的代码,把返回地址覆盖为buffer的起始地址,植入的代码放到buffer中
实验验证:向password.txt文件中植入一个二进制机器码,这段机器码用来调用windows的一个api函数MessageBoxA,最终在桌面弹出一个消息框并显示"failwest"字样。
code
/*****************************************************************************
To be the apostrophe which changed "Impossible" into "I'm possible"!
POC code of chapter 2.4 in book "Vulnerability Exploit and Analysis Technique"
file name : stack_overflow_exec.c
author : failwest
date : 2006.10.1
description : demo show how to redirect EIP to executed extra binary code in buffer
Noticed : should be complied with VC6.0 and build into debug version
the address of MessageboxA and the start of machine code in buffer
have to be make sure in file "password.txt" via runtime debugging
version : 1.0
E-mail : failwest@gmail.com
Only for educational purposes enjoy the fun from exploiting :)
******************************************************************************/
#include <stdio.h>
#include <windows.h> // 为了能够调用LoadLibrary函数
#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);
system("pause");
}
0x02 实验环境:
操作系统 | windows10 | |
---|---|---|
编译器 | visual C++6.0 | 有个bug需要注意:在退出程序的时候,最好还是按任意键退出程序,直接关闭窗口这种操作方式,有可能会导致程序并没停止 |
编译选项 | 默认编译选项 | |
build版本 | debug版本 | release和debug都可以 |
0x03 实验验证
3.1 验证前的准备工作:
1、 分析调试漏洞程序,获得淹没返回地址的偏移
2、获得buffer的起始地址,并将其写入到password.txt的相应偏移处,用来冲刷返回地址。
3、 在password.txt中写入可执行的机器代码,调用api弹出一个消息框。
处于字节对齐和容易辨认的目的,仍把“4321”作为一个单元输入,那么
buffer[44] –> 需要11个单元
authenticated –> 需要1个单元
前栈帧EBP –> 需要1个单元
返回地址 –> 需要1个单元
先输入11组获取一些信息,ollydbg的调试如下:
局部变量名 | 内存地址 | 偏移3处地址 | 偏移2处地址 | 偏移1处地址 | 偏移0处地址 |
---|---|---|---|---|---|
buffer[0-3] | 0019FAA0 | 0x31(’q’) | 0x32(’q’) | 0x33(’q’) | 0x34(’q’) |
…. | (9个双字) | 0x31(’q’) | 0x32(’q’) | 0x33(’q’) | 0x34(’q’) |
buffer[40-43] | 0019FAC8 | 0x31(’q’) | 0x32(’q’) | 0x33(’q’) | 0x34(’q’) |
authenticated(覆盖前) | 0019FACC | 0x00 | 0x00 | 0x00 | 0x31 (‘1’) |
authenticated(覆盖后) | 0019FACC | 0x00 | 0x00 | 0x00 | 0x00 (NULL) |
前栈帧 EBP | 0019FAD0 | 0x00 | 0x19 | 0xFF | 0x30 |
返回地址 | 0019FAD4 | 0x00 | 0x40 | 0x10 | 0xEB |
现在得到了两个信息:
1、buffer的起始地址: 0019FAA0 即将把这个大小写入password.txt中的53-56个字符中
2、 返回地址:0019FAD4
3.2 调用api弹出一个消息框
现在获取第三个信息:调用api弹出一个消息框得二进制代码
int MessageBox(
HWND hWnd, // handle to owner window
LPCTSTR lpText, // text in message box
LPCTSTR lpCaption, // message box title
UINT uType // message box style
);
1、 MessageBoxA是user32.dll得导出函数
2、汇编语言中调用MessageBoxA函数需要这个函数的入口
3、调用之前需要向栈中按从右到左得顺序压入MessageBoxA得四个参数
入口函数是通过user32.dll在系统中加载得基址和MessageBoxA在库中得偏移相加得到的。
用这个工具来找这些信息,运行depends,把它自己拖进去查看一下信息
MessageBoxA函数的入口地址(0X69E81230) = user32.dll基址(0x69E00000) + MessageBoxA偏移(0X00081230)
Ollydbg中获取弹窗的二进制编码
修改后的状态,最后的53-56是buffer的起始地址,其余用90(nop)填充。
notepad++中显示:
3.3 框框 失败了
这样就构造了验证程序,验证结果:
3.4 调试定位问题原因
调试一下,确定返回地址是正确的
数据跳转正确
eax和ebx的值也对
走到这里 有这样的提示信息
放到xp下跑试试,修改一下地址
MessageBoxA函数的入口地址(0x77D507EA) = user32.dll基址(0x77D10000) + MessageBoxA偏移(0X000407EA)
修改值如下:
调试未果,无法访问