|
作者: yimarong [yimarong] 版主 | 登录 |
如何突破网关的种种限制与外界自由通讯 作者:ey4s<ey4s@21cn.com> <<第一部分:欺骗网关上QQ>> 首先感谢shotgun<shotgun@xici.net>,没有他的帮助不会有这第一部分:) QQ乃朋友之间交流,和MM沟通感情必备之品,少了它怎么能行呢,呵呵。但是通常公 司为了提高员工的工作效率,会禁止员工在工作时间上QQ。一是从行政上制裁,如发现一 次扣xxx工资之类,二是从技术上封锁,例如在网关上做些限制。当然这样做无可厚非,可 以理解。但是下了班之后,通常封锁仍然不会打开,这样就很不爽了。这时候想要上QQ那 可就要自己想办法了。 OK!正所谓知己知彼,百战不殆!如果我们知道网关是通过什么技术来封锁的话,那么 要突破就相对容易多了。OK!先换个角度来想想,假如我们是网管,我们会怎么样来封锁呢? QQ用的是UDP协议,默认是用4000端口与外界通讯,那么我们在网关上把 源端口是4000 的UDP包丢弃就可以实现封闭QQ的目的了,呵呵。我们公司的网关就是这样干的,把源端 口是4000-4010的UDP包丢弃。怎么突破?哈哈,很简单,我们让QQ不用4000端口就OK 了。怎么改端口呢?直接改很麻烦,我不知道,呵呵,但我们可以间接的改啊。QQ默认是 用4000端口,如果4000被占用的话,那么它就会用4001,类推。OK!那我们在启动QQ之 前,先把UDP 4000-4010端口都占用掉,那么QQ启动的时候,就会顺理成章的使用4011 端口了。很简单,不是吗?呵呵,那我们就来写个小程序实现这个目的。 程序代码如下: /****************************************************************************** Module:BindUDP.c Author:ey4s<ey4s@21cn.com> Date:2001/6/2 http://eyas.3322.net ******************************************************************************/ #include <stdio.h> #include <conio.h> #include <winsock2.h> #define MaxNum 20 #pragma comment(lib,"ws2_32.lib") void ShowError(char *); int main(int argc,char **argv) { WSADATA wsd; int iRet,i,j=0, iStart=4000,iEnd=4019;//默认占用UDP 4000-4019的端口 SOCKET s[MaxNum]; struct sockaddr_in addr; //也可以让用户提供参数 if(argc==3) { iStart=atoi(argv[1]); iEnd=atoi(argv[2]); } else if(argc!=1) { printf("\nUsage:%s <UDPStartPort> <ENDPort>",argv[0]); return 1; } __try { //load winsock library iRet=WSAStartup(MAKEWORD(1,1),&wsd); if(iRet!=0) { ShowError("WSAStartup"); __leave; } addr.sin_family=AF_INET; addr.sin_addr.s_addr=INADDR_ANY; for(i=iStart;i<=iEnd;i++,j++) { if(j>=MaxNum) break; //创建一个UDP socket s[j]=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); if(s[j]==INVALID_SOCKET) { ShowError("\nCreate UDP socket"); __leave; } addr.sin_port=htons(i); //bind udp socket iRet=bind(s[j],(struct sockaddr *)&addr,sizeof(addr)); if(iRet==SOCKET_ERROR) { printf("\nBind UDP port %d failed.",i); continue; } else printf("\nBind UDP port %d ok.",i); } printf("\nPress any key to exit."); getch(); } __finally { for(j=0;j<MaxNum;j++) closesocket(s[j]); WSACleanup(); } return 0; } void ShowError(char *msg) { printf("\n%s failed:%d.",GetLastError()); } |
地主 发表时间: 07/28 03:35 |
回复: yimarong [yimarong] 版主 | 登录 |
<<第二部分:通过socket代理上IRC>> 通常公司不但会封锁QQ,而且只允许员工浏览网页。例如在网关上做限制,除了允许 访问外面的TCP 80端口,连接外面的其他端口的请求都会被丢弃。这时候我们想上IRC去 和朋友们交流,聊天的时候,就不能如愿了。QQ和IRC都是上网必备之品?不是么?呵呵, 反正我一上网就上IRC和QQ的,呵呵。 OK!我们怎么来突破呢?也比较简单。网关不是允许我们访问外面服务器的TCP 80端口 么,那么我们找个端口是80的socket代理就解决问题了。但是,如果我们自己动手来解决 这个问题,感觉不是更爽么,我们提倡的是DIY[Do It Yourself]。当然这也不是说什么东 西都要自己来写,只是各人的兴趣罢了,呵呵。当初也曾雄心壮志的想写个socket代理的 程序,但看了一会儿socket 5代理的RFC后,我就晕的不行了,NND,英文的,咱看不懂。 也罢,以后再说,hoho~ 复杂的socket 5代理程序咱不会,咱写个简单的socket数据转发程序还不行吗,呵呵。 OK!程序流程是这样的,我们找一台互联网上的机器来给我们做数据转发,这样的机器很容 易找,不是吗?呵呵。习惯性的,我们称这个为肉鸡吧。假如肉鸡的IP是202.202.202.202, 那么在肉鸡上运行一个我们写的程序TCPAgent.exe,监听TCP 80端口[没办法啊,网关只 允许我们连接外面的80端口,rcch这个可怜虫所在的公司就是这样压迫他的,哈哈],假 如这个端口已经被IIS占用的话,那么就换一台没有启动IIS服务器的机器吧,重用端口不 稳定。OK!启动IRC客户段[我以前喜欢用cjcbot2000,现在改用HIRC了,呵呵],在IRC 服务器栏填202.202.202.202这个地址,端口是80。当我们的TCPAgent检测到我们的IRC 客户端已经连接上来后,马上创建一个socket,连接到真正的IRC 服务器202.109.72.40 的TCP 6667端口[这个IP是irc.sunnet.org的IP,我常去的IRC,喜欢去哪个IRC,随便 换好了,呵呵]。OK!这样数据通道就建好了,HIRC??肉鸡??IRC Server,HIRC把发往 服务器的数据发送到了肉鸡,然后肉鸡把它转发给服务器,肉鸡再把服务器的返回数据转发 给HIRC。很简单,不是吗?呵呵。 这个程序其实是我在<<突破TCP-IP过滤-防火墙进入内网(一)>>这篇文章里面提高的 程序的改进版本,这个版本代码相对更加精简和高效了,但其实还是很烂,请各位老大多多 指点:))。 程序下载 程序代码如下: /********************************************************************** Module Name:TCPAgent.c Date:2001/6/2 Author:ey4s<ey4s@21cn.com> http://eyas.3322.net 说明:TCP数据包转发工具,或者也可以叫端口重定向工具吧,在网关上运行, 把端口重定向到内网的IP、PORT,就可以进入内网了 **********************************************************************/ #include <winsock2.h> #include <stdio.h> #pragma comment(lib,"ws2_32.lib") #define BuffSize 20*1024 //缓冲区大小20k /////////////////////////////////////////////////////////////////////////////// // //定义&初始化全局变量 // char TargetIP[50]={0};//目标IP int TargetPort,//目标端口 ListenPort;//本地监听的端口 /////////////////////////////////////////////////////////////////////////////// //显示错误信息函数 void ShowError(char *); //TCP数据转发函数 DWORD WINAPI TCPDataRedird(LPVOID); /////////////////////////////////////////////////////////////////////////////// int main(int argc,char **argv) { WSADATA wsd; SOCKET sListen=INVALID_SOCKET,//本机监听的socket sock1[2],sock2[2]; struct sockaddr_in Local,Client,Target; int iAddrSize; HANDLE hThread[2]={NULL,NULL}; DWORD dwThreadID,dwRet; //检查参数 if(argc!=4) { printf("\nTCPAgent use for TCP socket date redird" "\nPower by ey4s<ey4s@21cn.com>" "\nhttp://eyas.3322.net" "\n2001/6/2" "\n\nUsage:%s <TargetIP> <TargetPort> <ListenPort>\n",argv[0]); return 1; } strncpy(TargetIP,argv[1],sizeof(TargetIP)-1); TargetPort=atoi(argv[2]); ListenPort=atoi(argv[3]); __try { //FreeConsole(); //load winsock library if(WSAStartup(MAKEWORD(1,1),&wsd)!=0) { ShowError("WSAStartup"); __leave; } //创建一个socket sListen=socket(AF_INET,SOCK_STREAM,IPPROTO_IP); if(sListen==INVALID_SOCKET) { ShowError("Create listen socket"); __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); //bind socket if(bind(sListen,(struct sockaddr *)&Local,sizeof(Local))==SOCKET_ERROR) { ShowError("bind"); __leave; } //listen if(listen(sListen,1)==SOCKET_ERROR) { ShowError("listen"); __leave; } //开始循环接受客户连接 while(1) { printf("\n\n*************Waiting Client Connect to**************\n\n"); iAddrSize=sizeof(Client); //等待客户连接 sock1[0]=accept(sListen,(struct sockaddr *)&Client,&iAddrSize); if(sock1[0]==INVALID_SOCKET) { ShowError("accept"); break; } printf("\nAccept client==>%s:%d",inet_ntoa(Client.sin_addr),ntohs(Client.sin_port)); //创建一个socket用于和最终目标连接 sock1[1]=socket(AF_INET,SOCK_STREAM,IPPROTO_IP); if(sock1[1]==INVALID_SOCKET) { ShowError("create socket"); break; } //连接到最终目标 if(connect(sock1[1],(struct sockaddr *)&Target,sizeof(Target))==SOCKET_ERROR) { ShowError("connect"); break; } printf("\nconnect to %s %d success!",TargetIP,TargetPort); //创建两个线程进行数据转发,双工效率高,感谢shotgun<shotgun@xici.net>给 的提示:))) hThread[0]=CreateThread(NULL,0,TCPDataRedird,(LPVOID)sock1,0,&dwThreadID); if(hThread[0]==NULL) { ShowError("create thread 1"); break; } //变换一下socket的顺序,作为参数传递给第二个线程 sock2[0]=sock1[1]; sock2[1]=sock1[0]; hThread[1]=CreateThread(NULL,0,TCPDataRedird,(LPVOID)sock2,0,&dwThreadID); if(hThread[1]==NULL) { ShowError("create thread 2"); break; } //等待两个线程中的其中一个结束,一个线程结束后立即中断另一个线程 dwRet=WaitForMultipleObjects(2,hThread,FALSE,INFINITE); if(dwRet==WAIT_FAILED) { ShowError("WaitForMultipleObjects"); break; } if((dwRet-WAIT_OBJECT_0)==0) TerminateThread(hThread[1],1); else TerminateThread(hThread[0],1); //关闭线程句柄 CloseHandle(hThread[0]); CloseHandle(hThread[1]); //关闭socket closesocket(sock1[0]); closesocket(sock1[1]); closesocket(sock2[0]); closesocket(sock2[1]); printf("\n\n*****************Connection Close*******************\n\n"); }//end of sock外循环 }//end of try __finally { if(sListen!=INVALID_SOCKET) closesocket(sListen); if(sock1[0]!=INVALID_SOCKET) closesocket(sock1[0]); if(sock1[1]!=INVALID_SOCKET) closesocket(sock1[1]); if(sock2[0]!=INVALID_SOCKET) closesocket(sock2[0]); if(sock2[1]!=INVALID_SOCKET) closesocket(sock2[1]); if(hThread[0]!=NULL) CloseHandle(hThread[0]); if(hThread[1]!=NULL) CloseHandle(hThread[1]); WSACleanup(); } return 0; } //////////////////////////////////////////////////////////////////////////////////// void ShowError(char *msg) { printf("\n%s failed:%d",msg,GetLastError()); } //////////////////////////////////////////////////////////////////////////////////// // //TCP socket数据转发函数,从s[0]接收数据,转发到s[1] // DWORD WINAPI TCPDataRedird(SOCKET *s) { int iRet, ret=-1,//select 返回值 iLeft, idx, iSTBCS=0;//STBCS=SendToBuffCurrentSize char szSendTo[BuffSize]={0}, szRecvFrom[BuffSize]={0}; fd_set fdread,fdwrite; DWORD dwThreadID=GetCurrentThreadId(); //开始一个循环来转发数据 while(1) { FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_SET(s[0],&fdread); FD_SET(s[1],&fdwrite); if((ret=select(0,&fdread,&fdwrite,NULL,NULL))==SOCKET_ERROR) { ShowError("select"); break; } if(ret>0) { //s[0]可读 if(FD_ISSET(s[0],&fdread)) { //接收s[0]发送来的数据 iRet=recv(s[0],szRecvFrom,BuffSize,0); if(iRet==SOCKET_ERROR) { ShowError("recv"); break; } else if(iRet==0) break; printf("\nThread %d recv %d bytes.",dwThreadID,iRet); //把从s[0]接收到的数据存添加到s[1]的缓冲区 memcpy(szSendTo+iSTBCS,szRecvFrom,iRet); //刷新s[1]的数据缓冲区当前buff大小 iSTBCS+=iRet; //清空接收s[0]数据的缓冲区 memset(szRecvFrom,0,BuffSize); } //s[1]可写,把从cRecvFrom接收到的数据发送到s[1] if(FD_ISSET(s[1],&fdwrite)) { iLeft=iSTBCS; idx=0; while(iLeft>0) { iRet=send(s[1],&szSendTo[idx],iLeft,0); if(iRet==SOCKET_ERROR) { ShowError("send"); break; } printf("\nThread %d send %d bytes.",dwThreadID,iRet); iLeft-=iRet; idx+=iRet; } //清空缓冲区 memset(szSendTo,0,BuffSize); //重置发往target的数据缓冲区当前buff大小 iSTBCS=0; } }//end of select Sleep(1); }//end of while return 0; } |
B1层 发表时间: 07/28 03:37 |
回复: yimarong [yimarong] 版主 | 登录 |
<<第三部分:通过TCP和UDP socket数据转发突破限制>> OK!我们在第一部分后面提到一种情况,网管在网关设置,把UDP包全部丢弃,限制我 们使用QQ。这时候,我们要突破就比较麻烦一点了,不过还是有办法的,前提是允许TCP 数据通过。这样我们可以用TCP和UDP socket数据转发来突破,为此我写了个小程序来实 现此功能,程序代码和注释附在后面。程序名称为SuperAgent,xixi,我们先来看看此程 序的用法: E:\ >SuperAgent.exe SuperAgent use for TCP and UDP socket data redird Power by ey4s<ey4s@21cn.com> http://eyas.3322.net 2001/6/7 usage: SuperAgent.exe <mode> [mode] -t <TargetIP> <TargetTCPPort> <LocalUDPPort> -u <TargetIP> <TargetUDPPort> <LocalUDPPort> <LocalTCPPort> 此程序有两种工作模式: <1>工作模式[-t],提供三个参数,目标IP地址,目标监听的TCP端口,和本地监听的 UDP端口。 <2>工作模式[-u],提供四个参数,目标IP地址,目标监听的UDP端口,本地监听的 UDP端口,本地监听的TCP端口。 OK!如果我们需要顺利的突破网关上QQ,我们需要一台互联网上的肉鸡的协助。假设 我们的肉鸡的IP是202.202.202.202,我们的网关的IP是101.101.101.101,咱的机器在内网 的IP为192.168.0.81,腾讯的QQ的服务器的IP是202.104.129.253,监听的是UDP8000 端 口。我们先在肉鸡运行SuperAgent,如下: E:\>SuperAgent -u 202.104.129.253 8000 4000 1234 OK!Work mode is [u]. Listen TCP 127.0.0.1:1234 ok! ************OK!SuperAgent working now************** Wait for ey4s connect to me......:) 然后在本地运行SuperAgent,如下: E:\>SuperAgent.exe -t 202.202.202.202 1234 8000 OK!Work mode is [t]. ************OK!SuperAgent working now************** Bind UDP port 8000 ok. Wait for UDP socket have data to be recv. 然后启动QQ,把服务器地址设置为127.0.0.1,端口8000,上线。怎么样?虽然网管封 杀了全部UDP包,但我们还是可以上QQ了吧?哈哈哈哈~不过这样QQ收发信息都是通 过服务器中转的,呵呵。 OK!我来解释一下流程。 <1>肉鸡运行SuperAgen.exet后,监听TCP 1234端口,然后阻塞,直到本地运行的 SuperAgent.exe连接上来。 <2>本地运行SuperAgent.exe后,监听UDP 8000端口,伪装成QQ的服务器,阻塞, 直到QQ连接上来。 <3>QQ请求上线,发送数据到我们伪装的QQ Server 127.0.0.1:8000。 <4>本地运行的SuperAgent.exe收到QQ发送过来的UDP数据后,连接到肉鸡监听的 TCP 1234端口 <5>本地的SuperAgent把UDP数据通过TCP socket发送到肉鸡 <6>肉鸡接收到本地发送来的TCP数据后,通过UDP socket转发到真正的QQ Server <7>肉鸡接收真正的QQ Server发送回来的数据后,通过TCP socket发送到本地的TCP socket <8>本地的TCP socket接收到肉鸡发送过来的TCP socket数据后,通过UDP socket转 发到QQ <9>重复5-8步骤 嗯!我表达的好像很不清楚。:((没有办法啦,水平有限的很,各位将就吧,呵呵。 OK!第一种情况是允许TCP数据通过,封闭所有UDP数据。我们来看第二种情况,封 闭所有TCP数据,只允许UDP数据。这时候可能有人要问:要是TCP和UDP数据都不让 通过,那怎么办?呵呵,TCP和UDP全部禁止,这叫网关吗?真这样的话,我们还是洗洗 回家睡觉吧,呵呵。不过如果ICMP允许的话,可以用ICMP来转发的,呵呵。 继续说第二种情况的解决办法。我们还是利用SuperAgent这个程序来达到我们的目的, 当然少不了一台互联网上的肉鸡的协助了。 我们先在本地运行: E:\>SuperAgent.exe -u 202.202.202.202 5000 6000 6667 OK!Work mode is [u]. Listen TCP 127.0.0.1:6667 ok! ************OK!SuperAgent working now************** Wait for ey4s connect to me......:) 202.202.202.202是肉鸡的IP,5000是肉鸡监听的UDP端口,6000是本地用来于肉鸡 通讯的UDP端口,这个可以随便填,最后面那个6667 是本地监听的TCP端口,这个也可 以随便填,一会儿在HIRC里面设置服务器里面填为和这个一致就可以了。 然后我们在肉鸡上这样运行: E:\>SuperAgent.exe -t 202.109.72.40 6667 5000 OK!Work mode is [t]. ************OK!SuperAgent working now************** Bind UDP port 5000 ok. Wait for UDP socket have data to be recv. 202.109.72.40是irc.sunnet.org的IP,6667是他监听的TCP 端口,这是真正的IRC服 务器。5000是肉鸡监听的UDP端口。 OK!启动HIRC,服务器地址填上127.0.0.1:6667,上线了吧?哈哈。 工作流程: <1>本地SuperAgent监听TCP 6667端口,阻塞,直到HIRC连接上来 <2>肉鸡SuperAgent监听UDP 5000端口,阻塞,直到本地的SuperAgent有数据发送过 来 <3>HIRC连接到本地伪装的IRC Server的TCP6667 <4>本地SuperAgent接收到HIRC发送来的TCP数据后,通过UDP socket转发到肉鸡 监听的UDP socket <5>肉鸡监听的UDP socket接收到本地发送过来的数据后,连接到真正的IRC Server 的TCP 端口,然后通过TCP socket把数据发送到IRC server <6>肉鸡接收IRC Server返回的TCP 数据,通过UDP socket转发到本地的UDP <7>本地接收到UDP数据后,通过TCP socket转发到HIRC <8>重复4-7,第5步连接到IRC Server的TCP 端口的不重复 用TCP和UDP socket数据转发有时候也可以用来突破防火墙的。不知道各位看过我写 的<<突破TCP-IP过滤-防火墙进入内网>>没有?其实这个程序的利用可以说是这个系列的 第三。这个思路早就有的,而且程序当时也写出来过,不过很苯,现在的是经过优化的版本。 当然,我水平实在太菜,程序还是写的很烂,请各位多指教。 OK!我们来看看这种情况。以下是网络拓朴图: 假设:[其实这样情况我遇到过,但没有以下说的复杂而已] 202.2.2.2是我们授权入侵的目标,前面的FireWall的过虑规则是只允许外面访问 202.2.2.2的80,不允许202.2.2.2TCP连接出去,UDP数据包不做过滤。经过我们检测发现 202.2.2.2的IIS有漏洞,我们可以通过80执行命令,而且打开了TermService服务,登录验 证漏洞没有补。但是由于有FW的阻挡,所以我们是连接不上目标的TermService来取得 admin 权限的。而且FW不允许TCP反向连接,这样,我们只能通过UDP和TCP socket 数据转发来达到目的了。[实际上我遇到的情况是允许TCP反向连接,详细情况见<<突破 TCP-IP过滤-防火墙进入内网(二)>>,] OK!这次我们不需要肉鸡的协助了,呵呵。我们先在本机192.168.0.2上运行: E:\>SuperAgent.exe -u 202.2.2.2 5000 6000 3389 OK!Work mode is [u]. Listen TCP 127.0.0.1:3389 ok! ************OK!SuperAgent working now************** Wait for ey4s connect to me......:) 202.2.2.2是目标的IP,5000是目标IP监听的UDP端口,6000是本地监听的UDP端口, 3389是本地监听TCP端口,伪装成TermService 然后我们在目标上通过80运行SuperAgent.exe -t 127.0.0.1 3389 5000,参数就不用解释 了吧。我来说说工作流程: <1>本地监听TCP 3389端口,阻塞,知道TermClient连接上来 <2>在目标机器上监听UDP 5000端口,阻塞,直到有UDP数据发送过来 <3>用TermClient连接本地的3389 <4>本地的SuperAgent把从TermClient接收到的TCP数据,通过UDP socket发送到目标的 UDP <5>目标的UDP socket接收到数据后,连接到本地的TCP 3389,真正的TermService <6>目标把接收到的UDP数据通过TCP socket转发给TermSerivice <7>目标接收TermService返回的TCP数据,通过UDP socket发送到攻击者的UDP <8>本地的UDP socket接收到目标UDP发送过来的数据后,通过TCP socket转发给 TermClient <9>重复4,6,7,8 OK!启动TermClient,连接本地的3389,出来的是防火墙后面的目标的终端服务的界面 吧?哈哈哈哈。 程序下载 OK!SuperAgent的完整的C程序代码如下,我加了很多注释,别嫌偶烦哦,写的烂,请 多指教:)) /****************************************************************************** Module:SuperAgent.c Author:ey4s<ey4s@21cn.com> WEB:http://eyas.3322.net Date:2001/6/6 用途:<1>在网关封闭了所有UDP数据包的情况下,通过TCP socket来转发数据,可以用 来上QQ <2>在网关封闭了所有TCP数据包的情况下,通过UDP socket来转发数据,可以用 来上IRC <3>在防火墙禁止了TCP往外的连接的情况下,通过UDP socket来转发数据,可以 绕过FW 这个版本只能供单用户使用,稍微修改就可以供多用户同时使用,我偷懒:)))有兴 趣的 人自己去修改吧,呵呵。BTW:不高兴去设置发送,接收,连接等的超时了,反正 自己 测试用还行,hoho~_* ******************************************************************************/ #include <stdio.h> #include <winsock2.h> #pragma comment(lib,"ws2_32.lib") #define BuffSize 20*1024 //缓冲区大小20k /////////////////////////////////////////////////////////////////////////////////////// /*如果模式为t,那么此地址结构是UDP Client的地址,此地址在接收到UDP Client数据后填 充 如果模式为u,那么此地址结构为Target的地址*/ struct sockaddr_in UDPRecv; BOOL bUDPRecvOK=FALSE;//上面的数据填充与否的标志 /////////////////////////////////////////////////////////////////////////////////////// //显示错误信息函数 void ShowError(char *); //从TCP socket接收数据,通过UDP socket发送出去 DWORD WINAPI T2URedird(LPVOID); //从UDP socket接收数据,通过TCP socket发送出去 DWORD WINAPI U2TRedird(LPVOID); //帮助信息函数 void usage(char *); /////////////////////////////////////////////////////////////////////////////////////// int main(int argc,char **argv) { int iRet; BOOL bT;//此值为TRUE表示工作在t模式,为FALSE表示工作在u模式 char szTargetIP[40]={0}; int iLocalTCPPort,iLocalUDPPort,iTargetPort; struct sockaddr_in UDPLocal,TCPLocal,Target; SOCKET sListen,s[2];//s[0]=>UDP socket s[1]=>TCP socket HANDLE hThread[2]={NULL,NULL}; DWORD dwThreadID,dwRet; WSADATA wsd; //判断参数个数 if((argc<5) || (argc>6)) { usage(argv[0]); return 1; } /*取得参数*/ //目标ip strncpy(szTargetIP,argv[2],sizeof(szTargetIP)-1); //目标端口,模式为t为tcp port,模式为u则为udp port iTargetPort=atoi(argv[3]); //本地监听的udp port iLocalUDPPort=atoi(argv[4]); //判断模式 if(strcmp(argv[1],"-t")==0) bT=TRUE; else if(strcmp(argv[1],"-u")==0) { bT=FALSE; //本地监听的TCP port iLocalTCPPort=atoi(argv[5]); } else { printf("\nmode error."); usage(argv[0]); return 1; } printf("\nOK!Work mode is [%c].",argv[1][1]); //load winsock library if(WSAStartup(MAKEWORD(1,1),&wsd)!=0) { ShowError("WSAStartup"); return 1; } //监听本地UDP port的地址结构 UDPLocal.sin_family=AF_INET; UDPLocal.sin_addr.s_addr=INADDR_ANY; UDPLocal.sin_port=htons(iLocalUDPPort); //目标地址结构 Target.sin_family=AF_INET; Target.sin_addr.s_addr=inet_addr(szTargetIP); Target.sin_port=htons(iTargetPort); //如果工作在u模式的话,监听一个TCP port等待客户连接 if(bT==FALSE) { //创建一个TCP socket sListen=socket(AF_INET,SOCK_STREAM,IPPROTO_IP); if(sListen==INVALID_SOCKET) { ShowError("\nCreate TCP socket"); WSACleanup(); return 1; } //监听本地TCP port的地址结构 TCPLocal.sin_family=AF_INET; TCPLocal.sin_port=htons(iLocalTCPPort); TCPLocal.sin_addr.s_addr=htonl(INADDR_ANY); //bind socket iRet=bind(sListen,(SOCKADDR *)&TCPLocal,sizeof(TCPLocal)); if(iRet!=0) { ShowError("bind TCP port"); closesocket(sListen); WSACleanup(); return 1; } //listen socket if(listen(sListen,1)==SOCKET_ERROR) { ShowError("listen"); closesocket(sListen); WSACleanup(); return 1; } UDPRecv.sin_family=Target.sin_family; UDPRecv.sin_addr=Target.sin_addr; UDPRecv.sin_port=Target.sin_port; bUDPRecvOK=TRUE; printf("\nListen TCP 127.0.0.1:%d ok!",iLocalTCPPort); } //开始循环 while(1) { __try { printf("\n\n************OK!SuperAgent working now**************\n\n"); //如果工作模式是U的话,accept阻塞直到有客户连接 if(bT==FALSE) { struct sockaddr_in addr; int iSize=sizeof(addr); //阻塞到客户连接 printf("\nWait for ey4s connect to me......:)"); s[1]=accept(sListen,(struct sockaddr *)&addr,&iSize); if(s[1]==INVALID_SOCKET) { ShowError("accept"); __leave; } printf("\nAccept ey4s %s:%d connect to me.",inet_ntoa(addr.sin_addr),ntohs(addr.sin_port)); } //创建一个UDP socket s[0]=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); if(s[0]==INVALID_SOCKET) { ShowError("\nCreate UDP socket"); __leave; } //bind UDP socket iRet=bind(s[0],(struct sockaddr *)&UDPLocal,sizeof(UDPLocal)); if(iRet==SOCKET_ERROR) { printf("\nBind UDP port %d failed.",iLocalUDPPort); __leave; } else printf("\nBind UDP port %d ok.",iLocalUDPPort); //如果工作模式是T的话,用select阻塞直到UDP socket有数据可读 //然后才TCP connect到Target监听的TCP Port if(bT==TRUE) { fd_set fdRead; int ret=-1; printf("\nWait for UDP socket have data to be recv."); FD_ZERO(&fdRead); FD_SET(s[0],&fdRead); if((ret=select(0,&fdRead,NULL,NULL,NULL))==SOCKET_ERROR) { ShowError("select"); __leave; } if((ret<=0) || (!FD_ISSET(s[0],&fdRead))) { ShowError("select"); __leave; } printf("\nOK!UDP socket active now."); //创建一个TCP socket s[1]=socket(AF_INET,SOCK_STREAM,IPPROTO_IP); if(s[1]==INVALID_SOCKET) { ShowError("\nCreate TCP socket"); __leave; } //connect to Target while(1) { iRet=connect(s[1],(SOCKADDR *)&Target,sizeof(Target)); if(iRet!=0) { printf("\nConnect to Target TCP %s:%d failed.Wait for try again.",szTargetIP,iTargetPort); Sleep(1000); } else { printf("\nConnent to Target TCP %s:%d ok.",szTargetIP,iTargetPort); break; } } } //创建两个线程进行数据转发,双工 hThread[0]=CreateThread(NULL,0,T2URedird,(LPVOID)s,0,&dwThreadID); if(hThread[0]==NULL) { ShowError("create thread 1"); __leave; } hThread[1]=CreateThread(NULL,0,U2TRedird,(LPVOID)s,0,&dwThreadID); if(hThread[1]==NULL) { ShowError("create thread 2"); __leave; } //等待两个线程中的其中一个结束,一个线程结束后立即中断另一个线程 dwRet=WaitForMultipleObjects(2,hThread,FALSE,INFINITE); if(dwRet==WAIT_FAILED) { ShowError("WaitForMultipleObjects"); __leave; } if((dwRet-WAIT_OBJECT_0)==0) TerminateThread(hThread[1],1); else TerminateThread(hThread[0],1); }//end of try __finally { if(s[0]!=INVALID_SOCKET) closesocket(s[0]); if(s[1]!=INVALID_SOCKET) closesocket(s[1]); if(hThread[0]!=NULL) CloseHandle(hThread[0]); if(hThread[1]!=NULL) CloseHandle(hThread[1]); }//end of finally printf("\n\n**************OK!SuperAgent shutdown now******************\n\n"); Sleep(1); }//end of while if(sListen!=INVALID_SOCKET) closesocket(sListen); WSACleanup(); return 0; } /////////////////////////////////////////////////////////////////////////////////////// void usage(char *name) { printf("\nSuperAgent use for TCP and UDP socket data redird" "\nPower by ey4s<ey4s@21cn.com>" "\nhttp://eyas.3322.net" "\n2001/6/7" "\n\nusage: %s <mode>" "\n[mode]" "\n\t-t <TargetIP> <TargetTCPPort> <LocalUDPPort>" "\n\t-u <TargetIP> <TargetUDPPort> <LocalUDPPort> <LocalTCPPort>\n",name); } /////////////////////////////////////////////////////////////////////////////////////// void ShowError(char *msg) { printf("\n%s failed:%d",msg,GetLastError()); } /////////////////////////////////////////////////////////////////////////////////////// // //从sock[1]=>TCP socket读 //往sock[0]=>UDP socket写 // DWORD WINAPI T2URedird(SOCKET *sock) { int iRet, ret=-1,//select 返回值 iLeft, idx, iUDPRepeat=3,//UDP发送失败后重复的次数 iSTBCS=0;//STBCS=SendToBuffCurrentSize char szSendTo[BuffSize]={0}, szRecvFrom[BuffSize]={0}; fd_set fdread,fdwrite; DWORD dwThreadID=GetCurrentThreadId(); //开始一个循环来转发数据 while(1) { FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_SET(sock[1],&fdread); FD_SET(sock[0],&fdwrite); if((ret=select(0,&fdread,&fdwrite,NULL,NULL))==SOCKET_ERROR) { ShowError("select"); break; } if(ret>0) { //sock[1]可读 if(FD_ISSET(sock[1],&fdread)) { //接收sock[1]发送来的数据 iRet=recv(sock[1],szRecvFrom,BuffSize,0); if(iRet==SOCKET_ERROR) { ShowError("recv"); break; } else if(iRet==0) break; printf("\nTCP Thread %d recv %d bytes.",dwThreadID,iRet); //把从sock[0]接收到的数据存添加到sock[1]的缓冲区 memcpy(szSendTo+iSTBCS,szRecvFrom,iRet); //刷新sock[1]的数据缓冲区当前buff大小 iSTBCS+=iRet; //清空接收sock[0]数据的缓冲区 memset(szRecvFrom,0,BuffSize); } //sock[0]可写,把从cRecvFrom接收到的数据发送到sock[0] if(FD_ISSET(sock[0],&fdwrite)) { iLeft=iSTBCS; idx=0; while(iLeft>0) { iRet=sendto(sock[0],&szSendTo[idx],iLeft,0,(SOCKADDR *)&UDPRecv,sizeof(UDPRecv)); if(iRet==SOCKET_ERROR) { ShowError("sendto"); //重复发送次数自减一 if((iUDPRepeat--)==0) break; printf("\nTry %d times to send.",iUDPRepeat); continue; } printf("\nUDP Thread %d sendto %s:%d %d bytes.", dwThreadID,inet_ntoa(UDPRecv.sin_addr),ntohs(UDPRecv.sin_port),iRet); iLeft-=iRet; idx+=iRet; } if(iLeft==0) { //清空缓冲区 memset(szSendTo,0,BuffSize); //重置发往target的数据缓冲区当前buff大小 iSTBCS=0; } } }//end of select Sleep(1); }//end of while return 0; } /////////////////////////////////////////////////////////////////////////////////////// // //往sock[1],TCP socket写 //从sock[0],UDP socket读 // DWORD WINAPI U2TRedird(SOCKET *sock) { int iRet, ret=-1,//select 返回值 iLeft, idx, iSTBCS=0;//STBCS=SendToBuffCurrentSize char szSendTo[BuffSize]={0}, szRecvFrom[BuffSize]={0}; fd_set fdread,fdwrite; DWORD dwThreadID=GetCurrentThreadId(); struct sockaddr_in from; DWORD dwSize=sizeof(from); //开始一个循环来转发数据 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) { ShowError("select"); break; } if(ret>0) { //sock[0]可读 if(FD_ISSET(sock[0],&fdread)) { //接收sock[0]发送来的数据 iRet=recvfrom(sock[0],szRecvFrom,BuffSize,0,(SOCKADDR *)&from,&dwSize); if(iRet==SOCKET_ERROR) { ShowError("recvfrom"); break; } else if(iRet==0) break; if(bUDPRecvOK!=TRUE) { UDPRecv.sin_family=AF_INET; UDPRecv.sin_addr=from.sin_addr; UDPRecv.sin_port=from.sin_port; bUDPRecvOK=TRUE; } printf("\nUDP Thread %d recvfrom %s:%d %d bytes.", dwThreadID,inet_ntoa(from.sin_addr),ntohs(from.sin_port),iRet); //把从sock[0]接收到的数据存添加到sock[1]的缓冲区 memcpy(szSendTo+iSTBCS,szRecvFrom,iRet); //刷新sock[1]的数据缓冲区当前buff大小 iSTBCS+=iRet; //清空接收sock[0]数据的缓冲区 memset(szRecvFrom,0,BuffSize); } //sock[1]可写,把从sock[0]接收到的数据发送到sock[1] if(FD_ISSET(sock[1],&fdwrite)) { iLeft=iSTBCS; idx=0; while(iLeft>0) { iRet=send(sock[1],&szSendTo[idx],iLeft,0); if(iRet==SOCKET_ERROR) { ShowError("send"); break; } printf("\nTCP Thread %d send %d bytes.",dwThreadID,iRet); iLeft-=iRet; idx+=iRet; } //清空缓冲区 memset(szSendTo,0,BuffSize); //重置发往target的数据缓冲区当前buff大小 iSTBCS=0; } }//end of select Sleep(1); }//end of while return 0; } |
B2层 发表时间: 07/28 03:38 |
|
20CN网络安全小组版权所有
Copyright © 2000-2010 20CN Security Group. All Rights Reserved.
论坛程序编写:NetDemon
粤ICP备05087286号