一、前言
活动目录(AD)委派(delegation)是一个非常有趣的话题,我们之前已经在一篇文章和某次研讨会中讨论过这方面内容。总而言之,活动目录可以将某些权限委派给非(域/森林/企业)管理员用户,以便管理员对特定AD区域执行管理任务。如果配置不当,那么攻击者也可以利用这种功能入侵AD。
先前我们只讨论了如何手动查找这类委派,大家可以阅读另一篇文章,了解其他一些工具在手动分析中的应用。在本文中,我们将介绍如何利用脚本,以(半)自动化的方式在网络中搜索这类委派。
二、实验环境
假设我们面临的是如下场景:
- 具备某个低权限域用户访问权限,该账户有一些限制条件,比如AppLocker禁用此账户执行powershell。
- 在加入域的某台主机上具备本地管理员访问权限。
- 可以利用这个本地管理员权限运行未受限的powershell脚本,然而我们需要登录域才能在AD域上执行枚举操作。
为了完成任务,我们准备使用两种不同的方法:
- 使用AD ACLScanner(半自动化方法)
- 使用NSS提供的自定义Powershell脚本(全自动化方法)
三、ADACLScanner
这款工具由canix1开发,可以用于通用型ACL扫描,大家可以访问GitHub下载该工具。我们可以利用该工具来搜索AD委派配置情况。下面让我们以某个例子来演示整个操作过程:
运行powershell脚本后,ADACLScanner为我们提供了一个非常友好的GUI(很少有powershell脚本能提供这么友好的GUI)。
图1. ADACLScanner
假设我们接入的AD名为plum
,地址为192.168.3.215
,如下图所示:
图2. 连接AD
当我们点击第一列的“Connect”按钮时,就会弹出对话框提示输入域凭据,以便枚举目标节点。需要注意的是,这里可以使用低权限域用户的凭据。
图3. 请求域凭据
输入正确的域凭据后,我们就能看到可用的节点,如下图所示:
图4. 枚举AD节点
现在我们需要选中第一列节点,确保已勾掉“Inherited Permissions”复选框,然后点击“Run Scan”按钮开始扫描。在上图中,我们选中的是DC=plum,DC=local
。扫描完成后就会生成扫描报告,如下图所示:
图5. ACL Scanner报告
如果我们选中“Resions”节点,再次扫描,那么最终报告有所不同。在报告中,我们可以发现Object列中代表我们扫描的目标节点,因此这里OU
的值为Regions
。
图6. Regions OU的ACL报告
同样,如果我们扫描USA OU,可以看到如下报告,了解USA OU的委派权限信息。
图7. AD ACL Scanner对OU USA的扫描结果
这里比较麻烦的是我们需要手动搜索每个节点,分析每个条目,才能找到正确的委派信息。这个过程对小型网络来说问题不大,但如果面对的是大型网络,这将变成分析人员的噩梦。此时我们第二种方法就可以派上用场。
四、使用自定义Powershell脚本
大家可以先看一下我们团队定制的这个脚本的工作过程,请参考此处视频。如果想直接使用这个自动化脚本,可以访问此处下载。如果大家对脚本的具体实现非常感兴趣,接下来我们就一步一步来分析:
1、获取用户凭据
我们使用的是一个本地管理员用户(非域用户),因此每当我们尝试挂载AD驱动或者导入活动目录模块时,都会看到如下错误:
图8. 导入AD模块错误
为了解决这个问题,我们可以传入-WarningAction SilentlyContinue
参数。
接下来具体看看脚本实现,第一部分代码如下:
Import-Module ActiveDirectory -WarningAction SilentlyContinue
# force use of specified credentials everywhere
$creds=Get-Credential
$PSDefaultParameterValues = @{"*-AD*:Credential"=$creds}
# GET DC Name
$dcname=(Get-ADDomainController).Name
New-PSDrive -Name AD -PSProvider ActiveDirectory -Server $dcname -Root //RootDSE/ -Credential $creds Set-Location AD:
由于我们没有使用域用户来执行操作,因此代码开头处我们使用-WarningAction SilentlyContinue
参数导入ActiveDirectory
模块,这样我们就能在不挂载AD驱动的情况下导入该模块。接下来我们尝试获取用户凭据,添加用户凭据后,我们为包含-AD
的所有命令设置PSDefaultParameterValues
。接下来我们使用Get-ADDomainController
命令获取服务器名称,然后配合新获取的凭据来挂载AD驱动。
其实如果我们已经以域用户身份登录,就无需执行这些操作。然而我们还是考虑了最坏的情况,比如我们可能以本地管理员身份访问目标系统,因此不受powershell访问限制,但所使用的域用户凭据权限较低。
2、遍历整个OU
获取所有域名、组织单元(Organization Units)以及ADObject。
$OUs = @(Get-ADDomain | Select-Object -ExpandProperty DistinguishedName)
$OUs += Get-ADOrganizationalUnit -Filter * | Select-Object -ExpandProperty DistinguishedName
$OUs += Get-ADObject -SearchBase (Get-ADDomain).DistinguishedName -SearchScope OneLevel -LDAPFilter '(objectClass=container)' | Select-Object -ExpandProperty DistinguishedName
这里代码第一行执行Get-ADDomain
,获取DistinguishedName
列,第二行执行Get-ADOrganizationalUnit
(过滤器为*
),获取这些对象的DistinguishedName
,将其添加到OUs
对象中。第三行获取匹配AD域DistinguishedName
的AD对象,使用LdapFilter
(过滤objectClass=container
的对象),只筛选一层,然后再打印DistinguishedName
列。
3、添加例外
$domain = (Get-ADDomain).Name
$groups_to_ignore = ( "$domain\Enterprise Admins", "$domain\Domain Admins")
# 'NT AUTHORITY\SYSTEM', 'S-1-5-32-548', 'NT AUTHORITY\SELF'
在这几行代码中我们排除了一些例外情况。我们首先获取域名,然后以此为基础添加待忽略的一些组。
4、提取相关的域用户/组权限
ForEach ($OU in $OUs) {
$report += Get-Acl -Path "AD:$OU" |
Select-Object -ExpandProperty Access | ? {$_.IdentityReference -match "$domain*" -and $_.IdentityReference -notin $groups_to_ignore} |
Select-Object @{name='organizationalUnit';expression={$OU}}, `
@{name='objectTypeName';expression={if ($_.objectType.ToString() -eq '00000000-0000-0000-0000-000000000000') {'All'} Else {$schemaIDGUID.Item($_.objectType)}}}, `
@{name='inheritedObjectTypeName';expression={$schemaIDGUID.Item($_.inheritedObjectType)}}, `
*
}
在前文第二步骤中,我们将所有信息存储在$OUs
中,现在我们使用ForEach
循环来提取这些信息并进一步处理。
前三行通过ForEach
循环获取$OUs
中所有单位的ACL路径,确保其中有与目标域匹配的IdentityReference
,同时不属于需排除的组中(例外组参考第4个步骤)。从第4行开始,代码提取了某些对象,如organizationalUnit
(使用$OU
表达式)、ObjectTypeName
(如果对象类型不等于root GUID,则只根据对象类型的值提取SchemaIDGUID
的详细信息)。
5、Inheritance == False
Inheritance为false
是非常关键的一点。我们只需要筛选出满足该条件的那些行。
$filterrep= $report | Where-Object {-not $_.IsInherited}
这样就能确保输出结果中不包含继承的对象。
6、格式化输出结果
Write-Output ( $filterrep | Select-Object OrganizationalUnit,ObjectTypeName,ActiveDirectoryRights,IdentityReference | Format-Table | Out-String)
以上代码能以表格的形式格式化输出结果,列出在特定对象上未继承权限(即具备委派权限)的用户。默认情况下,委派权限会应用到整颗OU树上,因此如果上层OU具备该权限,那么除非显式移除权限,否则下层OU就会自动具备该权限。
图9. 自动化脚本处理结果
我们已经在最新的2019版高级基础设施黑客教程中介绍了这种技术(还包括其他有用的技术),我们也会为内部安全和SOC团队提供内部培训和CTF服务,帮助大家提高技术水平。