从编程角度来看IPC$空连接的利用和防范

 
前言
  我们知道,一般的攻击行为的首要步骤是收集目标的系统信息,对于NT/2K/XP系统而言,最简单的收集方法就是利用IPC$空连接。本文从原理入手介绍IPC$,并从编程的角度来看如何利用它,最后介绍一些简单的防范。本文要求读者有一定编程和C的基础,对网络知识有所了解。 我会收集一些常用的IPC$攻击方式及其编程的实现。
   对于NT机制的系统(NT/2K/XP,下同),默认安装都是允许进行IPC$连接的。和一般的连接不同,该连接可以不任何的用户名和密码就可以进行连接。当然,该连接是不能进行任何的系统操作,否则NT还有什么安全可言?呵呵。那么这个空连接对攻击者来说有什么作用呢?作用可大了,如果这个系统可以允许IPC$的话,我们可以利用其收集帐户信息,共享信息甚至可以穷举密码。著名的攻击工具Letmein和流光等就是利用它。
  下面我们来介绍一下这个东东。

  一、IPC$空连接的原理

  利用NET USE命令,我们可以在DOS窗口敲入如下命令就可以进行IPC$的连接。建立了空连接后,作为攻击者来说首要目标就是获取信息和取得Admin的密码,获取密码的漏洞有NULL.printer缓冲区溢出、idq.dll漏洞等等。有兴趣的人自己研究吧,相关资料到处都是。

Net use  //211.162.33.33/IPC$  或者是:

Net use  //211.162.33.33/IPC$ password /user:username

  那么什么是空连接呢,既然有这么多隐患?为什么系统要提供这个连接呢?IPC的英文是Interprocess Communication (进程通讯),用于共享“命名管道”的资源,它对于程序间的通讯很重要。在远程管理计算机和查看计算机的共享资源时使用,NT主机用来它来互相连接并通过这个共享来获得各种必要的信息。关于什么是进程通讯,这其中的原理不是很好理解,需要一些操作系统原理方面的知识,请参考其他方面的资料,这里不再叙述。

 二、从编程角度看IPC$的利用

  以下Net函数的用法可以参考MSDN,我都是用C来实现的,这些函数在VB下完全可以使用,需要转换成VB的形式可以和我联系。

1、 连接

  除了利用刚才所说的Net 命令来进行IPC$连接外,我们来看一下如何编程实现连接:

BOOL ConnetIPC(char * RemoteName)
{ char tmp[128]="////";
 strcat(tmp,RemoteName);
 strcat(tmp,"//ipc$");
 NETRESOUCE NetResouce;
 NetResouce.lpRemoteName=tmp;
 NetResouce.dwType=RESOURCETYPE_ANY;
 NetResouce.lpProvider=NULL;
 if (WnetAddConnection2(&NetResouce,””,””,FLASE)==NO_ERROR)
  //建立连接!
  return FALSE;
 else
  return TRUE;
}

  上面的函数可以实现Net use //211.162.33.33/IPC$ ,这个函数比较简单,大家可能对此不熟悉的就是NETRESOUCE这个结构了,这个结构主要描述了当前网络资源的一些情况,可以查以上的连接得到详细说明。函数返回TRUE就表示连接成功。这里我们利用的是WnetAddConnection2这个函数,当然我们也可以利用WnetAddConnection3,WnetAddConnection2函数的原型是如下:

DWORD WNetAddConnection2(
  LPNETRESOURCE lpNetResource// 连接的网络资源详细情况
  LPCTSTR lpPassword,           
  LPCTSTR lpUsername,           
  DWORD dwFlags                 // 连接方式的选项

);

  需要的注意的是:该函数的第一个参数说明了网络资源的一些信息, lpPassword如果为NULL则使用当前用户的密码信息,如果为空则说明该用户不使用密码。LpUsername和此类似。在函数中,lpPassword和lpUsername我都是采用””空字串,这说明这个连接不用任何的验证。DwFlags用来说明连接模式的,赋值false也说明了,该连接不采用验证模式。这两个函数的详细信息请参考:

http://msdn.microsoft.com/library/en-us/wnet/networks_84z6.asp

http://msdn.microsoft.com/library/en-us/wnet/networks_84z7.asp

2、枚举用户帐户信息

  当我们使用以上代码对目标机器建立了IPC$ NULL Session后,我们所要做的一般就是获取目标的帐户信息,得到帐户信息后获取该密码只是时间和运气问题了。看下面这个函数:

NET_API_STATUS NetUserEnum(
  LPCWSTR servername,    
  DWORD level,           
  DWORD filter,          
  LPBYTE *bufptr,        
  DWORD prefmaxlen,      
  LPDWORD entriesread,   
  LPDWORD totalentries
  LPDWORD resume_handle  

);

  该函数可以获取目标机器的帐户信息。第一个参数Servername指明了用DNS 或 NetBIOS name表示的目标机器;第二个参数很重要,它说明了你要获取的信息的范围,不同的level值所对应的第四个参数bufptr指针所指的结构类型也不同;例如,如果你给level赋1,那么bufptr指向的是结构为USER_INFO_1的类型;第三个参数filter是表示过滤参数,如果是0表示眉举所有的帐号类型。其他的参数都不是很重要,请参考:

http://msdn.microsoft.com/library/en-us/netmgmt/ntlmapi2_3kx9.asp

  下面介绍利用该函数获取用户信息的代码片段,这个是我从网上找来改的,

... //相关的声明,略去!完整的CODE,找我索取
   do{
      nStatus = NetUserEnum(szServerName,0,0,(LPBYTE*)&pBuf,-1,&dwEntriesRead, 
                           &dwTotalEntries,NULL);
      if ((nStatus == NERR_Success) || (nStatus == ERROR_MORE_DATA)){
         if ((pTmpBuf = pBuf) != NULL)
         {
            for (i = 0; (i < dwEntriesRead); i++)
            {
               assert(pTmpBuf != NULL);//校验获取的值
               if (pTmpBuf == NULL)
               {
                  fprintf(stderr, "An access violation has occurred/n");
                  break;
               }
               wprintf(L"/t-- %s/n", pTmpBuf->usri0_name);
               pTmpBuf++;               
            }
         }
      }
      else
         fprintf(stderr, "A system error has occurred: %d/n", nStatus);
      if (pBuf != NULL)
      {
         NetApiBufferFree(pBuf); //释放缓冲区资源
         pBuf = NULL;
      }
   }while (nStatus == ERROR_MORE_DATA);
   if (pBuf != NULL)

      NetApiBufferFree(pBuf);

  在以上代码中,我利用LPUSER_INFO_0类型变量pTmpBuf获得帐户信息,由于level为0,因此我只能得到usri0_name,也就是帐户名称。不断进行调用这个函数来获取其他的帐户名称,直到该函数返回ERROR_MORE_DATA标志。注意的是缓冲pBuf必须要用函数NetApiBufferFree来释放资源。

  其他的获取用户信息的函数如下:

http://msdn.microsoft.com/library/en-us/netmgmt/ntlmapi2_3crz.asp

http://msdn.microsoft.com/library/en-us/wnet/networks_1ik2.asp

 http://msdn.microsoft.com/library/en-us/wnet/networks_43la.asp

3、 获取其他信息

  除了用户信息外,我们还可以利用IPC$来获得系统其他信息,如机器名、共享信息、系统进程信息等等。太可怕了,连目标机器上在做什么都可以知道。

  下面再来看一个API函数NetQueryDisplayInformation

 大家看了这么多代码是不是都有点晕啊?耐心点啦。:P

 NET_API_STATUS NetQueryDisplayInformation(
  LPCWSTR ServerName,            
  DWORD Level,                   
  DWORD Index,                   
  DWORD EntriesRequested,        
  DWORD PreferredMaximumLength
  LPDWORD ReturnedEntryCount,    
  PVOID *SortedBuffer            

);

  该函数可以用来列举Computer Name Comment Group ID等等信息。第一个参数含义跟NetUserEnum函数中的一样;第二个参数level指明了我们要得到的信息内容是什么,0表示获取用户信息1表示获取机器信息2表示获取用户组信息;第三个index就不用说了吧?不懂自己看MSDN去!我们来看一下如何利用这个函数的CODE SAMPLE

  do
   { 
      res = NetQueryDisplayInformation(szServer, 1, i, 1000, 0xFFFFFFFF, &dwRec, &pBuff);
      if((res==ERROR_SUCCESS) || (res==ERROR_MORE_DATA))
      {
         p = pBuff;
         for(;dwRec>0;dwRec--)
         {
            printf("Comment:      %S/n"
                  p->usri1_comment);
            i = p->usri1_next_index;
            p++;
         }
         NetApiBufferFree(pBuff);//释放缓冲区资源
      }
      else
         printf("Error: %u/n", res);

   } while (res==ERROR_MORE_DATA);

  这个例子比较简单,有了前面的基础,相信大家都能看懂,主要就是明白PNET_DISPLAY_USERNET_DISPLAY_MACHINENET_DISPLAY_GROUP这几个结构的作用。我就不罗嗦了。

  利用空连接,还可以获取很多很多的信息,具体的API函数自己到MSDN上找了。利用未公开的PHD API甚至可以将目标机器上进程信息杀死,达到破坏对方系统的作用,当然前提是有获得足够的权限了。

该函数参考:

http://msdn.microsoft.com/library/en-us/netmgmt/ntlmapi2_2f5a.asp

4、 穷举密码

  最激动人心的时刻到了!在通过上面几个措施后,如何得到已知用户名的密码呢?呵呵,其实啊,这是最简单的了。利用我第一措施中写的函数ConnetIPC,构造一个User和Pass,替换两个空字串就可以了。不断地调用这个函数就可以做到穷举啦,如果返回真的话那你就太幸福了!具体的构造过程可以利用ASCII码表,也可以利用字典,这么简单的,不用我再写CODE吧?

 三、如何防范IPC$空连接

  这里,我们先弄清一个概念:(1)禁止匿名用户进行IPC$ NULL Session;(2)禁止匿名用户利用IPC$ NULL Session获取SAM信息;这两个其实是不同的,很多人以为做到了2就不允许连接了。

  如果你的机器只是用来上网浏览、发邮件等工作,那么完全可以禁止IPC$连接,可以采用以下方法:

1、我们首先运行regedit,找到

[HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/LSA]

把RestrictAnonymous = DWORD的键值改为:00000001

2、在本地安全策略中的安全选项中修改。

3、Disable 了Netbios Over TCP/IP

  实际使用中,由于我们的机器要提供一些服务,如SQL SERVER是不可能禁用它的。那么我可以允许连接,但是禁止它来获取系统信息。那么我可以这样实现:RestrictAnonymous = DWORD的值改为00000002;当然也可以在本地安全策略中修改,这两者本质是一样的,只不过后者提供了一个界面而已。

 四、IPC$的高级进阶

  本来我没打算写这部分内容的,后来觉得能起点拨的作用,就简单地提一下这部分内容,其实都是参考其他文章的。

  我们知道,一般的服务器很难禁止IPC$连接,但是可以做到不让你枚举用户信息,那么我们有什么措施呢?有,利用SID!SID就是Security ID,每个用户、组都对应了一个SID。在建立了IPC$后,我们可以利用LookupAccountName来获取已知用户名(一般我们用GUEST或IUSR_xxxx)的SID,再根据SID的系统类似性来穷举帐户信息,这个API是LookupAccountSID。这方面的东西内容非常多,我只做个简单的提示。如果可以,我再专门写个这方面的文章。

  通过以上说的一些措施获取到ADMIN的权限后,如果只是想破坏系统而并非入侵,那么利用编程和IPC$,我们还可以用PHD API来直接远程杀死目标系统的进程,达到破坏服务的作用。PHD API是微软没有公布的API,我也只是看了一点相关的资料,等熟悉了后还可以写个相关文章。呵呵!

 总结

  本文内容大都是可以用NET命令实现,但是对于初级“黑客”而言,可能连NET命令甚至DOS命令都不会用,另外,有的时候程序可以帮你省却很多工作。这就是本文的目的之一。利用本文第2部分所讲的内容,我们也可以写出一个简单的扫描器。

  IPC$空连接不能说是一个系统漏洞,只能说是一个隐患吧。而且,收集目标信息的方式有很多,如ICMP、SNMP、IIS Banner、FTP  Welcome Message等等。本文只是帮助初学者理解IPC$,利用和防范IPC$。

  本人在业余时间写了一个小软件,可以利用这个小软件来穷举Administrator的6位密码(大于这个长度暴力破解其实也没多大意义),其原理就是利用IPC$空连接。当然这个小软件只是起个抛砖引玉的作用,功能很弱,也不能使用字典。有兴趣的人可以找我索取代码。

你可能感兴趣的:(编程技术)