文章来源:http://blog.csdn.net/lake2/
文章作者:lake2

  探测远程主机上防火墙允许开放的端口

  上次拿到一个webshell,可是接着遇到麻烦——主机装了硬件防火墙。虽然发现主机的MSSQL存在hello溢出漏洞,但是由于防火墙的阻挠始终拿不到shell(反向连接时发现仅仅能够连接,没有数据过来),另外又试了N种本地提升权限的方法但以失败告终。郁闷!后来又想到如果在webshell里用sqlhello溢出绑定一个防火墙允许开的端口,那不就ok了。当然这个端口必须是现在关闭着的。

  大家都知道如果能够连接远程主机的某个端口,那么这个端口自然是防火墙允许开放的。现在的问题是,现在端口关闭着,如何判断呢?

  这里我想到有大虾说过telnet远程主机端口时,如果很快返回连接失败就说明端口关闭;如果等了十多秒才返回多半是对方装有防火墙。这个方法是对的,可是一共有65535个端口,不会让我慢慢去telnet吧,所以就写个程序自动去扫。

  同端口扫描程序类似,这个程序也调用winsock的connect函数,但由于端口是关闭的,所以connect会返回一个错误码10061(连接被拒。由于被目标机器拒绝,连接无法建立);但如果是对方的防火墙拦截了连接请求的话,过段时间就会返回10060错误(连接超时)。利用返回的错误类型我们就可以判断该端口是否为远程主机防火墙允许开放的了。不过这里注意,如果目标ip不存在主机的话也会超时的哦。

  原理搞懂了写程序也就很简单了,就是调用winsock的connect。关于winsock编程参考《WINDOWS网络编程技术》吧;嗯,另外注意用多线程,不然的话,呵呵,一整天都扫不完。多线程要使用CreateThread这个API函数,看看MSDN吧。随便在网上找了个扫描器代码参考,写了这个程序,代码如下:



#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <winbase.h>
#include <winsock.h>
#pragma comment(lib,"ws2_32.lib")

#define MAXThreadCount 100//设置最大线程数
#define SumScanCount 65535//设置扫描端口总数
struct sockaddr_in server;
int ThreadCount=0;
int dwThrdParam = 1; //CreateThread的参数,提到前面好计算

unsigned int resolve(char *name)
{
  struct hostent *he;
  unsigned int ip;

  if((ip=inet_addr(name))==(-1))
  {
    if((he = gethostbyname(name))==0)
{
  printf("ERROR: Don't find the %s .\n",name);
        exit(0);
}
    memcpy(&ip,he->h_addr,4);
  }
  return ip;
}

DWORD WINAPI Scan(LPVOID lpParam )
{
int mysock,code,port=(int)lpParam ;
mysock=socket(AF_INET,SOCK_STREAM,0);
if(mysock < 0) { printf("socket error!"); }


server.sin_port = htons(port);

if(connect(mysock,(struct sockaddr *) & server,sizeof(server))!=0)
{
code=GetLastError();
if(code==10061)printf("port %d allown open\n",port);
}
else
{
printf("port %d openning\n",port);
}
closesocket(mysock);
ThreadCount--;
  return 0;
}
void thread(int port)
{
DWORD dwThreadId;
  HANDLE hThread;
WSADATA ws;
if   (WSAStartup( MAKEWORD(2,2), &ws )!=0)
{
  printf(" [-] WSAStartup() error\n");
  exit(0);
}

  hThread = CreateThread(
    NULL,                 // no security attributes
    0,                   // use default stack size
    Scan,             // thread function
    (LPVOID)port,           // argument to thread function
    0,                   // use default creation flags
    &dwThreadId);           // returns the thread identifier
  if (hThread == NULL)
  printf( "CreateThread failed." );
dwThrdParam++;
ThreadCount++;
Sleep(200);   //延时,否则CPU会用满……
CloseHandle(hThread);
}


void main(int argc, char* argv[])
{
if(argc!=2)
{
printf("\n- This program find port that firewall allow open -\n");
printf("- Only for test by lake2 - \n");
printf("Usage: %s IP\n",argv[0]);
exit(0);
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = resolve( argv[1] );
printf("Starting and waiting..............\n");
while( dwThrdParam <= SumScanCount )
{
if( ThreadCount < MAXThreadCount ){ thread(dwThrdParam); }
}
while( ThreadCount!=0 ){ }
WSACleanup();
printf("Done!");
}


  运行程序,填上ip它就会自动探测所有端口,由于那些被过滤的端口大概都差不多要等二十秒,速度比较慢,可以自己设个超时值加快速度;另外也可以修改一下让用户自定义扫描范围等等,现在不管了,用得起就行。编译好的程序这里可以找到:http://lake2.512j.com/soft/PortScan.exe

  程序做好了当然要拿来用啦,经过漫长的3小时多的扫描之后,得到结果:目标主机防火墙只开放80端口。当场晕死!唉,“路漫漫其修远兮,吾将上下而求索”……

  lake2
  2005-1-18