mercredi 11 février 2009

Sauvegarder sa bdd rapidement et efficacement (ou pas ?)

Salut, la compagnie !
Non, je ne suis pas (encore) mort ! Et si je poste un nouvel article, c'est bien pour vous le montrer.

On va pas y aller avec un gros sujet sensible, je vais juste vous parler d'un petit outil simpliste que j'ai fait. Il permet de sauvegarder une base de données, mais restons modestes : il est à optimiser, et il ne prend pas en charge toutes les structures spécifiques de tables MySQL, à savoir :
- Si y'a des FOREIGN KEY ou non ;
- La valeur actuelle générée par l'AUTO_INCREMENT.

Lien : http://venom630.free.fr/geo/tools/dbsave_php.txt
Bien sûr, c'est à optimiser. On pourrait l'utiliser en CLI en fournissant respectivement en argument l'host, l'utilisateur, le mot de passe et la base de données à sauvegarder. On peut aussi l'adapter pour le web, y'a pas grand souci.

Si y'en a que ça intéresse, la source est dispo, donc, aucun problème de ce côté-là. (Celui qui me fait un reproche sur les noms de variable ambigus, c'est ma poing dans son gueule à ce p'tit con !)

Voilà. (C'était une conclusion du tonnerre, il faut le dire !)

Geo

samedi 24 janvier 2009

ROOT@LOCALHOST a dit... faites le chien !

Et c'est là que tout le monde se met à aboyer, qui qu'on soit. Ca serait amusant, comme spectacle !
Bon, ok, le titre n'est pas très original, mais j'essayais de me faire comprendre de quelque manière que ce soit ; ce tutoriel traitera des injections SQL possibles quand on a les privilèges root avec.

Petit préambule pour ceux qui veulent pratiquer en même temps que l'article. Je suppose que vous avez un environnement apache + mysql + php à disposition. Connectez-vous en ROOT, et faites les requêtes suivantes :
CREATE USER SecondRoot IDENTIFIED BY 'toor';
CREATE DATABASE BaseDeRoot;
GRANT ALL PRIVILEGES ON BaseDeRoot.* TO 'SecondRoot'@'%';


Trois lignes de requêtes :
- La première créé un utilisateur sql nommé SecondRoot, dont le mot de passe sera toor. Cet utilisateur sera dépourvu de droit, il n'en aura AUCUN ;
- la seconde ligne créé une base de données BaseDeRoot ;
- la troisième ligne assigne tous les privilèges SecondRoot pour manipuler la base BaseDeRoot.

C'est un peu comme ça que font les hébergeurs web pour vous créer une base de données, en fait.

Ce qu'il faut savoir
Il existe des méta-bases, pour mysql. L'une d'elles s'appelle tout simplement mysql, et renferme les informations des utilisateurs, des privilèges etc... Une autre s'appelle information_schema, qui renferme les informations sur le nom des bases de données, des tables etc...

Aucun utilisateur autre que root lui-même - si les autres n'ont pas les mêmes droits que root - ne peut adresser de requête à la base mysql.

Faisons, par exemple, la requête suivante une fois connecté sous root :
SELECT Host, User, Password FROM mysql.user


Résultat :
+-----------+------------+-------------------------------------------+
| Host | User | Password |
+-----------+------------+-------------------------------------------+
| localhost | root | *9CFBBC772F3F6C106020035386DA5BBBF1249A11 |
| % | SecondRoot | *9CFBBC772F3F6C106020035386DA5BBBF1249A11 |
+-----------+------------+-------------------------------------------+


On obtient la liste des utilisateurs. On s'aperçoit que root et secondroot on le même mot de passe, mais ça, on s'en fout. Ce qu'on aperçoit, surtout, c'est qu'on ne peut se connecter en root qu'à partir de localhost, donc impossible à distance. Quant à SecondRoot, on peut faire ça de partout. Allons un peu plus loin, et regardons les privilèges de chaque utilisateur :

SELECT User, Select_priv, Insert_priv, Update_priv, Delete_priv FROM mysql.user;


Résultat :
+------------+-------------+-------------+-------------+-------------+
| User | Select_priv | Insert_priv | Update_priv | Delete_priv |
+------------+-------------+-------------+-------------+-------------+
| root | Y | Y | Y | Y |
| SecondRoot | N | N | N | N |
+------------+-------------+-------------+-------------+-------------+


Voilà, c'était juste un exemple.

Imaginez le code suivant :
<?php
mysql_connect("localhost","root","toor");
mysql_select_db("BaseDeRoot");
//...
?>


On remarque que le script php se connecte avec les droits root. On peut donc aisément interroger la base mysql pour obtenir des informations sensibles, d'où le pass de root.

Exemples de requêtes :
UPDATE membre SET age=19
-- Et là, l'injection
, profil= (SELECT Password FROM mysql.user LIMIT 0,1) WHERE pseudo='Geo'; /*
-- La suite de la requête (par exemple)
WHERE pseudo='Geo';


Dans mon profil apparaîtra le hash de root. Il ne manque plus qu'à le casser, et ça peut prendre 10 minutes comme une décennie.

Conclusion ?



L'article n'était pas très long et explicatif, mais il nous a montré qu'il fallait plutôt passer par un utilisateur autre que root si nous voulons, à la base, manipuler une base de données associée. On peut, certes, accéder à information_schema (ce que nous n'avons pas vu, mais peut-être plus tard) mais en aucun cas à mysql.

Geo

(D'un côté, ça prouve que je suis encore en vie, hahaha !)

dimanche 18 janvier 2009

Petit délire d'ASCII art

Salut, salut !
Histoire de poster un truc pour vous montrer que le blog n'est pas encore mort, je vais vous parler d'un petit script à la con que j'ai fait hier en même pas 15 minutes. Ca m'a permis de pratiquer un peu la bibliothèque GD de php.

Je préviens, au passage, que je vois déjà ma monture - UnKnOwN*DrAgOoN - se foutre de ma gueule. :]

Le script a pour fonction de prendre quatre arguments en méthode GET :
- La skin a afficher en ascii art ;
- la couleur de fond sur laquelle afficher l'ascii art ;
- les coordonnées x de la frame ;
- les coordonnées y de la frame.

Imaginez la skin suivante :


Le but du script serait de prendre une frame (celle de face, par exemple) et de l'afficher en ascii art avec les couleurs. On imagine donc bien l'algorithme qui :
- se positionne au 1er pixel de la frame ;
- lit, de façon séquentielle, la couleur des pixels ;
- affiche des caractères HTML colorés.

J'ai donc déjà au moins ça :
<?php
if(!empty($_GET['bgcolor'])) {
$colordefault = "#".htmlentities($_GET['bgcolor']);
} else {
$colordefault = "#000000";
}
echo
"<body bgcolor=\"".$colordefault."\" text=\"#FFFFFF\">";



J'avoue que ça doit pas être très optimisé niveau sécu' ou quoi, mais c'est juste que, sur le moment, je me faisais chier comme pas possible.

Ensuite, sachant qu'une frame fait 24 pixels sur la largeur et 32 pixels sur la longueur, on peut continuer là-dessus :
if(isset($_GET['skin'])) {
$MyImage = @imagecreatefrompng($_GET['skin']);

if(isset($_GET['x'])) {
$framex = abs(intval($_GET['x']));
} else {
$framex = 0;
}

if(isset($_GET['y'])) {
$framey = abs(intval($_GET['y']));
} else {
$framey = 0;
}

$debutx = 24*$framex;
$debuty = 32*$framey;

$dest = imagecreatetruecolor(24,32);
imagecopymerge($dest, $MyImage, 0, 0, $debutx, $debuty, 24, 32, 100);
// ...



On créer une petite image de destination aux dimensions 24x32 et on y copie la frame à afficher. C'est inutile mais ça m'a permis de faire du pas à pas.

Voici en suite la portion de code qui servirait à afficher l'ascii art coloré :
echo "<font size=\"1\" face=\"Courier New\">";
for($j = 0; $j <= 32; $j++) {
for($i = 0; $i <= 24; $i++) {
$color = imagecolorat($dest,$i,$j);
$r = ($color >> 16) & 0xFF;
$g = ($color >> 8) & 0xFF;
$b = $color & 0xFF;
if($color) {
echo "<font color=\"#".
($r <= 15 ? "0".dechex($r) : dechex($r)).
($g <= 15 ? "0".dechex($g) : dechex($g)).
($b <= 15 ? "0".dechex($b) : dechex($b))."\">0101</font>";
} else {
echo "<font color=".$colordefault.">0101</font>";
}
}
echo "<br />";
for($i = 0; $i <= 24; $i++) {
$color = imagecolorat($dest,$i,$j);
$r = ($color >> 16) & 0xFF;
$g = ($color >> 8) & 0xFF;
$b = $color & 0xFF;
if($color) {
echo "<font color=\"#".
($r <= 15 ? "0".dechex($r) : dechex($r)).
($g <= 15 ? "0".dechex($g) : dechex($g)).
($b <= 15 ? "0".dechex($b) : dechex($b))."\">0101</font>";
} else {
echo "<font color=".$colordefault.">0101</font>";
}
}
echo "<br />";
}
echo "</font>";



Petites explications : On balaye chaque ligne, on lit la couleur des pixels et on l'affiche en <font color="couleur lue">ascii art</font>. Si je fais deux boucles for() sur la largeur, c'est pour éviter que l'ascii art soit trop tassé.

On peut terminer avec une petite notice d'utilisation - flemme d'avoir codé un formulaire html...
} else {
echo "<pre>Utilisation : script.php?skin=skin.png[&bgcolor=couleur_hexa][&x=valeur][&y=valeur]</pre>";
}
?>


Comme quoi, c'est juste pour le délire que j'ai fait ça.
Un petit aperçu ? :]

hebergé sur tof.center.free.fr


Voili voulou. Et, vu que j'aurais pas écrit beaucoup de choses, autant publier mes résultats merdiques du BTS blanc :
- Droit : 4,25 ;
- Economie : 8,5 ;
- Comptabilité : 8,5 ;
- Architecture matérielle : 9 ;
- Français : 10,7 ;
- Anglais : 12 ;
- Analyse (Méthode merise) : 13,5 ;
- Architecture logicielle (SQL, excel...) : 16,5 ;
- Algorithmie : 18,5 ;
- Maths : 18,5 ;
- GEOSI (Gestion des entreprise et organisation des systèmes d'information) : 20,5, car, en fait, la notation a été revue pour être sur 23. Ca me fait 0.5 point de bonus.

Ca me fait une moyenne de merde, les matières informatiques étant regroupées dans un coefficient global de 5. L'éco-droit, coeff 3 (Aïe !), et tout le reste coeff 2.

C'était... ma vie passionnante ! C'est bien la dernière fois que je dis des trucs qui n'ont rien à voir avec le blog...

Conclusion ?


Pour en revenir au sujet de l'article, celui-ci ne sert un peu à rien comparé aux autres - sh4ka m'a même dit qu'il préférait la crypto. Néanmoins, c'est toujours ça de plus de coder des petits trucs pour en tirer une petite satisfaction. Je sais pas pour vous, mais, ça m'a fait délirer de faire de l'ascii art (premier truc que j'ai fait).

Geo


PS : Ajout de kmkz dans la liste des copains. Blog sympathique (comme les autres) à aller voir !
PS2 : Ajout du site de shp - mon sacalain, ma propriété privée - dans la liste des copains. Je t'aime, mon bichon.
PS3 : Ajout du blog de 5m0k3, mon prédécesseur, dans la liste des copains.

samedi 10 janvier 2009

StegaWav beta v0.1 - "J'ai rien entendu !"

Les week-ends... Ils ont leurs avantages tout comme leurs inconvénients ; c'est reposant, mais parfois, on peut s'faire chier comme un rat mort.

Il n'y a pas si longtemps que ça, je me suis mis en tête de coder un petit programme qui se sert du bit de poids faible d'un fichier x pour y dissimuler tous le contenu d'un fichier y. Une technique de stéganographie efficace mais très connue. Pour savoir ce qu'est - en détail - la stéganographie, je vous redirige sur ce lien :
http://fr.wikipedia.org/wiki/St%C3%A9ganographie

Je reprends... Je me suis donc mis en tête de coder l'outil pour cacher les informations, et l'autre pour les extraire.

J'élabore un petit cahier des charges dans ma tête. Pourquoi wav ? Parce que, généralement, les fichiers de ce type sont volumineux, car non compressés. En plus, il faudrait élaborer un petit truc sympa. Je me suis donc dit que je cacherai carrément un fichier dans le son. On commencerait donc par cacher des en-têtes, du genre :

Name: fichier.txt\n
Taille : 15\0

Ainsi, on cache le contenu. Ca peut servir pour l'extracteur, qui va lire le nom du fichier et qui ira ensuite extraire suivant la taille.

Ayant eu un souci en C auquel j'ai été confronté longtemps sans trouver de solution, je demande de l'aide sur #nibbles. Ivanlef0u, j0rn, Baboon et Deimos se penchent sur mon problème ; en fait, ça viendrait de fseek(), une fonction dont je me sers pour parcourir le fichier. Résultat, personne ne trouve malgré les théories élaborées, et ça finit en gentil troll.

J'ai plus qu'à faire ça en PHP. :(


J'ai commencé par pondre des scripts en console. Pour les télécharger, c'est ici :
http://venom630.free.fr/geo/?path=tools/StegaWav

Utilisez-les en CLI. De toute façon, z'avez pas le choix.

Je les compile avec bambalam, content de moi. Effectivement, je pourrai les diffuser aux gens (coucou Tybalt !) qui n'ont pas PHP d'installé sur leur bécane ! \o/

Oui, j'étais content de mon petit machin débile. Je l'ai donc fait essayer à certains amis qui avaient le temps, mais, le souci, c'est qu'ils n'avaient pas l'habitude d'utiliser la console. Donc, je me suis dit... Pourquoi ne pas leur faire d'interface graphique avec winbinder ?

C'est ce que j'ai fait !

Avantages :
- Prise en main facile ;
- programmation facile.

Inconvénients :
- Lent ;
- pas portable ;
- Eventuellement quelques bugs.
- Ca se peut que ça ne marche pas... Je suis pas pro en portabilité de winbinder.

Vous pouvez donc télécharger l'archive à cette adresse :
http://venom630.free.fr/geo/?path=tools/StegaWav_Gui

Elle contient :
- Les exécutables (quand même !) ;
- Les sources.

Ce que je prévois pour la suite :
- Vérification des fichiers : il faut que le fichier son soit environ neuf fois plus gros que le fichier à cacher (pas huit, parce que j'ai envie) ;
- Cacher plusieurs fichiers à la suite ? Eventuellement, faire un header principal du genre "NombreDeFichiers: 3"... ;
- Proposez-moi vos idées ? De toute façon, les sources sont diffusées. Vous faites ce que vous voulez.


Rien de compliqué, donc je vais, à votre plus grand malheur, m'arrêter là.

Geo

mardi 6 janvier 2009

Fyury's challenge - Keygenme

Il m'a sauvé la vie, le dude. Et moi qui pensait rouiller avec du php... C'est en cette soirée du 06 janvier 2009 que je me résigne à visiter son blog, et là, je tombe sur son challenge de crackme :
Après un petit rappelle de xylitol (merci), je viens vous mettre mon foome I ..

Je l'avais présenté sur FC et donc je n'ai pas vu d'importance à l'exposer sur le blog (vu les critiques :p) .

level : 0.5 || 1
secure : no package ..
Anti debugger (mal implémenté)

Objectifs :

- faire un keygen. ( 1 )
- trouver le serial pour son pseudo. (0.5 )


Article en question : http://fyury.blogspot.com/2008/11/foome-part-i.html.

Je télécharge l'archive sans trop lire les infos, je me focalise juste sur ça :

- faire un keygen. ( 1 )
- trouver le serial pour son pseudo. (0.5 )


Je me suis dit, au début, que je n'arriverai pas à faire le keygen. J'y suis finalement arrivé, après plusieurs essais car je suis quelqu'un de trop pressé.

Allez, je décompresse l'archive dans un dossier, et je lance foome.exe.
C:\Documents and Settings\Geoffrey\Bureau\foome>"foome {part I}.exe"
[ foome part I by fyuw]

Login : Geo0w
pwd : 15612


Une fenêtre apparaît, et me dit "t4pz" avec pour titre "Iz N0t da g00d password". Put*** de foome de m****, j'vais te montrer qui c'est la tapz ! <>

Je me précipite pour ouvrir le bordel avec ollydbg. Je ne tarde pas à trouver la section de code la plus intéressante :
00401431  |> C70424 2C30400>MOV DWORD PTR SS:[ESP],foome_{p.0040302C ; ||||ASCII "                 [ foome part I by fyuw]

Login : "
00401438 |. E8 C7060000 CALL <JMP.&msvcrt.printf> ; |||\printf
0040143D |. 8D85 88FEFFFF LEA EAX,DWORD PTR SS:[EBP-178] ; |||
00401443 |. 894424 04 MOV DWORD PTR SS:[ESP+4],EAX ; |||
00401447 |. C70424 5F30400>MOV DWORD PTR SS:[ESP],foome_{p.0040305F ; |||ASCII "%s"
0040144E |. E8 A9060000 CALL <JMP.&msvcrt.scanf> ; ||\scanf
00401453 |. 8D85 88FEFFFF LEA EAX,DWORD PTR SS:[EBP-178] ; ||
00401459 |. 890424 MOV DWORD PTR SS:[ESP],EAX ; ||
0040145C |. E8 93060000 CALL 00401461 |. 83F8 04 CMP EAX,4 ; |
00401464 |. 77 1B JA SHORT foome_{p.00401481 ; |
00401466 |. C70424 6230400>MOV DWORD PTR SS:[ESP],foome_{p.00403062 ; |ASCII "Need more 5 char..."
0040146D |. E8 92060000 CALL <JMP.&msvcrt.printf> ; \printf
00401472 |. C785 84FEFFFF >MOV DWORD PTR SS:[EBP-17C],0
0040147C |. E9 F5000000 JMP foome_{p.00401576
00401481 |> 8D85 88FEFFFF LEA EAX,DWORD PTR SS:[EBP-178] ; ||
00401487 |. 890424 MOV DWORD PTR SS:[ESP],EAX ; ||
0040148A |. E8 65060000 CALL 0040148F |. 83F8 0B CMP EAX,0B ; |
00401492 |. 76 1B JBE SHORT foome_{p.004014AF ; |
00401494 |. C70424 7630400>MOV DWORD PTR SS:[ESP],foome_{p.00403076 ; |ASCII "Need less 10 char..."
0040149B |. E8 64060000 CALL <JMP.&msvcrt.printf> ; \printf
004014A0 |. C785 84FEFFFF >MOV DWORD PTR SS:[EBP-17C],0
004014AA |. E9 C7000000 JMP foome_{p.00401576
004014AF |> C70424 8B30400>MOV DWORD PTR SS:[ESP],foome_{p.0040308B ; |||||ASCII "pwd : "
004014B6 |. E8 49060000 CALL <JMP.&msvcrt.printf> ; ||||\printf
004014BB |. 8D85 B4FEFFFF LEA EAX,DWORD PTR SS:[EBP-14C] ; ||||
004014C1 |. 894424 04 MOV DWORD PTR SS:[ESP+4],EAX ; ||||
004014C5 |. C70424 9230400>MOV DWORD PTR SS:[ESP],foome_{p.00403092 ; ||||ASCII "%d"
004014CC |. E8 2B060000 CALL <JMP.&msvcrt.scanf> ; |||\scanf
004014D1 |. 0FBE9D 8AFEFFF>MOVSX EBX,BYTE PTR SS:[EBP-176] ; |||
004014D8 |. 8D85 88FEFFFF LEA EAX,DWORD PTR SS:[EBP-178] ; |||
004014DE |. 890424 MOV DWORD PTR SS:[ESP],EAX ; |||
004014E1 |. E8 0E060000 CALL 004014E6 |. 89C2 MOV EDX,EAX ; ||
004014E8 |. 89D0 MOV EAX,EDX ; ||
004014EA |. 01C0 ADD EAX,EAX ; ||
004014EC |. 01D0 ADD EAX,EDX ; ||
004014EE |. C1E0 09 SHL EAX,9 ; ||
004014F1 |. 01D0 ADD EAX,EDX ; ||
004014F3 |. 01C3 ADD EBX,EAX ; ||
004014F5 |. 8B85 A0FEFFFF MOV EAX,DWORD PTR SS:[EBP-160] ; ||
004014FB |. 890424 MOV DWORD PTR SS:[ESP],EAX ; ||
004014FE |. E8 F1050000 CALL <JMP.&msvcrt.strlen> ; |\strlen
00401503 |. 29C3 SUB EBX,EAX ; |
00401505 |. 89D8 MOV EAX,EBX ; |
00401507 |. 83C0 0C ADD EAX,0C ; |
0040150A |. 3985 B4FEFFFF CMP DWORD PTR SS:[EBP-14C],EAX ; |
00401510 |. 74 33 JE SHORT foome_{p.00401545 ; |
00401512 |. C74424 0C 0000>MOV DWORD PTR SS:[ESP+C],0 ; |
0040151A |. C74424 08 9530>MOV DWORD PTR SS:[ESP+8],foome_{p.004030>; |ASCII "Iz N0t da g00d password"
00401522 |. C74424 04 2730>MOV DWORD PTR SS:[ESP+4],foome_{p.004030>; |ASCII "t4pZ"
0040152A |. C70424 0000000>MOV DWORD PTR SS:[ESP],0 ; |
00401531 |. E8 06060000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
00401536 |. 83EC 10 SUB ESP,10
00401539 |. C785 84FEFFFF >MOV DWORD PTR SS:[EBP-17C],0
00401543 |. EB 31 JMP SHORT foome_{p.00401576
00401545 |> C74424 0C 0000>MOV DWORD PTR SS:[ESP+C],0 ; |
0040154D |. C74424 08 AD30>MOV DWORD PTR SS:[ESP+8],foome_{p.004030>; |ASCII "U win.. make a keygen"
00401555 |. C74424 04 2730>MOV DWORD PTR SS:[ESP+4],foome_{p.004030>; |ASCII "t4pZ"
0040155D |. C70424 0000000>MOV DWORD PTR SS:[ESP],0 ; |
00401564 |. E8 D3050000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA


Je fais un break sur l'adresse 004014CC, qui va appeler la fonction scanf lors de l'input du password. Je lance, et là, une autre fenêtre avec titre "U sUck" et qui m'affiche de nouveau un "t4pZ". Mais quelle connasse ! (même plus envie de censurer, c'est plus fort que moi)

Je me dis donc - toujours sans avoir lu qu'il y avait un antidebuger mal implémenté - qu'il y a une protection à contourner. Miracle, je repère ce bout de code :

00401324  |. C785 98FEFFFF >MOV DWORD PTR SS:[EBP-168],foome_{p.0040>; |ASCII "OLLYDBG.EXE"
0040132E |. C785 9CFEFFFF >MOV DWORD PTR SS:[EBP-164],foome_{p.0040>; |ASCII "idag.exe"
00401338 |. C785 A0FEFFFF >MOV DWORD PTR SS:[EBP-160],foome_{p.0040>; |ASCII "windbg.exe"


Sans hésitation, je modifie les valeurs dans le dump :
- "OLLYDBG.EXE" devient "tasoeur.EXE" ;
- "idag.exe" devient "stfu.exe" ;
- "windbg.exe" devient "azerty.exe".

Je relance, et là... Pas de fenêtre ! C'est qui la tapz ?! Haha !

Je rentre donc en login : Geo0w, et en pwd : 2151 (truc au pif, quoi).

Je continue...

Sans rentrer dans les détails, j'arrive à la ligne suivante après quelques coups de F8 (pour tracer le code sans s'attarder dans les CALLs) :
0040150A  |. 3985 B4FEFFFF  CMP DWORD PTR SS:[EBP-14C],EAX  


Je regarde eax, et il contient 00001E76. En décimal, ça donne : 7798.
Je ferme ollydbg et tout le bordel, puis je relance foome.exe en ligne de commande :


C:\Documents and Settings\Geoffrey\Bureau\foome>"foome {part I}.exe"
[ foome part I by fyuw]

Login : Geo0w
pwd : 7798


Encore une fenêtre, sauf que, dorénavant, son titre est différent : "U win.. make a keygen", puis, elle affiche encore un "t4pZ". Cette saloperie mériterait que je l'insulte comme un DR_KILLER. Au passage, make me a sandwich, saloperie !

Bon, désolé pour la vulgarité, mais bon... C'est éprouvant, ça sera mon premier keygen de ma vie ! Oui, je suis énervé et j'oublie le fait d'avoir pensé tout à l'heure que je n'y arriverai pas. Je fonce, tête baissée !

Je réouvre mon copain ollydbg, je remodifie les valeurs dans le dump :
- "OLLYDBG.EXE" devient "tasoeur.EXE" ;
- "idag.exe" devient "stfu.exe" ;
- "windbg.exe" devient "azerty.exe".

Puis, cette fois, je break sur :
004014CC  |. E8 2B060000    CALL <JMP.&msvcrt.scanf>                 ; |||\scanf


Cette ligne correspond au CALL juste après l'input du password. Hop, je lance, je rentre "albert" en login et "11111" en pwd, puis ça break. Je trace le code :
004014E6  |. 89C2           MOV EDX,EAX                              ; ||
004014E8 |. 89D0 MOV EAX,EDX ; ||
004014EA |. 01C0 ADD EAX,EAX ; ||
004014EC |. 01D0 ADD EAX,EDX ; ||
004014EE |. C1E0 09 SHL EAX,9 ; ||
004014F1 |. 01D0 ADD EAX,EDX ; ||
004014F3 |. 01C3 ADD EBX,EAX ; ||
004014F5 |. 8B85 A0FEFFFF MOV EAX,DWORD PTR SS:[EBP-160] ; ||
004014FB |. 890424 MOV DWORD PTR SS:[ESP],EAX ; ||
004014FE |. E8 F1050000 CALL <JMP.&msvcrt.strlen> ; |\strlen
00401503 |. 29C3 SUB EBX,EAX ; |
00401505 |. 89D8 MOV EAX,EBX ; |
00401507 |. 83C0 0C ADD EAX,0C ; |
0040150A |. 3985 B4FEFFFF CMP DWORD PTR SS:[EBP-14C],EAX ; |


C'est à la dernière ligne que notre password entré est comparé à la clef véritable. Donc, j'analyse le code assembleur au-dessus, et j'en viens à traduire cela en l'algorithme suivant (après plusieurs sessions de debugging) :

keygen <- longueur(login)
keygen <- keygen * 3
keygen <- keygen * 512
keygen <- keygen + longueur(login) (merci à UnKnOwN*DrAgOoN pour avoir signalé l'oubli)
keygen <- keygen + (valeur entière)login[3]
keygen <- keygen - longueur_chaine("windbg.exe")
keygen <- keygen + 12


Au final, je fais mon keygen :
http://venom630.free.fr/geo/autre_chose/foome__fyuw/keygen_c.txt

Il marche niquel.


Conclusion ?


Eprouvant, très éprouvant. Fyury, si tu passes sur ce blog, je tenais à te remercier d'avoir mis à disposition un tel challenge. J'espère résoudre d'autres de tes oeuvres avec une difficulté croissante ; c'est en forgeant qu'on devient forgeron.

Geo

Edit : ajout de http://xylitol.free.fr/Home/index.php dans la liste des copains. Superbe site sur le reverse engineering à visiter !

"Bambalam!" ou "compile-moi du PHP !"

Mon DS d'éco-droit ayant été littéralement... Foiré, et n'ayant pas envie de réviser mes maths pour demain, je décide de consacrer un article toujours aussi simpliste qui traitera de Bambalam.

Non, ce n'est pas de la musique. Voici, d'ailleurs, en premier lieu, l'URL du site du projet :
http://www.bambalam.se/bamcompile/


On voit en gros sur la page :
Bambalam PHP EXE Compiler/Embedder


Alors que PHP est censé être un langage interprété, on peut le compiler pour :
- Masquer du code ;
- Faire des applications windows portables ;
- (théoriquement) accroître la vitesse d'exécution.

Elle est pas belle, la vie ?

Et puis, si vous utilisez linux, il y a la source du projet à télécharger !

Allez, on télécharge l'archive, on l'extrait dans un dossier, et on regarde le contenu :
- readme.txt : on passe ;
- project_template.bcp : on passe ;
- bamcompile.exe : le fichier qui va recevoir plein d'arguments pour "compiler" notre php ;
- examples : un dossier contenant plein d'exemples intéressants. Je vous laisse regarder.

Pour nous mettre à l'aise, créons un dossier projets. Dans ce dossier projets, créons un dossier hello et allons dans celui-ci. Maintenant, dans ce dossier, créons un fichier nommé hello.php Et mettons-y le code suivant :
<?php
echo 'Hello!';
?>


Il va maintenant falloir le compiler. Tout d'abord, vous avez le choix entre :
- Aller en ligne de commande pour vous déplacer dans le dossier de bambalam puis rentrer vos options à la main ;
- Faire un fichier batch qui va exécuter de façon séquentielle vos commandes et en garder une trace.

Pour ma part, je penche pour la seconde option.

Voyons ce qu'on nous dit sur le site du projet :
Usage:
bamcompile [-options] infile.php [outfile.exe]
bamcompile [-options] project_directory mainfile.php [outfile.exe]
bamcompile projectfile.bcp

Options:
-w Hide console window for windowed applications
-c Compress output exe (using UPX)
-d Do not encode PHP files
-e:extension.dll Embed and use PHP extension
-i:icon.ico Add icon to exe


Testons la première ligne pour compiler notre unique fichier PHP ! Créons un fichier nommé make.bat dans le dossier courant, et mettons-y les lignes de code suivantes :
@echo off
"../../bamcompile.exe" hello.php
rem On va éviter de fermer la console automatiquement
pause


Eh oui, il faut veiller à mettre ../../ pour remonter dans le dossier parent ; je ne vous prends pas pour des imbéciles non plus, mais pensons-y par réflexe !

On lance make.bat et on n'a même pas le temps de dire "Agaga poireau." :
Bambalam PHP EXE Compiler/Embedder 1.21

Mainfile: hello.php
Outfile: hello.exe

Encoding and embedding hello.php

hello.exe created successfully!
Appuyez sur une touche pour continuer...



On a un superbe exécutable qui s'est créé dans le même dossier. On l'ouvre, et il se ferme à la vitesse de l'éclair ; normal.

On va voir ce que ça donne en ligne de commande :
C:\bamcompile1.21\projets\hello>hello.exe

Hello!


La classe, Matias !
Bon, ok, y'a une ligne vide au-dessus de notre phrase, mais on s'en fout pas mal.

Revenons dans le dossier projets, faisons un second dossier nommé age. On va dedans, et on va créer deux fichier :
- main.php (le fichier principal)
<?php
require_once('age.php');
if($_SERVER['argc'] < 2) {
    echo "Utilisation : ".$_SERVER['argv'][0]." [nombre]\n";
    exit(-1);
}
echo AfficherSuivantAge(abs($_SERVER['argv'][1]));
?>


J'explique le code vite fait. On commence par inclure le fichier age.php (qu'on va écrire après), on vérifie qu'on a entré l'argument en ligne de commandes - qui correspond à l'âge d'une personne - et, en suite, on appelle la fonction AfficherSuivantAge() qui sera définie dans le fichier age.php. Enfin, la fonction intval() permet de s'assurer que l'argument sera une valeur numérique, et abs() pour qu'elle soit positive (vous avez déjà vu des gens âgés de -15 ans ? Tss... Menteurs !)

Passons au fichier age.php :
<?php
if(!defined("AGE_PHP")) {
    define("AGE_PHP",TRUE);
    function AfficherSuivantAge($var) {
        return $var >= 18 ? "Tu es majeur" : "Tu es mineur";
    }
}
?>


En bref, je protège le fichier des inclusions multiples (même si ça sert pas à grand-chose ici) et je définis ma fonction. Car, si on définit la fonction avec le même nom plus d'une fois, ça plante ; normal. La fonction retourne une chaîne de caractère :
- "Tu es majeur" si l'âge est supérieur ou égal à 18 ;
- "Tu es mineur" si l'âge est strictement inférieur à 18.

Pour ceux qui ne comprennent pas le principe de l'instruction ternaire, elle consiste à affecter une valeur à une variable suivant une condition. Exemple :
$variable = condition ? "valeur_si_condition_vraie" : "valeur_si_condition_fausse";


Ca me rappelle la terminale, où on faisait du C en électronique logique. J'ai utilisé des instructions ternaires, et le prof m'a sorti "Mais, ça, c'est pas du C !". Enfin, bref. (xD)

Le code équivalent est le même que pour l'exemple ci-dessus :
if(condition)
    $variable = "valeur_si_condition_vraie";
else
    $variable = "valeur_si_condition_fausse";


Une ligne pour l'instruction ternaire ; quatre pour le test de condition ci-dessus. Ca explique pourquoi j'ai choisi l'expression ternaire.

Mais enfin, ne dérivons pas du sujet.

Maintenant, ce que nous allons faire, c'est revenir dans le dossier où se trouve bamcompile.exe. Créons un fichier nommé make_age.bat et mettons-y le code suivant :
@echo off
bamcompile.exe projets/age main.php projets/age/age.exe
pause


En effet, sur le site de bambalam, on nous dit qu'on peut utiliser :
bamcompile [-options] project_directory mainfile.php [outfile.exe]


Par identification :
project_directory = projets/age ;
mainfile.php = main.php ;
outfile.exe (argument optionnel) = projets/age/age.exe

On lance donc notre fichier batch et c'est l'extase (normalement !).

Bambalam PHP EXE Compiler/Embedder 1.21

Mainfile: main.php
Outfile: projets/age/age.exe
Project dir: projets/age

Embedding age.exe
Encoding and embedding age.php
Encoding and embedding main.php

projets/age/age.exe created successfully!
Appuyez sur une touche pour continuer...


On va exécuter age.exe en CLI :

C:\bamcompile1.21\projets\age>age.exe 18
Tu es majeur
C:\bamcompile1.21\projets\age>age.exe 16
Tu es mineur
C:\bamcompile1.21\projets\age>age.exe aaa
Tu es mineur
C:\bamcompile1.21\projets\age>age.exe -4
Tu es mineur
C:\bamcompile1.21\projets\age>age.exe -18
Tu es majeur
C:\bamcompile1.21\projets\age>age.exe 32
Tu es majeur


Ok, le programme n'a pas beaucoup d'intérêt, mais c'est déjà un bon exemple !


J'ai le regret de vous annoncer que le tour de manège est terminé. Disons que cet article m'a occupé à vous présenter un outil que j'adore vraiment (j'ai pu envoyer un exe sympathique à une copine, y'a longtemps) et qui m'amuse toujours autant !

Regardez la section examples, ça vaut le coup. Il y a même un exemple de calculatrice codée avec winbinder - extension PHP pour faire de l'interface graphique. Bref, tout cela pour dire que ça vaut absolument le coup pour ceux qui font des scripts PHP en CLI et qui voudraient les partager avec des utilisateurs qui n'ont pas forcément PHP d'installé sur leur ordinateur.

C'est tout. A la revoyure !

Geo

dimanche 4 janvier 2009

phpsploitclass.php

Télécharger phpsploitclass.php

Je vais commencer en douceur avec un article qui étudiera la classe "phpsploit", codée par darkfig. Il m'a dit, en effet, que seulement trois personnes utilisaient cette classe pour programmer leurs exploits, leurs outils web, etc... Dire qu'avant, je me tapais l'algo à la main pour récupérer la réponse d'un serveur web... Tout ça, c'est terminé. Bien qu'une description anglaise soit inscrite dans le contenu du fichier (car il faut permettre la compréhension aisée à tous), autant expliquer de nouveau quelques notions en français, et de sorte à convaincre les lecteurs !

Je ferai comme si vous possédez PHP 5 en CLI - Commande Line Interface - car c'est avec cet outil que je fais tourner mes scripts. Si vous avez un serveur web, tant mieux, mais je trouve la console plus pratique.

Allez, on commence par inclure la classe (jusque là, rien de compliqué) :
<?php
require_once('./phpsploitclass.php');
?>



Jusqu'ici, rien de compliqué. En explorant le fichier, on voit cette ligne :
class phpsploit {


On fera donc dans notre script :
<?php
require_once('./phpsploitclass.php');
$objet = new phpsploit();
?>


J'imagine que, pour la plupart d'entre vous, vous ayez déjà fait un peu de POO - Programmation Orientée Objet. Par conséquent, vous saurez donc que notre objet possède :
- des attributs : des sortes de variables internes à l'objet. Ces attributs sont généralement privés, et n'ont pas à être modifiés par l'utilisateur ;
- des méthodes : des sous-outils de manipulation de l'objet. Elles sont généralement publiques, mais peuvent être privées (et il y en a, dans la phpsploitclass !).


get()


La première méthode que nous devrions utiliser n'est autre que la méthode get(). Cette méthode ne prend en compte qu'un seul et unique argument : l'adresse source de la page dont on doit récupérer les informations, j'entends par là les en-têtes de réponses ainsi que le contenu HTML. La méthode retourne la réponse du serveur complète.
<?php
require_once('./phpsploitclass.php');
$objet = new phpsploit();
echo $objet->get("http://geo0w.blogspot.com/");
?>

On teste !

C:\php>php phpsploit1.php
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Last-Modified: Sun, 04 Jan 2009 15:05:21 GMT
Cache-Control: max-age=0 private
ETag: "5b0762bd-de9c-4df7-830f-8fe7e1b4f4ef"
Transfer-Encoding: chunked
Date: Sun, 04 Jan 2009 15:07:09 GMT
X-Content-Type-Options: nosniff
Server: GFE/1.3
Connection: Close

7006
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html dir='ltr' xmlns='http://www.w3.org/1999/xhtml' xmlns:b='http://www.google.com/2005/gml/b' xmlns:data='http://www.google.com/2005/gml/data' xmlns:expr='http://www.google.com/2005/gml/expr'>
<head>

[...]


Faites attention, ça risque de défiler à mort dans la console. Utilisez l'opérateur de redirection de flux > pour enregistrer l'echo du script dans un fichier, afin de le consulter. Chez moi, la réponse fait 37Ko et des poussières !

Bref, on a la réponse du serveur.

Codons-nous un outil qui va permettre de récupérer la source d'une page quelconque, l'argument étant fourni en ligne de commande et correspondant à l'URL.

<?php
require_once('./phpsploitclass.php');
if(!empty($_SERVER['argv'][1])) {
    $objet = new phpsploit();
    echo $objet->get($_SERVER['argv'][1]);
} else {
    echo "Utilisation : ".$argv[0]." [url]\n";
}
?>


Et testons.
C:\php>php phpsploit2.php http://www.google.fr/
HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Date: Sun, 04 Jan 2009 15:20:40 GMT
Expires: -1
Content-Type: text/html; charset=ISO-8859-1
Set-Cookie: PREF=ID=584abc4a64322246:TM=1231082440:LM=1231082440:S=Zvx70flgh8_ZY
o5V; expires=Tue, 04-Jan-2011 15:20:40 GMT; path=/; domain=.google.fr
Server: gws
Transfer-Encoding: chunked
Connection: Close

1785
<html><head><meta http-equiv="content-type" content="text/html; charset=ISO-8859
-1"><title>Google</title><style>body,td,a,p,.h{font-family:arial,sans-serif}.h{c
olor:#36c;font-size:20px}.q{color:#00c}.ts td{padding:0}.ts{border-collapse:coll
apse}#gbar{height:22px;padding-left:2px}.gbh,.gbd{border-top:1px solid #c9d7f1;f
ont-size:1px}.gbh{height:0;position:absolute;top:24px;width:100%}#gbi,#gbs{backg
[...]


On peut désormais récupérer le couple en-têtes de réponses + source de n'importe quelle page, à condition que celle-ci soit disponible. Bref, vous m'avez compris.


post()


Quasiment pareille que la méthode get(). Cependant, celle-ci prendra deux arguments :
- La page cible de la requête post - jusqu'ici, rien de différent de get() ;
- Les données à envoyer, codées sous la forme attribut1=valeur1&attribut2=valeur2...

Un exemple vaut mieux qu'un discours à l'arrache. Faisons un script php qui va s'attendre à recevoir des données postées (celui-là, il sera à mettre sur votre serveur web) :

<?php
if(!empty($_POST)) {
    echo "Tu as posté :\n";
    readfile("php://input");
} else {
    echo "Tu n'as rien posté.";
}
?>


On enregistre sous target.php et on suppose qu'on y a accès à l'URL http://localhost/target.php. Voici, par conséquent, un exemple de script à exécuter sous CLI :

<?php
require_once('./phpsploitclass.php');
$objet = new phpsploit();
echo $objet->post("http://localhost/target.php","pseudo=Geo&pass=superpapi");
?>


On teste sur la console !
C:\php>php phpsploit3.php
HTTP/1.1 200 OK
Date: Mon, 05 Jan 2009 12:30:21 GMT
Server: Apache/2.2.6 (Win32) PHP/5.2.5
X-Powered-By: PHP/5.2.5
Content-Length: 39
Connection: close
Content-Type: text/html

Tu as posté :
pseudo=Geo&pass=superpapi


Magie, magie ! \o/
On passe à la vitesse supérieure.


addcookie(), agent(), addheader()


Deux fonctions très importantes. Elles permettent de bricoler notre requête HTTP.

La fonction addcookie() attend deux paramètres, représentant respectivement la variable et sa valeur. Exemple :
<?php
require_once('./phpsploitclass.php');
$obj = new phpsploit();
$obj->addcookie('admin',1);

// On peut faire nos requêtes...
$reponse = $obj->get("http://localhost/page.php");
// etc...
?>


De ce fait, à chaque fois que l'on visitera des pages via get() ou post(), le cookie sera inséré dans les en-têtes. Vous pouvez, bien sûr, appelez la fonction addcookie() autant de fois que nécessaire.

La fonction agent() spécifie une valeur pour le champ User-Agent de votre requête HTTP. Cela sert à préciser un navigateur avec lequel vous visitez la page. Une sorte de falsification ; il existe, en effet, des sites qui ne répondent aucun code HTML quand le champ User-Agent est vide ou inexistant. La fonction prend un argument : la valeur d'User-Agent que vous souhaitez. Exemple d'utilisation :

<?php
require_once('./phpsploitclass.php');
$obj = new phpsploit();
$obj->agent("Mozilla Firefox");

// On peut faire nos requêtes...
$reponse = $obj->get("http://localhost/page.php");
// etc...
?>


La fonction addheader() permet de rajouter une en-tête dans votre requête. Elle prend deux arguments, qui sont respectivement le titre de l'en-tête et sa valeur.

<?php
require_once('./phpsploitclass.php');
$obj = new phpsploit();
$obj->addheader("X-Forwarded-For","127.0.0.1");
$obj->addheader("Referer","http://www.google.fr");

// On fait nos requêtes, ...
?>


Note : Bien que des méthodes permettant de manipuler les cookies ainsi que l'User-Agent soient implémentées, il ne nous est pas interdit de faire :
$obj->addheader("User-Agent","Mozilla Firefox");
$obj->addheader("Cookie","PHPSESSID=UnSuperPHPSESSIDPasTresCorrect; admin=1; pseudo=Geo");


On se rend compte que la classe est complète, et ce n'est pas fini. Si je devais la présenter entièrement, je n'en finirais pas.


reset()


Il est important de parler de cette méthode. Elle prend soit 0 argument, soit un. Lorsqu'elle n'en reçoit aucun, elle réinitialise les headers, les cookies et d'autres paramètres. L'appeler ? C'est facile :
$obj->reset();



Conclusion ?


Cet article avait pour but de vous sensibiliser. Je reconnais quand même que je suis allé un peu loin en parlant de plusieurs méthodes implémentées dans l'objet phpsploit. Il y en a d'autres :
- Méthode permettant de récupérer le contenu de Set-Cookie dans la réponse du serveur ;
- Méthode permettant d'afficher les en-têtes uniquement ou le contenu HTML uniquement ;
- Méthode permettant d'uploader un fichier ;
- ...

N'hésitez pas à lire dans phpsploitclass.php, tout y est expliqué en anglais, et simplement.

Si vous voulez un exemple d'exploit web implémenté qui utilise phpsploit, je vous redirige sur cette adresse :
http://venom630.free.fr/geo/tutz/securite_informatique/injections_sql_imbriquees/.
Je vous préviens, je n'avais pas de correcteur orthographique, donc le contenu est peut-être un peu caca à certains endroits.

Je vous laisse, je vais réviser mon éco-droit pour demain. :(
J'espère que cela vous a plu.

Geo