论坛: 菜鸟乐园 标题: 如何突破网关的种种限制与外界自由通讯 复制本贴地址    
作者: 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号