导语:一直以来,我对Active Directory组的范围总是有点搞不清楚。对于任何从事过AD系统管理员背景的人来说,这个话题可能并不是很难,但是直到我阅读了SS64的这篇文章后,关于AD组范围的所有东西我都搞明白了。

一直以来,我对Active Directory组的范围总是有点搞不清楚。对于任何从事过AD系统管理员背景的人来说,这个话题可能并不是很难,但是直到我阅读了SS64的这篇文章后,关于AD组范围的所有东西我都搞明白了。我想记录一些关于这个话题的相关说明(我所知道的),以防其他任何人都有同样的困惑。我还将介绍这些组范围如何与林全局目录和域信任进行交互,并在此过程中加入新的PowerView功能。

Active Directory组

Active Directory组 可以有两种类型:分发组和安全组。“ 分发组”用于电子邮件分发列表,不能用于控制对资源的访问,所以我们并不关心他们的目的。大多数AD组都是“安全组”,可用于控制访问并添加到自由访问控制列表(DACL)中。一个组是安全组还是分发组可以通过该组的groupType属性来进行判断,详细描述如下图所示。

安全组可以有三个范围。组的范围决定了可以添加哪些类型的组对象以及可以嵌套组中的其他组。ss64.com的描述如下:

·  全局组可以嵌套在域本地组,通用组和同一域内的其他全局组内。

·  通用组可以嵌套在域本地组和任何域中的其他通用组内。

·  域本地组不能嵌套在全局或通用组中。

groupnesting.jpg

https://ss64.com/nt/syntax-groups.html

groupType 属性是一个二进制字段,其可能的值可以在这个页面的底部 下的“备注”部分找到。为了使用LDAP搜索二进制字段,我们需要使用LDAP_MATCHING_RULE_BIT_AND  LDAP搜索语法。这是通过LDAP搜索二进制字段的方式。以下是相关搜索的过滤器:

·  域本地范围:'(groupType:1.2.840.113556.1.4.803 = = 4)'

·  全局范围:'(groupType:1.2.840.113556.1.4.803 = = 2)'

·  通用范围:'(groupType:1.2.840.113556.1.4.803:= 8)'

·  安全:'(groupType:1.2.840.113556.1.4.803:= 2147483648)'

·  分发:'(!(groupType:1.2.840.113556.1.4.803:= 2147483648))'

·  “系统创建”:  '(groupType:1.2.840.113556.1.4.803:= 1)'

我最近推送了一个PowerView的开发分支 ,可以通过Get-DomainGroup cmdlet 提取所有这些内容  。以下是一些与上述LDAP过滤器作用相同的参数:

·   域本地范围:  Get-DomainGroup -GroupScope DomainLocal

·  非域本地范围:  Get-DomainGroup -GroupScope NotDomainLocal

·  全局范围:  Get-DomainGroup -GroupScope Global

·  非全局范围:  Get-DomainGroup -GroupScope NotGlobal

·  通用范围:  Get-DomainGroup -GroupScope Universal

·  非通用范围:  Get-DomainGroup -GroupScope NotUniversal

·  安全性:  Get-DomainGroup -GroupProperty安全性

·  分发:  Get-DomainGroup -GroupProperty分发

·  “由系统创建”:  Get-DomainGroup -GroupProperty CreatedBySystem

以下是使用PowerView搜索当前域中所有通用组的示例:

1501988740619946.png

以下是使用PowerView搜索当前域中所有非域本地(即通用或全局)组的示例:

1501988764263596.png

此外,另一个最近提交的开发分支中,  PowerView支持自动将发现的组的结果中的groupType属性(以及userAccountControl,accountexpires和samaccounttype)解析为人类可读的枚举值,从而更容易进行分类。我认为这些应该是我解析的最后一个二进制/不可读的默认属性。以下是一个单一的结果:

1501988792477807.png

安全组范围

域本地组

这里给出一个最简单的解释 —— 这些是当前域的本地组。也就是说,域本地组的目的是帮助在单个域中管理对资源的访问。域本地组不能添加到全局组的事实是一种预期的设计:(域本地)授予对特定资源的访问权限的组不能添加到  企业组(即全局组)中,这可以防止添加了一些意外的组后可能导致意外访问的嵌套。

可以嵌套在: 只能嵌套在其他域本地组,来自同一个域

可以包含:全局组,普通组和  外部可信成员。

可以分配权限的域:在同一个域中

成员在全局编录复制:无

tl; dr:如果你想要一个只允许访问  同一个域中的资源的组,但可以包含任何其他组范围(包括跨外部信任的用户)的组那么你可以使用  域本地作用域。

全局组

全局组可能是三个范围中最棘手的一个。它通常用于共享可比较的网络访问要求的用户的组织结构。全局组也不能跨域嵌套  ,这意味着来自一个域的全局组不能嵌套在另一个域中的组中。此外,来自同一个域的用户/计算机不能嵌套在另一个域中的全局组中,这就是为什么来自同一个域的用户不符合在外部域中的“域管理员”的成员资格(由于其全局范围的影响 )。因为全局组不会在全局目录中复制(因为会有命名冲突),你可以修改全局组的成员资格,而不会导致到林中其他域的复制流量。

可以嵌套在: 通用和  域本地组

可以包含: 只有  全局组,来自同一个域

可以在哪些域中分配权限:任何域

成员在全局编录中复制:无

tl; dr:如果你希望可以在林或信任域中的任何域中使用组  ,但只能包含该组域的用户,请使用全局作用域。

普通组

如果你需要一个组,其中包含来自同一林中的一个或多个域的成员,并且可以授予对该林中任何资源的访问权限,则需要使用通用组。对于嵌套组成员身份,所有组都可以是相同组类型的成员(对于全局组来说,这仅适用于同一域中的其他全局组)。对于具体的通用组,成员资格的任何更改将传播到  全局目录。我将在下一节介绍所有这些全局目录互动。

可以嵌套在: 域本地组和其他  通用组中

可以包含:  全局组和其他  通用组

可以在任意域或林中分配权限

会员资格在全球目录中复制:是

tl; dr:如果你想要一个可以访问林中任何东西的组,并且可以在林中包含任何用户/组/计算机,请使用通用组

全局目录

全局编录的所有对象的部分副本中的Active Directory林中,意味着一些对象属性(但不是全部)都包含在其中。该数据在标记为林全局目录的所有域控制器之间进行复制。全局目录的一个要点是快速进行对象搜索和解密,而不需要引用其他域(此处将提供更多信息)。从攻击者进攻的角度来看,好的副作用是,我们可以快速查询关于林中有关我们的主域控制器的简单查询的所有域和对象的信息,但稍后将会提供更多信息。

复制的属性在林模式中标记为“部分属性集”。你可以使用PowerView轻松枚举这些属性名称:

Get-DomainObject -SearchBase "CN=Schema,CN=Configuration,DC=testlab,DC=local" -LDAPFilter "(isMemberOfPartialAttributeSet=TRUE)" | Select name

注: 初始全局编录是在林中第一个域中创建的第一个域控制器上生成的。默认情况下,每个新子域的第一个域控制器也被设置为全局目录,但可以添加其他子域。

查找全球目录

在你可以与全球目录进行交互之前,它有助于你知道它们在哪里。通过像nslookup和dsquery这样的工具,显然还有很多选择,但是我们依旧使用一些PowerShell代码来实现。.NET具有很好的内置功能:

$Forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
$Forest.FindAllGlobalCatalogs()

使用PowerView,你可以使用  Get-ForestGlobalCatalog:

1501988874829342.png

搜索全局目录

要使用PowerView搜索全局编录,请为-SearchBase参数指定LDAP搜索字符串时将“ LDAP:// … ”替换为“ GC:// ” 。实际上,通常可以使用“ -SearchBase”GC://domain.com“ ,它将映射到该域的全局编录。这通常是我的偏好做法。有关操作示例,可以使用如下所示的PRIMARY.testlab.local父域全局目录枚举当前林中的所有计算机DNS主机名:

1501988917260933.png

而这里是对同一个林中的另一个域的另一个全局目录运行相同的查询的结果,SECONDARY.dev.testlab.local:

1501988917560376.png

组范围和全局编录

当涉及到全局目录复制时,组的范围很重要。域本地组和全局组的成员未复制到全局编录,虽然组对象是它们本身。普通组与其完整的成员身份一起进行复制。微软提供了另一种方式,“ 具有通用范围的组及其成员,仅列在全球目录中。具有全局或域局部范围的组也列在全局目录中,但是其成员不是。“所以让我们尝试从进攻的角度来看看这些操作的含义。

一个很好的副作用是:我们可以通过与同一域中的域控制器进行通信,轻松枚举林中任何域的任何通用组的成员。这意味着我们只在当前域中的域控制器启动流量。使用PowerView,我们可以枚举在全局编录  testlab.local的所有成员组:

Get-DomainGroup -SearchBase "GC://testlab.local" -Properties grouptype,name,member -LDAPFilter '(member=*)'

1501988965203050.png

这些结果证明了复制的差异。以上只有一组来自dev.testlab.loca l,由于其通用范围而返回成员结果。以下是通过直接LDAP /非全局目录查询完整的组成员资格。您可以看到其他组结果以及其全局/域本地作用域:

Get-DomainGroup -LDAPFilter '(member=*)' -Domain dev.testlab.local -Properties distinguishedname,grouptype | fl

1501989021705267.png

微软在这里解释说,这是一个轻微的例外。我将在即将发布的博文中再说一遍,但是member / memberof是链接属性,这意味着  memberof(后向链接)的值是根据成员(前向链接)的值来计算的  。由于通用组 的成员身份在全局目录中复制,所以用户在通用组中的成员资格应该复制到林中的所有GC。然而,因为域本地/全局组成员的数据不被复制到全局编录, memberOf的用户结果会有所不同,因为这些反向链接可能无法被追踪。Microsoft也证实了这一点:

由于“全局目录”所列举组的方式,使得反向链接的结果[即 根据你是否搜索全局目录(端口3268)或域(端口389),用户所属的组(全局组与域本地组)以及用户是否属于组在本地域外。

从上面这段话我可以看出,如果绑定到同一个域中的用户所属的组成员身份的全局目录,则这些(域本地或全局)组成员资格将填充memberof属性。请记住,这些结果将根据你绑定到的域/全局目录而有所不同。

组范围及外部信任

外部或林信任中存在的用户(从域的当前林外部)仍然可以添加到  指定域中的域本地组。这些用户在CN = ForeignSecurityPrincipals,DC = domain,DC = com中显示为新条目  。或者,正如Microsoft解释的那样,“ 当林中的域和该林之外的域之间建立信任时,来自外部域的安全主体可以访问内部域中的资源。Active Directory在内部域中创建外部安全主体对象,以从受信任的外部域中表示每个安全主体。这些外部安全负责人可以成为内部域名的域名本地组织的成员 “。

请记住,“安全主体”是指组,用户或计算机,即具有安全标识符的任何内容。你可以通过将搜索的SearchBase设置为“CN = ForeignSecurityPrincipals,DC = domain,DC = com”来快速枚举这些成员。例如:

domainobject_foreignprincipals-1024x269.png

你可以在这些结果的底部看到两个外部域SID。如果这些外部用户中的任何一个是你的目标域中的组成员,那么  Get-DomainForeignGroupMember函数也应该也是这些。但请记住,唯一可能的办法是,如果组是  域本地范围:

domain_local_external_member-1024x879.png

进攻行动

我以前曾经在全局目录中使用Active Directory环境中的命令和控制(某些想法是受到了BlackHat的启发),但是还有一些其他的原因,我想到在处理多域时可以使用全局目录林。第一个是如果你得到一个用户/组/计算机的简单的samaccountname,并想知道该帐户所在的域。这是我们对BloodHound ingestor做的,因为从Get-NetSession结果返回的samaccountname 不包含域名。实际上,这是构建全局目录的主要原因之一,用于对象解析:

gc_deconflict_user-1024x675.png

另一种选择是快速枚举整个林中某种类型的所有对象,即获取整个设置的所有计算机DNS名称,如我们在“搜索全局目录”部分中所看到的。所以让我们进一步来看看,并枚举整个林中的所有Kerberoastable帐户,因为servicePrincipalName属性已经被复制:

这也适用于域信任!可以使用'(objectClass = trustedDomain)'过滤器通过LDAP枚举信任,所以对于PowerView的一些最新版本,我们可以运行以下命令来快速枚举信任网格中的所有域:

请注意,这不会像Get-DomainTrustMapping (之前叫Invoke-MapDomainTrust)那么准确,但是这是一个快速的方法。

不幸的是,由于如何将member / memberOf属性链接到一起,如果将用户添加到外部域/林中的组(即不在同一个林中的域中),则会将特定组的  成员属性更新为外部安全主体可分辨的名称,但添加的用户/组对象的  memberOf字段未更新。而且,这些外部成员只能添加到不在全局目录中复制的域本地组

所以我们可以使用全局目录枚举一些内部林但是跨域的成员资格,但是对于外部/外部的外部成员资格,我们必须 按域搜索CN = ForeignSecurityPrincipals容器域。幸运的是,这些数据在全球编目中已经被复制!只需使用-LDAPFilter'(objectclass = foreignSecurityPrincipal)':

Get-DomainObject -Properties name,objectsid,distinguishedname -SearchBase "GC://dev.testlab.local" -LDAPFilter '(objectclass=foreignSecurityPrincipal)' | ? {$_.objectsid -match '^S-1-5-.*-[1-9]d{2,}$'} | fl

gc_foreign_principals-1024x378.png

请注意,我们在当前的  dev.testlab.local,以及使用的子域的全局编录,但仍能够枚举ForeignSecurityPrincipals在testlab.local。

由于我们现在知道外部信任用户只能添加到具有域本地作用域的组中,所以我们可以从该名称中提取外部用户被添加到的域,直接用域成员查询域本地作用域,并比较每个针对外部的用户名单:

# query the global   catalog for foreign security principals with domain-based SIDs, and extract   out all distinguishednames
$ForeignUsers = Get-DomainObject -Properties objectsid,distinguishedname -SearchBase "GC://dev.testlab.local" -LDAPFilter '(objectclass=foreignSecurityPrincipal)' | ? {$_.objectsid -match '^S-1-5-.*-[1-9]d{2,}$'} | Select-Object -ExpandProperty distinguishedname
$Domains = @{}
$ForeignMemberships = ForEach($ForeignUser in $ForeignUsers) {
    # extract the domain the foreign user was added to
    $ForeignUserDomain = $ForeignUser.SubString($ForeignUser.IndexOf('DC=')) -replace 'DC=','' -replace ',','.'
    # check if we've already enumerated this domain
    if (-not $Domains[$ForeignUserDomain]) {
        $Domains[$ForeignUserDomain] = $True
        # enumerate all domain local groups from the given domain that   have any membership set
        Get-DomainGroup -Domain $ForeignUserDomain -Scope DomainLocal -LDAPFilter '(member=*)' -Properties distinguishedname,member | ForEach-Object {
            # check if there are any overlaps between the domain local   groups and the foreign users
            if ($($_.member | Where-Object {$ForeignUsers  -contains $_})) {
                $_
            }
        }
    }
}
$ForeignMemberships | fl

写在最后

我相信这个话题可能对某些人来说有些晦涩难懂,但我希望这有助于有兴趣的人澄清一些我所理解的一些误会。域组范围提供了一些有趣的攻击机会,并且施加了一些限制,并对林的架构产生了影响(在另外一段时间内更是如此)希望你能从这篇文章中得到一些有用的细节,帮助他们进行交流前锋。

和往常一样,如果我在这个帖子的某个地方犯了一个错误,请让我知道,我会进行修改!

源链接

Hacking more

...