← 返回信息流
AI 资讯Hacker News·2 小时前

如何解密视图状态消息

原标题:Decrypting View State Messages

速览

视图状态消息是Web开发中用于保存页面状态的数据,但可能被恶意篡改。本文解析了如何解密这些消息,帮助开发者理解其安全风险。该技术对于提升Web应用的安全性具有重要意义,尤其适用于安全测试与漏洞修复场景。

AI 深度解读

背景

近期,有安全研究人员发现 Windows 应用程序日志中记录了一个编号为 1316 的事件,其中包含一个疑似恶意的 View State 消息。问题在于该 View State 已被加密,而调查人员仅能获取到宿主机的磁盘镜像。在提取受影响站点的 web.config 文件后,他们发现该站点配置了自动生成密钥(autogen keys)。虽然他们能够从 Windows 注册表中导出这些 autogen keys,但不知道如何使用它们来解密 View State。

作者指出,解密 View State 的复杂度跨度很大:对于旧式(legacy)加密配置,只需从缓冲区末尾移除验证哈希,然后使用正确的密钥和对称算法即可解密;而对于现代(modern)配置,传统的做法是利用反射“欺骗”IIS 代为解密。作者通常使用 CyberChef 处理旧式 View State,使用 Blacklist3r 处理现代 View State,但认为这两个工具使用起来都有些繁琐,因此在文章末尾会分享一个新工具。

回到原始问题:无论加密 View State 是旧式还是现代配置,仅拥有 autogen keys 还不够,实际需要的是最终的 machine keys 才能解密。那么,如何从存储在注册表或 LSA Secret 中的 autogen key blob,推导出可用的解密密钥呢?

本文是《View State, The unpatchable IIS forever day being actively exploited》的续篇,强烈建议先阅读前文。前文已从高层介绍了密钥生成过程,并提及了一些为保障跨应用密钥唯一性而传入的修饰符(modifiers),但主要集中在旧式(仍占主导)的加密配置上,几乎未涉及现代配置。本篇将涵盖:

  • autogen keys 的生成方式
  • 从 autogen keys 推导出主 machine keys(master machine keys)
  • 从主 machine keys 推导出最终 machine keys(final machine keys)
  • 如何使用最终密钥解密 View State 消息

并且,本次将同时覆盖旧式(legacy)和现代(modern)两种加密配置。

核心内容

什么是 autogen key?如何生成?

“Autogen key”这个命名并不准确,因为它本质上不是密钥,但微软在代码和注册表中都这样称呼,本文沿用此叫法。autogen key 是一个 1024 字节的数据块,其中在特定偏移处包含了 IIS 的主验证密钥(master validation key)和主解密密钥(master decryption key)。该值存储在注册表或(加密的)LSA Secret 中,在运行时被读取。

生成过程位于 System.Web.HttpRuntime::SetAutogenKeys() (注:本文提到的所有 Namespace.Class::Function 组合都可在 .NET Framework 的 System.Web 程序集中找到)。原始方法体如下(已清理变量名以便理解):

internal static byte[] s_autogenKeys = new byte[1024];

private static void SetAutogenKeys()
{
    byte[] randBytes = new byte[HttpRuntime.s_autogenKeys.Length];
    byte[] autogenKey = new byte[HttpRuntime.s_autogenKeys.Length];
    bool existingKeyLoaded = false;

    RNGCryptoServiceProvider rngcryptoServiceProvider = new RNGCryptoServiceProvider();
    rngcryptoServiceProvider.GetBytes(randBytes);

    if (!existingKeyLoaded)
    {
        existingKeyLoaded = UnsafeNativeMethods.EcbCallISAPI(IntPtr.Zero, 
            UnsafeNativeMethods.CallISAPIFunc.GetAutogenKeys, 
            randBytes, randBytes.Length, 
            autogenKey, autogenKey.Length) == 1;
    }

    if (existingKeyLoaded)
    {
        Buffer.BlockCopy(autogenKey, 0, HttpRuntime.s_autogenKeys, 0, HttpRuntime.s_autogenKeys.Length);
        return;
    }

    Buffer.BlockCopy(randBytes, 0, HttpRuntime.s_autogenKeys, 0, HttpRuntime.s_autogenKeys.Length);
}

SetAutogenKeys 被调用(作为 HttpRuntime 初始化的一部分)时,会定义两个 1024 字节的数组:randBytes 填充随机数据,autogenKey 保持默认值 0。两者连同常量 CallISAPIFunc.GetAutogenKeys 一起传入 EcbCallISAPI 函数(推测意为 Extension Control Block Call Internet Service API)。EcbCallISAPI 充当通往多个内部 IIS 函数的桥梁,包括检索 autogen key。该函数会尝试从本地安全机构(LSA)和 Windows 注册表的若干位置加载现有 autogen key。如果找到现有密钥,则将其复制到 autogenKey 数组;如果未找到,则将 randBytes 的内容视为新生成的 autogen key,并依据当前 IIS 应用程序池的权限存储在 LSA 或注册表中,然后返回。最后,无论是已存在的密钥还是新生成的随机数据,都会被复制到 s_autogenKeys 数组中,供整个应用程序使用。

从 autogen keys 到 IIS machine keys

接下来分别针对旧式(legacy)和现代(modern)加密配置进行说明。

旧式(Legacy)配置 —— 主 machine key 的生成

密钥的生成(本质上是提取)发生在 System.Web.Configuration.MachineKeySection::RuntimeDataInitialize() 中。主验证密钥(master validation key)直接取 autogen key 的前 64 字节,主解密密钥(master decryption key)取随后的 24 字节。

private static int _AutoGenValidationKeySize = 64;
private static int _AutoGenDecryptionKeySize = 24;

private byte[] _ValidationKey;
private byte[] _DecryptionKey;

private void RuntimeDataInitialize()
{
    // 提取验证密钥
    Buffer.BlockCopy(HttpRuntime.s_autogenKeys, 0, this._ValidationKey, 0, MachineKeySection._AutoGenValidationKeySize);
    // 提取解密密钥
    Buffer.BlockCopy(HttpRuntime.s_autogenKeys, MachineKeySection._AutoGenValidationKeySize, this._DecryptionKey, 0, MachineKeySection._AutoGenDecryptionKeySize);
}

举例说明:假设有如下 autogen key(十六进制,截断):

726E2B4BF328A110EBBA089F1ED4A347CB45FFA9D2164C9D7510320A96500330FA7D2516FC41CD03A925FD242979CFE08551B59846B21436B38A156D46C1FB6AFD0A2D2785BFE3F5C747A3E2FF29AFF77EFBC2852C26B93685FB784A613372491F668C85403F1427B409BE784B5E7142C0D8ABA49803463408D0661453EE1681D6E91EB9FEB846A40F21B8CADB347AD291134191B7FA6D44EFAC1718ED460EDEF50EFC782E9AB97B1CA948CD259B26FDEED6DA36CBC37083A82C96B58989918270204CAD473DC721A4F8D4412250B25582080064D05B1A964FFBBC5E9552918...

则主验证密钥为前 64 字节:726E2B4BF328A110EBBA089F1ED4A347CB45FFA9D2164C9D7510320A96500330FA7D2516FC41CD03A925FD242979CFE08551B59846B21436B38A156D46C1FB6A,主解密密钥为随后的 24 字节。

现代(Modern)配置 —— 待后续补充

原文在介绍完 legacy 配置后,由于被截断,尚未展开现代配置的详细推导过程,也未给出最终 machine keys 的完整推导以及解密示例。后续部分(包括现代加密配置的密钥推导、如何使用最终密钥解密 View State 消息,以及作者计划分享的新工具)在用户提供的文本中缺失。但基于文章结构,可以推断现代配置的密钥推导过程更为复杂,涉及额外的修饰符(如应用程序路径、应用程序池标识等),以确保不同

查看原文 →zeroed.tech