无论在PC还是服务器上,新建用户都是较为可疑的行为。许多安全软件已经对其进行拦截,但经过测试,大多数只过滤运行net.exe时的命令行。对于通过API函数NetUserAdd添加用户则无能为力。这样就有一个明显的漏洞,黑客可以通过VBS或者上传一个小程序来创建用户。
密码过滤器(PasswordFilter)正好可以填补这一漏洞。简单的说,密码过滤器是一个DLL,它导出的PasswordFilter和PasswordChangeNotify回调会分别在密码创建/修改前后被LSA调用。如果PasswordFilter拒绝当前操作,则修改密码创建/修改失败。我们可以在该函数内询问用户是否允许添加用户。代码如下:
#includeNtsecapi.h #includeWtsapi32.h #includeiostream #includestring #pragmacomment(lib,Netapi32.lib) #pragmacomment(lib,Wtsapi32.lib) usingnamespacestd; BOOLAPIENTRYDllMain(HMODULEhModule, DWORD ul_reason_for_call, LPVOIDlpReserved ) { switch(ul_reason_for_call) { caseDLL_PROCESS_ATTACH: caseDLL_THREAD_ATTACH: caseDLL_THREAD_DETACH: caseDLL_PROCESS_DETACH: break; } returnTRUE; } externC__declspec(dllexport) BOOLEAN_stdcallPasswordFilter( _In_ _In_ _In_ PUNICODE_STRINGAccountName, PUNICODE_STRINGFullName, PUNICODE_STRINGPassword, _In_ BOOLEANSetOperation ){ DWORDsessionId=WTSGetActiveConsoleSessionId(); DWORDret=0; wstringMsgTilte=L用户密码变动; wstringMsg=L用户+wstring(AccountName-Buffer)+L的密码正在被修改/创建, 是否允许?\n\n如果您未在10秒内作出选择,该操作将被拒绝。; BOOL bSuccess = WTSSendMessage(0, sessionId,(LPWSTR)MsgTilte.c_str(),2*MsgTilte.length(), MB_YESNO,15,ret,true); //只有明确的允许才返回true if(bSuccessret==IDYES)returntrue; //其他情况均返回false (LPWSTR)Msg.c_str(),2*Msg.length(), returnfalse; }
PasswordFilter函数有四个参数,其中前三个为用户名、用户全名和密码。第四个参数为SetOperaion,MSDN里说如果它为true,则密码正在被添加,否则就在被修改,但事实上它总是true。不过我们并不需要区分添加新用户和修改用户密码,这两种行为都要被监控,否则黑客可以将某个较少使用的用户据为己有,并隐秘的进入系统。
PasswordFilter会弹出一个对话框询问是否允许操作。注意,PasswordFilter被lsass.exe加载,所以一定运行在Session0中。直接弹出对话框用户是看不到的,所以需要用WTSGetActiveConsoleSessionId获得当前活动Session,并用WTSSendMessage函数在该Session里弹出对话框。这里WTSSendMessage设置一个Timeout是很有必要的,否则如果该用户一直不做出选择,PasswordFIlter函数就无法返回,那么涉及用户的操作都无法进行。比如一个程序在启动时需要确定登陆的用户,那么它毫无疑问会卡住,这对于无人值守的服务器来说,是不能接受的。
安装PasswordFilter也十分简单,只需将DLL复制到\Windows\System32下,并将DLL的名字(不含后缀)添加到HKLM\SYSTEM\CurrentControlSet\Control\Lsa下的NotificationPackages键值即可。
cd/d%~dp0 copy/YPasswordFilter.dll%systemroot%\SYSTEM32 regADDHKLM\SYSTEM\CurrentControlSet\Control\Lsa/vNotificationPackages/t REG_MULTI_SZ/dPasswordFilter/f pause
重启后尝试添加用户,如图1所示,PasswordFilter弹出对话框询问。
由于PasswordFilter可以直接得到密码明文,所以除了用来监控用户创建,还可以对密码的复杂度做一些规定。比如密码最少为8位,必须是数字和字母的组合等等,而这正是PasswordFilter机制的本意,有兴趣的读者可以自行研究。