Java代码审计Spring框架思路篇中,斗哥为大家讲述了如何得到Spring审计的Demo,审计源码,根据IDEA与Spring框架审计思路初步判定是否存在漏洞。
Java代码审计Spring框架知识篇中,斗哥讲述Spring框架漏洞分析和利用的必备知识,如java命令执行函数、SpEL表达式使用,两者的配合使用构造Spring框架漏洞的命令执行POC。
本期Java代码审计Spring框架实例篇将结合前两篇的知识,以Spring Messaging 远程命令执行漏洞为例,根据审计思路来分析,深入学习Spring框架的代码审计。
0X01 漏洞环境说明
Spring曝出的漏洞并不多但危害都很大,比如Spring Messaging 远程命令执行漏洞。
1.Spring框架中通过spring-messaging模块来实现STOMP。 2.客户端定义headers并且其中包含selector,传入SpEL(可带有恶意代码),向服务器端发送消息。 3.服务端和客户端建立起连接后,服务端接收到SUBSCRIBE订阅消息后获取headers并且在当前会话中查找headers中的selector值最终执行。
0X02 漏洞流程复现
1、STOMP说明:
STOMP(Simple Text-Orientated Messaging Protocol) 面向消息的简单文本协议,用于服务器在客户端之间进行异步消息传递,它定义了服务端与客户端之间的格式化文本传输方式。 STOMP是基于帧的协议:由命令和一个或多个头信息、一个空行及负载(文本或字节)所组成。 其中可用的命令包括: CONNECT、SEND、SUBSCRIBE、UNSUBSCRIBE、BEGIN、COMMIT、ABORT、ACK、NACK、DISCONNECT 客户端可以使用SEND命令来发送消息以及编辑消息的内容,用SUBSCRIBE命令来订阅消息以及确定接收对象。
2、WebSocket说明:
WebSocket 协议提供了 通过一个套接字实现全双工通信的功能。也能够实现 web 浏览器 和 server 间的 异步通信。(支持SockJS,用来解决浏览器端、服务器以及代理不支持WebSocket的问题。)
WebSocket是底层协议,而 STOMP 是基于 WebSocket(SockJS)的上层协议 就像HTTP在TCP套接字之上添加了请求-响应模型层一样,STOMP在WebSocket之上提供了一个基于帧的线路格式(frame-based wire format)层,用来定义消息的语义。
3、建立连接:
1.客户端与服务器进行HTTP握手连接。
2.客户端通过发送CONNECT帧建立连接。
3.服务器端接收到连接尝试返回CONNECTED帧。
4.客户端通过SUBSCRIBE向服务端订阅消息。
连接服务器JS代码:
function run() {
selector = document.getElementById('expression').value
stompClient = Stomp.client('ws://' + window.location.hostname + ':' + window.location.port + '/hello');
//向服务器发起连接
stompClient.connect({}, function(frame) {
//连接成功时,服务器响应CONNECT帧的回调方法
stompClient.subscribe('/topic/greetings', function() {}, {
"selector": selector
})
});
}
headers如果客户端进行定义,也就是说只要我们在headers当中的selector传入SpEL命令执行的poc就可以达到表达式注入的目的。
0X03 动态分析
分析流程: 1.已爆出漏洞方法或自认为可疑处打上断点 2.debug运行 3.在客户端发送初步POC 4.动态调试 5.在客户端发送POC,调试修改直到成功执行 (1)动态调试发现服务器根据订阅ID来确定会话,从客户端获取headers和selector进行绑定。
(2)然后从会话headers中获取selector值当作expression最后执行(上文提到headers可以在客户端定义,所以我们在headers当中的selector传入poc就可以达到表达式注入的目的。而selector则是用SpEL表达式编写)。 DefaultSubscriptionRegistry类的addSubscriptionInternal方法中,有expression = this.expressionParser.parse Expression(selector)
如果要命令执行,则还需要expression.getValue或epression.setValue。 (3)查看调用栈,客户端在发送send message时会调用getValue。 服务器调用filterSubscription对消息进行过滤,最终到通过expression.getValue()执行了POC。
Boolean.TRUE.equals(expression.getValue(context, Boolean.class))最终到通过expression.getValue()执行了POC。
0X04 小小总结
相信通过本期Java代码审计Spring框架实例篇。相信小伙伴们对Spring框架的代码审计有了更深入的了解,当你要审计某个源码时一定要先知道整个代码的逻辑流程,再进行动态调试这样可以事半功倍。 下期斗哥将带来Java代码审计Spring框架修复篇,对Spring Messaging 远程命令执行漏洞demo进行修改与补丁分析。
PS:回答文章下方的选择题,回答正确者即有机会获得斗哥独家赠送的文章源码与材料哦!(答案请在文章下方留言)
STOMP协议中什么命令是用来订阅消息与服务器进行交互?
A. SEND
B. SUBSCRIBE
C. BEGIN
D. COMMIT