精华区 [关闭][返回]

当前位置:网易精华区>>讨论区精华>>电脑技术>>● 计算机安全>>◇网络安全◇>>安全技术>>再谈突破TCP-IP过滤/防火墙进入内网(icmp篇)2

主题:再谈突破TCP-IP过滤/防火墙进入内网(icmp篇)2
发信人: angellotus(ANGELLOTUS)
整理人: williamlong(2002-12-01 16:41:24), 站内信件
首先,我们更改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)   
                {

                    if(sin[0][3].sin_addr.s_addr==htonl(0))            
                {
                    cout<<"sin[0][3].sin_addr.s_addr==htonl(0)"<<endl;
istbcs=0;
memset(msgsend,0,sizeof(msgsend));
break;
}

iret=sendto(sock[0][1],msgsend,istbcs,0,(struct sockaddr *)&sin[0][3],addrlen);
if(iret==SOCKET_ERROR)
{
cout<<"Sendto sock[0][1] Error: "<<GetLastError()<<endl;
break;
}
cout<<"Thread 0 send "<<iret<<" bytes to \t"<<inet_ntoa(sin[0][3].sin_addr)<<endl;
istbcs-=iret;
}
memset(msgsend,0,sizeof(msgsend));
istbcs=0;
}
Sleep(20);
}
}
return 0;
}


DWORD WINAPI i2u(LPVOID num)
{
UNREFERENCED_PARAMETER(num);
fd_set fdread,fdwrite;
char msgrecv[maxsize]={0},msgsend[maxsize]={0};
int ret,iret,idx,istbcs=0,ileft;
DWORD dwbufferlen[10];
DWORD dwbufferinlen=1;
DWORD dwbytesreturned=0;
struct ipheader *iphdr;
struct icmpheader *icmphdr;

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

WSAIoctl(sock[1][0],SIO_RCVALL,&dwbufferinlen,sizeof(dwbufferinlen),&dwbufferlen,sizeof(dwbufferlen),&dwbytesreturned,NULL,NULL);
iphdr=(struct ipheader *)msgrecv;
icmphdr=(struct icmpheader *)(msgrecv+sizeof(struct ipheader));

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

if((ret=select(0,&fdread,&fdwrite,NULL,NULL))==SOCKET_ERROR)
{
cout<<"Select in thread 1 Error: "<<GetLastError()<<endl;
break;
}
if(ret>0)
        {
            if(FD_ISSET(sock[1][0],&fdread))
            {
                {
                iret=recvfrom(sock[1][0],msgrecv,sizeof(msgrecv),0,(struct sockaddr *)&temps,&addrlen);
                if(iret==SOCKET_ERROR)
                {
                    cout<<"Recvfrom sock[1][0] Error: "<<GetLastError()<<endl;
break;
}

if(iret<=28)
{
break;
}
if((icmphdr->type!=0) || (icmphdr->code!=0) || ((icmphdr->id)!=htons(65456)) || ((icmphdr->seq)!=htons(65456)))
                {
                    break;
                }
                if((sin[1][0].sin_addr.s_addr!=htonl(0)) && (sin[1][0].sin_addr.s_addr!=temps.sin_addr.s_addr))
                    break;
                }
                else if(sin[1][0].sin_addr.s_addr==htonl(0))           
                {
                    sin[1][0].sin_addr.s_addr=temps.sin_addr.s_addr;
                    sin[0][3].sin_addr.s_addr=temps.sin_addr.s_addr;
                    cout<<"sin[0][3] ==> "<<inet_ntoa(sin[0][3].sin_addr)<<endl;
}

cout<<"\nThread 1 Recv "<<iret<<" bytes from \t"<<inet_ntoa(temps.sin_addr)<<endl;

memcpy(msgsend+istbcs,msgrecv,iret);
istbcs+=iret;
memset(msgrecv,0,sizeof(msgrecv));
}
}
else if(FD_ISSET(sock[1][1],&fdwrite))
{
ileft=istbcs-28;
idx=28;
while(ileft>0)
                {
                    iret=sendto(sock[1][1],&msgsend[idx],ileft,0,(struct sockaddr *)&sin[1][3],addrlen);
                    if(iret==SOCKET_ERROR)
                    {
                        cout<<"Sendto sock[1][1] Error: "<<GetLastError()<<endl;
break;
}
cout<<"Thread 1 send "<<iret<<" bytes to \t"<<inet_ntoa(sin[1][3].sin_addr)<<endl;
ileft-=iret;
idx+=iret;
}
istbcs=0;
memset(msgsend,0,sizeof(msgsend));
}
Sleep(20);
}
}
return 0;
}


int main(int argc,char *argv[])
{
WSADATA wsa;
BOOL gl;
HANDLE hthreads[2];
DWORD hthreadid[2];
struct hostent *hp;
char cname[100];
int dwret,log;

system("cls.exe");
start();

if(argc==2)
{
if(strcmp(argv[1],"-h")==0)
{
ShellExecute(NULL,"open","help.txt",NULL,NULL,SW_SHOWMAXIMIZED);
return 0;
}
else
{
usage();
return -1;
}
}
else if(argc!=4)
{
usage();
return -1;
}
if(!strcmp(argv[1],"-g"))
gl=true;
else if(!strcmp(argv[1],"-l"))
gl=false;
else
{
usage();
return -1;
}

if(WSAStartup(MAKEWORD(2,2),&wsa)!=0)
{
cout<<"WSAStartup Error: "<<GetLastError()<<endl;
return -1;
}

gethostname(cname,sizeof(cname));
hp=gethostbyname(cname);
for(int ipnum=0;hp->h_addr_list[ipnum]!=NULL;ipnum++)
        sag.sin_addr=*(in_addr *)hp->h_addr_list[ipnum];
    sag.sin_family=AF_INET;
    sag.sin_port=htons(65456);

    sal=sag;
       if(ipnum>1)
        sal.sin_addr=*(in_addr *)hp->h_addr_list[ipnum-2];

    if(gl)
    {
        sin[0][0].sin_addr.s_addr=inet_addr(argv[2]);
        sin[0][0].sin_family=AF_INET;
        sin[0][0].sin_port=htons(8000);

        sin[0][1].sin_addr.s_addr=htonl(INADDR_ANY);       
        sin[0][1].sin_family=AF_INET;
        sin[0][1].sin_port=htons(atoi(argv[3]));

           sin[0][2]=sal;                                    

        memset(&sin[0][3],0,sizeof(sin[0][3]));            
        sin[0][3].sin_family=AF_INET;
    }
    else
    {
        sin[0][0].sin_addr.s_addr=inet_addr("127.0.0.1");
        sin[0][0].sin_family=AF_INET;
        sin[0][0].sin_port=htons(4000);                

        sin[0][1].sin_addr.s_addr=htonl(INADDR_ANY);
        sin[0][1].sin_family=AF_INET;
        sin[0][1].sin_port=htons(atoi(argv[3]));

        sin[0][2]=sal;                                   

        sin[0][3].sin_addr.s_addr=inet_addr(argv[2]);
        sin[0][3].sin_family=AF_INET;
    }
       sin[1][0]=sin[0][3];       
       sin[1][1]=sin[0][2];  
       sin[1][2]=sin[0][1];   
       sin[1][3]=sin[0][0];       

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

cout<<"\n正常工作中..."<<endl;

hthreads[0]=CreateThread(NULL,0,u2i,(LPVOID)0,NULL,&hthreadid[0]);
hthreads[1]=CreateThread(NULL,0,i2u,(LPVOID)1,NULL,&hthreadid[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)
{
CloseHandle(hthreads[0]);
closesocket(sock[0][1]);
hthreads[0]=CreateThread(NULL,0,u2i,(LPVOID)0,NULL,&hthreadid[0]);
}
else if(log==1)
{
CloseHandle(hthreads[1]);
closesocket(sock[1][0]);
hthreads[1]=CreateThread(NULL,0,i2u,(LPVOID)1,NULL,&hthreadid[1]);
}
else
{
for(int no1=0;no1<2;no1++)
{
CloseHandle(hthreads[no1]);
for(int no2=0;no2<2;no2++)
closesocket(sock[no1][no2]);
}
}
}
WSACleanup();
return 0;
}

本文相关软件T-QQ主要针对禁止使用QQ的网关,提供UDP,TCP及ICMP数据报转发功能,本软件同样适用于各种基于UDP协议的通信软件。其中的TCP数据报转发功能,也可以使用UDP数据报来转发TCP数据。相关软件及源代码下载地址: http://www.cshu.net/down/t-qq.rar


----
▇▇▇▇▇▇▇▇▇
▇網易虛拟社区章▇
▇  灌水专用  ▇
▇★ANGELLOTUS★▇
▇▇▇▇▇▇▇▇▇

[关闭][返回]