您的位置:首页 > 其它

如何判断一台机器是否属于域

2010-12-14 17:13 218 查看
ref : http://blog.csdn.net/amandar/archive/2005/12/29/564774.aspx





如何判断一台机器是否属于域
收藏

解决问题的方向

查看 Windows LOGON 的描述.

1.概念.

NT的LOGON描述开始了.在讲述NT的LOGON之前,有几个关键的字眼要说一下.

LOGON进程: NT的登录进程.拥有工作站,桌面,键盘,鼠标的独占控制.

GINA: Graphical Identification and Authentication,图形身份验证

GINA STUB: 实现部分GINA接口的一个DLL.

LSA: Local Security Authority, 本地安全验证

MPR: Multiple Provider Router.网络供应者路由器.:D

NP: Network Provider.网络供应者.

LOGON进程乃是登录的初始者,也是用户在使用安装有NT计算机时通常会经历的登录阶段的前台程序.LOGON本身是个很特殊的应用程序.名字为登录,但是实际上并不负责登录验证.他仅仅收集用户名,密码,域的信息.进行一些特定的操作.这些特定的操作将在后面讲到.

GINA

实际上是个DLL.MS对他的定义是图形身份验证,其实也不负责验证.那么为什么要称为图形身份验证呢?关键是LOGON进程把验证请求扔给GINA后就
不管了.对LOGON来说就是验证了.:DDD 这是我的猜测不是MS官方的信息.
GINA本身是LOGON用到的一个DLL.这个DLL在LOGON的地址空间内. GINA本身能够很大程度上影响LOGON的运行逻辑.

GINA STUB,MS介绍了GINA STUB的概念,它是个轻量级的GINA.本身实现部分的接口,其他的接口仍然有老的GINA实现,GINA STUB则负责PASS DOWN函数调用.

LSA,从INSIDE NT书上讲,LSASS(LSA的实际实现)乃是LOGON进程的子进程.从实际的NT运行实际看,尽管LSASS是LOGON的子进程,但是在逻辑上却是平级的.LOGON通过LPC和LSASS交互,来实际进行登录操作.

MPR,

很关键的NT网络实现组件.由于NT允许多个网络架构的存在,如同时有NETWARE服务器存在于NT网络上.所以,MPR成为了WINDOWS网络应用
的实际枢纽.如同在本机上的IO管理器,拥有对本机的绝对权威,而MPR则在本机访问网络时有绝定性作用.从NT的实际实现上看,任何一个
WIN32API在访问一个资源时,IO管理器都会检查该资源是否为网络资源.如果为网络资源,则将控制转MPR.有MPR负责对该资源的控制.

NP: 为了让多种架构的网络同时并存于NT.网络供应商必须提供他自己的DLL,并且实现MS规定的特定的接口,以变MPR对网络资源的调度.

当NT启动LOGON时,LOGON会加载一些DLL.这些DLL就是GINA和一些NP.(关于大体的描述,在INSIDE NT第二版里有描述.这里描述一些关键的小细节.)

GINA本身有注册表里的/HKEY_LOCAL_MACHINE/Software/Microsoft/Windows NT/CurrentVersion/Winlogon/


的键GinaDLL定义.该处的值为GINA的实际DLL名.GINA负责的乃是提供用户界面和搜集登录信息.通常对应LOGON进程最大的误解就是
LOGON负责登录的验证,但是其实真正的验证是在LSA进行的.由于GINA本身能够获取纯文本形式的用户名和密码,所以黑白两道都对GINA青眼有
加.但是正由于GINA本身被这么多的程序员盯住,任何人都不能保证自己开发的GINA不会在其他软件被人家的GINA替换调.这里我将先分析GINA,
并且尝试给出另外的方法获取登录通知.

LOGON本身和LSA的联接需要调用

NTSTATUS

LsaRegisterLogonProcess(

IN PLSA_STRING LogonProcessName,

OUT PHANDLE LsaHandle,

OUT PLSA_OPERATIONAL_MODE SecurityMode

);

由于所有的LSA调用都是特权调用,连ADMINISTRATOR也没有权限调用该函数.LSA调用只有操作系统才能进行,这些都是出于安全的考虑.为了表明自己就是OS或者自己从属于OS的一部分,调用者必须具有SeTcbPrivilege特权.

当LsaRegisterLogonProcess

成功后,调用者就获得的一个对LSA调用的令牌.现在,LSA已经知道,有个进程是登录进程,而且获得了他的注册名供审计用.现在,LOGON进程需要个
GINA沟通了.因为验证需要通过GINA参与进行.根据MS的功能模块定义,GINA才是和LSA最终打交道的模块.

那么就看看如何和GINA沟通吧.

GINA
通过EXPORT一个函数WlxNegotiate告诉LOGON自己的版本,并且得到LOGON的版本,用以支持不同的的协议集.当LOGON和
GINA都认为对方的版本可以满足自己的运行需求时,GINA的WlxInitialize函数被调用.在该函数被调用时,GINA将获得LOGON提供
的函数集.

NT3.51支持的函数集为

Typedef struct __win32_DISPATCH_VERSION_1_0 {

PWLX_USE_CTRL_ALT_DEL WlxUseCtrlAltDel;

PWLX_SET_CONTEXT_POINTER WlxSetContextPointer;

PWLX_SAS_NOTIFY WlxSasNotify;

PWLX_SET_TIMEOUT WlxSetTimeout;

PWLX_ASSIGN_SHELL_PROTECTION WlxAssignShellProtection;

PWLX_MESSAGE_BOX WlxMessageBox;

PWLX_DIALOG_BOX WlxDialogBox;

PWLX_DIALOG_BOX_PARAM WlxDialogBoxParam;

PWLX_DIALOG_BOX_INDIRECT WlxDialogBoxIndirect;

PWLX_DIALOG_BOX_INDIRECT_PARAM WlxDialogBoxIndirectParam;

PWLX_SWITCH_DESKTOP_TO_USERT WlxSwitchDesktopToUser;

PWLX_SWITCH_DESKTOP_TO_WINLOGON WlxSwitchDesktopToWinlogon;

PWLX_CHANGE_PASSWORD_NOTIFY WlxChangePasswordNotify;

} WLX_DISPATCH_VERSION_1_0;

NT4.0支持的函数集为

Typedef struct __win32_DISPATCH_VERSION_1_1 {

PWLX_USE_CTRL_ALT_DEL WlxUseCtrlAltDel;

PWLX_SET_CONTEXT_POINTER WlxSetContextPointer;

PWLX_SAS_NOTIFY WlxSasNotify;

PWLX_SET_TIMEOUT WlxSetTimeout;

PWLX_ASSIGN_SHELL_PROTECTION WlxAssignShellProtection;

PWLX_MESSAGE_BOX WlxMessageBox;

PWLX_DIALOG_BOX WlxDialogBox;

PWLX_DIALOG_BOX_PARAM WlxDialogBoxParam;

PWLX_DIALOG_BOX_INDIRECT WlxDialogBoxIndirect;

PWLX_DIALOG_BOX_INDIRECT_PARAM WlxDialogBoxIndirectParam;

PWLX_SWITCH_DESKTOP_TO_USERT WlxSwitchDesktopToUser;

PWLX_SWITCH_DESKTOP_TO_WINLOGON WlxSwitchDesktopToWinlogon;

PWLX_CHANGE_PASSWORD_NOTIFY WlxChangePasswordNotify;

PWLX_GET_SOURCE_DESKTOP WlxGetSourceDesktop;

PWLX_SET_RETURN_DESKTOP WlxSetReturnDesktop;

PWLX_CREATE_USER_DESKTOP WlxCreateUserDesktop;

} WLX_DISPATCH_VERSION_1_1;

NT4.0SP4的函数集为

Typedef struct __win32_DISPATCH_VERSION_1_2 {

PWLX_USE_CTRL_ALT_DEL WlxUseCtrlAltDel;

PWLX_SET_CONTEXT_POINTER WlxSetContextPointer;

PWLX_SAS_NOTIFY WlxSasNotify;

PWLX_SET_TIMEOUT WlxSetTimeout;

PWLX_ASSIGN_SHELL_PROTECTION WlxAssignShellProtection;

PWLX_MESSAGE_BOX WlxMessageBox;

PWLX_DIALOG_BOX WlxDialogBox;

PWLX_DIALOG_BOX_PARAM WlxDialogBoxParam;

PWLX_DIALOG_BOX_INDIRECT WlxDialogBoxIndirect;

PWLX_DIALOG_BOX_INDIRECT_PARAM WlxDialogBoxIndirectParam;

PWLX_SWITCH_DESKTOP_TO_USERT WlxSwitchDesktopToUser;

PWLX_SWITCH_DESKTOP_TO_WINLOGON WlxSwitchDesktopToWinlogon;

PWLX_CHANGE_PASSWORD_NOTIFY WlxChangePasswordNotify;

PWLX_GET_SOURCE_DESKTOP WlxGetSourceDesktop;

PWLX_SET_RETURN_DESKTOP WlxSetReturnDesktop;

PWLX_CREATE_USER_DESKTOP WlxCreateUserDesktop;

PWLX_CHANGE_PASSWORD_NOTIFY_EX WlxChangePasswordNotifyEx;

PWLX_CLOSE_USER_DESKTOP WlxCloseUserDesktop;

} WLX_DISPATCH_VERSION_1_2

注意,在MSDN里声称1.2版函数表在WIN2000里启用是不对的.其实,从NT4SP4就开始了.并且,由于对应函数集支持的问题,很多第三方的GINA就被废了.导致系统不能启动.

WIN2000的函数集为

Typedef struct __win32_DISPATCH_VERSION_1_3 {

PWLX_USE_CTRL_ALT_DEL WlxUseCtrlAltDel;

PWLX_SET_CONTEXT_POINTER WlxSetContextPointer;

PWLX_SAS_NOTIFY WlxSasNotify;

PWLX_SET_TIMEOUT WlxSetTimeout;

PWLX_ASSIGN_SHELL_PROTECTION WlxAssignShellProtection;

PWLX_MESSAGE_BOX WlxMessageBox;

PWLX_DIALOG_BOX WlxDialogBox;

PWLX_DIALOG_BOX_PARAM WlxDialogBoxParam;

PWLX_DIALOG_BOX_INDIRECT WlxDialogBoxIndirect;

PWLX_DIALOG_BOX_INDIRECT_PARAM WlxDialogBoxIndirectParam;

PWLX_SWITCH_DESKTOP_TO_USERT WlxSwitchDesktopToUser;

PWLX_SWITCH_DESKTOP_TO_WINLOGON WlxSwitchDesktopToWinlogon;

PWLX_CHANGE_PASSWORD_NOTIFY WlxChangePasswordNotify;

PWLX_GET_SOURCE_DESKTOP WlxGetSourceDesktop;

PWLX_SET_RETURN_DESKTOP WlxSetReturnDesktop;

PWLX_CREATE_USER_DESKTOP WlxCreateUserDesktop;

PWLX_CHANGE_PASSWORD_NOTIFY_EX WlxChangePasswordNotifyEx;

PWLX_CLOSE_USER_DESKTOP WlxCloseUserDesktop;

PWLX_SET_OPTION WlxSetOption;

PWLX_GET_OPTION WlxGetOption;

PWLX_WIN31_MIGRATE WlxWin31Migrate;

PWLX_QUERY_CLIENT_CREDENTIALS WlxQueryClientCredentials;

PWLX_QUERY_IC_CREDENTIALS WlxQueryInetConnectorCredentials;

PWLX_DISCONNECT WlxDisconnect;

} WLX_DISPATCH_VERSION_1_3;

这些函数在GINA本身的使用中将十分有用.当获取这些信息的同时,GINA通常会分配一些自己需要的内存.在MS自己的样板例程里,GINA需要分配一段内存,记录的是一些全局变量.这些变量的定义如下:

typedef struct _Globals {

BOOL fAllowNewUser;

BOOL fAutoLogonAtBoot;

BOOL fAutoLogonAlways;

HANDLE hUserToken;

PMiniAccount pAccount;

} Globals, * PGlobals;

PMiniAccount指针指向自己更感兴趣的用户名和密码结构:

typedef struct _MiniAccount {

struct _MiniAccount * pNext;

PWSTR pszUsername;

PWSTR pszDomain;

PWSTR pszPassword;

PWSTR pszComment;

DWORD IconId;

DWORD Flags;

} MiniAccount, * PMiniAccount;

好了,现在GINA相对于LOGON的初始化已经完成.但是现在还没有用户登录界面.当然,为了让GINA有机会显示欢迎图画,LOGON要求GINA EXPORT一个函数:

VOID WINAPI WlxDisplaySASNotice(PVOID pContext);


函数的唯一功能就是显示欢迎窗口.并且监督是否有自己定义的SAS(安全提示码序列)出现.如果出现,则要通知LOGON有个登录请求发出.SAS在NT

下缺省情况为CTL+ALT+DEL.但是并不一定只有CTL+ALT+DEL才能作为SAS.GINA本身可以提供SAS监督.当然,用CTL+ALT
+DEL更为方便.因为在初始化时GINA已经收到了一个函数:

VOID WlxUseCtrlAltDel(HANDLE hWlx);

该函数通知LOGON,GINA使用CTL+ALT+DEL为SAS.如果要用其他的SAS,GINA必须自己HOOK热键.并且通过:

WlxSasNotify(hGlobalWlx, dwSasType);

报告SAS出现.由于HOOK将更增GINA写作工作量,而且MS提供缺省的CTL+ALT+DEL服务,那么用CTL+ALT+DEL在决大多数情况下就够了.

会到话题.现在出现的是欢迎画面.当用户键入CTL+ALT+DEL时,登录接口出现了.:DDD现在我们就进入了MS所谓的INTERACTIVE LOGON.

现在,LOGON调用GINA的

int WlxLoggedOutSAS(

PVOID pWlxContext,

DWORD dwSasType,

PLUID pAuthenticationId,

PSID pLogonSid,

PDWORD pdwOptions,

PHANDLE phToken,

PWLX_MPR_NOTIFY_INFO pMprNotifyInfo,

PVOID *pProfile

);

函数.GINA现在用这个函数来显示对话框并且收集用户信息并且调用LSA进行验证.如果通过了验证,那么就会填写MprNotifyInfo结构.这个结构用以通知MPR:用户登录喽!


时,NT带的GINA会分析本机是否在一个DOMAIN里,根据不同的情况显示不同的对话框.当用户机器不属于DOMAIN.那么根本就没机会填写
DOMAIN名字.当机器隶属于一个NT网络架构的网,用户将可以有DOMAIN域填写.用以告知NT用户希望以什么身份登录.


次说到WlxLoggedOutSAS.该函数的实现中,GINA搜集了用户名,密码.如果机器在网络上,还有域名也被搜集到了.当然,搜集用户名和密码
本身并不是GINA的根本目的.GINA的根本目的是要把经过授权验证的用户登录.现在,GINA就根据搜集到的用户名和密码调用Lsa来登录用户.

首先,必须调用的是

NTSTATUS

LsaRegisterLogonProcess(

IN PLSA_STRING LogonProcessName,

OUT PHANDLE LsaHandle,

OUT PLSA_OPERATIONAL_MODE SecurityMode

);

该函数只有有SeTcbPrivilege的特权的程序可以调用.

通过第一参数,审计程序将记录是什么进程尝试了登录.这样才能达到所谓的C2级安全性:所有的行为能够被审计.

当该函数成功后,进程将获得和LSA交互的权限.

然后,调用

NTSTATUS

LsaLookupAuthenticationPackage(

IN HANDLE LsaHandle,

IN PLSA_STRING PackageName,

OUT PULONG AuthenticationPackage

);

GINA将查找MSV1_0_PACKAGE_NAME的验证包.该包提供缺省的登录验证服务.

当验证包被确定后,调用

NTSTATUS

LsaLogonUser(

IN HANDLE LsaHandle,

IN PLSA_STRING OriginName,

IN SECURITY_LOGON_TYPE LogonType,

IN ULONG AuthenticationPackage,

IN PVOID AuthenticationInformation,

IN ULONG AuthenticationInformationLength,

IN PTOKEN_GROUPS LocalGroups OPTIONAL,

IN PTOKEN_SOURCE SourceContext,

OUT PVOID *ProfileBuffer,

OUT PULONG ProfileBufferLength,

OUT PLUID LogonId,

OUT PHANDLE Token,

OUT PQUOTA_LIMITS Quotas,

OUT PNTSTATUS SubStatus

);

这里乃是一个LSA的CALL.通知LSA有人企图登录啦.

现在程序的控制被转移到了LSASS.

我们回头在讲述一下LSA这里的动静.

LSA和LOGON进程交互时,既然LOGON进程指定了验证包,那么验证包的初始化是一定要进行的.所以,LSA自己对于验证包要求必须EXPORT一个函数.这个函数就是

NTSTATUS

LsaApInitializePackage(

IN ULONG AuthenticationPackageId,

IN PLSA_DISPATCH_TABLE LsaDispatchTable,

IN PLSA_STRING Database OPTIONAL,

IN PLSA_STRING Confidentiality OPTIONAL,

OUT PLSA_STRING *AuthenticationPackageName

);

这个函数将只被调用一次.以后就永远不被调用了.并且是在系统启动LSASS时就调用了,并不等待LOGON的CALL才进行.

LSA当被调用LsaLogonUser时,LSA本身并不处理多少,将调用传递到

NTSTATUS

LsaApLogonUser(

IN PLSA_CLIENT_REQUEST ClientRequest,

IN SECURITY_LOGON_TYPE LogonType,

IN PVOID AuthenticationInformation,

IN PVOID ClientAuthenticationBase,

IN ULONG AuthenticationInformationLength,

OUT PVOID *ProfileBuffer,

OUT PULONG ProfileBufferLength,

OUT PLUID LogonId,

OUT PNTSTATUS SubStatus,

OUT PLSA_TOKEN_INFORMATION_TYPE TokenInformationType,

OUT PVOID *TokenInformation,

OUT PLSA_UNICODE_STRING *AccountName,

OUT PLSA_UNICODE_STRING *AuthenticatingAuthority

);

就算完事.同时,由于C2审计的原因,上面的函数缺少对客户机器名的审计,所以导致下面函数也进入了规范.

NTSTATUS

LsaApLogonUserEx(

IN PLSA_CLIENT_REQUEST ClientRequest,

IN SECURITY_LOGON_TYPE LogonType,

IN PVOID AuthenticationInformation,

IN PVOID ClientAuthenticationBase,

IN ULONG AuthenticationInformationLength,

OUT PVOID *ProfileBuffer,

OUT PULONG ProfileBufferLength,

OUT PLUID LogonId,

OUT PNTSTATUS SubStatus,

OUT PLSA_TOKEN_INFORMATION_TYPE TokenInformationType,

OUT PVOID *TokenInformation,

OUT PUNICODE_STRING *AccountName,

OUT PUNICODE_STRING *AuthenticatingAuthority,

OUT PUNICODE_STRING *MachineName

);

最后一个参数表明了客户机的名称.在微软自己的验证包里,它返回一个NETBIOS机器名.

当LsaApLogonUser

(Ex/Ex2)被调用时,验证包就获得了用户名和密码等信息.我们可以看到,在AuthenticationInformation指针处其实乃是一个
关键的结构.通常我们执行的是MSV1_0_INTERACTIVE_LOGON,指针则指向

typedef struct _MSV1_0_INTERACTIVE_LOGON {

MSV1_0_LOGON_SUBMIT_TYPE MessageType;

UNICODE_STRING LogonDomainName;

UNICODE_STRING UserName;

UNICODE_STRING Password;

} MSV1_0_INTERACTIVE_LOGON;

结构.MessageType用来表明这次LOGON是什么样的LONON.这里的一切都是以明文形式存在,包括用户名,密码,域名/机器名.:)

现在,MS的验证包就开始登录验证.从SAM里找出用户名,并验证密码.然后返回用户的令牌.


于登录目标不是本机,而是网络主域,那么LOGON调用NETLOGON
SERVICE完成登录.对于LSA来说,NETLOGN则比LOGON进程差不多.因为他们都调用LSA来完成登录.而NETLOGON比LOGON多
调用几次LsaApLogonUser(Ex/Ex2).因为需要完成对主域控制器和后备服务器的登录同步.

调用LSA的LsaLogonUser时.MS的验证包判断机器名是否为本机,如果不是本机,则执行一个PASS-THROUGH验证.

也就是说,验证由目标机验证包完成.本机验证包负责传送数据到目标机.

我们讲述一下PASS-THROUGH验证.


机将登录请求发送到本机所属的域控制器.然后域控制器检查是否域名和自己的域名相同.如果相同,则验证于域控制器继续进行.完成验证后返回数据给本机.并
且允许访问本机和域资源.如果域名不同于控制器的域名,域控制器检查是否该域是自己的信任域.如果是,域控制器将验证PASS到该信任域的域控制器.由信
任域的域控制器验证.验证完毕后,数据返回到域控制器,由域控制器返回数据到本机.而验证的具体步骤则仍如上所述.

验证完成后.一个令牌被返回.验证包填写的令牌信息为:

typedef struct _LSA_TOKEN_INFORMATION_V1 {

LARGE_INTEGER ExpirationTime;

TOKEN_USER User;

PTOKEN_GROUPS Groups;

TOKEN_PRIMARY_GROUP PrimaryGroup;

PTOKEN_PRIVILEGES Privileges;

TOKEN_OWNER Owner;

TOKEN_DEFAULT_DACL DefaultDacl;

} LSA_TOKEN_INFORMATION_V1, *PLSA_TOKEN_INFORMATION_V1;

而实际LsaLogonUser获得的是根据这些信息合成的TOKEN HANDLE.TOKEN本身的数据结构是不公开的.尽管我认为了解该结构似乎没有很大的意义.但是通过KD的!tokenfields命令我们可以看到数据结构.

另外还返回了用户的LOGON脚本于ProfileBuffer:

typedef struct _MSV1_0_INTERACTIVE_PROFILE {

MSV1_0_PROFILE_BUFFER_TYPE MessageType;

USHORT LogonCount;

USHORT BadPasswordCount;

LARGE_INTEGER LogonTime;

LARGE_INTEGER LogoffTime;

LARGE_INTEGER KickOffTime;

LARGE_INTEGER PasswordLastSet;

LARGE_INTEGER PasswordCanChange;

LARGE_INTEGER PasswordMustChange;

UNICODE_STRING LogonScript;

UNICODE_STRING HomeDirectory;

UNICODE_STRING FullName;

UNICODE_STRING ProfilePath;

UNICODE_STRING HomeDirectoryDrive;

UNICODE_STRING LogonServer;

ULONG UserFlags;

} MSV1_0_INTERACTIVE_PROFILE, *PMSV1_0_INTERACTIVE_PROFILE;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: