某安全数据交换系统的漏洞挖掘
2023-9-18|2023-9-18

倾旋
type
status
date
slug
summary
tags
category
icon
password
URL
本文写于2022年,分享一下挖掘某安全数据交换系统漏洞的过程。
最初拿到的系统是一个vmware虚拟机,系统是Linux
基本信息:
- 后台管理界面用户名密码:admin/nxg@LL99
- 操作系统:root / bo%Fn!71、uninxg / lx$zR9ce
配置网络
根据产品安装文档环境搭建完毕后,手动设置IP地址和DNS:
手工修改
/etc/resolv.conf
修改
/etc/NetworkManager/NetworkManager.conf
文件,在main部分添加 “dns=none” 选项:网络IP地址配置文件在
/etc/sysconfig/network-scripts
文件夹下:
我添加了两个网卡,其中一个用来供本机访问:

/etc/sysconfig/network-scripts/ifcfg-eth1-1
观察启动命令行:
/home/leagsoft/SafeDataExchange/Apache
是Tomcat的安装目录,webapps目录下是部署的应用源代码:
将war包通过ssh拷贝至本地就可以看到整个项目的源代码了。

源代码解密
将war包拷贝到本地通过idea打开,发现关键代码的实现都是空,连spring的控制器都是空,初步怀疑是被加密了,那么它是如何加密的呢?

既然网站可以正常跑起来,那么应该是运行时的某种技术手段实现,观察启动命令行:
命令行中有一个javaagent引起了我的注意:
将lib文件夹拷贝到项目中,观察jar包的结构:

看样子是调用了javassist实现了一种内存补丁技术,找到Agent的入口方法,看看它做了什么:
跟进
CoreAgent.premain
:这里可以看到,它是先通过ECFileConfig初始化,然后解密读取Ini/ec.file
跟进
ECFileConfig.getConfig()
:恰好我在服务器上找到了这个文件 ECFile.ini :

再看看
AgentTransformer
的实现:AgentTransformer
重写了ClassFileTransformer
的transform
方法,将每一个class和密码放入JarDecryptor.doDecrypt
进行解密,最终返回字节码。再来看看
JarDecryptor.doDecrypt
的实现:
通过
readEncryptedFile
方法读取META-INF/.classes/
下的class文件进行解密。回到文件目录,在META-INF下发现了许多加密的class字节码文件:

这里我通过编写一个类,调用
JarDecryptor.doDecrypt
对全部class进行了解密:
跑一下Main方法就能将所有的加密class字节码文件还原,大功告成。
远程调试Tomcat
修改Tomcat安装目录下
bin/catalina.sh
文件,通过定义catalina的配置选项可以在tomcat启动时开启远程调试端口。修改文件:
/home/leagsoft/SafeDataExchange/Apache/bin/catalina.sh

加入内容:
然后重启tomcat就可以进行远程调试了。

打开idea,将原本没有方法实现的class替换为已经解密的class,添加远程调试配置:
这里我替换了:
WEB-INF/classes/com/leagsoft/nxg/dlp/controller/FileTrackMarkMessageController.class

添加一个调试配置,点击Edit Configurations:

点击添加按钮,新增一个Remote配置:

填入远程调试的IP地址和端口:

然后在要调试的方法下断点,点击调试按钮,控制台会提示已经连接到目标JVM:

当访问到对应的控制器,并且代码执行时,断点会生效:

通过观察调用栈、局部变量的值可以很方便的帮助我们进行输入输出的判断。
后台命令执行一
通过审计发现
FileTrackMarkMessageController.class
中的getUploadFileID
方法调用了Runtime.getRuntime().exec
可能会存在命令执行漏洞。我们的输入点是request对象,它被传入了
getMultiParamterMap
方法,跟进查看:request
被传入了ServletFileUpload
,看来是一个文件上传的数据包。构造一个文件上传的数据包发送过去调试看看:
此时局部变量的值:

我发现文件名被带入了
/bin/sh -c
意味着文件名也可以作为命令执行,由于前面有进行文件扩展名的获取解析,这个方法会取文件名的最后一个.
作为分割,把扩展名取得后拼接在最后面,最好的命令注入点是文件扩展名,最终我的payload如下:
利用
``
和${IFS}
替代空格 在shell中的特点,可以达到任意命令执行的目的,我还发现它的java服务是以root用户启动的,意味着获取这个命令执行的权限就是最高权限。
后台命令执行二
com.leagsoft.uex.sysparam.controller.NoticeConfigController.class
中的testNoticeEmailAction
方法存在命令注入,在调用JavaShellUtil.executeCommand
方法时,将用户输入带入了bash脚本后面,但LeagUtil.filterCmdParams
对输入的值进行了过滤替换,不过因为参数没有放入单引号中,可以使用;
对前面的脚本进行闭合,从而绕过限制执行任意命令。发送数据包:
思考
这款产品使用了javassist的动态执行技术,但是java始终还是java,我们只需要hook或者针对它最上层的代码进行研究即可,于是我根据本次漏洞挖掘,编写了一个工具:Rvn0xsy/DumperAnalyze: 通过JavaAgent与Javassist技术对JVM加载的类对象进行动态插桩,可以做一些破解、加密验证的绕过等操作 (github.com)
通过JavaAgent与Javassist技术对JVM加载的类对象进行动态插桩,可以做一些破解、加密验证的绕过等操作。