SQL Server, it’s a black hole
for the security
Injection SQL
Les différentes
techniques d’injection se dérouleront de la façon suivante :
-
1.0 Introduction
-
2.0 Mam, what that mean SQL?
-
3.0 Les
différentes requêtes
-
4.0 Exploitation
des failles
- Inscription a une newsletter.
- Post de news ou commentaires (architecture
assez tordu)
- Procédure d’authentification en PHP. (+
requêtes SQL liées au PHP)
-
5.0 Sécurité
-
6.0 Conclusion
-
7.0 Sources,
inspiration et remerciement
1.0 Introduction
-=-=-=-=-=-=-=-=-=-
L’injection par requête SQL
est une faille très rependue sur le Web qui est exploitable assez facilement
par certains SK en manques de sensation…
L’injection SQL est un simple
terme signifiant l’acte de passer dans une application un code SQL non prévu
par le développer.
Elle est extrêmement
dangereuse puisqu’elle permet de manipuler directement les bases de données des
sites pouvant entraîné de nombreuses possibilités comme le vol de mot de
passes, de données, utiliser les droits d’administrateur, modifier une
newsletter, changement d’un post sur un forum, et j’en passe...
Mais avant tout rappelons que
l’injection est possible a cause d’un mauvais filtrage au niveau de l’entré de
l’utilisateur donc il est possible d’outre passe certaine protection SQL
login/password... ;)
2.0 Mum, what that mean SQL ?
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Par définition SQL («
langage d’interrogation structuré », de l’anglais « Structured
Query
Language »)
est un langage qui vous permet de communiquer avec les bases de donnéesJ, pour se faire il faut envoyer une (des) requête(s)
au serveur de base de données. La plupart du temps les requêtes sont faite
grâce a des application en PHP/ASP/CFML/JSP...
2.0 Les différentes requêtes
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Alter Table (Base
de données et table)
Create Database (Base de données et table)
Create Function (User Defined Functions)
Create Index
(Manipulation des données)
Create Table
(Base de données et table)
Delete (Manipulation des données)
Describe
(Information sur les bases)
Drop Database
(Base de données et table)
Drop Function (User Defined Functions)
Drop Index
(Manipulation des données)
Explain
(Information sur les bases)
Flush
(Manipulation des données)
Grant (Gestion
des droits d'accès)
Insert (Manipulation des données)
Kill (Manipulation des données)
Load Data (Manipulation des données)
Lock Tables
(Gestion des droits d'accès)
Optimize Table
(Base de données et table)
Replace (Manipulation des données)
Revoke (Gestion
des droits d'accès)
Select (Manipulation des données)
Set (Information
sur les bases)
Show (Information sur les bases)
Unlock Tables
(Gestion des droits d'accès)
Update (Manipulation des données)
Use (Base de
données et table)
4.0 Exploitation des failles de programmations
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Bon alors on commence par
quoi ? Y’en à tellement mais moi j’opterai plutôt pour commencer par des
bases en SQL (maniement des données) puis après le plus simple pour un peut
vous échauffer, inscription a une newsletter, puis après une procédure
d’authentification en PHP, et après on verra ;)
Newsletter :
Pour ce cas de figure on va
directement communiquer avec la base de donnée ;)
On va commencer
tranquillement avec cette mise en situation : soit la table (My) SQL
« newsletter » comportant 2 champs a remplir, le nom (pseudo) et email (l’adresse
email). Quelques commandes avant de s’attaquer a la faille :
Tout d’abord pour sélection
la ligne et le nom ou pseudo « Skin » on va demander :
« select * from newsletter where nom=’Skin’ »
Presque pareil, pour sélectionner
l’email et le nom de la personne: “Skin” :
« Select nom, email from newsletter where nom = ’Skin’ »
Pour remplacer l’email de la
personne nommé Skin par Skin@arenhack.com:
« update newsletter set email=’Skin@Arenhack.com’ where nom= ’Skin’ »
Pour effacer l’inscrit nommé
Skin avec ses information bien sur (nom+email)
« delete from newsletter where nom=’Skin’ »
Pour la totale maintenant, exécuter
plusieurs requête SQL sur une ligne il faut les finir par un « ; ».
« delete from newsletter where nom=’Skin’; delete from newsletter
nom=’Skin2’ »
Voila! C’est quand même ultra
simple, je pense que vous comprenez mieux maintenant ;)
Maintenant passons aux l’explication !!!
Vous arrivez sur un site Web
qui vous propose de vous inscrire à une newsletter, super non ?
Vous arrivez sur le même type
de formulaire vue précédemment, c'est-à-dire nom plus email, par théorie vous
allez remplir les 2 champs et vous inscrire normalement comme n’importe
qui ;)
Mais sinon quand vous avez
appuyer sur ce petit bouton « SEND » que c’est-il vraiment passer
derrière ? C’est le genre de question que personne ne se pose ça
encore !
Comme vu précédemment, le
formulaire va envoyer un script a la base SQL qui va demander d’ajouter une
ligne, ‘nom’ plus ‘email’
Maintenant si on analyse le
code source de la page, on pourra peut être tomber là-dessus :
<impute type=text name= »nom »><input type=text
name= »email »>
Toujours la même chose, on
suppose que le script va demander d’ajouter une ligne de la base de donnée SQL
du site.
Admettons que Skin a tapé son
nom et son email et qu’il a validé, la formulaire passer les variable a un
script qui les interpréter et en faire des requêtes SQL sur le serveur de base
de données.
Le script va rajouter une
ligne dans la table newsletter de la façon suivante : (en PHP)
<?
Connexion au server SQL
mysql_query("insert into newsletter ('$nom','$email')"); //exécution de la requêtes
echo "Vous venez d\'être inscrit à la newsletter\n";
// ce script est basique mais c'est plus simple
pour débuter
?>
Analysons ce code, on voit
que les variables ($nom & $email) correspondent aux noms qu’on avait
attribué au tag<input> du formulaire vu un peut plus haut en HTML.
Le script va donc exécuter la
requête : « insert into newsletter
(‘Skin’,’Skin@arenhack.com’) »
Voila, Skin a été ajouter a la base de données SQL, le codeur est
content son script marche bien.
Mais ce n’est pas fini, car
pour l’instant nous avons juste démontré que Skin était bien inscrit dans la
base donnée SQL du serveur grâce à un scripte qui va interpréter les
variables.Mais maintenant allons un peut plus loin dans l’exécution du script,
essayons d’inscrire 2 personne en une seul fois.
Que va-t-il falloir faire
pour inscrire 2 personnes en même temps ? IL va falloir qu’on exécute 2
requêtes SQL en même temps sur la même ligne séparer par un « ; »
Ce qui va donnée quelque
chose dans ce genre :
"insert into newsletter ('billy','billy@billy.fr');insert into
newsletter ('billy2','billy2@billy.fr')"
Donc si nous voulons exécuter
ce type de requête sur un serveur SQL, il va falloir que notre script PHP
l’exécute :
---------------------------------------------------------------
Nom : Skin
Email: « Skin@arenhack.com’);insert into newsletter
(‘Skin2’,’Skin2@arenhack.com’)”
---------------------------------------------------------------
Le but est “d’imbriqué” une
nouvel requête SQL sur la même ligne dans notre variable $email
Je sais pas si vous m’avez
suivit, mais c’était juste un exemple concret, c’est sure que maintenant vous
aller pas vous amuser a inscrire 2 personne en une fois a une newsletter c’est
sure. Mais vous avez appris les « bases » si je pourrais dire du
stockage et du déplacement des données SQL.
Mais d’autres problèmes se
poses :
Déjà dans le cas précèdent,
c’était vraiment super simple puisqu’on connaissait déjà le nom de la table et
en plus nous savions comment été structuré le script PHP.
Mais en réalité ce ne sont pas les seuls problèmes :
- Si nous ne connaissons pas
la requête SQL et que le script l’aurai envoyé au serveur SQL alors nous
airions une page d’erreur, donc déjà cette faille ne s’adapte pas dans tout les
cas.
Ensuite pour écrire notre
requête, nous ne possédons pas assez d’information car il y aurait très bien pu
avoir un champ ID avant le nom et l’email ou tout autre chose donc nous ne
connaissons pas l’existence.
En faite au départ, l’attaque
est supers simple, mais elle est compromise par pas mal de facteur comme le
type de la base de données, le nom de la table, le nom des champs, etc....comme
je viens de vous le prouvez.
C’est pour cela que l’ont dit
dans ce cas, que le serveur et une black box, une boite noir autrement dit.
Mais il y a un point que je
n’est pas encore abordé, comment déceler ce genre de
faille.
Cela peut être aussi
important que pour le hacker, que pour le webmaster qui veut sécuriser son
site.
- Alors d’abord analyser le
code source de la page, pour se faire afficher le a partir de votre navigateur
ou enregistrez le sur votre HD. Maintenant, regardez le nom des variable qui
vont être envoyer et essayer de trouver des <input type=hidden> qui
pourrait nous aider.
- Maintenant, on va faire
comme tout a l’heure, mettez vous a la place du programmeur et le programmeur a
la place du hacker vis versa.
Vous vous rappelez ce qu’on
avait dit sur le nom de la table ? Un nom simple, pas
« GHUYF89 », donc une faut un peut d’intuition pour trouver le bon
nom de la table/champs.
- Maintenant essayer de provoquer une erreur lors de l’exécution du script,
une requête qui n’est pas attendu par le serveur car si le script est mal codé
vous pourrez voir la ligne de code afficher par votre browser ce qui vous
permettra de voir le code source. Aussi vous pouvais utiliser une technique Buffer Overflow en mettant un maximum de données qui
ne sont pas attendu par le serveur comme
#|^^£*ù% !;: »’--_@ .
Mais avant même de vous
épuiser a faire sa, taper ‘ou » dans un champs et si le serveur ne vous
retourne aucune erreur, le script risque d’être sécurise a 99%L.
Apres avoir vue la technique
du Buffer Overflow, il y a aussi celle d’utiliser un exploit
sur le serveur Web pour récupéré le code source :
-Utilisez showcode.asp sur
IIS installer par défaut (encore une connerie...)
- Si vous avez un script sur
le serveur, ce sui st assez fréquent, qui permet de télécharger un fichier en
passant par le nom en variable comme par exemple downloads.cgi ?file=fichier.zip
il suffit d’un peut d’intelligence pour transformer le script en downloads.cgi ?file=fichier
qu’on veut.zip sans oublier qu’il est
peut être possible de remonter dans le répertoire downloads.cgi ?file=../../../etc/passwd.
Post de news
Dans certains sites (comme
Arenhack.com) ou moteur de recherche laisse la possibilité a leurs visiteurs de
poster une news ou même un commentaire. Dans certains scripts, l’utilisateur
doit s’authentifier ce qui restreint le nombre de personnes indésirables. En
revanche il existe encore plusieurs sites qui ne demandent pas
d’authentification. Voici le code vulnérable :
if ( $action=="ajout" )
{
$date=date("Y/m/d
H:i");
$ajout_sql =
mysql_query("insert into $table (nom, auteur, email, texte, date) values ('$nom',
'$auteur', '$email', '$texte', '$date')",$connexion);
}
Le formulaire transmet a la
page le script une variable ‘hidden’. Si son contenue est ajout alors le script
a pour valeur ajout alors, il va
l’ajouter dans la base de données SQL. Le nom de la table est variable
selon la news et lui correspond donc par exemple si il s’agit d’un commentaire
sur la new 70 alors le nom de la table pourra être new_70.
Voici la pseudo faille qui
peut effectivement paraître assez inutile mais assez embêtante pour les
webmasters.
L’attaquant va poster un
commentaire ‘fantôme’ (‘hidden’ vu plus haut), ainsi imaginons que la requête
d’ajout de news soit :
http://arenhack/addcommentaire.php?newsID=70&nom=skin&email=skin@arenhack.com&texte=blablabla
%200wnz%Thv69
Donc si la news numéro 70
existe, alors elle va être poster, or si elle n’existe pas elle va quand même être
poster, J là est le problème!
Bon, c’était vraiment un
exemple tout con d’injection, bien sur c’est extrêmement rare de voir un script
aussi mal coder, c’est même impossible, c’est juste à titre d’exemple !
NOTA BENE...
Pour ceux qui auraient eu le
déshonneur de coder ce genre de scripte voici comment le sécuriser :
$query = "SELECT * FROM table_news";
$requete = mysql_query($query);
$nb = mysql_numrows($requete);
if ( ($action=="ajout") && ($newsID < $nb) )
{
$date=date("Y/m/d H:i");
$ajout_sql = mysql_query(...);
}
Procédure d’authentification en PHP :
Alors voila je vous expose au
faits, on est dans un espace membre donc on est un peut aller traîner dans le
fichier log_admin.php dans le fichier caché du site après avoir repéré les
faille du service PHP. Et on se retrouve devant sa :
< ?
include (« member/config.php) ;
if($pseudo=’’ ||
$password== ‘’)
{
[…]
exit;
}
db_connect();
$sql= mysql_query(“SELECT password FROM admin_conf
where
login= ‘$pseudo’”);
$nb = mysql_num_rows($sql);
if($nb == 0)
{
echo “<center><h3>Mauvais
Indentification</h3></center>”;
mysql_close();
exit;
}
else
{
$sql2 = “SELECT id_conf FROM admin_conf WHERE login =
‘$pseudo’”;
$req2 = mysql_query($sql2) or die(‘ Erreur SQL !
<br>’.$sql2.’<br>’.mysql_error());
$data2 = mysql_fetch_array($req2);
mysql_close();
$id_conf = $data2[‘id_conf’];
$expire = 365*24*3600;
setcookie(“admin”,”$pseudo”,time()+$expire,”/”,””);
setcookie(“id_conf”,”$id_conf”,time()+$expire,”/”,””);
session_start();
session_register(‘pseudo’);
session_register(‘admin_id’);
$_SESSION[‘log_admin’] = $pseudo;
$_SESSION[‘id_admin’] = $id_conf;
header(“Location: _admin/administration.php”);
}
?>
Bon alors on va faire dans
l’ordre, déjà on voit deux variables qui ne doivent pas être vides: $pseudo et
$password. Ensuite on extrait le mot de passe de la table admin_conf en
fonction du $pseudo, après si il y a un résultat, donc que le pseudo est un log
admin, on extrait l’id_conf de l’admin de la même table. Mais attention ! Grosse faute du programmeur car
le password n’est pas vérifié !!! Ainsi si on connaît le login de l’admin,
on peut accéder dans la zone membre ;)
Super, mais l’injection SQL, c’est
pour quand ? ;)
Dans le fichier login.php, il
y a une possibilité d’injection SQL SI la
configuration du serveur Web est magic_quotes_gpc=OFF
Code :
-------------------------------------------------------------------
$sql = « select password from $dbtable where login =
‘userlogin’ » ;
$req = mysql_query($sql);
-------------------------------------------------------------------
Si on donne a $userlogin la
valuer: ‘OR 1=1 INTO OUTFILE ‘/complete/patch/file.txt et une valeur quelconque
a $password, tous les mots de passé seront enregistrés dans le fichier
/complete/patch/file.txt.
Attention ! Enorme faille ! Grâce à cette injection vous
pouvez avoir le mpd de quelqu’un ! Il suffit d’ajouter le pseudo au début
de la valeur et de virer le OR 1=1
Exemple: Bob’ INTO OUTFILE’/complete/patch/file.txt
Les différentes requêtes
liées a PHP :
mysql_affected_rows
mysql_change_user
mysql_close
mysql_connect
mysql_create_db
mysql_data_seek
mysql_db_name
mysql_db_query
mysql_drop_db
mysql_escape_string
mysql_fetch_array
mysql_fetch_assoc
mysql_fetch_field
mysql_fetch_lengths
mysql_fetch_object
mysql_fetch_row
mysql_field_flags
mysql_field_name
mysql_field_len
mysql_field_seek
mysql_field_table
mysql_field_type
mysql_free_result
mysql_get_client_info
mysql_get_host_info
mysql_get_proto_info
mysql_get_server_info
mysql_insert_id
mysql_list_dbs
mysql_list_fields
mysql_list_tables
mysql_num_fields
mysql_num_rows
mysql_pconnect
mysql_query
mysql_result
mysql_select_db
mysql_tablename
mysql_unbuffered_query
5.0 Sécurisation des failles
-=-=-=-=-=-=-=-=-=-=-=-=-=-
A tout problème existe une
solution, enfin presque...rien n’est impossible en
informatique de toute manière.Le principe, comme je l’es dit dans
l’introduction est filtré les donnes rentrantes de façon a évité les script
malveillant. Prénoms un exemple simple :
J’ai un formulaire qui me
demande mon nom de famille, donc si je met des chiffres sa va sembler bizarre
non ? (A moins que me m’appelle C3PO, mais bon c’est rare...J).
Donc pour résoudre ce
problème, il y a plusieurs méthodes qui s’offre a vous :
- Soit sécuriser avec du javascript au niveau du client,
vérification du champs « nom » et si ce champs contient des chiffres alors il est refusé.Comme par
exemple :
<SCRIPT LANGUAGE="JavaScript">
function checkstring(text){
pat=/^[A-Za-z0-9]{6,10}$/;
result=text.match(pat);
return TRUE;
}
function Send(){
if (checkstring(txtName) &&
checkstring(txtPassword)){
login.submit();
}
}
</SCRIPT>
Le but étant d’enlever les
caractères dangereux.
Mais ce n’est
vraiment pas une bonne idée d’utiliser ce genre de script car il peut être lui même détourner par un autre
script.
Mais ce n’est pas la seul
contrainte de ce genre de sécurité car supposons que le formulaire envoie des
données en POST, si nous remplissons le formulaire avec des caractères non
conformes le script va fonctionner. Mais maintenant, si on fait un système,
c'est-à-dire que lieu de remplir directement le formulaire, on envoie
directement les variables avec quelque chose comme sa : formulaire.php ?=cequevousvoulez, la variable
sera interpréter par le serveur et non pas par le client.
Donc cette sécurité est vraiment inefficace, je vous conseil de
directement de sécurisé au niveau du serveur.
- Maintenant parlons de la
sécurité la plus sûre, c’est notre script PHP qui va analyser les données
entrées. Et si elles sont non conformes, il les refuse et envoie un message
d’erreur.
- Mais le mieux est encore de
sécurisé au 2 niveau, c'est-à-dire au niveau du client
et au niveau du serveur, c’est le moyen
le plus sûre. Mais si il y a un conseil que je peux donnée au webdevelopper,
c’est de ne pas sous estimer cette faille car elle peut faire très malJ.
6.0 Conclusion
-=-=-=-=-=-=-=-=-=-
J’ai pu vous démontrez dans
cette article que les bases de données SQL sont très facilement piratable en
connaissance de quelques information sur les différente tables/champs. Bien
entendu les faille de se genre se font de plus en plus rare car les webmasters
sont vigilent. Tout de même certaines injection reste possible, vous pouvez vous
en rendre compte sur www.security-corporation.com
qui reste à jour sur toute les nouvelles failles, injection et techniques de
buffer overflow (US).
7.0 Inspiration, Sources, Remerciement
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Inspiration de départ :
Hackademy manuel n°5
Quelques sources :
Hackademy journal n°11, tutorial de Crazy
Lord //SQL hacking, tutorial de Memonix //SQL #1
Remerciement :
SpS6m3N pour m’avoir donner quelques sources de tutoriaux et Nocte qui m’a
redonner confiance en moi quand je pensée que mon tuto était une kiche