⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 再谈突破tcp-ip过滤-防火墙进入内网.txt

📁 可以对黑客编程有一定的了解
💻 TXT
📖 第 1 页 / 共 2 页
字号:
再谈突破TCP-IP过滤/防火墙进入内网(icmp篇) 


    随着Internet网络的普及,各个中大型公司均建立了自己的局域网络。而公司内部人员上网的限制也逐渐成为一个大家关心的话题。目前最为流行的网络工具大多是基于TCP/IP协议的,而其中最主要的两个协议就是TCP和UDP协议。HTTP,FTP等上层协议均是建立在TCP协议之上了,而DNS,ICQ,TFTP等则是建立在UDP协议之上的。往往我们会遇到这样情况:公司禁止了UDP协议,因为很大一部分的网络通讯软件都是建立在UDP协议之上的,而开通了TCP协议。这样,我们就可以通过TCP协议来为我们转发UDP数据报,具体实现原理可以参看eyas的《突破TCP-IP过滤/防火墙进入内网》,里面详细讨论了如何实现TCP与UDP数据报之间的相互转发,也可以参看本文相关软件T-QQ的源代码,里面也包含了TCP与UDP相互转发的功能,在此就不多说了。现在进入正题,如何实现用ICMP数据报来突破网关的限制? 

    ICMP协议(Internet Control Messages Protocol, 网际控制报文协议)是一种多功能的协议,在网络上有很多用处,比如ICMP扫描,拒绝服务(DOS)攻击,隧道攻击,以及我们最常用到的PING程序。而我们就是利用ICMP协议来为我们传送(TCP/UDP)数据。大家知道一般的防火墙都是过滤了来自外部主机的回送请求(echo Request)报文,但为了是自己能够探测外部主机的当前状态,防火墙都不会过滤掉回送应答(echo Reply)数据报,而且ICMP报文可以在广域网上传送,这样我们就可以利用它来突破网关的种种限制。本文主要针对使用ICMP协议来转发UDP数据报的功能,并以OICQ为背景,至于突破TCP的限制,也大同小异。 
    以下是QQicmp的工作原理: 

                            ----->-----                    ----->-----                         ----->----- 
        QQ客户端 <     UDP     > QQicmp(l) <    ICMP     > QQicmp(g) <     UDP     >Tencent服务器 
                            -----<-----                     -----<-----                         -----<-----   

    其中QQ客户端和QQicmp(l)都运行在本机上,而QQicmp(g)则是运行在网关上(QQicmp(l) 与 QQicmp(g)均是同一程序,只是运行模式不同:-l 运行于本地主机, -g 运行于网关上),Tencent服务器我想大家都清楚吧。QQ客户端与QQicmp(l),QQicmp(g)与Tencent服务器之间以UDP通信,QQicmp(l)与QQicmp(g)之间则是以ICMP通信。  Win2000/xp都提供了自己构造数据报的功能,也就是我们可以自己定义发送数据报的各项内容,当然也可以监听通过主机的基于IP协议的各种数据报。为了发送ICMP数据报及接收所有的IP数据报,我们必须自定义数据报的格式及校验和的求解: 
    typedef struct ipheader 
    { 
    unsigned char  h_lenver;          //头部长度及版本 
    unsigned char  tos;               //服务类型 
    unsigned short total_len;         //报文总长度 
    unsigned short ident;             //信息包标志 
    unsigned short frag_and_flags;    //标志及分段偏移量 
    unsigned char  ttl;               //生命周期 
    unsigned char  proto;             //协议类型 
    unsigned short checksum;          //IP校验和   
    unsigned int   sourceip;          //源IP地址   
    unsigned int   destip;            //目的IP地址 
    }ipheader; 

    typedef struct icmpheader 
    { 
    unsigned char   type;             //ICMP类型 0->回送应答 8->回送请求 
    unsigned char   code;             //代码 
    unsigned short  checksum;         //校验和 
    unsigned short  seq;              //序号 
    unsigned short  id;               //标识符   
    }icmpheader; 

    unsigned short checksum(unsigned short *buffer,int size) 
    { 
    unsigned long cksum=0; 
    while(size>0)                         //各位求和 
    { 
        cksum+=*buffer++; 
        size-=sizeof(unsigned short); 
    } 
    if(size) 
        cksum+=*(unsigned char *)buffer; 
    cksum=(cksum>>16)+(cksum & 0xffff); 
    cksum+=(cksum>>16); 
    return (unsigned short)(~cksum);      //再求补 
    } 

    首先,我们更改QQ客户端里的服务器地址为127.0.0.1,端口改为QQicmp(l)的监听QQ客户端端口,当然你也可以保持默认的8000,这样QQicmp(l)就应该在8000端口监听QQ客户端的数据。同时,QQ客户端也在端口4000(假设为非内网主机上的第一个QQ)监听来自QQicmp(l)的数据报。 
    我们可以看到,QQicmp(l)的主要作用就是将接收到了来自QQ客户端的UPD数据报, 
       sock[0][0]=socket(AF_INET,SOCK_DGRAM,0);              //创建基于UDP协议的套接字 
       bind(sock[0][0],(struct sockaddr *)&sin[0][1],addrlen);           //绑定到指定地址,指定端口上 
       iret=recvfrom(sock[0][0],msgrecv,sizeof(msgrecv),0,(struct sockaddr *)&tempr,&addrlen);   //接收来自QQ客户端的UDP数据 

    然后以ICMP数据报的形式发送到QQicmp(g),在此需要自己构造ICMP echo Reply数据报,并将接收到的UDP数据报填充到ICMP报文的数据段, 
    sock[0][1]=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);           //创建ICMP协议的原始套接字,用来发送自定义数据报 
    bind(sock[0][1],(struct sockaddr *)&sin[0][2],addrlen);     //并捆绑到指定地址,指定端口上 

       icmphdr.type=0;    //类型:echo reply 
    icmphdr.code=0;    //代码 
    icmphdr.id=htons(65456);   //序号 
    icmphdr.seq=htons(65456);  //标志符,用以过滤数据报 
    icmphdr.checksum=0; 

    if(istbcs==0)     //填充ICMP数据报头部 
    { 
          memset(msgsend,0,sizeof(msgsend)); 
             memcpy(msgsend,&icmphdr,sizeof(icmphdr)); 
          istbcs+=sizeof(icmphdr); 
    } 
    memcpy(msgsend+istbcs,msgrecv,iret);  //将接收到的UDP数据报的内容提取,准备以ICMP的形式发送 

    iret=sendto(sock[0][1],msgsend,istbcs,0,(struct sockaddr *)&sin[0][3],addrlen); //发送到网关 
    同时,QQicmp(l)监听通过本机的IP数据报,筛选出来自QQicmp(g)及网关的数据报, 
    sock[1][0]=socket(AF_INET,SOCK_RAW,IPPROTO_IP);            //创建原始套接字,接收所有的IP数据报 
    bind(sock[1][0],(struct sockaddr *)&sin[1][1],addrlen);    //绑定到指定地址,端口 

    DWORD   dwbufferlen[10]; 
    DWORD   dwbufferinlen=1; 
    DWORD   dwbytesreturned=0; 
    WSAIoctl(sock[1][0],SIO_RCVALL,&dwbufferinlen,sizeof(dwbufferinlen),&dwbufferlen,sizeof(dwbufferlen),&dwbytesreturned,NULL,NULL); 
       //设置为接收所有的数据报,需要mstcpip.h头文件,T-QQ相关文件里就有,或安装SDK 

    iret=recvfrom(sock[1][0],msgrecv,sizeof(msgrecv),0,(struct sockaddr *)&temps,&addrlen);   //接收所有数据报 
    if(iret<=28)     //文件过小 
    { 
        break; 
    } 
    if((icmphdr->type!=0) || (icmphdr->code!=0) || ((icmphdr->id)!=htons(65456)) || ((icmphdr->seq)!=htons(65456)))  //不符合接收条件 
    { 
        break; 
    } 

    memcpy(msgsend+istbcs,msgrecv,iret);    //将接收到的ICMP数据报的内容提取,准备以UDP的形式发送 
     解包后,用UDP数据报将接收到的来自网关的数据发送到QQ客户端, 
    idx=28;    //ICMP数据报的前20字节是IP头部,接着的8字节是ICMP头部, 
    iret=sendto(sock[1][1],&msgsend[idx],ileft,0,(struct sockaddr *)&sin[1][3],addrlen);    //发送到QQ客户端 
       
     我们创建了两个线程在两个方向(udp-->icmp,icmp-->udp)上接收并传送数据,如果某个线程出错,就重新创建该线程,而未出错的线程则保持不变, 
    hthreads[0]=CreateThread(NULL,0,u2i,(LPVOID)0,NULL,&hthreadid[0]);     //创建udp接收数据,icmp发送数据的线程0 
    hthreads[1]=CreateThread(NULL,0,i2u,(LPVOID)1,NULL,&hthreadid[1]);     //创建icmp接收数据,udp发送数据的线程1 

    while(1) 
    { 
    dwret=WaitForMultipleObjects(2,hthreads,false,INFINITE);                //等待某个线程的结束 
    if(dwret==WAIT_FAILED)                                                  //等待出错 
    { 
        cout<<"WaitForMultipleObjects Error: "<<GetLastError()<<endl; 
        return -1; 
    } 
    log=dwret-WAIT_OBJECT_0; 
    if(log==0)                                                              //线程0结束 
    { 
        CloseHandle(hthreads[0]);                                        //关闭线程handle 
           closesocket(sock[0][1]);                                                //关闭套接字 
           hthreads[0]=CreateThread(NULL,0,u2i,(LPVOID)0,NULL,&hthreadid[0]);      //重新创建线程0 
    } 
    else if(log==1)                                                         //线程1结束 
    { 
        CloseHandle(hthreads[1]); 
           closesocket(sock[1][0]); 
           hthreads[1]=CreateThread(NULL,0,i2u,(LPVOID)1,NULL,&hthreadid[1]); 
    } 
     
     以上就是QQicmp(l)的工作原理,QQicmp(g)运行在网关上,虽然模式不同,但工作原理是一样的,只是数据报的流动方向有点差异。 
     QQicmp之源代码如下: 

#include <iostream.h> 
#include <winsock2.h> 
#include <windows.h> 
#include <mstcpip.h> 

#pragma comment (lib,"ws2_32") 
#define maxsize 64*1024 

typedef struct ipheader 
{ 
    unsigned char  h_lenver; 
    unsigned char  tos; 
    unsigned short total_len; 
    unsigned short ident; 
    unsigned short frag_and_flags; 
    unsigned char  ttl; 
    unsigned char  proto; 
    unsigned short checksum; 
    unsigned int   sourceip; 
    unsigned int   destip; 
}ipheader; 

typedef struct icmpheader 
{ 
    unsigned char   type; 
    unsigned char   code; 
    unsigned short  checksum; 
    unsigned short  seq; 
    unsigned short  id; 
}icmpheader; 

unsigned short checksum(unsigned short *buffer,int size) 
{ 
    unsigned long cksum=0; 
    while(size>0) 
    { 
        cksum+=*buffer++; 
        size-=sizeof(unsigned short); 
    } 
    if(size) 
        cksum+=*(unsigned char *)buffer; 
    cksum=(cksum>>16)+(cksum & 0xffff); 
    cksum+=(cksum>>16); 
    return (unsigned short)(~cksum); 
} 

void start() 
{ 
    cout<<"            ---------------------------------------------------\n"; 
    cout<<"              ||                                                  || \n"; 
    cout<<"              ||             QQicmp  (ICMP转发)             || \n"; 
    cout<<"              ||                                                  || \n"; 
    cout<<"              ||         Author:TOo2y     SafeChina        || \n"; 
    cout<<"              ||                                                  || \n"; 
    cout<<"            ---------------------------------------------------"<<endl; 
} 

void usage() 
{ 
       cout<<"\nUsage:\r\n\tQQicmp  -l[-g]  ip  port"<<endl; 
    cout<<"\tQQicmp  -h"<<endl; 
    cout<<"Example:\r\n"; 
    cout<<"\tQQicmp  -l  192.168.0.1     8000"<<endl; 
    cout<<"\tQQicmp  -g  61.144.238.156  11282"<<endl; 
    cout<<"Attention:"<<endl; 
    cout<<"\t选项 -l :  运行于本机上,ip填网关地址,port为本地监听客户端端口;"<<endl; 
         cout<<"\t选项 -g :  运行于网关上,ip填腾讯服务器地址,port为自定义端口;"<<endl; 
    cout<<"\t选项 -h :  查看相关帮助文件。"<<endl; 
} 

int    addrlen=sizeof(struct sockaddr_in); 
SOCKET sock[2][2]; 
struct sockaddr_in sin[2][4],sag,sal,tempr,temps; 

DWORD WINAPI u2i(LPVOID num) 
{ 
    UNREFERENCED_PARAMETER(num); 
       char   msgrecv[maxsize]={0},msgsend[maxsize]={0}; 
    fd_set fdread,fdwrite; 
    int    iret,ret,istbcs=0; 
       struct icmpheader icmphdr; 

    memset(&icmphdr,0,sizeof(icmphdr)); 
    icmphdr.code=0; 
    icmphdr.id=htons(65456); 
    icmphdr.seq=htons(65456); 
       icmphdr.type=0; 
    icmphdr.checksum=checksum((unsigned short *)&icmphdr,sizeof(icmphdr));       

    if((sock[0][1]=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP))==INVALID_SOCKET) 
    { 
        cout<<"Socket sock[0][1] Error: "<<GetLastError()<<endl; 
        return -1; 
    } 
    if(bind(sock[0][1],(struct sockaddr *)&sin[0][2],addrlen)==SOCKET_ERROR) 
    { 
        cout<<"Bind sock[0][1] Error: "<<GetLastError()<<endl; 
        return -1; 
    } 

    while(1) 
    { 
        FD_ZERO(&fdread); 
        FD_ZERO(&fdwrite); 
        FD_SET(sock[0][0],&fdread); 
        FD_SET(sock[0][1],&fdwrite); 

        if((ret=select(0,&fdread,&fdwrite,NULL,NULL))==SOCKET_ERROR) 
        { 
            cout<<"Select in thread 0 Error: "<<GetLastError()<<endl; 
            break; 
        } 
        if(ret>0) 
        { 
            if(FD_ISSET(sock[0][0],&fdread)) 
            { 
                iret=recvfrom(sock[0][0],msgrecv,sizeof(msgrecv),0,(struct sockaddr *)&tempr,&addrlen); 
                if(iret==SOCKET_ERROR) 
                { 
                    cout<<"\nRecvfrom sock[0][0] Error: "<<GetLastError()<<endl; 
                    break; 
                } 
                else if(iret==0) 
                { 
                    cout<<"Iret==0"<<endl; 
                    break; 
                } 
                cout<<"\nThread 0 Recv "<<iret<<" bytes from\t"<<inet_ntoa(tempr.sin_addr)<<endl; 
                if(istbcs==0) 
                { 
                                  memset(msgsend,0,sizeof(msgsend)); 
                                   memcpy(msgsend,&icmphdr,sizeof(icmphdr)); 
                                  istbcs+=sizeof(icmphdr); 
                } 
                memcpy(msgsend+istbcs,msgrecv,iret); 
                istbcs+=iret; 
                memset(msgrecv,0,sizeof(msgrecv)); 
            } 
            else if(FD_ISSET(sock[0][1],&fdwrite)) 
            { 
             
                     while(istbcs>0)   
                { 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -