Le site web est simple, il y a peu d’éléments. Seulement un formulaire dans /main qui prend une adresse mail et le reflète dans la page. Une vérification est faite côté backend, pour s’assurer que la valeur envoyée correspond bien au format d’une adresse mail.
Pour récupérer le flag, il va falloir RCE pour exécuter le binaire getflag.
Résolution
Afin de résoudre ce challenge, il va falloir trouver comment bypass la vérification sur le format de l’adresse mail. Ensuite il suffit d’exploiter une SSTI pour RCE.
Server Side Template Injection
Pour commencer, si on observe le code de l’application, on se rend vite compte qu’une SSTI est possible :
La valeur de la variable email est placée dans email_template et est ensuite rendu, il est donc possible d’envoyer par exemple {{ 7*7 }}@mail.com et le rendu affichera [email protected]. Cependant, le fait que la variable email passe par la classe EmailModel(), crée une erreur lorsque l’on commence à mettre des guillemets ou des parenthèses.
Analyse et bypass de la classe EmailModel
Pour éviter de trigger l’erreur et pour qu’on puisse utiliser les parenthèses, ainsi que les guillemets afin d’exécuter une payload pour RCE via la SSTI. Il va falloir trouver l’endroit où le check sur le format de l’email est effectué dans la classe EmailModel ou plutôt dans EmailStr.
Si on suit un peu le code, on tombe dans la classe EmailStr, puis dans _validate() et dans validate_email(). Dans cette fonction on y retrouve ces lignes :
m = pretty_email_regex.fullmatch(value) # value = emailname: str |None=Noneif m:
unquoted_name, quoted_name, value = m.groups()
name = unquoted_name or quoted_name
email = value.strip()
try:
parts = email_validator.validate_email(email, check_deliverability=False)
except email_validator.EmailNotValidError as e:
raise PydanticCustomError(
'value_error', 'value is not a valid email address: {reason}', {'reason': str(e.args[0])}
) from e
On comprend que pour éviter de trigger une erreur, en utilisant les guillemets ou les parenthèses, il faut match le groupe quoted_name. La regex à matcher se situe dans pretty_email_regex:
Lorsque l’on match quoted_name_group, il faut aussi matcher avec email_group. Le bon format à utiliser est donc celui ci : "(SSTI)" <[email protected]>.
Exploitation
Maintenant qu’on peut utiliser les parenthèses et les guillemets, il ne manque plus qu’à récupérer un payload SSTI pour RCE, ceux sur Hacktricks par exemple.