On s’enregistre avec le token de la France. On voit nos flags.
On lit le code source qui est fourni, et immédiatement, on trouve une injection SQL dans la fonction qui récupère les flags getData(user User)
:
req := fmt.Sprintf(`SELECT ctf, challenge, flag, points
FROM flags WHERE country = '%s';`, user.Country);
En remontant l’arbre des appels, on voit que le user
vient de la session, qui est chargée lors de la connexion
à partir de la base de données. Et évidemment, le country
en base de données est celui que l’on a fourni à l’enregistrement. Mais
une tentative de s’enregistrer avec un country
différent de France ne fonctionne pas, car il doit correspondre au token
spécifique au pays. Creusons un peu plus cette vérification faite lors de l’enregistrement. D’abord checkToken
est appelé :
stmt, err := db.Prepare(`SELECT id FROM country_tokens
WHERE country = SUBSTR($1, 1, 2)
AND token = encode(digest($2, 'sha1'), 'hex')`)
Ce qu’il est intéressant de remarquer, c’est que seuls les deux premiers caractères du pays sont utilisés pour cette vérification. Si
on continue de suivre la phase d’enregistrement, on arrive sur la fonction RegisterLoginPassword
:
stmt, err = db.Prepare(`INSERT INTO users (username, password, country)
VALUES (
$1,
encode(digest($2, 'sha1'), 'hex'),
$3
)`)
[...]
_, err = stmt.Exec(username, password, country_enc)
Ici, c’est bien l’intégralité du pays qui est enregistré (sous forme chiffrée, mais ce n’est pas important, il sera déchiffré à l’ouverture
de la session). Il nous faut donc une injection SQL dont les deux premiers caractères valent fr
pour passer l’enregistrement, puis
l’injection sera déclenchée sur la récupération des flags. On sait que l’on cherche à voir les flags suisses, donc on s’enregistre avec le
country fr'or+country='ch
. L’enregistrement fonctionne, et dans la liste des flags, on trouve :
FCSC{fad3a47d8ded28565aa2f68f6e2dbc37343881ba67fe39c5999a0102c387c34b}