关于冰盾 | 使用条款 | 网站地图
 
解剖WIN2K下的空会话
解剖WIN2K下的空会话
作者:冰盾防火墙 网站:www.bingdun.com 日期:2014-12-10
 

I、 Introduction 
II、 About TCP port 445 
III、The null session 
IV、 Break through "RestricAnonymous=1" 
V、 Conclusion


终于有时间可以写自己的东西了。呵呵,直入主题,不废话了。

I、 Introduction

关于WIN2K下面的空会话,已经是一个很老的话题了。当然,也一直被认为是WIN2K自带的一个后门。当建立一个空会话之后,对于一台配置不到位的WIN2K服务器来说,那么将能够得到非常多的信息,比如枚举帐号等等。


II、 About TCP port 445 WIN2000的TCP 445端口

SMB(Server Message Block)协议在NT/2000中用来作文件共享,在NT中,SMB运行于NBT(NetBIOS over TCP/IP)上,使用137,139(UDP),139(TCP)端口。在2000中,SMB可以直接运行在tcp/ip上,而没有额外的NBT层,使用TCP 445端口。因此在2000上应该比NT稍微变化多一些。

可以在“网络连接/属性/TCPIP协议/属性/高级/WINS中设置启用或者禁用NBT(NetBIOS over TCP/IP)。

当2000使用网络共享的时候,就面临着选择139或者445端口了。下面的情况确定会话使用的端口:

1、如果客户端启用了NBT,那么连接的时候将同时访问139和445端口,如果从445端口得到回应,那么客户端将发送RST到139端口,终止这个端口的连接,接着就从445端口进行SMB的会话了;如果没有从445端口而是从139得到回应,那么 
就从139端口进行会话;如果没有得到任何回应,那么SMB会话失败。 
2、如果客户端禁用了NBT,他就将只从445端口进行连接。当然如果服务器(开共享端)没有445端口进行SMB会话的话,那么就会访问失败了,所以禁用445端口后,对访问NT机器的共享会失败。 
3、如果服务器端启用NBT,那么就同时监听UDP 137、138端口和TCP139,445。如果禁用NBT,那么就只监听445端口了。

所以对于2000来说,共享问题就不仅仅是139端口,445端口同样能够完成。


III、The NULL session关于空会话

NULL会话(空会话)使用端口也同样遵循上面的规则。NULL会话是同服务器建立的无信任支持的会话。一个会话包含用户的认证信息,而NULL会话是没有用户的认证信息,也就好比是一个匿名的一样。

没有认证就不可能为系统建立安全通道,而建立安全通道也是双重的,第一,就是建立身份标志,第二就是建立一个临时会话密匙,双方才能用这个会话进行加密数据交换(比如RPC和COM的认证等级是PKT_PRIVACY)。不管是经过NTLM还是经过Kerberos认证的票据,终究是为会话创建一个包含用户信息的令牌。(这段来自Joe Finamore)

根据WIN2000的访问控制模型,对于空会话同样需要提供一个令牌。但是空会话由于是没有经过认证的会话,所以令牌中不包含用户信息,因此,建立会话双方没有密匙的交换,这也不能让系统间发送加密信息。这并不表示空会话的令牌中不包含SID,对于一个空会话,LSA提供的令牌的SID是S-1-5-7,这就是空会话建立的SID,用户名是 ANONYMOUS LOGON。这个用户名是可以在用户列表中看到的。但是是不能在SAM数据库中找到,属于系统内置的帐号。 
(关于这部分对NULL SESSION的分析,可以参照:《NULL Sessions In NT/2000http://rr.sans.org/win/null.php)

NULL会话几乎成为了微软自己安置的后门,但是微软为什么要来设置这样一个“后门”呢?我也一直在想这个问题,如果NULL会话没有什么重要的用途,那么微软也应该不会来设置这样一个东西。好不容易才在微软上找到这个:

当在多域环境中,要在多域中建立信任关系,首先需要找到域中的PDC来通过安全通道的密码验证使用空会话能够非常容易地找到PDC,还有就是关于一些系统服务的问题。而且LMHOSTS的#Include就需要空会话的支持,可以参考文章: 
aspx?scid=kb;EN-US;q121281">http://support.microsoft.com/default.aspx?scid=kb;EN-US;q121281 
http://support.microsoft.com/default.aspx?scid=kb;EN-US;q124184

其实建立一个空会话的条件也非常严格。首先要能够满足上面的,也就是打开TCP 139和TCP 445端口。我们可以从一次关闭这两个端口的情况中看得出来。服务器关闭445和139端口,然后我们来进行空会话的连接。首先,客户端打算 
连接的是445端口,然后再试图连接139端口。当然最后还是失败了。 
仅仅开放这两个端口还不行,服务器还必须得打开IPC$共享。如果没有IPC共享,即使共享一个文件,有权限为Anonymous Logon,也不能建立会话,即使权限设置为完全控制,出现的连接错误依然是权限不够。这和其他帐号是不一样的。如果要允许一个文件夹共享能够类似IPC$(命名管道而非共享)能够使用空会话,那么需要修改注册表: 
HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServiceslanmanserverparameters中的:NullSessionShares, 
添加新的共享名,这样才能建立一个共享的空会话。这时,将不依赖IPC的存在了。(即使这样的空会话对于后面的突破也是一点没可取之处的,因为没有了IPC$命名管道,RPC不可取了,这下知道IPC这个命名管道的具体实现了。呵呵)

虽然空会话建立的要求很严格,但是那都是默认建立的。既然是默认的,对于使用WIN2K系统的服务器来说,就还是有利用的价值。最明显的就是空会话可以很方便地连接到其他的域枚举用户、机器等。这也就是扫描软件进行探测的原理。我举个简单的程序例子来说明这个用途,并枚举用户组和用户。

#include <windows.h> 
#include <stdio.h> 
#include <lm.h>

#pragma comment (lib "Mpr.lib") 
#pragma comment (lib "Netapi32.lib")

void explorer_groups(char *);

void main( int argc char *argv[ ] ) 
{ 
DWORD ret; 
char username[100] = "" password[100] = ""; 
char server[100] = "" ipc[100] = ""; 
NETRESOURCE NET;

if (argc == 1) { 
exit(1); 
}

strncpy(serverargv[1]100); 
printf("server: %s " server);

sprintf(ipc"\\%s\ipc$"server);

NET.lpLocalName = NULL; 
NET.lpProvider = NULL; 
NET.dwType = RESOURCETYPE_ANY; 
NET.lpRemoteName = (char*)&ipc;

printf("setting up session... "); 
ret = WNetAddConnection2(&NET(const char *)&password(const char *)&username0);

if (ret != ERROR_SUCCESS) 
{ 
printf("IPC$ connect fail. "); 
exit(1); 
} 
else printf("IPC$ connect success. "); 
explorer_groups((char*)&server);

printf("Disconnect Server... "); 
ret = WNetCancelConnection2((char*)&ipc0TRUE); 
if (ret != ERROR_SUCCESS) 
{ 
printf("fail. "); 
exit(1); 
} 
else printf("success. "); 
exit (0); 
}

void explorer_groups(char *server) 
{ 
DWORD ret read total resume = 0; 
int i; 
LPVOID buff; 
char comment[255]; 
wchar_t wserver[100];

do { 
ret = NetLocalGroupEnum(wserver 1 (unsigned char **)&buff MAX_PREFERRED_LENGTH &read &total &resume);

if (ret != NERR_Success && ret != ERROR_MORE_DATA) 
{ 
printf("fail "); 
break; 
} 
PLOCALGROUP_INFO_1 info = (PLOCALGROUP_INFO_1) buff;

for (i=0; i<read; i++) { 
printf("GROUP: %S "info[i].lgrpi1_name);

WideCharToMultiByte(CP_ACP 0 info[i].lgrpi1_comment -1 comment255NULLNULL); 
printf(" COMMENT: %s "comment);

DWORD ret read total resume = 0; 
ret = NetLocalGroupGetMembers((const unsigned short*)&wserver info[i].lgrpi1_name 2 (unsigned char **)&buff 1024 &read &total &resume);

if (ret != NERR_Success && ret != ERROR_MORE_DATA) { 
printf("fail ");en 
break; 
}

PLOCALGROUP_MEMBERS_INFO_2 info = (PLOCALGROUP_MEMBERS_INFO_2) buff;

for (unsigned i=0; i<read; i++) { 
printf(" %S " info[i].lgrmi2_domainandname); 
printf(" SID:%d " info[i].lgrmi2_sid); 
printf(" SIDUSAGE:%d "info[i].lgrmi2_sidusage); 
} 
NetApiBufferFree (buff); 
}

NetApiBufferFree (buff);

} while (ret == ERROR_MORE_DATA ); 
}

这是一个简单的例子。当然可以查询更多的东西。类似,就不再重复了。枚举用户名是很重要的用途,因为接下来可以做的就是进行密码的猜解,这对系统安全构成的威胁是非常大的。

想到有威胁,就需要知道怎么防范。防范很简单。不过这里需要提醒的是关于注册表(或者安全策略中)中可以设置Restrictanonymous为1,这样可以禁止空连接进行枚举。因为很多安全配置介绍中都是这样做的,因为如果设置为2的 
话,有一些问题会发生。比如一些WIN的服务出现问题等等。但是,RestricAnonymous设置为1并不会组织用户帐号的枚举。因为空连接是一样能够建立的,并不是说阻止了空连接的建立。但是我们这里需要来突破!!


IV、 Break through "RestricAnonymous=1"突破RestricAnonymous=1的限制进行用户枚举

虽然我们还是能够建立空连接,但是却没有那些NET函数的访问权限了。这个可以看MSDN上关于对网络管理函数的安全问题。但是,有一个突破点,呵

 

 
最新内容:
如何防止IP地址被被盗[2014-12-10]
局域网安全:解决ARP攻击的方法[2014-12-10]
如何通过DNS技术检查与排除网络故障?[2014-12-10]
如何对移动应用进行黑盒测试[2014-12-10]
对某安全网站DNS区域传送漏洞的检测分析[2014-12-10]
加载页面:网站如何导致用户感染恶意软件[2014-12-10]
相关内容:

合作伙伴: 黑基网 补天科技 威盾科技 站长下载 新飞金信 北京电信 ZOL应用下载
中华人民共和国增值电信业务经营许可证京ICP备14024464 公安备案号 京1081234 
版权所有©2003-2014 冰盾防火墙  www.BingDun.com 法律声明
总机:(010)51661195