Solution de lrstx pour ENISA Flag Store 1/2

web golang

4 mai 2024

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}