备注 by jhonguy:
char recvBuf[5000]={0};
recv(sockConn,recvBuf,5000,0);
char sendBuf[10]={0};
sendBuf声明在recvBuf后,通常离ebp越远(当然这个也有可能不是这样,这要看编译器的处理,不过我用vc6编译的时候,是离ebp远的),要想覆盖到栈帧中的数据,这就需要给sendBuf复制跨越recvBuf更多的数据,而你socket接收的数据最多就是recvBuf的大小,当然如果这个recvBuf到retaddr之间的局部变量没有存在0值的数据,strcpy才有可能覆盖到栈帧,如果存在0值数据,那怎么样都覆盖不到这个函数的栈帧的。
arg1
retaddr -------------------------
ebp |
other loc var more then 5000
recvBuf[5000] |
sendBuf[10] -------------------------
所以要比较方便能够溢出,最好把char sendBuf[10]={0};放在recvBuf[5000]之前,这样sendBuf 就会距离栈底近,而且距离远远小于5000。
配合该echo服务端程序,以及反调试工具(代码见我另外的帖子http://blog.csdn.net/yatere/article/details/7307266),可以研究下远程漏洞开发和shellcode的原理。
可以用nc或者下面py脚本来测试这个echo服务器,使用调试工具监控服务器端异常。
import socket mys=socket.socket() mys.connect(('192.168.1.100',9999)) mys.send(b'A'*9999) b=mys.recv(9999) print (b.decode())
vc6源码:
编译好的exe:
http://howfile.com/file/2611e8a1/98aca589/
#include "stdafx.h" #include <stdio.h> #include <WinSock2.h> #pragma comment (lib,"ws2_32.lib") int main() { WSADATA wsaData; WSAStartup(MAKEWORD(2,2),&wsaData); SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0); SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY); addrSrv.sin_family=AF_INET; addrSrv.sin_port=htons(9999); bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR)); printf("正在监听端口:%d\n",9999); listen(sockSrv,5); SOCKADDR_IN addrClient; int len=sizeof(SOCKADDR); while(1) { SOCKET sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len); char recvBuf[5000]={0}; recv(sockConn,recvBuf,5000,0); char sendBuf[10]={0}; strcpy(sendBuf,recvBuf); printf("%s",sendBuf); _asm{ mov eax,eax; mov eax,eax; mov eax,eax; } send(sockConn,sendBuf,strlen(sendBuf)+1,0); closesocket(sockConn); } return 0; }
使用我另外一个pydbg脚本捕捉出错时候的信息截图如下:提示 thread 1228 访问异常 没有覆盖eip,覆盖了ebp以及seh,以前都是关于利用覆盖eip的,这次需要再研究下了。