作者:
EtherDream
·
2015/03/03 11:37
0x00 前言
XSS 的本質仍是一段指令碼。和其他文件元素一樣,頁面關了一切都銷燬。除非能將指令碼蔓延到頁面以外的地方,那樣才能獲得更長的生命力。
慶幸的是,從 DOM 誕生的那一天起,就已為我們準備了這個特殊的功能,讓指令碼擁有突破當前頁面的能力。
下面開始我們的續命黑魔法。
0x01 反向注入
一個不合理的標準,往往會埋下各種隱患。
按理來說,只有透過指令碼彈出的頁面,才能擁有 opener 屬性。然而事實上,透過超連結點開的頁面居然也有。這為 XSS 開啟了一扇大門 —— XSS 不僅可以操控當前頁面,甚至還能傳染給同源的父頁面。
XSS 一旦感染到父頁面裡,戰鬥力就大幅提升了。
可以想象,只要看了一個帶有 XSS 的帖子,即使立即關了,那麼帖子列表頁也會遭到感染。
更有趣的是,opener 這個屬性不受同源策略限制。即使父頁面不同源,但父頁面的 opener 仍然可以訪問。
我們可以順著 opener.opener.opener... 一直往上試探,只要是和當前頁面同源的,仍然能夠進行操控 —— 儘管中間隔著其他不同源的頁面。
網站的主頁面顯然比詳細頁更受使用者的信任,停留的時間也會更長,因此攻擊力可成倍的增加。
0x02 正向注入
如果說反向注入是苟且偷生的話,那麼正向注入就是當家做主翻身的機會了。
儘管我們能夠控制父頁面,但從父頁面點開的網頁仍然不受操控。如果具有控制子頁面的能力,那就更完美了。
不幸的是,我們無法控制超連結開啟的新頁面。唯一能夠操控的新頁面,那就是 window.open 的彈框頁。幸運的是,在絕大多數瀏覽器上,它們看起來的效果是一樣的。
因此,我們可以在使用者的點選瞬間,遮蔽掉預設的超連結行為,用彈框頁取而代之,即可把 XSS 注入到 window.open 返回的新頁面裡了。
類似的,透過子頁面遞迴開啟的新頁面,同樣也無法逃脫。於是子子孫孫盡在我們的掌控之中。
反向注入,讓我們佔據已有的地盤;正向注入,把我們的勢力擴大蔓延出去。兩者結合,即可佔據半壁江山了。
值得注意的是,正向注入中有個細節問題。並非所有的超連結都是彈出型的(_blank),也有不少是在當前頁面跳轉的。若是想劫持的狠點,可以忽略這個問題;如果不想被細心的使用者發現,那麼可以判斷下當前超連結以及<base>
的 target 屬性,決定是否劫持。
0x03 頁面監督
上面提到,如果是在當前頁面裡跳轉,那麼還能繼續感染嗎?或者說,某個頁面重新整理之後,是否就丟失了?
答案是肯定的。如果我們不採取一些措施,任憑佔據的地盤不斷丟失,那麼我們的勢力範圍就會越來越小,直到消亡。
相比進攻,防守則更為困難。我們不知何時會失去,因此必須定時去檢查。
一旦發現對方已擺脫我們的控制,那麼必須立即重新注入,以恢復我們的勢力。
對於新頁面的 XSS 來說,當然是注入的越早越好。越前面擁有越高的優先順序,甚至可以攔截頁面的正常業務功能。
為了能儘快獲知頁面重新整理、跳轉等行為,我們還可跟蹤 unload
事件,在頁面即將丟失的瞬間,將訊息通知出去,讓對方儘快來拯救自己。
這樣,就不必等待定時器了,可以最快的速度恢復。甚至能趕在頁面的第一個指令碼之前,執行我們的 XSS。
當然,並非任何情況都能收回的。如果跳轉到了不同源的頁面,那顯然是無能為力了 —— 不過,就此而放棄它嗎?回答是:決不妥協!
儘管頁面已經和我們分道揚鑣了,但所在的窗體仍然被我們掌控。我們可以跳轉、關閉它,甚至還有可能出現奇蹟:只要頁面跳轉回我們的站點,又可被我們所收復!
0x04 互相聯結
不難發現,只要還有一個頁面存在,就有可能收回曾經被佔領的地盤。因此,我們要將可控的頁面都聯結起來,讓每個頁面都知曉並監督所有成員。
當有新成員加入時,通知給大家,記錄在各自的頁面裡。
這樣即使其中一個頁面意外關閉了,也不會丟失重要的資訊 —— 資訊已被分佈儲存在各個頁面裡了。
因此,頁面開的越多,相互聯結就越牢固。
如果只剩最後一個頁面,那麼一旦重新整理之後就沒人來拯救了,於是就會消亡。
所以,把超連結都變成新頁面中開啟,還是有很大的優勢的。
0x05 降域嘗試
一些網站為了方便通訊,將 document.domain 降到根域。例如支付寶網站的絕大部分頁面,都是 alipay.com。這樣原本不同源的子站,這時也能夠相互操控了。
因此,遇到不同源的頁面,可以嘗試降低自身的域,再次發起操作,或許就能成功注入了。
0x06 表單劫持
之前說到正向注入,是透過劫持超連結點選實現的。事實上,除了超連結外,還有個進入新頁面的方式,那就是表單提交。
相比超連結,表單顯得棘手一些。我們不僅得開啟一個新頁面,還要把表單裡的資料也提交上去。如果把整個表單的元素克隆到新頁面提交,一些資料又會丟失。
不過,仔細研究一下表單元素,會發現有一個非常簡單的方法:原來 window.open 第二個引數可以賦予新視窗一個 name,然後將 name 賦予表單的 target 屬性,即可在我們建立的新視窗裡提交。這樣就可以把 XSS 注入進去了。
0x07 框架注入
不同頁面之間可以正反注入。同個頁面中,可能存在多個框架頁,因此還可以嘗試框架頁之間的上下注入。
也許,XSS 位於頁面中某個小框架。如果只侷限於自身頁面,那麼是毫無發展空間的。因此得跳出圈子,向更廣闊的 parent 頁面注入。
類似的,如果主頁面僅僅是個外殼,實際內容執行在某個框架裡,那麼得注入到子框架中,才能獲取更有意義的資訊。
同樣,我們還可以將上下注入結合,即可讓 XSS 從某個框架頁裡破殼而出,感染到所有的框架頁裡。
0x08 後記
儘管這些特徵從 DOM 誕生起就已存在了,不過要寫出一個完善的指令碼並不容易。直到如今的 IE 11,不同窗體間的操作,仍有各種奇怪問題,更不用說那些非主流 IE 了。
不過好在除 IE 外的其他主流瀏覽器,都能很好的執行。下面分享一個 Demo,其中實現了上述部分功能:
http://www.etherdream.com/FunnyScript/XSSGhost/
當我們順著超連結往前點,一旦進入有 XSS 的頁面,先前的父頁面都遭到感染。更嚴重的是,被感染的頁面開啟的子頁面,也都無一倖免。即使重新整理,也會被其他頁面監控到,從而立即恢復。
正如幽靈鬼魂一般揮之不去。
本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!