如何为Active Directory配置密码黑名单 - 嘶吼 RoarTalk – 网络安全行业综合服务平台,4hou.com

如何为Active Directory配置密码黑名单

lucywang web安全 2018-07-23 11:02:57
263526
收藏

导语:Yelp是美国著名商户点评网站,创立于2004年,类似于中国的大众点评网。在这篇文章中,将详细描述一下Yelp是如何利用现有的开源DLL来构建密码黑名单服务,以满足他们的安全策略和需求。

360截图16241228356989.jpg

Active Directory的密码漏洞

活动目录(Active Directory)是面向Windows Standard Server、Windows Enterprise Server以及Windows Datacenter Server的目录服务。(Active Directory不能运行在Windows Web Server上,但是可以通过它对运行Windows Web Server的计算机进行管理。)Active Directory存储了有关网络对象的信息,并且让管理员和用户能够轻松的查找和使用这些信息。Active Directory使用了一种结构化的数据存储方式,并以此作为基础对目录信息进行合乎逻辑的分层组织。

Microsoft Active Directory服务是Windows平台的核心组件,它为用户管理网络环境各个组成要素的标识和关系提供了一种有力的手段。不过常见的一个漏洞是,对于那些并不关心活动目录安全的用户来说,应该如何去实施强化活动目录密码?毫无疑问,在日益严重的安全环境中,弱活动目录密码是最大的漏洞之一,就连许多企业的专业安全人员使用的密码都容易受到攻击。

毫无疑问,许多攻击者目前已经掌握了多种破解密码的专业知识,其中破解流行密码的字典攻击变得越来越有攻击力。因此,美国国家标准与技术研究院(NIST)建议为Active Directory配置密码黑名单,以阻止此类攻击。不过,为Active Directory配置密码黑名单目前仍然是一项相对较新的创新,企业尚未实现广泛的应用。

然而,对于像Yelp这样注重安全的人气网站来说,他们已经及时采用了此类防御机制。由于Yelp使用Active Directory(AD)对所有员工进行身份验证和管理,因此可以实现他们自己的自定义密码过滤器动态链接库(Password Filter DLL)。Yelp是美国著名商户点评网站,创立于2004年,类似于中国的大众点评网。在这篇文章中,将详细描述一下Yelp是如何利用现有的开源DLL来构建密码黑名单服务,以满足他们的安全策略和需求。

为什么Yelp不使用付费的商业安全策略

鉴于目前可用的安全方案的选择过多,Yelp首先讨论了是使用付费的商业解决方案还是使用现有的开源自定义安全策略。虽然许多第三方安全提供商都提供了易于设置并证明是有效的解决方案,但是,它们通常缺乏密码过滤的透明度。另外,他们还担心第三方出现的任何故障都可能导致其子系统服务崩溃,从而导致蓝屏死机并重新启动所有受影响的域控制器(DC)。因此,使用付费的商业解决方案的风险是:

1.如果发生第三方解决方案的崩溃,将极大地影响Yelp的业务;

2.依赖第三方提供商处理安全敏感问题,会增加Yelp的攻击范围;

因此Yelp的安全管理人员选择了一种开源解决方案,可以根据他们的安全需求提供各种自定义的安全控制。

选择解决方案

经过大量的研究和测试,Yelp的安全管理人员发现OpenPasswordFilter(OPF)最符合他们的需求。他们选择了最原始的版本,并给它增加了连接SQL数据库的能力,而不是比较纯文本中的哈希值。使用自定义密码过滤器动态链接库的最大问题之一是本地安全机构(LSA)运行的任何错误都可能导致正在运行的DC服务器崩溃。另一个主要的问题是确保在不影响用户体验的情况下快速有效的添加新密码。所选择的解决方案通过结合面向服务的体系结构解决了这两个问题,该体系结构将基本的LSA线程代码与过滤功能分离,同时还集成了可由服务直接查询的基于SQL的数据库。此外,在过滤过程中,该设计还进行了安全保护,任何触发的异常或错误都将导致系统打开失败,从而最大程度的限制了令人担忧的DC关闭的可能性。鉴于LSA对DLL错误的脆弱性,这是必要的权衡,特别是密码重置被破坏后所造成的记录错误。

系统架构

密码过滤服务由三部分组成:

· OPF Service:用于密码验证的模块(通过 loopback与DLL通信);

· OPF DLL:原始密码过滤器DLL,它与LSA连接以用于凭证验证;

· OPF DB:数据库中包含所有易受攻击密码的SHA-1哈希值;

每当客户端请求更改密码时,此请求将通过其指定的与LSA联系的域控制器进行路由。如果未满足默认密码策略(最小密码长度和某些字符标准的组合),则不会调用密码筛选器DLL,并自动拒绝密码。但是,如果满足默认策略要求,则将使用密码调用DLL。该过程的示意图如下所示:

image00.png

Active Directory密码过滤器身份验证流程

具体步骤如下,总共7步:

1.客户端通过DC向LSA发起密码请求更改,从DC到LSA的联系是通过配置LSA通知包完成的。如果满足默认密码策略,则将调用已注册的DLL,否则将拒绝密码。

2.PasswordFilter函数是Microsoft的PasswordFilter DLL接口的三种核心方法之一。此函数根据是否应进行重置返回一个布尔响应。OPF版本尝试连接到loopback接口上的特定端口,以调用已注册的服务。如果连接失败,则由于其故障安全性,该函数返回true。

3.如果可以连接建立起来后,则DLL会尝试将凭据发送到OPF服务。首先发送preamble码,即随机接入前导码,然后发送凭证。

4.然后检查哈希凭证(SHA-1)是否存在于容易受损密码的数据库中,对密码哈希值的索引使得这一过程明显更快。

5.根据是否找到哈希,将代表成功或失败的消息返回给OPFService,OPFService以初始DLL的形式,将该消息作为布尔值返回给LSA。

6.对所有已注册的DLL重复上述过程,假设一切都成功,密码将正式提交给安全帐户管理器(SAM)。

7.然后调用PasswordChangeNotify函数为每个注册DLL进行同步。

安全性测试

最后的安全性测试尤为重要,因为一旦安全性得不到实际保证,则任何实际中的错误都会产生严重影响,比如导致域控制器崩溃。此外,为了确保系统不会因测试而占用大量的系统资源。因此,在测试之前,测试人员先在一个独立的域控制器上测试了该服务,然后再在实验室环境中进行了测试。方法如下:

1.在独立域或实验室域中设置一个DC;

2.根据Yelp的密码策略配置默认的域密码策略设置;

3.下载一些最常被攻击的密码列表,从中进行抽样;

4.将抽样的密码随机分成四个子集,每个大小为5000:

· 4.1 符合默认政策但属于黑名单的子集命名为A;

· 4.2 符合默认政策但不属于黑名单的子集命名为B;

· 4.3 不符合默认策略且属于黑名单的子集命名为C;

· 4.4不符合默认策略且不属于黑名单的子集命名为D;

对于上述四个子集,安全人员只期望子集B可以重置成功。

5.为子集B和子集C生成SHA-1哈希值;

6.在要测试的总密码数量中创建启用的LDAP用户;

7.创建一个CSV文件,每行包含用户、密码和与密码分类相关的类别(A,B,C,D);

8.运行他们定制的PowerShell脚本(下面会提到),以检查已验证的安全行为;

Powershell脚本的详细信息

1.每个启用的用户都尝试重置各自的密码;

2.使用秒表记录所需的总时间;

3.根据退出代码验证预期的重置成功;

4.然后执行AD绑定以验证是否成功登录;

5.预期的AD绑定行为也基于退出代码并要进行验证;

6.结果按密码类别汇总并输出,具体而言,就是每个密码重置的平均时间和发现的错误数量;下面的脚本就是执行上述测试的:

param([string]$file, [string]$dc, [string]$admin_usr, [string]$admin_pwd)# Default error usage message
    Set-Variable errUsg -option Constant -Value "$($MyInvocation.MyCommand.Name) [CSV_FILE] [DC] [ADMIN_USR] [ADMIN_PWD]"# Ensure proper parameters are given
    $CommandName = $MyInvocation.InvocationName    $ParameterList = (Get-Command -Name $CommandName).Parameters    foreach ( $key in $ParameterList.Keys  ) {
        $value = (Get-Variable $key -ErrorAction SilentlyContinue).Value            if ([string]::IsNullOrEmpty($value)) {
                Write-Host "Required parameter not found."
                Write-Host "$errUsg"
                exit 1            }
    }# Check existence of csv fileif (!(test-path $file)) {
    Write-Host "File $file not found."
    exit 1}# Set password types and associated expectations (0 = failure, 1 = success)$csv = Import-CSV -Path $file$pwdTypes = @("NO_POLICY_NO_DUMP", "NO_POLICY_YES_DUMP", "YES_POLICY_NO_DUMP", "YES_POLICY_YES_DUMP")$expected = @(0, 0, 1, 0)$times = @(0) * 4$errors = @(0) * 4$counts = @(0) * 4# Check provided DC is valid and that admin login credentials validdsquery user -u $admin_usr -p $admin_pwd -s $dc -q > $null 2>&1if ($LastExitCode -ne 0) {
    Write-Host "Invalid remote credentials or DC server specified."
    exit 1}# Start loggingstart-transcript -path C:\nail\syslog\DLL_LOG_$(get-date -format 'MM-dd-yyyy-HH-mm-ss').logForeach ($el in $csv) {

    # Extracted relevant fields
    $ex = $expected[$el.Id]    $type = $pwdTypes[$el.Id]    $usr = dsquery user -samid $el.User -s $dc -u $admin_usr -p $admin_pwd
    $pwd = $el.Password    # Record time in milleseconds for password reset
    $sw = [system.diagnostics.stopwatch]::startNew()
    dsmod user $usr -pwd "$pwd" -mustchpwd no -d $dc -u $admin_usr -p "$admin_pwd" > $null 2>&1    $sw.Stop()

    # Check exit code with expectations to validate reset success
    $r_s = If ($lastexitcode -ne 0) {0} Else {1}
    $t = $sw.get_ElapsedMilliseconds()
    $times[$el.Id] += $t
    if ($r_s -ne $ex) {
        $errors[$el.Id]++    }

    # Perform AD bind and check with expectations to verify successful login
    (new-object directoryservices.directoryentry "", $usr, $pwd).psbase.name -ne $null > $null 2>&1    $b_s = If ($lastexitcode -ne 0) {0} Else {1}
    if ($b_s -ne $ex) {
        $errors[$el.Id]++    }

    # Log appropriately in the format of (EXPECTED, ACTUAL) for both the reset and bind
    $logline = "($usr) : [ $type  ] : RESET ($ex,$r_s) : BIND ($ex,$b_s) : TIME ($t)"
    if (($b_s -ne $ex) -or ($r_s -ne $ex)) {
        $logline = "[ERROR] [PASSWORD = $pwd] $logline"
    }
    $counts[$el.Id]++    Write-Output $logline}# Aggregate final resultsWrite-Output ("*" * 22)Write-Output "RESULTS:"for ($i=0; $i -lt $pwdTypes.Length; $i++) {
    $type = $pwdTypes[$i]
    if ($counts[$i] -ne 0) {
        $t = $times[$i] / $counts[$i]
    } else {
        $t = 0    }
    $es = $errors[$i]
    Write-Output "($type) ERRORS: $es AVG TIME: $t"}  stop-transcript

安全测试结果

通过测试,安全管理人员不仅可以验证密码过滤服务的正确性,还可以查看重置时间间隔等数据。

3.png

AD密码重置时间间隔(带有DLL))

更重要的是,DLL还进行了边际时间的计算:

4.png

AD密码重置时间间隔(带有DLL)

5.png

AD密码重置时间间隔(带有DLL)

在对安全人员找出的100万个密码样本进行检测后,他们有了以下发现:

平均剩余时间(在独立的域控制器测试环境下) :

6.jpg

平均剩余时间(在试验环境下):

7.jpg

总结

总而言之,这个安全解决方案使Yelp能够更好的理解AD身份验证背后的安全基础,并为Yelp提供了更强大的安全防护层,以防止针对易受攻击的密码字典发起的攻击。

在此,我强烈建议在公司环境中应该采用类似的黑名单措施。至少,它可以确保不会出现密码被攻击的危险。一句话,黑名单提供了一种更有效的方法来缓解字典攻击,同时又不会产生让密码的保护变得极其复杂。

  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论

 
本站4hou.com,所使用的字体和图片文字等素材部分来源于原作者或互联网共享平台。如使用任何字体和图片文字有侵犯其版权所有方的,嘶吼将配合联系原作者核实,并做出删除处理。
©2022 北京嘶吼文化传媒有限公司 京ICP备16063439号-1 本站由 提供云计算服务