RSAT

背景

Remote Server Administration Tools(RSAT)自 Windows 2000 时代起就是 Windows 的一部分。RSAT 允许系统管理员从运行 Windows 10、Windows 8.1、Windows 7 或 Windows Vista 的工作站上,远程管理 Windows Server 角色和功能。RSAT 只能安装在 Windows 的 Professional 或 Enterprise 版本上。在企业环境中,RSAT 可以远程管理 Active Directory、DNS 等服务

工具列表

  • SMTP Server Tools
  • Hyper-V Management Tools
  • Hyper-V Module for Windows PowerShell
  • Hyper-V GUI Management Tools
  • Windows Server Update Services Tools
  • API and PowerShell cmdlets
  • User Interface Management Console
  • Active Directory Users and Computers Snap-in
  • Active Directory Sites and Services Snap-in
  • Active Directory Domains and Trusts Snap-in
  • Active Directory Administrative Center Snap-in
  • ADSI Edit Snap-in
  • Active Directory Schema Snap-in (Not Registered)
  • Active Directory Command Line Tools
  • Active Directory Module for Windows PowerShell
  • IIS Management Tools
  • IIS Management Console
  • IIS Management Compatibility
  • Feature Tools
  • Remote Desktop Services Tools
  • Role Tools
  • Update Services Tools
  • Group Policy Tools

枚举

如果我们攻陷了一台已加入域的系统(或者客户要求我们从他们的一台工作站执行 AD 评估),就可以利用 RSAT 来枚举 AD

另外,如果一台主机没有加入域,只要它所在的子网可以与域控制器通信,我们也可以通过命令行使用 “runas” 启动任意 RSAT 管理单元来枚举域。这个方法在内部评估中尤其有用:当我们获得了有效的 AD 凭据,并希望从 Windows 虚拟机上执行枚举时,可以这样操作。
我们也可以在未加入域的计算机上使用下面的命令语法打开 MMC Console:

1
runas /netonly /user:Domain_Name\Domain_USER mmc

概述

LDAP(Lightweight Directory Access Protocol,轻量级目录访问协议)是 Active Directory 的核心组成部分。最新 LDAP 规范为第 3 版,发布为 RFC 4511。理解 LDAP 在 AD 环境中的工作方式,对攻击者和防守者都非常重要。

LDAP 是开源、跨平台的目录服务访问协议,可用于对 AD 等目录服务进行认证和查询。AD 存储用户账户和安全信息,并让网络中的其他设备共享这些信息。LDAP 就是应用程序与目录服务器通信的“语言”。换句话说,网络系统通过 LDAP 与 AD 交谈。

LDAP 会话首先连接到 LDAP 服务器,也称 Directory System Agent。AD 中的域控制器会监听 LDAP 请求,包括安全认证请求。AD 与 LDAP 的关系可类比为 Apache 与 HTTP:Apache 是使用 HTTP 协议的 Web 服务器,AD 是使用 LDAP 协议的目录服务器。少数环境可能没有 AD 但使用 LDAP,例如 OpenLDAP。

认证

LDAP 通过 BIND 操作对 AD 凭据进行认证,并为 LDAP 会话设置认证状态。LDAP 认证主要有两类:

  • 简单认证:包括匿名认证、未认证认证以及用户名/密码认证。用户名和密码会构造 BIND 请求提交给 LDAP 服务器。
  • SASL 认证:Simple Authentication and Security Layer 使用 Kerberos 等其他认证服务绑定 LDAP 服务器,再通过该认证服务完成 LDAP 认证。SASL 将认证方法与应用协议分离,能提供更好的安全性。

默认情况下,LDAP 认证消息以明文发送,内部网络中的攻击者可能嗅探 LDAP 消息。因此建议使用 TLS 或类似加密手段保护传输过程。

匿名查询

可以使用 LDAP 查询向目录服务请求信息。

LDAP 查询非常强大,可用于收集大量信息、绘制 AD 环境结构、发现错误配置。后续章节将深入讲解 AD 与 LDAP 搜索过滤器。

Windapsearch

Windapsearch 是一个 Python 脚本,可通过 LDAP 查询执行匿名或认证的 AD 用户、组、计算机枚举。它可替代需要手写复杂 LDAP 查询的 ldapsearch。使用空用户名 -u “” 可确认 LDAP NULL session,并可用 —functionality 查看域功能级别。

1
2
3
python3 windapsearch.py --dc-ip 10.129.1.207 -u "" --functionality
python3 windapsearch.py --dc-ip 10.129.1.207 -u "" -U
python3 windapsearch.py --dc-ip 10.129.1.207 -u "" -C

凭证化LADP枚举

与 SMB 类似,一旦拥有域凭据,就可以从 LDAP 提取大量信息,包括用户、组、计算机、信任、GPO、域密码策略等。ldapsearch-ad.py 与 windapsearch 都适合做此类枚举。

Windapsearch

1
2
windapsearch --dc-ip 10.129.1.207 -u inlanefreight\james.cross --da
windapsearch --dc-ip 10.129.1.207 -d inlanefreight.local -u inlanefreight\james.cross --unconstrained-users

这些命令可枚举 Domain Admins 以及拥有非约束委派的用户。

ldapsearch-ad

1
2
3
4
5
6
ldapsearch-ad -l 10.129.1.207 -d inlanefreight -u james.cross -p Summer2020 -t pass-pols

ldapsearch-ad -l 10.129.1.207 -d inlanefreight -u james.cross -p Summer2020 -t kerberoast | grep servicePrincipalName:

ldapsearch-ad -l 10.129.1.207 -d inlanefreight -u james.cross -p Summer2020 -t asreproast

这些内置查询能快速拉取密码策略、可能被 Kerberoasting 的用户,以及可被 ASREPRoasting 的用户。

Windows下进行查询

进行渗透测试时,往往需要查看当前域中的用户、组、计算机、OU、GPO、委派、SPN、密码策略等信息。
在 Windows 上做 LDAP 查询主要有两种方式:

在 Windows 上做 LDAP 查询主要有两种方式:

  1. 有 AD PowerShell 模块:
    Get-ADUser / Get-ADGroup / Get-ADComputer / Get-ADObject
  2. 没有 AD PowerShell 模块:
    使用.NET DirectorySearcher,也就是 [ADSISearcher]

如果目标机器是域内主机,但没有安装 RSAT / ActiveDirectory 模块,[ADSISearcher] 通常更加实用。

查询当前域 Base DN

LDAP 查询首先需要知道当前域的 Base DN。

例如域名是:

1
inlanefreight.local

对应的 Base DN 通常是:

1
DC=inlanefreight,DC=local

使用 PowerShell 查询 RootDSE

1
([ADSI]"LDAP://RootDSE").defaultNamingContext

示例结果:

1
DC=inlanefreight,DC=local

也可以查询更多 RootDSE 信息:

1
[ADSI]"LDAP://RootDSE"

常见字段:

1
2
3
4
5
defaultNamingContext        当前域 
DNconfigurationNamingContext 配置分区
DNschemaNamingContext 架构分区
DNrootDomainNamingContext 根域
DNdnsHostName 当前 DC 主机名

如果安装了 AD 模块:

1
2
Get-ADRootDSE
Get-ADDomain | Select-Object DNSRoot,DistinguishedName

使用 AD PowerShell 模块查询

如果机器上存在 ActiveDirectory 模块,可以直接使用:

1
Import-Module ActiveDirectory

查看是否存在模块:
1
Get-Module -ListAvailable ActiveDirectory

查询域用户

查询所有用户:

1
Get-ADUser -Filter * |  Select-Object Name,SamAccountName,DistinguishedName

查询指定用户:

1
Get-ADUser -Identity james.cross |  Select-Object Name,SamAccountName,DistinguishedName

按 LDAPFilter 查询:

1
Get-ADUser -LDAPFilter "(sAMAccountName=james.cross)" |  Select-Object Name,SamAccountName,DistinguishedName

查询用户详细属性:

1
Get-ADUser -Identity james.cross -Properties * |  Select-Object Name,SamAccountName,Description,MemberOf,LastLogonDate,PasswordLastSet

查询域组

查询所有组:

1
Get-ADGroup -Filter * |  Select-Object Name,SamAccountName,DistinguishedName

查询管理员相关组:

1
Get-ADGroup -Filter 'Name -like "*admin*"' |  Select-Object Name,DistinguishedName

查询指定组成员:

1
Get-ADGroupMember "Domain Admins"

递归查询嵌套组成员:

1
Get-ADGroupMember "Domain Admins" -Recursive

查询某个用户属于哪些组:

1
Get-ADUser james.cross -Properties MemberOf |  Select-Object -ExpandProperty MemberOf

查询域计算机

查询所有计算机:

1
Get-ADComputer -Filter * |  Select-Object Name,DNSHostName,OperatingSystem,DistinguishedName

查询 Windows Server:

1
Get-ADComputer -Filter 'OperatingSystem -like "*Server*"' -Properties OperatingSystem |  Select-Object Name,DNSHostName,OperatingSystem

查询域控:

1
Get-ADDomainController -Filter * |  Select-Object HostName,IPv4Address,Site,Domain

查询 OU

1
Get-ADOrganizationalUnit -Filter * |  Select-Object Name,DistinguishedName

指定 OU 下查询用户:

1
Get-ADUser -Filter * `  -SearchBase "OU=Users,DC=inlanefreight,DC=local" |  Select-Object Name,SamAccountName

查询 GPO

1
Get-GPO -All

查询 GPO 名称和 GUID:

1
Get-GPO -All |  Select-Object DisplayName,Id,Owner

如果没有 GroupPolicy 模块,也可以使用 LDAP 查询:

1
Get-ADObject -LDAPFilter "(objectClass=groupPolicyContainer)" `  -SearchBase "CN=Policies,CN=System,DC=inlanefreight,DC=local" `  -Properties displayName,gPCFileSysPath |  Select-Object displayName,gPCFileSysPath,DistinguishedName

使用 ADSISearcher 查询

如果没有 AD 模块,可以直接使用 PowerShell 内置的 .NET DirectorySearcher

基础模板:

1
$Searcher = New-Object DirectoryServices.DirectorySearcher$Searcher.SearchRoot = "LDAP://DC=inlanefreight,DC=local"$Searcher.Filter = "(objectClass=user)"$Searcher.FindAll()

也可以写成简写形式:

1
([ADSISearcher]"(objectClass=user)").FindAll()

ADSISearcher 查询用户

查询所有用户:

1
([ADSISearcher]"(&(objectCategory=person)(objectClass=user))").FindAll()

只输出用户名:

1
([ADSISearcher]"(&(objectCategory=person)(objectClass=user))").FindAll() |  ForEach-Object {    $_.Properties.samaccountname  }

查询指定用户:

1
([ADSISearcher]"(sAMAccountName=james.cross)").FindOne()

输出指定属性:

1
([ADSISearcher]"(sAMAccountName=james.cross)").FindOne().Properties

ADSISearcher 查询组

查询所有组:

1
([ADSISearcher]"(objectClass=group)").FindAll() |  ForEach-Object {    $_.Properties.cn  }

查询 Domain Admins:

1
([ADSISearcher]"(cn=Domain Admins)").FindOne().Properties

查询组成员:

1
([ADSISearcher]"(cn=Domain Admins)").FindOne().Properties.member

ADSISearcher 查询计算机

1
([ADSISearcher]"(objectClass=computer)").FindAll() |  ForEach-Object {    $_.Properties.dnshostname  }

查询服务器:

1
([ADSISearcher]"(&(objectClass=computer)(operatingSystem=*Server*))").FindAll() |  ForEach-Object {    $_.Properties.dnshostname    $_.Properties.operatingsystem  }

常见 LDAP 过滤器

LDAP 查询最重要的是过滤器。
格式大概如下:

1
(属性=值)

多个条件组合:

1
2
3
4
(&(条件1)(条件2))    
AND(|(条件1)(条件2))
OR(!(条件))
NOT

用户查询过滤器

查询所有用户:

1
(&(objectCategory=person)(objectClass=user))

查询指定用户名:

1
(sAMAccountName=james.cross)

查询存在邮箱的用户:

1
(&(objectCategory=person)(objectClass=user)(mail=*))

查询描述字段不为空的用户:

1
(&(objectCategory=person)(objectClass=user)(description=*))

查询被禁用用户:

1
(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=2))

查询未禁用用户:

1
(&(objectCategory=person)(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))

查询密码永不过期用户:

1
(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=65536))

查询不需要 Kerberos 预认证的用户,常用于 ASREPRoasting 目标发现:

1
(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=4194304))

组查询过滤器

查询所有组:

1
(objectClass=group)

查询指定组:

1
(cn=Domain Admins)

查询管理员相关组:

1
(cn=*Admin*)

查询某用户所在组:

1
(member=CN=James Cross,OU=Users,DC=inlanefreight,DC=local)

查询某组的嵌套成员:

1
(member:1.2.840.113556.1.4.1941:=CN=James Cross,OU=Users,DC=inlanefreight,DC=local)

计算机查询过滤器

查询所有计算机:

1
(objectClass=computer)

查询服务器:

1
(&(objectClass=computer)(operatingSystem=*Server*))

查询 Windows 10:

1
(&(objectClass=computer)(operatingSystem=*Windows 10*))

查询域控:

1
(&(objectCategory=computer)(userAccountControl:1.2.840.113556.1.4.803:=8192))

SPN 查询过滤器

查询配置了 SPN 的用户,常用于 Kerberoasting 目标发现:

1
(&(objectCategory=person)(objectClass=user)(servicePrincipalName=*))

PowerShell:

1
Get-ADUser -LDAPFilter "(&(objectCategory=person)(objectClass=user)(servicePrincipalName=*))" `  -Properties servicePrincipalName |  Select-Object SamAccountName,ServicePrincipalName

ADSISearcher:

1
([ADSISearcher]"(&(objectCategory=person)(objectClass=user)(servicePrincipalName=*))").FindAll() |  ForEach-Object {    $_.Properties.samaccountname    $_.Properties.serviceprincipalname  }

委派查询过滤器

查询非约束委派用户:

1
(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=524288))

查询非约束委派计算机:

1
(&(objectClass=computer)(userAccountControl:1.2.840.113556.1.4.803:=524288))

查询约束委派:

1
(msDS-AllowedToDelegateTo=*)

查询 RBCD:

1
(msDS-AllowedToActOnBehalfOfOtherIdentity=*)

PowerShell:

1
Get-ADObject -LDAPFilter "(msDS-AllowedToDelegateTo=*)" `  -Properties msDS-AllowedToDelegateTo |  Select-Object Name,ObjectClass,msDS-AllowedToDelegateTo
1
Get-ADObject -LDAPFilter "(msDS-AllowedToActOnBehalfOfOtherIdentity=*)" `  -Properties msDS-AllowedToActOnBehalfOfOtherIdentity |  Select-Object Name,ObjectClass,DistinguishedName

Linux 下 ldapsearch 查询

Linux 下可以使用原生 ldapsearch
它比 windapsearchldapsearch-ad 更底层,需要手动指定:

1
2
3
4
5
-H    LDAP 服务器
-D 绑定用户
-W 交互式输入密码
-b Base DN
-s 查询范围

基础格式:

1
2
3
4
5
6
ldapsearch -x \  
-H ldap://10.129.1.207 \
-D 'inlanefreight\james.cross' \
-W \
-b 'DC=inlanefreight,DC=local' \
'(LDAP过滤器)' \ 需要返回的属性

查询 Base DN

1
2
3
4
5
ldapsearch -x \  
-H ldap://10.129.1.207 \
-s base \
-b "" \
defaultNamingContext

带凭据:

1
2
3
4
5
6
7
ldapsearch -x \  
-H ldap://10.129.1.207 \
-D 'inlanefreight\james.cross' \
-W \
-s base \
-b "" \
defaultNamingContext

查询用户

1
2
3
4
5
6
7
ldapsearch -x \  
-H ldap://10.129.1.207 \
-D 'inlanefreight\james.cross' \
-W \
-b 'DC=inlanefreight,DC=local' \
'(&(objectCategory=person)(objectClass=user))' \
cn sAMAccountName distinguishedName

查询指定用户:

1
2
3
4
5
6
7
ldapsearch -x \  
-H ldap://10.129.1.207 \
-D 'inlanefreight\james.cross' \
-W \
-b 'DC=inlanefreight,DC=local' \
'(sAMAccountName=james.cross)' \
cn sAMAccountName memberOf distinguishedName

查询组

1
2
ldapsearch -x \ 
-H ldap://10.129.1.207 \ -D 'inlanefreight\james.cross' \ -W \ -b 'DC=inlanefreight,DC=local' \ '(objectClass=group)' \ cn distinguishedName

查询 Domain Admins:

1
ldapsearch -x \  -H ldap://10.129.1.207 \  -D 'inlanefreight\james.cross' \  -W \  -b 'DC=inlanefreight,DC=local' \  '(cn=Domain Admins)' \  cn member distinguishedName

查询计算机

1
ldapsearch -x \  -H ldap://10.129.1.207 \  -D 'inlanefreight\james.cross' \  -W \  -b 'DC=inlanefreight,DC=local' \  '(objectClass=computer)' \  cn dNSHostName operatingSystem distinguishedName

查询 SPN

1
2
3
4
5
6
7
ldapsearch -x \  
-H ldap://10.129.1.207 \
-D 'inlanefreight\james.cross' \
-W \
-b 'DC=inlanefreight,DC=local' \
'(&(objectCategory=person)(objectClass=user)(servicePrincipalName=*))' \
sAMAccountName servicePrincipalName

查询 ASREPRoast 目标

1
2
3
4
5
6
7
ldapsearch -x \ 
-H ldap://10.129.1.207 \
-D 'inlanefreight\james.cross' \
-W \
-b 'DC=inlanefreight,DC=local' \
'(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=4194304))' \
sAMAccountName userAccountControl

查询密码策略

1
2
3
4
5
6
7
ldapsearch -x \  
-H ldap://10.129.1.207 \
-D 'inlanefreight\james.cross' \
-W \
-b 'DC=inlanefreight,DC=local' \
-s base \ '(objectClass=domainDNS)' \
minPwdLength lockoutThreshold maxPwdAge pwdHistoryLength