Group Policy Preferences密码如何被解密?
红队备忘录 - Windows凭证获取
在Windows域环境的日常管理中,管理员为了统一部署配置,常常会利用一个名为“组策略首选项”的功能。这功能初衷极好,本意是为了省去逐台机器设置的麻烦,比如批量创建本地账户、部署计划任务或者映射网络驱动器。为了完成这些操作,策略里不可避免地需要嵌入密码——数据库连接密码、服务账户密码,或是那个最要命的本地管理员密码。
一个“善意”的致命缺陷
微软的工程师们当然知道明文存储密码是灾难。于是,他们为这些在组策略首选项里配置的密码设计了一套加密机制。当管理员在图形界面里填入密码并保存时,系统会使用一个32字节的AES密钥进行加密,然后将加密后的密文(也就是那个著名的cpassword属性)写入到名为Groups.xml、Services.xml这类XML策略文件中。这些文件随后被复制到域控制器的SYSVOL共享目录,供域内所有计算机下载和应用。
问题出在哪?出在这个AES密钥上。为了能让域内所有计算机都能解密并使用这个密码,微软选择了一个公开的、静态的密钥。更糟糕的是,这个密钥随着组策略首选项功能的SDK文档一起被发布了出来。任何能访问到SYSVOL目录的人(在默认配置下,这意味着域内任何经过认证的用户),都能拿到这些包含cpassword的XML文件,然后用这个公开的密钥进行解密。
解密过程:从密文到明文
整个解密链条清晰得令人不安。攻击者或安全审计人员首先需要定位到这些文件。它们通常位于域控制器的SYSVOL域名Policies{GUID}MachinePreferences下的各个子目录中,或者在客户端本地的C:ProgramDatamicrosoftGroup PolicyHistory缓存目录里。使用一句简单的findstr /s cpassword \域名SYSVOL*.xml命令就能把它们全揪出来。
找到文件后,提取出cpassword属性的值。这个值看起来是一长串Base64编码的字符串。解密的第一步,就是用Base64解码它,得到AES加密后的二进制数据。
接下来就是核心的解密步骤。微软使用的那个公开AES密钥是:4e 99 06 e8 fc b6 6c c9 fa f4 93 10 62 0f fe e8 f4 96 e8 06 cc 05 79 90 20 9b 09 a4 33 b6 6c 1b。使用这个密钥,以CBC模式,对刚才解码出的数据进行AES-256解密。初始向量IV是全零。解密后的数据,还需要进行一次Unicode解码,最终,那个被管理员认为“安全存储”的明文密码就赤裸裸地呈现出来了。
工具自动化与安全启示
整个过程早已被工具化。从早期的PowerShell脚本Get-GPPPassword,到Metasploit中的post/windows/gather/credentials/gpp模块,再到渗透测试框架里各种现成的插件,输入一个cpassword值,敲下回车,明文密码秒出。这根本不是什么高深的技术,而是一个只要知道方法,小学生都能执行的标准化流程。
微软在2014年的MS14-025安全公告中正式移除了通过组策略首选项部署密码的功能,并强烈建议管理员清理遗留的包含cpassword的文件。但尴尬的是,时至今日,在不少企业的内网渗透测试中,这依然是成功率最高、收获最丰厚的突破口之一。那些陈年的策略文件,就像埋在地下的宝藏地图,安静地躺在SYSVOL里,等待着被人发现。
这个案例几乎成了网络安全教学的经典反面教材:依赖“隐蔽性”而非“真正加密”的安全设计是多么不堪一击。它提醒每一位管理员,在共享存储上存放任何敏感信息前,都必须追问一句:加密的密钥,到底掌握在谁的手里?如果答案是“所有人”,那所谓的加密,不过是一层一捅就破的窗户纸。

参与讨论
之前排查问题的时候还真在SYSVOL里找到过这种文件,吓出一身冷汗
findstr找cpassword这命令好使,回头试试
原来用公开密钥就能解密,这设计也太坑了😓
这漏洞居然到现在还能用,太离谱了
微软这波操作真是迷之自信
@ 梦的彼岸 这设计真让人摸不着头脑