一、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) |
上面的函数可以实现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_USER、NET_DISPLAY_MACHINE、NET_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$空连接。当然这个小软件只是起个抛砖引玉的作用,功能很弱,也不能使用字典。有兴趣的人可以找我索取代码。