用于测试的漏洞程序如下:
#include<stdio.h>
#include<windows.h>
void pf()
{
char buf[50];
gets(buf);
printf("%s\n",buf);
}
int main()
{
int a;
printf("this is just a test\n");
pf();
system("pause");
return 0;
}
pf函数中开启了一块大小为50字节的缓冲区,并调用
gets()函数获取用户输入。gets()函数,不受输入限制
可能会覆写掉栈中的返回地址。造成缓冲区溢出,人
为写入返回地址会导致程序执行恶意代码。
由于是在win10上实验,我又额外写了个小程序用于
重定向输入至一个txt文本文件,并用16进制编辑软件
来写入shellcode。
程序功能很简单,输入字符串,回显:
我测试让程序输出两次 欢迎字符串 “this is just a test”
win32下程序拥有固定的内存加载位置,所以可以通过反汇编软件找出
指令地址,我用了od实验。
40152c处字符串传参,下一条指令调用函数输出。
所以目标是将40152c这个地址覆写入pf()函数所在栈区的返回地址。
od中跟进,大概计算出偏移量3A+4 个字节便是返回地址之前要填充的
缓冲区,我不太明白为什么时3A(58字节)我的数组时50字节
现在构造一个输入,我只是测试一下缓冲区,所以也不弄shellcode了,前面
的缓冲区用字节填充,最后补上40152c用作返回地址,也就是之前 欢迎字符串
传参的地址。最后补上/r/n刷新缓冲区。
现在用一个重定向程序将文本的值刷入程序输入中,使用win32的管道就可以重
定向输入,输出了。
构造的输入保存在a.txt中
至此完成,程序除了输出回显外,有输出了一次我们的欢迎字符串
不过在这之后,也果不其然的崩溃掉了。
下面是我写的重定向的代码
#include "stdafx.h"
#include<Windows.h>
#include<iostream>
using namespace::std;
char name[256] = "\x00";
char app[256] = "\x00";
char wbuf[1024] = "\x00";
char rbuf[1024] = "\x00";
int size = 0;
void cancellast(char buf[]);
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE cproc = GetModuleHandle(NULL);
GetModuleFileName((HMODULE)cproc,name,256);
cancellast(name);
cout<<"gets app name"<<endl;
gets(app);
strcat(name,app);
STARTUPINFO si;
HANDLE victim;
HANDLE w1,r1;
memset(&si,0,sizeof(si));
si.cb = sizeof(si); //置为默认
SECURITY_ATTRIBUTES sa;
sa.bInheritHandle = TRUE;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL; //进程权限
if(CreatePipe(&r1,&w1,&sa,0))
cout<<"\npipe ready"<<endl;
else {cout<<"\npipe failed"<<endl; getchar(); return 0;}//通道
si.hStdInput = r1; //输入重定向到r1
si.dwFlags= STARTF_USESTDHANDLES;
PROCESS_INFORMATION ia;
if(!CreateProcess(name,NULL,&sa,NULL,TRUE,CREATE_NEW_CONSOLE,NULL,NULL,&si,&ia))
{
cout<<"\nfailed! enter app again"<<endl;
system("pause");
return 0;
}
cancellast(name);
cout<<"\nget txt name"<<endl;
gets(app);
strcat(name,app);
while(1)
{
cout<<"\n------read file (Y/N)?----"<<endl;
char confirm;
cin>>confirm;
if(confirm != 'y' && confirm != 'Y')
break;
FILE* intxt;
intxt = fopen(name,"r");
if(intxt == NULL)
{cout<<"failed open txt!! enter the name"<<endl;
break;
}
int words = fread(wbuf,1,1024,intxt);
fclose(intxt);
DWORD fwords = 0;
WriteFile(w1,wbuf,1024,&fwords,NULL);
cout<<"\n-------------------------"<<endl;
}
CloseHandle(w1);
CloseHandle(r1);
TerminateProcess(ia.hProcess,0);
system("pause");
return 0;
}
void cancellast(char buf[]) //获取目录
{
int strsize = strlen(buf);
while(name[strsize] != '\\')
{
strsize--;
}
buf[strsize+1] = '\0';
}