ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

GOAD靶场搭建:ActiveDirectoryDSC配置失败排查指南

GOAD靶场搭建:ActiveDirectoryDSC配置失败排查指南 在搭建AD安全实验环境这件事上GOADGame of Active Directory一直是我比较推荐的靶场之一。它不是单纯跑一个域控给你练习而是把一套包含多域、多主机、大量攻击路径的AD环境用Vagrant和Ansible自动编排起来适合做权限提升、域信任、ACL滥用、委派攻击这类练习。不过很多人第一轮搭建根本走不到“好好玩攻击路径”那一步卡就卡在自动配置阶段的ActiveDirectoryDSC配置失败。我自己最早也被这个问题折腾过几轮后来把失败日志、Ansible连接参数、Windows主机上的PowerShell运行环境全部重新梳理了一遍才稳定跑通。这篇文章就把GOAD靶场搭建过程中ActiveDirectoryDSC配置失败的原因和解决办法完整写出来给正在被这套自动化流程折磨的人一点参考。1. 先搞清楚ActiveDirectoryDSC究竟在GOAD里负责什么1.1 GOAD自动化搭建过程不是“装虚拟机”那么简单很多人第一次接触GOAD时容易把它理解为“Vagrant拉几个Windows镜像起来就完事”。实际上镜像启动只是第一步后面还有一套相当重的配置工程。Vagrant负责创建虚拟机、分配IP、配置虚拟网络但真正让这些Windows机器变成域环境的是Ansible。Ansible通过WinRM连进每一台Windows主机然后执行大量PowerShell任务安装ADDS角色、创建域、提升域控、配置DNS、创建用户、创建组、设置ACL、建立域信任、往指定OU里塞测试对象。这个过程的复杂程度远高于“用脚本创建几个用户”。GOAD要模拟的是一套相对真实的企业AD所以里面会有很多互相关联的AD对象。单靠传统命令一个个执行不仅慢而且很难做到“重跑不报错”。于是项目选用了PowerShell DSC这套机制让目标主机自己判断“当前状态是否符合预期”不符合就执行变更。ActiveDirectoryDSC就是这个机制里专门管AD对象的资源模块。1.2 ActiveDirectoryDSC在整套配置链里的位置你可以把Ansible理解成“总指挥官”WinRM是它进入Windows主机的大门而ActiveDirectoryDSC是被调到Windows本地上执行具体AD操作的“施工队”。Ansible任务里往往通过win_dsc或类似方式声明“我要让这个ADUser存在”、“我要让这个ADGroup包含某个成员”剩下的状态判断和操作由DSC资源在Windows端完成。这里有个很关键的转变Ansible不会自己去调用ActiveDirectory PowerShell原生命令而是把目标状态描述扔给Windows主机的DSC引擎。ActiveDirectoryDSC模块里的ADUser、ADGroup、ADOrganizationalUnit、ADDomain这些资源会先做Test再看是否要执行Set。这样做的好处是幂等重复执行同一套playbook时不会因为“用户已存在”就报错。问题也恰恰出在这里只要目标Windows环境本身不稳定比如PowerShell模块没装全、WinRM会话断掉、远程令牌权限不够、DSC资源版本和Ansible任务参数不匹配那个Test或者Set就会在深处抛出异常最后反映到Ansible上就是一行很唬人的failed。1.3 配置失败造成的影响不是“重跑一遍”那么简单ActiveDirectoryDSC失败最麻烦的地方在于环境已经被改了一半。比如ADDomain资源已经把域创建完成但在创建后续用户对象时失败那么你手上就出现了一个半成品域域是存在的可预期的用户、组、委派关系全部缺失。如果不去纠正后面任何依赖这些对象的攻击路径练习都无法进行。还有的情况是执行过程中服务器已经重启但Ansible认为任务没有成功于是重跑时又尝试去创建同一个域、同一个用户这时候报错信息还会变。所以处理ActiveDirectoryDSC失败不能只盯着最后那一行红字而是要判断失败发生在哪个阶段是DSC模块安装之前、正在执行资源时还是执行完成后的通信中断。把阶段判断清楚才能决定是补依赖、改参数、还是直接恢复快照重来。2. ActiveDirectoryDSC配置失败的真实现场先别急着搜报错2.1 报错信息长得五花八门但你可以先归类我经历过几次比较典型的ActiveDirectoryDSC配置失败Ansible输出里出现过类似这样的信息fatal: [dc01]: FAILED! {changed: false, msg: Unhandled exception while executing DSC resource...} fatal: [dc01]: FAILED! {msg: winrm or request timed out} fatal: [dc01]: FAILED! {msg: The module ActiveDirectoryDsc was not installed, please install it first}很多人在网上搜报错看到一条就照着改一条结果今天改好这个明天冒出那个。我的建议是先给失败现象分类下面这个表格是我自己排查时常用的归类方式失败现象大概率原因初步排查方向模块找不到、模块版本不满足ActiveDirectoryDSC未安装或版本和playbook不匹配在Windows主机上检查Get-Module -ListAvailableWinRM超时、连接中断主机重启、网络抖动、操作时间窗口太短重启后等待WinRM恢复、调大Ansible超时参数Access is denied、权限不足使用的账号不是管理员、UAC远程限制确认账号权限、设置LocalAccountTokenFilterPolicyDSC执行到一半报Unhandled exceptionPowerShell环境问题或参数类型不对在目标主机手动执行同一资源看详细PowerShell异常域存在但后续对象创建失败上一轮配置残留了半成品状态恢复快照或清理已创建的AD对象不要被这几种现象吓到GOAD本身是本地靶场环境比生产环境相对可控。只要把你自己的执行环境“调教”到符合ActiveDirectoryDSC那几个预设条件大多数失败都能绕过去。2.2 判断失败阶段比看日志内容更优先Ansible执行playbook时会输出当前任务名。你先看失败的任务名和它前面的任务顺序能快速定位阶段。通常GOAD搭建流程里会先有一段安装PowerShell模块、准备WinRM的环境任务然后才是真正调用ActiveDirectoryDSC配置域资源的环境任务。如果你失败在“安装模块”这一步那是模块源或PowerShellGet的问题如果模块已经装完失败在“创建域/用户/OU”这一步那是DSC资源和参数的问题如果机器在任务中重启然后Ansible报连接超时那是WinRM恢复顺序的问题。别小看这个判断很多人明明失败在安装NuGet provider却一直去调ActiveDirectoryDSC资源参数完全用错了方向。2.3 排查前先收集三份现场信息看到failed之后不要立刻重跑。先收集三份信息。第一份是Ansible详细输出重跑的时候可以加-vvvv会打印WinRM请求和响应细节能看出是不是底层通信出了问题。第二份是Windows主机上的DSC操作日志在目标机PowerShell里执行Get-WinEvent -LogName Microsoft-Windows-DSC/Operational -MaxEvents 30 | Format-List TimeCreated, Id, Message这份日志能直接看到DSC资源在Windows端到底是因为什么原因停下来的。第三份是目标机上ActiveDirectoryDSC模块的安装状态Get-Module -ListAvailable ActiveDirectoryDsc | Select-Object Name, Version, Path如果第三份信息显示模块没安装或者版本和你预期不一致那后续很多问题都不需要继续深挖。3. 根因拆解ActiveDirectoryDSC配置失败的五类高频问题3.1 PowerShell模块源和底层组件没提前“铺好”Windows Server 2016和2019自带Windows PowerShell 5.1看起来够用但ActiveDirectoryDSC从PowerShell Gallery安装时还依赖几个东西NuGet provider、PowerShellGet、以及对PSGallery存储库的访问权限。如果这些底层组件没准备好Install-Module会报错或者明明显示安装成功Ansible下一次连上去还是说模块找不到。这里面还有一个很容易忽略的点如果Windows主机无法通过TLS1.2访问PowerShell GalleryInstall-PackageProvider这步会一直超时。很多GOAD的Windows镜像里默认服务端协议配置并不一定包含TLS1.2所以最好在安装模块前先把安全协议设置成Tls12再执行安装。仓库里很多历史issue都指向这个细节。3.2 WinRM连接参数和系统重启后的恢复窗口问题使用Ansible配置WindowsWinRM是命门。GOAD里的Windows主机会在AD配置过程中多次重启特别是安装ADDS角色、提升域控之后系统重启几乎是必然的。问题是重启后WinRM服务并不是立刻就能接受连接有时候还需要等待网络配置完成。如果Ansible超时设置太短它会在WinRM还没就绪时就报错导致整个playbook中断。我见过最典型的情况是第一次跑playbook配置过程很顺利到了域控提升完成Windows开始重启Ansible等了30秒没连上直接fatal。很多人以为是自己操作有问题实际上是默认读取超时本来就不够覆盖一次完整重启。这种情况不需要改DSC只需要把Ansible对WinRM的operation_timeout和read_timeout调大并在任务层面处理系统重启后的等待。3.3 远程令牌权限被UAC“削”了ActiveDirectoryDSC要创建域、提升域控、创建用户必然需要管理员权限。如果你用Windows本地管理员账号通过WinRM远程执行UAC会对远程会话的访问令牌进行过滤。简单说你虽然属于Administrators组但远程登录时令牌可能只是一个标准用户权限很多AD管理操作根本没权限执行。这个问题在服务器本机操作时不容易暴露因为本地控制台会话默认有高权限令牌但通过WinRM远程执行时就不一样。解决办法是在Windows注册表里设置LocalAccountTokenFilterPolicy为1让远程管理员会话也能拿到完整权限令牌。这个设置只适合本地测试环境生产环境不要这样干。3.4 Ansible任务里传的参数和DSC资源要求不一致ActiveDirectoryDSC每个资源都有一组参数要求。例如ADUser资源需要指定至少包括用户名、域信息、凭据、状态等参数部分参数有强制要求。如果你用的playbook是基于某个版本写的但Windows主机上安装的是另一个版本ActiveDirectoryDSC资源参数名或参数类型可能发生变化最终执行时就会抛异常。这种问题看报错信息往往不太明显因为它会显示成“Unhandled exception while executing DSC resource”。需要你在目标主机上手动调用一次资源才能看到真正的PowerShell错误。处理方式也简单先确认playbook里win_dsc声明的module版本和实际安装版本一致再根据目标机上的资源语法来调整参数。3.5 上一次失败残留的半成品AD对象没有清理干净这是很多人最后才意识到的问题。ActiveDirectoryDSC优点是幂等但前提是状态没有处于“中间态”。如果上一次跑playbook时ADDomain资源已经创建了域但是后续创建用户的任务失败那么你修复了问题再重跑ADDomain资源可能会发现域已经存在而不执行但之前一些没跑完的步骤也不会自动补偿。更麻烦的情况是某些资源测试时认为对象不存在实际AD里却残留了同名对象于是执行创建时报“对象已存在”。遇到这种状态最好的办法不是继续修复而是恢复到你开始这一轮配置前的干净快照把预置步骤做好后再重跑。硬在残局里反复尝试往往浪费更多时间。4. 解决实操让GOAD的ActiveDirectoryDSC配置不再半路翻车4.1 第一优先在Vagrant预置脚本里打好底子我现在搭建GOAD的习惯是不让Ansible从零搞定所有环境准备而是把“PowerShell模块源、NuGet、执行策略、WinRM、UAC远程令牌”这些基础事项提前在Vagrant provision阶段处理完。这样Ansible跑ActiveDirectoryDSC时目标Windows主机已经是“可被远程管理的高权限PowerShell环境”。下面这段PowerShell脚本是典型的预置内容适合放到Vagrantfile里每个Windows VM的shell provision中执行# 预置ActiveDirectoryDSC运行环境仅用于本地测试靶场 $ErrorActionPreference Stop # 1. 允许远程会话使用完整管理员令牌 reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f # 2. 关闭或放开WinRM Basic认证靶场环境使用 winrm quickconfig -q winrm set winrm/config/service/auth {Basictrue} winrm set winrm/config/service {AllowUnencryptedtrue} # 3. 放宽执行策略 Set-ExecutionPolicy -ExecutionPolicy Bypass -Force # 4. 设置TLS1.2保证能访问PowerShell Gallery [Net.ServicePointManager]::SecurityProtocol [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 # 5. 安装NuGet和PowerShellGet Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force Install-Module -Name PowerShellGet -Force -AllowClobber -SkipPublisherCheck # 6. 信任PSGallery并安装ActiveDirectoryDsc Set-PSRepository -Name PSGallery -InstallationPolicy Trusted Install-Module -Name ActiveDirectoryDsc -Force -AllowClobber -SkipPublisherCheck # 7. 刷新模块路径并确认 Get-Module -ListAvailable ActiveDirectoryDsc | Select-Object Name, Version注意这段脚本里的WinRM认证配置、执行策略放开都基于“本地隔离靶场环境”这个前提。如果哪一步失败单独在Windows主机上用管理员身份打开PowerShell执行能更直观看到错误。4.2 第二优先把Ansible的WinRM连接参数调到能扛住重启GOAD的playbook在默认情况下不一定适合每个人的网络环境。我的经验是不要直接修改仓库里所有逻辑而是在Ansible的inventory或group_vars里加上一组更稳妥的WinRM连接参数ansible_connection: winrm ansible_winrm_transport: ntlm ansible_winrm_server_cert_validation: ignore ansible_winrm_operation_timeout_sec: 300 ansible_winrm_read_timeout_sec: 500 ansible_winrm_connection_timeout: 60 ansible_winrm_port: 5985为什么要把operation_timeout和read_timeout调大因为ActiveDirectoryDSC里部分资源执行一次可能超过一分钟域控提升过程甚至可能触发重启。如果timeout太短Ansible会主动断开然后报“超时”。很多所谓的DSC配置失败其实只是Ansible“等不及”了不是DSC本身运行失败。此外如果playbook里同一个剧本要同时配置多台域控建议把执行策略改成串行避免多台VM同时提升域角色时相互之间DNS和复制状态还没准备好。可以在playbook级别加serial: 1或者用--limit先跑DC再跑member server。虽然会慢一点但稳定性明显提升。4.3 第三优先不要整本playbook一条龙跑到底GOAD的完整playbook执行链比较长中间任何一环失败都会让后面全部中断。为了精细排查ActiveDirectoryDSC失败我建议第一次搭建时不要整本跑而是拆开跑。先从最基础的域控制器开始确认第一个域起来了再扩到第二个域、再配信任和其他对象。执行时可以用类似这样的命令先限定到某一台主机ansible-playbook -i your_inventory_file -l dc01 your_setup_playbook.yml当dc01上的ActiveDirectoryDSC任务都成功后再去跑其他主机。这个方式能最大程度减少干扰因素因为多主机并行执行时如果有一台还没就绪另一台已经尝试去连接域控很容易出现“找不到域”、“域名无法解析”这类错误。单独跑之后很多问题就消失了。4.4 在目标主机上手动调用DSC资源拿到最真实的错误当Ansible报ActiveDirectoryDSC执行失败但你看不出原因时直接在出问题的那台Windows主机上打开PowerShell手动调用一次出错的DSC资源。不需要完整跑一遍playbook只需要调用当前失败的这样一个资源。先用这个命令看模块里有哪些资源和参数语法Get-DscResource -Module ActiveDirectoryDsc | Select-Object Name Get-DscResource -Name ADUser -ModuleName ActiveDirectoryDsc -Syntax拿到语法之后再按实际参数调用。比如ADUser资源失败你可以构造一个简单的Set操作先创建测试用户看PowerShell会不会给出比Ansible更详细的异常信息$cred New-Object System.Management.Automation.PSCredential(DOMAIN\Administrator, (ConvertTo-SecureString YourPassword -AsPlainText -Force)) Invoke-DscResource -Name ADUser -ModuleName ActiveDirectoryDsc -Method Set -Property { DomainName yourlab.local DomainAdministratorCredential $cred UserName testuser Ensure Present Password (ConvertTo-SecureString Password123! -AsPlainText -Force) } -Verbose手动执行会打印很多详细日志能定位到具体是哪一行PowerShell代码失败。如果手动执行成功但Ansible执行失败那就要回过去检查Ansible传给win_dsc的参数是不是缺少了某个必填项或者类型不一样。手动执行这一步虽然费时间但对解决那些“看起来莫名其妙”的ActiveDirectoryDSC失败非常有用。4.5 失败后是修还是恢复快照别纠结如果你已经按照前面步骤铺好底子结果还是失败最理智的选择往往是恢复快照而不是在残局里反复重跑。因为ActiveDirectoryDSC在配置域环境时会做很多状态变更单靠Ansible重跑不能保证把上一轮的残留状态全部回滚干净。我第一次跑通GOAD时策略很简单先把所有VM能正常启动并完成基础配置的快照保存好再开始跑Ansible。每次失败我大概花几分钟看日志如果判断是普通依赖问题就修一下如果已经是域环境半成品状态直接恢复快照再跑。这样反复几次之后整个流程的稳定性反而越来越高。5. 跑通之后的验证思路与后续维护建议5.1 验证域环境不是只看“命令不报错”ActiveDirectoryDSC配置完成后先用简单的AD管理命令验证环境。比如在域控上执行Get-ADDomain Get-ADForest Get-ADUser -Filter * Get-ADGroup Domain Admins -Properties Members如果这些命令返回正常说明核心域环境已经起来。不过GOAD的价值在于后续攻击路径练习所以还要验证一些具体对象有没有被正确创建。你可以在域控上用ADUC或
返回列表