Sécurité de Typo3 & entropie de rand()

Le 30-07-2010

La Typo3 Security Team vient de publier le 28 juillet deux bulletins (http://typo3.org/teams/security/security-bulletins/) regroupant pas moins de 14 failles de sécurité dont 13 affectent le cœur de Typo3 ! La dangerosité des vulnérabilités varie beaucoup suivant les cas. L'une d'entre elle nous paraît intéressante. felogin est une extension de Typo3 qui apporte des fonctionnalités d'authentification et de gestion plus avancées que celles qui étaient disponibles jusqu'à aujourd'hui. Cette extension souffrirait d'une faiblesse lors d'une génération de hash qui permettrait d'usurper des comptes utilisateurs. C'est cette fonction qui est mise en cause :

protected function generateAndSendHash($user) {

$hours = intval($this->conf['forgotLinkHashValidTime']) > 0 ? intval($this->conf['forgotLinkHashValidTime']) : 24;

$validEnd = time() + 3600 * $hours;

$validEndString = date($this->conf['dateFormat'], $validEnd);

$hash =  md5(rand());

$randHash = $validEnd . '|' . $hash;

$randHashDB = $validEnd . '|' . md5($hash);

//write hash to DB

$res = $GLOBALS['TYPO3_DB']->exec_UPDATEquery('fe_users', 'uid=' . $user['uid'], array('felogin_forgotHash' => $randHashDB));

....

$link = ($isAbsRelPrefix ? '' : $this->conf['linkPrefix']) . $this->pi_getPageLink($GLOBALS['TSFE']->id, '', array(
$this->prefixId . '[user]' => $user['uid'],
$this->prefixId . '[forgothash]' => $randHash
));

$msg = sprintf($this->pi_getLL('ll_forgot_validate_reset_password', '', 0), $user['username'], $link, $validEndString);

....

// send the email

$this->cObj->sendNotifyEmail($msg, $user['email'], '', $this->conf['email_from'], $this->conf['email_fromName'], $this->conf['replyTo']);
....

Fonctionnement

Un utilisateur a perdu son mot de passe. Il fait donc une demande de réinitialisation de mot de passe qui lui envoie automatiquement un mail. Ce lien qu'il devra suivre pour mettre à jour son mot de passe lui permettra de reprendre la possession de son compte utilisateur.

Deux choses à retenir :

  • Le mail est toujours envoyé à l'adresse email de la personne qui a créé le compte utilisateur. Il n'y a que la personne qui peut consulter les mails de cette adresse qui pourra réinitialiser le mot de passe.
  • Le lien contenu dans l'email est la clef de voûte du système de réinitialisation de mot de passe. Un des paramètres est un secret qui permettra d'accéder à ce système. Ce secret n'est connu que du serveur et de la personne qui peut relever les emails.

On identifie le propriétaire du compte utilisateur et on lui transmet un secret que personne ne pourra connaître à l'exception des parties concernées. Le système paraît parfait !

Faiblesses du système

Ils restent pourtant deux axes d'attaques pour déstabiliser un tel système. Il est bien sûr possible d'intercepter la communication si celle ci ne transite pas sur HTTPS. C'est d'une probabilité assez faible car les attaques de type "Man in the Middle" sont assez rares et complexes à mettre en œuvre sur Internet. L'opportunité la plus crédible pour un attaquant est d'essayer de deviner ce secret. Grâce au code source, il va pouvoir déterminer le nombre de valeurs différentes que peut prendre ce secret et ainsi décider si une attaque se basant sur le manque d'aléa du système de génération de secret est possible.

Le secret est une chaîne de caractère composée de deux parties séparées par un pipe. La première partie est un entier obtenu à partir de :

$validEnd = time() + 3600 * $hours;
La seconde partie est un hash MD5 du retour de la fonction rand
$hash =  md5(rand());

Voilà a quoi ressemble un lien de réinitialisation :

http://dotsafe/index.php?id=2&tx_felogin_pi1[user]=1&tx_felogin_pi1[forgothash]=1280460503%7Ca5f97c78b2391923b39262f26f548c59

On remarque le paramètre tx_felogin_pi1[user] renseigne le serveur sur le compte utilisateur à réinitialiser et le paramètre tx_felogin_pi1[forgothash] contient le secret tant convoité. Une fois les caractères URL-encodés supprimés, on reconnaît plus nettement la construction décrite précédemment : 1280460503|a5f97c78b2391923b39262f26f548c59

Concrètement pour un attaquant, la première partie est facilement déductible grâce à l'entête Date de la réponse HTTP. La variable $hours est un entier qui peut être déduit d'une précédente demande de réinitialisation. Cela se corse pour la deuxième partie, il faut arriver à deviner le md5 d'un entier allant de 0 à .... getrandmax() Alors que sous Linux l'entier maximum culmine à 2147483647, il est seulement de 32768 sur les systèmes Windows.

Cette injustice rend les installations Typo3 vulnérables à des attaques en bruteforce. Une fois la première partie récupérée, Il suffit à l'attaquant de tester tous les md5 générés à partir des entiers compris entre 0 et 32768. Au maximum, il devra transmettre au serveur 32768 requêtes HTTP, ce qui reste faisable en 9 heures en transmettant 1 requête par seconde. Une exploitation sous linux est extrêmement improbable car elle prendrait plus de 68 années à cette même cadence !

On vous rappelle ?

Indiquez votre numéro de téléphone

ainsi que la tranche horaire où vous êtes disponible. Nous vous appellerons dans les plus brefs délais

 

Actualités

  • 30-07-2010 Sécurité de Typo3 & entropie de rand()
  • 28-07-2010 Décompilation d'application flash
  • 06-04-2010 Les 9 objections à la sécurité des sites internet - Développement externalisé