0X00 前言

Newtonsoft.Json,这是一个开源的Json.Net库,官方地址:https://www.newtonsoft.com/json ,一个读写Json效率非常高的.Net库,在做开发的时候,很多数据交换都是以json格式传输的。而使用Json的时候,开发者很多时候会涉及到几个序列化对象的使用:DataContractJsonSerializer,JavaScriptSerializer 和 Json.NET即Newtonsoft.Json。大多数人都会选择性能以及通用性较好Json.NET,这个虽不是微软的类库,但却是一个开源的世界级的Json操作类库,从下面的性能对比就可以看到它的性能优点。

用它可轻松实现.Net中所有类型(对象,基本数据类型等)同Json之间的转换,在带来便捷的同时也隐藏了很大的安全隐患,在某些场景下开发者使用DeserializeObject方法序列化不安全的数据,就会造成反序列化漏洞从而实现远程RCE攻击,本文笔者从原理和代码审计的视角做了相关介绍和复现。

0X01 Json.Net序列化

在Newtonsoft.Json中使用JSONSerializer可以非常方便的实现.NET对象与Json之间的转化,JSONSerializer把.NET对象的属性名转化为Json数据中的Key,把对象的属性值转化为Json数据中的Value,如下Demo,定义TestClass对象

并有三个成员,Classname在序列化的过程中被忽略(JsonIgnore),此外实现了一个静态方法ClassMethod启动进程。 序列化过程通过创建对象实例分别给成员赋值,

用JsonConvert.SerializeObject得到序列化后的字符串

Json数据中并没有包含方法ClassMethod,因为它是静态方法,不参与实例化的过程,自然在testClass这个对象中不存在。这就是一个最简单的序列化Demo。为了尽量保证序列化过程不抛出异常,笔者引入 SerializeObject方法的第二个参数并实例化创建JsonSerializerSettings,下面列出属性

修改代码添加 TypeNameAssemblyFormatHandling.Full、TypeNameHandling.ALL

将代码改成这样后得到的testString变量值才是笔者想要的,打印的数据中带有完整的程序集名等信息。

0x02 Json.Net反序列化

2.1、反序列化用法

反序列过程就是将Json字符串转换为对象,通过创建一个新对象的方式调用JsonConvert.DeserializeObject方法实现的,传入两个参数,第一个参数需要被序列化的字符串、第二个参数设置序列化配置选项来指定JsonSerializer按照指定的类型名称处理,其中TypeNameHandling可选择的成员分为五种

默认情况下设置为TypeNameHandling.None,表示Json.NET在反序列化期间不读取或写入类型名称。具体代码可参考以下

2.2、攻击向量—ObjectDataProvider

漏洞的触发点也是在于TypeNameHandling这个枚举值,如果开发者设置为非空值、也就是对象(Objects) 、数组(Arrays) 、自动识别 (Auto) 、所有值(ALL) 的时候都会造成反序列化漏洞,为此官方文档里也标注了警告,当您的应用程序从外部源反序列化JSON时应谨慎使用TypeNameHandling。

笔者继续选择ObjectDataProvider类方便调用任意被引用类中的方法,具体有关此类的用法可以看一下《.NET高级代码审计(第一课)XmlSerializer反序列化漏洞》,首先来序列化TestClass

指定TypeNameHandling.All、TypeNameAssemblyFormatHandling.Full后得到序列化后的Json数据

如何构造System.Diagnostics.Process序列化的Json字符串呢?笔者需要做的工作替换掉ObjectInstance的$type、MethodName的值以及MethodParameters的$type值,删除一些不需要的Member、最终得到的反序列话Json数据如下

再经过JsonConvert.DeserializeObject反序列化(注意一点指定TypeNameHandling的值一定不能是None),成功弹出计算器。

2.3、攻击向量—WindowsIdentity

WindowsIdentity类位于System.Security.Principal命名空间下。顾名思义,用于表示基于Windows认证的身份,认证是安全体系的第一道屏障肩负着守护着整个应用或者服务的第一道大门,此类定义了Windows身份一系列属性

对于用于表示认证类型的AuthenticationType属性来说,在工作组模式下返回NTLM。对于域模式,如果操作系统是Vista或者以后的版本,该属性返回Negotiate,表示采用SPNEGO认证协议。而对于之前的Windows版本,则该属性值为Kerberos。Groups属性返回WindowsIdentity对应的Windows帐号所在的用户组(User Group),而IsGuest则用于判断Windows帐号是否存在于Guest用户组中。IsSystem属性则表示Windows帐号是否是一个系统帐号。对于匿名登录,IIS实际上会采用一个预先指定的Windows帐号进行登录。而在这里,IsAnonymous属性就表示该WindowsIdentity对应的Windows帐号是否是匿名帐号。

2.3.1、ISerializable

跟踪定义得知继承于ClaimsIdentity类,并且实现了ISerializable接口

查看定义得知,只有一个方法GetObjectData

在.NET运行时序列化的过程中CLR提供了控制序列化数据的特性,如:OnSerializing、OnSerialized、NonSerialized等。为了对序列化数据进行完全控制,就需要实现Serialization.ISeralizable接口,这个接口只有一个方法,即 GetObjectData,第一个参数SerializationInfo包含了要为对象序列化的值的合集,传递两个参数给它:Type和IFormatterConverter,其中Type参数表示要序列化的对象全名(包括了程序集名、版本、公钥等),这点对于构造恶意的反序列化字符串至关重要

另一方面GetObjectData又调用SerializationInfo 类提供的AddValue多个重载方法来指定序列化的信息,AddValue添加的是一组<key,value> ;GetObjectData负责添加好所有必要的序列化信息。

2.3.2、ClaimsIdentity

ClaimsIdentity(声称标识)位于System.Security.Claims命名空间下,首先看下类的定义

其实就是一个个包含了claims构成的单元体,举个栗子:驾照中的“身份证号码:000000”是一个claim、持证人的“姓名: Ivan1ee”是另一个claim、这一组键值对构成了一个Identity,具有这些claims的Identity就是ClaimsIdentity,通常用在登录Cookie验证,如下代码

一般使用的场景我想已经说明白了,现在来看下类的成员有哪些,能赋值的又有哪些?参考官方文档可以看到 Lable、BootstrapContext、Actor三个属性具备了set

查阅文档可知,这几个属性的原始成员分别为actor、bootstrapContext、lable如下

ClaimsIdentity类初始化方法有两个重载,并且通过前文介绍的SerializationInfo来传入数据,最后用Deserialize反序列化数据。

追溯的过程有点像框架类的代码审计,跟踪到Deserialize方法体内,查找BootstrapContextKey才知道原来它还需要被外层base64解码后带入反序列化

2.3.3、打造Poc

回过头来想一下,如果使用GetObjectData类中的AddValue方法添加“key : System.Security.ClaimsIdentity.bootstrapContext“、”value :  base64编码后的payload“,最后实现System.Security.Principal.WindowsIdentity.ISerializable接口就能攻击成功。首先定义WindowsIdentityTest类

笔者用ysoserial生成反序列化Base64 Payload赋值给BootstrapContextKey,实现代码如下

到这步生成变量obj1的值就是一段poc,但还需改造一下,将$type值改为System.Security.Principal.WindowsIdentity完全限定名

最后改进后交给反序列化代码执行,抛出异常之前触发计算器,效果如下图

0x03 代码审计视角

从代码审计的角度其实很容易找到漏洞的污染点,通过前面几个小节的知识能发现需要满足一个关键条件非TypeNameHandling.None的枚举值都可以被反序列化,例如以下Json类

都设置成TypeNameHandling.All,攻击者只需要控制传入参数 _in便可轻松实现反序列化漏洞攻击。Github上很多的json类存在漏洞,例如下图

代码中改用了Auto这个值,只要不是None值在条件许可的情况下都可以触发漏洞,笔者相信肯定还有更多的漏洞污染点,需要大家在代码审计的过程中一起去发掘。

0x04 案例复盘

最后再通过下面案例来复盘整个过程,全程展示在VS里调试里通过反序列化漏洞弹出计算器。

1. 输入http://localhost:5651/Default Post加载value值

2. 通过JsonConvert.DeserializeObject 反序列化 ,并弹出计算器

最后附上动图

0x05 总结

Newtonsoft.Json库在实际开发中使用率还是很高的,攻击场景也较丰富,作为漏洞挖掘者可以多多关注这个点,攻击向量建议选择ObjectDataProvider,只因生成的Poc体积相对较小。最后.NET反序列化系列课程笔者会同步到 https://github.com/Ivan1ee/https://ivan1ee.gitbook.io/ ,后续笔者将陆续推出高质量的.NET反序列化漏洞文章,请大伙持续关注。

.NET高级代码审计(第二课) Json.Net反序列化漏洞的更多相关文章

  1. .NET高级代码审计(第三课)Fastjson反序列化漏洞

    0X00 前言 Java中的Fastjson曾经爆出了多个反序列化漏洞和Bypass版本,而在.Net领域也有一个Fastjson的库,作者官宣这是一个读写Json效率最高的的.Net 组件,使用内置 ...

  2. .NET高级代码审计(第四课) JavaScriptSerializer反序列化漏洞

    0X00 前言 在.NET处理 Ajax应用的时候,通常序列化功能由JavaScriptSerializer类提供,它是.NET2.0之后内部实现的序列化功能的类,位于命名空间System.Web.S ...

  3. .NET高级代码审计(第一课)XmlSerializer反序列化漏洞

    0X00 前言 在.NET 框架中的 XmlSerializer 类是一种很棒的工具,它是将高度结构化的 XML 数据映射为 .NET 对象.XmlSerializer类在程序中通过单个 API 调用 ...

  4. .NET高级代码审计(第五课) .NET Remoting反序列化漏洞

    0x00 前言 最近几天国外安全研究员Soroush Dalili (@irsdl)公布了.NET Remoting应用程序可能存在反序列化安全风险,当服务端使用HTTP信道中的SoapServerF ...

  5. Asp.Net Web API 2(CRUD操作)第二课

    Asp.Net Web API 2(CRUD操作)第二课 Asp.Net Web API 导航   Asp.Net Web API第一课:入门http://www.cnblogs.com/aehyok ...

  6. 【Web探索之旅】第二部分第二课:服务器语言

    内容简介 1.第二部分第二课:服务器语言 2.第二部分第三课预告:框架和内容管理系统 第二部分第二课:服务器语言 介绍了Web的客户端,我们来谈谈Web的服务器端. 既然客户端有客户端的编程语言(HT ...

  7. 【C++探索之旅】第一部分第二课:C++编程的必要软件

    内容简介 1.第一部分第二课:C++编程的必要软件 2.第一部分第三课预告:第一个C++程序 C++编程的必要软件 经过上一课之后,大家是不是摩拳擦掌,准备大干一场了呢. 这一课我们来做一些C++开发 ...

  8. 【C语言探索之旅】 第二部分第二课:进击的指针,C语言的王牌!

    内容简介 1.课程大纲 2.第二部分第二课: 进击的指针,C语言的王牌 3.第二部分第三课预告: 数组 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C语言 ...

  9. 【C语言探索之旅】 第二课:工欲善其事,必先利其器

    内容简介 1.课程大纲 2.第一部分第二课:工欲善其事,必先利其器 3.第一部分第三课预告:你的第一个程序 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C ...

随机推荐

  1. TensorFlow—多层感知器—MNIST手写数字识别

    1 import tensorflow as tf import tensorflow.examples.tutorials.mnist.input_data as input_data import ...

  2. K.O. -------- Eclipse中Maven的报错处理

    ----------------------siwuxie095                                 K.O. -------- Eclipse 中 Maven 的报错处理 ...

  3. sqserver2008触发器

    @参考博文 先上代码 先建个表用于测试 CREATE TRIGGER INSERT_forbidden on s after INSERT AS BEGIN RAISERROR(,) ROLLBACK ...

  4. 批量MD5命名文件

    #coding=utf-8 import os import hashlib def GetFileMd5(filename): if not os.path.isfile(filename): pr ...

  5. php5.3 php-fpm 开启 关闭 重启

    自php5.3开始,php源码中包含了php-fpm,不需要单独通过补丁的方式安装php-fpm,在源码安装的时候直接 configure 中增加参数 –enable-fpm 即可.   所以启动.关 ...

  6. dede后台一片空白

    原因是你修改了后台的数据库连接信息文件data/common.inc.php,保存的后文件编码并不是utf-8,而是变成了ANSI或utf-8 + bom的. 解决方法: 用editplus或note ...

  7. 使用第三方容器服务,自动化部署.Net Core

    1.为什么用第三方,而不自建,有哪些第三方,最后实现的效果 a.尝试过自建,并成功了,但是很麻烦,要敲一堆命令,无法达到全自动化部署的要求. b.自建,就算用第三方的镜像包,感觉下载还是不快,不知道为 ...

  8. bootstrap下modal模态框中webuploader控件按钮异常(无法点击)问题解决办法【转】

    http://bbs.csdn.net/topics/391917552 具体如下:   $(function () {         var _$modal = $('#MyModal');    ...

  9. 【DBCP】DBCP基本配置和重连配置+spring中配置

    最近在看一些dbcp的相关内容,顺便做一下记录,免得自己给忘记了.   1. 引入dbcp (选择1.4) <dependency> <groupId>com.alibaba. ...

  10. 2018.09.27 bzoj3029: 守卫者的挑战(概率dp)

    传送门 概率dp经典题目. 直接f[i][j][k]f[i][j][k]f[i][j][k]表示当前是第i次挑战,已经胜利了j次,目前的背包剩余空间是k. 然后用前面的转移后面的就行了. 注意第三维可 ...