Jeudi le 10 septembre 2009 à 03:07
La faille MySQL Column truncation
Hello les amis !
Aujourd’hui, je vous parlerai d’un nouveau type de faille, il s’agit de MySQL column truncation!
Pendant que les failles du types SQL Injections restent parmi les vecteurs d’attaque les plus discutés sur le Web, il existe un autre genre qui a été discuté pour la première fois par Stefan Esser, ce dernier a illustré son exploitation dans un bug reporté sur bugtraq affectant wordpress!
Comment ça marche ?
Par défaut, la comparaison de deux chaine de caractère dans MySQL ne se fait pas en mode binaire, ceci se fait en « relaxed mode », ce mode compare deux chaines on ignorant les espaces et les caractères nuls de la fin de la chaine, du coup, pour mysql, la chaine de caractères ‘admin’ est égale à ‘admin ‘! .
De ce fait mysql refusera d’enregistrer un nouvel utilisateur qui essaie de s’incrire avec ‘admin ‘ (admin+espace) ce qui est tout à fait logique!
Ou est le problème?
Pour illustrer le problème on immagine l’application suivante:
- Un forum de discution ou un blog ou tous le monde peut s’enregistrer
- Le champs username de la table utilisateurs est limité à 16 caractères
- L’administrateur du forum est ‘admin’
- MySQL est utilisé dans le mode par défaut
- Pas de vérification sur la longueur du nom d’utilisateur
Qu’est ce qui se passe si on essaie de créer un compte avec comme nom d’utilisateur ‘admin xD’ (admin+11 espaces+xD) et un mot de passe ‘p455wd’:
MySQL va cherche si il existe un utilisateur avec comme username ‘admin xD’, et comme aucun utilisateur ne l’as pris l’application va l’accepter et continuera pour inserer le nouvel utilisateur dans la base.
La chaine du nom d’utilisateur fait 18 caractères (admin+11 espaces+xD), mySQL va automatiquement tronquer les deux dernier caractères (xD) car le champ username est limité à 16 caractères, ce qui donnera ‘admin ‘ (admin+11 espaces), ce dernier sera accepté par l’application et inséré dans la table d’utilisateurs, on aura donc deux utilisateur avec le même login ‘admin’ (rappellez vous que la comparaison en mysql dans le mode par défaut ne prends pas en compte les espaces!).
Dans ce cas, un problème de sécurité potentiel peut affecter l’application, en dépendance de la façon dont elle traite le champ username!
Exemple d’une application vulnérable:
Connexion :
if(!empty($_POST['username']) && !empty($_POST['password']){
$username = $_POST['username'];
$password= $_POST['password'];
if(login($username,$password)){
$userdata = getUserInfoByLogin($username);
}
}
la fonction getUserInfoByLogin()
function getUserInfoByLogin($username){
$query = mysql_query("SELECT * FROM utilisateurs WHERE username = '$username");
$userinfo= mysql_fetch_array($query);
return $userinfo ;
}
Espace membre
if($userdata['username'] == 'admin'){
//espace privé : console d'administration
}
else{
// espace membre!
}
Resultat:
Puisque l’attaquant a un compte avec le login ‘admin ‘, il pourra se connecter à ce dernier avec le passe ‘p455wd’ ! et puisque l’enregistrement du vrai administrateur est le premier en base, celuila sera retourné ! et l’attaquant aura accès à l’espace administrateur du forum!
Ceci est juste une illustration, la faille peut se présenter différemment sur une application web,je cite là wordpress qui était le premier victime de ce type de vulnérabilités!
Comment sécuriser mon application?
Toujours vérifier la longueur des champs sensibles (comme username dans notre exemple), et interrompre l’exécution de votre application si cella dépasse la longueur maximale configurée dans votre table mysql!
Tags :attaque par champs tronqués, faille mysql, mysql column truncation, sql injection- Categorie: Hacking
- (9) Commentaires














pynsso
septembre 10th, 2009 at 4 h 17 min
j’att une article detaillé sur les injections sql de ta part :D
sir ts7er ++
Mohammed CHERIFI
septembre 10th, 2009 at 4 h 23 min
@pynsso, ça ne va pas tarder mon ami, keep ON!
UpDeL
septembre 10th, 2009 at 4 h 25 min
OMG impressionnant ! j’apprends tout les jours quelques chose de nouveau sur ton blog, très informatif attend que je fais quelques tests :O
UpDeL
septembre 10th, 2009 at 5 h 23 min
La solution serait donc un
if(strlen($_POST['username']) > 100){
echo »Pseudo trop long »;
}
ou mieux encore limiter les caractères à 100 et interdire les espaces et les caractères spéciaux genre :
preg_match(« /^[a-z0-9_\-]{5,100}$/ », $_POST['username']);
Mohammed CHERIFI
septembre 12th, 2009 at 17 h 47 min
Oui @UpDel, vérifier avec une expression régulière me semble la meilleur solution!
Mehdi
septembre 14th, 2009 at 12 h 23 min
comme d’habitude un bon sujet !
mais
pour un varchar par exemple ça me donne cette erreur
#1406 – Data too long for column ‘df’ at row 1
…
pour un TEXT ca l’enregistre !
Mohammed CHERIFI
septembre 15th, 2009 at 22 h 06 min
@Mehdi, c’est quoi la version mysql que tu utilise? avait elle la configuration par defaut?
fait ce petit test et dis moi ce que ça donne :
Tu crée la table utilisateurs :
CREATE TABLE `utilisateurs` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`username` VARCHAR( 12 ) NOT NULL ,
`password` VARCHAR( 32 ) NOT NULL
) ENGINE = MYISAM
Puis tu insère un utilisateur dont le nom dépasse 12 caractères
INSERT INTO `test`.`utilisateurs` (
`id` ,
`username` ,
`password`
)
VALUES (
NULL , ‘abcdefghijklmno’, MD5( ‘test’ )
);
abcdefghijklmno ça fait 15 caractères, la requête sql aboutit mais un warning s’affiche! (cf http://www.mcherifi.org/data/mysqltruncation/warningtruncated.png )
si on affiche la les lignes de la table user on trouvé bien notre enregistrement mais tronqué à 12 caractères (cf http://www.mcherifi.org/data/mysqltruncation/truncatedcolumn.png)
par-contre pour un champs de type TEXT il n’y aura pas de warning, il sera correctement enregistré!
Mehdi
septembre 15th, 2009 at 23 h 40 min
Version du client MySQL: 5.0.51a
ça donne :
#1406 – Data too long for column ‘username’ at row 1
et rien n’est enregistré …
Stack
octobre 20th, 2009 at 1 h 38 min
beau boulot mon frère en apprend toujours de toi quelque chose de très spéciale