前言 当拿下域控权限时,为了维持权限,常常需要驻留一些后门,从而达到长期控制的目的。Windows AD域后门五花八门,除了常规的的添加隐藏用户、启动项、计划任务、抓取登录时的密码,还有一些基于 ACL 的后门。ACL介绍 ACL是一个访问控制列表,是整个访问控制模型(ACM)的实现的总称。常说的ACL主要分为两类,分别为特定对象安全描述符的自由访问控制列表 (DACL) 和系统访问控制列表 (SACL)。对象的 DACL 和 SACL 都是访问控制条目 (ACE) 的集合,ACE控制着对象指定允许、拒绝或审计的访问权限,其中Deny拒绝优先于Allow允许。 安全描述符包含与安全对象关联的安全信息。 安全描述符由 SECURITY_DESCRIPTOR 结构和关联的安全信息组成。 安全描述符可以包含以下安全信息:: 1、对象所有者和主组的安全标识符 (SID) 。 2、指定允许或拒绝特定用户或组的访问权限的 DACL 。 3、一个 SACL ,指定为对象生成审核记录的访问尝试的类型。 4、一组控制位,用于限定安全描述符或其单个成员的含义。 隐藏安全描述符 当可控一个用户时,不想该用户被轻易发现,可以对其进行隐藏。首先查看该用户所用者,默认是域管组: 可以在GUI上对所有者进行修改,也可以使用 powerview 进行修改:Set-DomainObjectOwner -identity jumbo -OwnerIdentity jumbo 修改完成后: 因为是权限维持,所以当前权限是域管,先尝试给域管添加一个对 jumbo 用户Deny 所有权限的ACL,但是发现powerview 的Add-DomainObjectAcl 方法并没有设置Deny 权限的操作,只有Allow : 当然,你可以使用 New-ADObjectAccessControlEntry 来完成手动ACL的添加,他的原理如下图: 上图看出还要手动做最后的ACL保存。既然 Add-DomainObjectAcl 已经完成了自动化的CommitChanges ,直接把Allow 默认可变的参数不就行了?首先手动在Add-DomainObjectAcl 添加一个AccessControlType 参数:.PARAMETER AccessControlType Specifies the type of ACE (allow or deny) 设置参数定义: [Parameter(Mandatory = $True, ParameterSetName="AccessRuleType")] [ValidateSet("Allow", "Deny")] [String[]] $AccessControlType, 删除之前的默认的 Allow : 最后把 AccessControlType 参数替换之前的ControlType : 现在就可以在使用 AccessControlType 参数来给对象添加Allow 或者Deny 的权限了。 【----帮助网安学习,需要网安学习资料关注我,私信回复"资料"免费获取----】 ① 网安学习成长路径思维导图 ② 60+网安经典常用工具包 ③ 100+SRC漏洞分析报告 ④ 150+网安攻防实战技术电子书 ⑤ 最权威CISSP 认证考试指南+题库 ⑥ 超1800页CTF实战技巧手册 ⑦ 最新网安大厂面试题合集(含答案) ⑧ APP客户端安全检测指南(安卓+IOS) 当尝试域管添加一个对 jumbo 用户Deny 所有权限的ACL后:Add-DomainObjectAcl -TargetIdentity jumbo -PrincipalIdentity S-1-5-21-12312321-1231312-123123-500 -AccessControlType Deny 当然,把 SID 改成SamAccountName 也是可以的:Add-DomainObjectAcl -TargetIdentity jumbo -PrincipalIdentity administrator -AccessControlType Deny 可以发现域管也没权限查看 jumbo 用户的属性了: 当使用 system 用户查看jumbo 用户ACL时,可以看到对应的Deny 的ACL: 现在域管对 jumbo 用户已经无法操作任何东西了,先用system 用户删除该Deny 权限,准备使用powerview 的Remove-DomainObjectAcl 方法时,发现也只有的Allow ,也就是默认只能移除对象的Allow 权限,老方法,把删除的ACL属性设置为可变参数: 进行删除: Remove-DomainObjectAcl -TargetIdentity jumbo -PrincipalIdentity S-1-5-21-12312321-1231312-123123-500 -Rights ALL -AccessControlType Deny 当然,把 SID 改成SamAccountName 也是可以的:Remove-DomainObjectAcl -TargetIdentity jumbo -PrincipalIdentity administrator -Rights ALL -AccessControlType Deny 那么同学们可能会想,如果真的有人进行了上面操作,真的没办法查看了吗,实际上并不是,对象的拥有者是有权限修改的,比如把 jumbo 用户的拥有者改成默认的域管组,然后对域管进行设置Deny 的ACL,但是实际上拥有者依然有权限修改其ACL,这也是为什么在文章开始的时候,要把jumbo 拥有者设置为jumbo 的目的: 上面尝试了拒绝域管对 jumbo 所有的权限,那为了隐藏,并且为了防止后续还要对jumbo 用户的一些其他修改,实际上可以对jumbo 用户设置everyone 拒绝读取的权限即可: 现在所有用户对其都没有查看权限了: 当然,只是设置了拒绝读取权限,实际上当域管去修改其ACL权限时,还是可以的: 现在通过 net user 命令已经看不到jumbo 这个用户了: 在"用户和计算机"里看用户长这样: 从上面的操作可以发现,给 everyone 用户添加拒绝读取权限时是通过GUI实现的,因为everyone 用户是个特殊的用户,属于特殊身份群体,是一个属于Well-known SIDs的用户,其对应的SID为S-1-1-0 : 当尝试使用 powerview 的Add-DomainObjectAcl 方法是无法完成给everyone 用户添加ACL的: 通过查看 powerview 的代码,会通过Get-ObjectAcl 方法获取对应用户的SID,但是刚刚提到,everyone 用户是个特殊的用户,导致查不到: 但是看了下还有个 New-ADObjectAccessControlEntry 方法,会判断输入的PrincipalIdentity 参数是不是SID ,如果是SID 就不走查询,因此可以照葫芦画瓢,把这个判断加到Add-DomainObjectAcl 方法中: if ($PrincipalIdentity -notmatch "^S-1-.*") { $PrincipalSearcherArguments = @{ "Identity" = $PrincipalIdentity "Properties" = "distinguishedname,objectsid" } if ($PSBoundParameters["PrincipalDomain"]) { $PrincipalSearcherArguments["Domain"] = $PrincipalDomain } if ($PSBoundParameters["Server"]) { $PrincipalSearcherArguments["Server"] = $Server } if ($PSBoundParameters["SearchScope"]) { $PrincipalSearcherArguments["SearchScope"] = $SearchScope } if ($PSBoundParameters["ResultPageSize"]) { $PrincipalSearcherArguments["ResultPageSize"] = $ResultPageSize } if ($PSBoundParameters["ServerTimeLimit"]) { $PrincipalSearcherArguments["ServerTimeLimit"] = $ServerTimeLimit } if ($PSBoundParameters["Tombstone"]) { $PrincipalSearcherArguments["Tombstone"] = $Tombstone } if ($PSBoundParameters["Credential"]) { $PrincipalSearcherArguments["Credential"] = $Credential } $Principal = Get-DomainObject @PrincipalSearcherArguments if (-not $Principal) { throw "Unable to resolve principal: $PrincipalIdentity" } elseif($Principal.Count -gt 1) { throw "PrincipalIdentity matches multiple AD objects, but only one is allowed" } $ObjectSid = $Principal.objectsid Write-Host ($ObjectSid) } else { Write-Host "..sid.." $ObjectSid = $PrincipalIdentity } $Identity = [System.Security.Principal.IdentityReference] ([System.Security.Principal.SecurityIdentifier]$ObjectSid) 现在尝试下,给 jumbo2 用户添加everyone 所有拒绝的ACL:Add-DomainObjectAcl -TargetIdentity jumbo2 -PrincipalIdentity S-1-1-0 -Rights All -AccessControlType Deny Remove-DomainObjectAcl 方法同理。隐藏主体 通过上面的步骤,除了 jumbo 用户本身可以查看jumbo 用户以为,其他用户都没有ReadControl 权限,但是在"Active Directory用户和计算机管理"里还是可以看到,虽然ico 图标都没了,接下来要让在"Active Directory用户和计算机管理"里也看不到。为了方便演示,笔者把jumbo 用户移到一个单独的OU 组里: 然后给这个 OU 设置everyone 拒绝读取权限即可: 遇到一些粗心大意的管理员,可能会觉得这只是无意残留的无害物质,无伤大雅。 Dcsync Dcsync 实际上就是给用户设置两条扩展权限,分别为:DS-Replication-Get-Changes (GUID: 1131f6aa-9c07-11d1-f79f-00c04fc2dcd2) DS-Replication-Get-Changes-All (GUID: 1131f6ad-9c07-11d1-f79f-00c04fc2dcd2) 当用户拥有这两条ACL后,即可使用 DRS 协议获取域hash 凭据。给用户在域对象上添加Dcsync 权限即可: 代理账号 上面提到,把 jumbo 用户拥有者改成自身,然后设置everyone 对其没有读取权限,这样就可以达到隐藏jumbo ,然后手上的jumbo 用户就可以肆无忌惮的做一些操作。但是有个问题,万一做操作的时候,该用户被发现了,管理员把该用户进行了禁用,那好不容易获取到的账号就废了。为了防止账号被发现后被禁用/被改密码不可用,应该设置个代理账号,把准备拿来攻击的账号(某个管理员用户或者有dcsync 类似权限的账号)的拥有者设置代理账号,代理账号是其拥有所有者,然后设置所有用户对攻击账号都不可操作,最后每次都可以使用代理账号控制攻击账号,就算攻击账号被禁用/被改密码,也可以使用代理账号来重新启用他。 首先攻击账号为 attack ,代理账号为good ,首先设置attack 账号所有者为good :Set-DomainObjectOwner -identity attack -OwnerIdentity good 给 attack 账号添加dcsync 权限:Add-DomainObjectAcl -TargetIdentity "DC=domain,DC=com" -PrincipalIdentity attack -Rights DCSync -AccessControlType Allow 设置 attack 都不可操作:Add-DomainObjectAcl -TargetIdentity attack -PrincipalIdentity S-1-1-0 -Rights All -AccessControlType Deny 这个时候,如果 attack 在发起攻击的时候被管理员发现了,把attack 账号密码重置了,但是good 账号是attack 账号的拥有者,可以修改attack 账号的ACL ,比如给自己添加修改密码的权限,然后去重置attack 账号的密码,然后就又可以拿来攻击了。总结 本文主要讲了在 Windows 域中如何利用ACL 进行后门隐藏,并对powerview 进行修改使其支持在添加ACL 或者删除ACL 时可以指定Allow 或者Deny ,也可以选择everyone 此类特殊用户。