作者:LoRexxar'@知道創宇404實驗室
時間:2018年11月14日
HCTF2018在出題的時候其實準備了一個特別好的web題目思路,可惜賽前智能合約花了太多時間和精力,沒辦法只能放棄了之前的web題,在運維比賽的過程中,我發現學弟出的一些題目其實很有意思值得思考。
bottle
bottle是小學弟@luo00出的題目,源碼如下 https://github.com/Lou00/HCTF2018_Bottle
整個站幾乎只有一個功能就是有一個可控的任意跳轉,然后根據題目功能可以判斷是一道xss題目。其實技巧挺明確的,就是比較冷門,我第一次見是阿里先知的xss挑戰賽。
https://lorexxar.cn/2017/08/31/xss-ali/#05%E8%B7%B3%E8%BD%AC
然后本題的思路主要來自于ph師傅的一篇分析 https://www.leavesongs.com/PENETRATION/bottle-crlf-cve-2016-9964.html
首先這個問題有意思的點在于挺多的,在原本的環境下,bottle有個特殊的鬼畜特性在于,他的header順序是會變得...
首先我們需要明白一個問題,在流量中,body和header是在一起的,在header的兩個換行后內容會被自動識別為body。
所以在bottle.redirect(path)中存在location頭注入,我們就可以通過傳入兩個換行來吧header擠到body中,這樣就可以控制頁面的返回了
150.109.53.69:/path?path=//150.109.53.69:0%2f%0D%0A%0D%0Atest
正常來說,直接注入script就可以了
http://150.109.53.69:3000/path?path=http://150.109.53.69:0%2f%0D%0A%0D%0A<html><head><script>alert`1`</script>
原文中說當端口小于80,firefox就會卡住,但我實際測試只有0端口會卡住,可能我環境不同。
這就是題目的原解,這里雖然加入了CSP,但其實沒區別,由于bottle頭隨機的問題,當CSP隨機到location下面時,就可以注入js了,但這樣就成了一個隨機的題目了,學弟想讓別人注意到bottle特性而不是隨便撞到,這里就設置了腳本定時重啟,然后讓頭更隨機一點兒。
攻擊者需要意識到這個問題然后不斷提交才可以攻擊成功,但可惜這種攻擊方式就隨機了,失去了ctf本身的樂趣,變得太無趣了。
-----------下面開始腦洞時間,實際沒有作用,不想看可以跳過----------------------
嘗試
仔細思考了一下邏輯我開始想辦法改進這題。當然,改進題目的基礎必然是想辦法減少隨機性,所以一些討論的基礎都在于CSP頭穩定在location之上。
其實可以發現,CSP特別簡單,最簡單的self CSP
response.add_header('Content-Security-Policy',"default-src 'self'; script-src 'self'")
self CSP最大的問題在于如果能找到一個self源內容可控的,那CSP就可以被繞過了。
然后我發現,這個漏洞不是剛好就是可以控制頁面內容嗎,于是一個漏洞利用鏈想到了
構造一個CLRF控制內容注入alert,然后構造CLRF,然后構造第二個CLRF注入script,然后src引入前面的鏈接。
聽起來非常完美的利用鏈。這其中也有幾個小坑。
首先構造一個alert
http://150.109.53.69:3000/path?path=http://150.109.53.69:0%2f%0D%0A%0D%0Aalert%60%31%60%3b
這里想到現代瀏覽器對content-type可能有要求,所以直接頭注入設置content-type為text/javascript
http://150.109.53.69:3000/path?path=http://150.109.53.69:0%2f%0D%0AContent-Type%3a+text/javascript%3b+charset%3dUTF-8%0D%0A%0D%0Aalert`1`
然后嘗試引入這個鏈接,然后需要注意二次urlencode,不然%0a%0d都會解開
http://150.109.53.69:3000/path?path=http://150.109.53.69:0%2f%0D%0A%0D%0A<html><head><script/src=%68%74%74%70%3a%2f%2f%31%35%30%2e%31%30%39%2e%35%33%2e%36%39%3a%33%30%30%30%2f%70%61%74%68%3f%70%61%74%68%3d%68%74%74%70%3a%2f%2f%31%35%30%2e%31%30%39%2e%35%33%2e%36%39%3a%30%25%32%66%25%30%44%25%30%41%43%6f%6e%74%65%6e%74%2d%54%79%70%65%25%33%61%2b%74%65%78%74%2f%6a%61%76%61%73%63%72%69%70%74%25%33%62%2b%63%68%61%72%73%65%74%25%33%64%55%54%46%2d%38%25%30%44%25%30%41%25%30%44%25%30%41%61%6c%65%72%74%60%31%60></script>
看上去很有道理,然后訪問...然后失敗...Orz,被CSP ban了
仔細回想上面的流程,其實有個很重要的問題沒有注意到,這個問題我也是第一次重視到。
CSP和cookie的同源策略一樣,不但對ip做限制,對端口也有限制。最過分的是,CSP在location頭存在的時候,會跟入判斷location
也就意味著,我們試圖引入http://150.109.53.69:3000/path?path=http://150.109.53.69:0%2f%0D%0AContent-Type%3a+text/javascript%3b+charset%3dUTF-8%0D%0A%0D%0Aalert作為目標js引入,會被認為引入http://150.109.53.69:0這個來源的js,端口為0,self的端口為3000,所以被攔截了。
而且值得注意的是,這里如果把CSP改為
response.add_header('Content-Security-Policy',"default-src 'self'; script-src 150.109.53.69")
CSP中如果不設置端口,默認會認為是80端口。同樣沒辦法繞過。
經過了一番研究我發現這個端口判定沒有別的解決辦法,如果不用跳0的辦法,正常的302是會跟隨跳轉過去的。
無奈我修改題目把CSP改成了
response.add_header('Content-Security-Policy',"default-src 'self'; script-src 150.109.53.69:*")
然后我開始繼續上面的測試,果然,仍然失敗了......這次報錯不一樣了,阻攔加載的并不是CSP。
firefox的控制臺顯示script加載失敗,仔細研究了一番突然意識到一個事情,是不是瀏覽器的不加載非200的靜態資源。
于是我用flask簡單寫了一段代碼測試了一下
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'alert(1);', 303
if __name__ == '__main__':
app.run()
事實證明的確是這樣的,瀏覽器在這塊的安全性已經做的非常好了,這種奇怪的操作完全不成立...
思考到最后,我忽然又意識到了一個問題,假設我把跳轉那個頁面生生改成200,然后去加載,有一個致命的利用問題。
模擬出來的頁面內容是這樣的
alert`1`;
xxxxxheader: xxxx
我沒辦法改變下面的內容,而js雖然是逐行渲染的,但遇到報錯之后整塊script都會阻止,不再繼續加載了,然后我就又回到了最初的問題,我必須保證locaion是最后一行header才行...我違背了最初想要去除隨機性的目的...
最后沒辦法,還是將題目改回原樣了,這里的思考過程挺有意思的,分享給大家,也感謝在試驗過程中@Math1as給我出了很多主意。
game
game這道題是我的另一個小學弟@undifined出的題目,后來聽他說起這個思路我覺得蠻有意思的,這里出成題目用了明文密碼入庫雖說是比較強行,但其實用來注其他信息還是不難的,是個很有趣的想法。
第一次見到這種思路是在pwnhub上
https://pwnhub.cn/questiondetail?id=3
這題目當時是上傳文件,然后后端展示的時候會有排序,通過不斷上傳就可以得到目標文件名字。
這里也是一樣,這里是一個近似于邏輯漏洞,站內只有兩個功能:
- 打游戲獲得積分
- 排行榜,可以根據不同的字段排行
排行榜的數據都是實時的,而且整個部分沒有任何的注入點,完全不能SQL注入,但由于可以根據不同的字段排行,所以order by后面的字段名可控,除了常規的id, username, sex, score以外,也可以更具password來排行,再加上數據庫中密碼是明文存取的(不是明文也可以,只是獲得的是hash)
知道了原理,我們就可以通過不斷插入新的賬號來逼近目標字符串,因為數據庫排序和前面說的linux文件名排序是一樣的,很有趣。
ac > adf > ad
想明白就可以直接寫腳本跑起來
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.jmbmsq.com/744/
暫無評論