0xtceb's lab
Sécurité informatique, inventions (surtout) tordues, et fun
Archives du blog
vendredi 12 avril 2013
IO level5
Nous voici arrivé au level5, un nouveau binaire avec ses sources nous est livré :
Nous remarquons d'entrée de jeu qu'il s'agit ici d'un buffer overflow classique. Un tableau se remplis grâce à l'argv mais le programme ne vérifie absolument pas la taille de l'argument. Je vais un peu passer sur certaines explication, par pure flemme et parce-qu'un article détaillant le fonctionnement de cette faille est présent sur ce blog !
Vu que GDB ajoute du padding, la solution est soit de bruteforcer la bonne adresse d'execution du shellcode ou simplement d'y aller a tâtons :
Moralité : toujours tester ce qui est rentré dans un tableau !
jeudi 22 novembre 2012
IO level4
Ce niveau est bien plus basique que les précèdents.
Voici ses sources :
Voici la tête du binaire une fois exécuté :
La faille ici se situe dans l'utilisation de la fonction System. En effet, cette fonction lance /bin/sh avec en paramètre n'importe quelle commande unix passée en chaîne de caractères, le problème, c'est que pour trouver ces dites commandes, Linux va chercher leurs correspondances dans les variables d'environnements, plus particulièrement la variable PATH qui contient les dossiers dans lesquels le shell va chercher ses commandes. Si un utilisateur mal intentionné se mettait a changer la valeur de PATH, il pourrait alors contrôler n'importe quelle exécution de commande shell...
Voici la fameuse variable PATH de ce level :
donc ici, System envoie la commande "id" au shell, si le shell ne trouve pas "id" dans "/usr/local/bin" , il cherchera dans le dossier suivant listé dans PATH, a savoir : /usr/bin et ainsi de suite...
Pourquoi System est faillible ?
-Parce-que PATH est modifiable par les utilisateurs
-Parce-que SYSTEM lance un shell avec les privilèges du programme lancé
-Parce-que Shell peut exécuter à peut près tout et n'importe quoi.
Nous allons donc créer un dossier dans un répertoire inscriptible ( /tmp ), dans ce dossier nous allons écrire un fichier nommé "id" avec une commande pour lire le mot de passe du niveau suivant , lui donner les droits d'écriture, lecture, exécution a tout les utilisateurs et faire pointer la variable PATH vers lui :
Modification de la variable PATH :
Voici donc le premier dossier dans quoi le shell devrait aller chercher notre nouvelle commande =) :
Lancement du binaire :
Moralité : NE JAMAIS UTILISER SYSTEM ! Utilisez plutôt de execl() ou execve().
lundi 29 octobre 2012
IO level3
Je préviens, cet article est un spoiler du level3 de IO
Nous voici donc au level3, nous sommes d'ailleurs encore en présence d'un binaire livré avec ses sources.
Analysons tout ça..
Un pointeur de fonction qui prend comme adresse celle de "bad", une fonction "good" qui nous donne le shell gagnant, une copie d'argument dans un buffer, si la taille de l'argument est inférieure à 4 alors le programme "ret" (pourquoi pas...) et..On nous affiche l'adresse des deux fonctions "bad" et "good".
On remarque que la copie dans le buffer n'est pas du tout vérifiée, on peut donc conclure a une faille type buffer overflow =)
Nous pouvons en effet voir que le nombre de bytes que nous copions dans le buffer ne dépends que de la taille de l'argument. Le programme ne vérifie en aucun cas si la taille de la variable est inférieure à celle de l'espace censé le contenir. Donc, si nous envoyons plus de données qui ne peut en être stockée dans le buffer, memcpy va simplement se contenter de réécrire par dessus le reste de la mémoire et de la pile du programme jusqu'à ce que le paramètre soit entièrement copié... Donc nous pouvons nous servir de ce bug pour contrôler et réécrire la donnée contenant la valeur de "functionpointer" et ainsi lancer la fonction "good".
Tout d'abords, ouvrons GDB et récupérons l'adresse de "good"
N'oublions pas qu'on est sur une architecture linux x86 donc le format des adresses est en little endian
0x8048474 = \x74\x84\x04\x08
Continuons avec notre analyse, voici le main désassemblé :
Lançons le programme avec un argument et examinons l'état de la pile :
Nous remarquons donc que nos "a" rentrés en paramètres sont bien présent (0x61616161)
On peut conclure que le buffer commence en 0xbffffdc80 et en analysant le reste des données on aperçoit une valeur familière, celle de "bad" : 0x080484a4 qui commence en 0xbffffdccc !
Une simple soustraction nous donne la taille exacte du buffer :
Donc pour écraser totalement l'adresse de la fonction "bad" et la remplacer par "good" il nous faut un paramètre d'une taille de 76 bytes ainsi que l'adresse qu'on a récupéré un peu avant : \x74\x84\x04\x08
Notez que pour me simplifier la vie j'utilise du python ou du perl parfois afin de pas passer une éternité a écrire 76 "a" =)
Moralité : Toujours vérifier la copie d'argument dans un buffer, cela peut mener a un joli stack-based buffer overflow comme celui-ci... (Evidemment des protections contre ce genre d'attaques existent depuis un moment.. Mais parfois cela ne suffit pas toujours...)
Un peu de lecture sur les protections utilisées de nos jours contre ces attaques :
dimanche 28 octobre 2012
IO level2
Je préviens, cet article est un spoiler au level2 de IO
Donc, arrivé au niveau2 la suite logique des évènements est de tester le binaire, mais cette fois-ci on nous livre les sources avec !
Notre programme nous conseille juste de lire son code qui se trouve dans le même dossier "level02.c"
Le voici :
Ça parait un peu plus évident maintenant. On remarque la fonction catcher qui lance notre message de congratulation habituel suivit d'un shell level3 seulement la fonction n'est lancée qu'au moment où le signal SIGFPE est levé. Ce dernier apparaît lorsqu'on amène l'ordinateur a faire une division par zéro ou qu'on dépasse un entier maximal (vous vous souvenez sur vos calculettes lorsque que vous faisiez 10 puissance 9999999999999 ?)
Et comme ici il se trouve que justement on a une division alors on pourrait se débrouiller pour faire planter le programme et ainsi, lever le signal SIGFPE.
Le calcul retourne la valeur absolue du premier paramètre divisé par le deuxième on pourrait croire qu'on peut faire notre division par 0 mais la présence d'un contrôle sur l'argv[2] nous en empêche.
La solution ici est donc de réaliser un integer overflow, c'est à dire un dépassement d'entier.
Tout d'abords il nous faut trouver la valeur maximale et minimale qu'un entier peut prendre :
Et là c'est plutôt une bonne nouvelle, il se trouve qu'on peut effectivement faire un integer overflow =)
si jamais je divise -2147483648 (qui est bien un entier minimal) par -1 il deviendra plus grand que l'entier maximal et alors, le système pourra lever le signal SGFPE qui lancera le shell !
Moralité, ben...Juste faire gaffe avec les divisions..
Donc, arrivé au niveau2 la suite logique des évènements est de tester le binaire, mais cette fois-ci on nous livre les sources avec !
Notre programme nous conseille juste de lire son code qui se trouve dans le même dossier "level02.c"
Le voici :
Ça parait un peu plus évident maintenant. On remarque la fonction catcher qui lance notre message de congratulation habituel suivit d'un shell level3 seulement la fonction n'est lancée qu'au moment où le signal SIGFPE est levé. Ce dernier apparaît lorsqu'on amène l'ordinateur a faire une division par zéro ou qu'on dépasse un entier maximal (vous vous souvenez sur vos calculettes lorsque que vous faisiez 10 puissance 9999999999999 ?)
Et comme ici il se trouve que justement on a une division alors on pourrait se débrouiller pour faire planter le programme et ainsi, lever le signal SIGFPE.
Le calcul retourne la valeur absolue du premier paramètre divisé par le deuxième on pourrait croire qu'on peut faire notre division par 0 mais la présence d'un contrôle sur l'argv[2] nous en empêche.
La solution ici est donc de réaliser un integer overflow, c'est à dire un dépassement d'entier.
Tout d'abords il nous faut trouver la valeur maximale et minimale qu'un entier peut prendre :
Et là c'est plutôt une bonne nouvelle, il se trouve qu'on peut effectivement faire un integer overflow =)
si jamais je divise -2147483648 (qui est bien un entier minimal) par -1 il deviendra plus grand que l'entier maximal et alors, le système pourra lever le signal SGFPE qui lancera le shell !
Moralité, ben...Juste faire gaffe avec les divisions..
IO level01
Bon, je préviens tout de suite cet article est un spoiler du level1 de IO (j'ai laissé tombé quelque temps la sécurité, et comme je reprends tout juste je me refais la main sur les bases et sur ma façon d'écrire mes articles =) )
Ici, nous sommes donc niveau 1 (oui y'a encore pas mal de route à faire...)
Dans le dossier /levels se trouvent les binaires faillibles du serveur. Comme nous sommes au niveau 1 nous ne pouvons que lancer level01.bin ! Testons :
Bon.. Apparemment ils ont pas changé le type de l'épreuve mais ils l'ont améliorés. Avant il était juste possible de passer ce niveau en lançant une commande "strings" pour lire les chaînes contenues dans le programme et y trouver notre mot de passe. Ici cette technique un peu bancale ne fonctionnera pas..
Ouvrons le avec GDB pour examiner ses entrailles :
La première chose que l'on remarque c'est la présence de la fonction "pass" en main+52 pas besoin de regarder autour, il ne s'agit après tout ici que du level1 et le nom est assez évident... ;)
Explorons plus en détail cette fonction :
On remarque le passage de 8 variables en mémoire, c'est notre mot de passe :
Mot de passe du binaire : SecretPW
Moralité (même si vous vous en doutez déjà), ne mettez jamais en dur un mot de passe dans n'importe quel programme que ce soit, ça reste réversible et dangereux.
Dans le dossier /levels se trouvent les binaires faillibles du serveur. Comme nous sommes au niveau 1 nous ne pouvons que lancer level01.bin ! Testons :
Bon.. Apparemment ils ont pas changé le type de l'épreuve mais ils l'ont améliorés. Avant il était juste possible de passer ce niveau en lançant une commande "strings" pour lire les chaînes contenues dans le programme et y trouver notre mot de passe. Ici cette technique un peu bancale ne fonctionnera pas..
Ouvrons le avec GDB pour examiner ses entrailles :
La première chose que l'on remarque c'est la présence de la fonction "pass" en main+52 pas besoin de regarder autour, il ne s'agit après tout ici que du level1 et le nom est assez évident... ;)
Explorons plus en détail cette fonction :
On remarque le passage de 8 variables en mémoire, c'est notre mot de passe :
Mot de passe du binaire : SecretPW
Moralité (même si vous vous en doutez déjà), ne mettez jamais en dur un mot de passe dans n'importe quel programme que ce soit, ça reste réversible et dangereux.
vendredi 4 mai 2012
Universe
Voila un moment que je n'ai pas écrit d'article sur mon blog.. Faute de temps !
Je peux vous annoncer que mes algorithmes sont fonctionnels et que mon travail d'équipe, bien qu'infructueux fût intéressant.
Je veux vous faire part d'une avancée majeure dans l'avenir du jeu sur internet. Cette avancée, subventionnée ou non, s'appelle "UNIVERSE". Ok ça fait un peu électro comme trouvaille mais le concept est là.
Je vous demande un peu de patience supplémentaire pour pouvoir vous faire découvrir mon prochain projet de développement. En HTML5 (donc multiplateforme), multijoueur, mêlant rpg, action shooter, real time strategy et j'en passe...
Je peux vous annoncer que mes algorithmes sont fonctionnels et que mon travail d'équipe, bien qu'infructueux fût intéressant.
Je veux vous faire part d'une avancée majeure dans l'avenir du jeu sur internet. Cette avancée, subventionnée ou non, s'appelle "UNIVERSE". Ok ça fait un peu électro comme trouvaille mais le concept est là.
Je vous demande un peu de patience supplémentaire pour pouvoir vous faire découvrir mon prochain projet de développement. En HTML5 (donc multiplateforme), multijoueur, mêlant rpg, action shooter, real time strategy et j'en passe...
mardi 24 janvier 2012
Pause du blog
M'étant récemment mis sur un projet de "grande" envergure à la fois personnelle et professionnelle (bon ok j’exagère peut être un peu ) je me suis absenté de la sphère du blogging et de la sécurité pour une petite période encore...Ça me déplaît autant à moi qu'à vous. Ayant un emploi du temps assez chargé en ce moment je ne peux plus me permettre de mettre à jour mon blog :/
Pour vous faire une petite idée de ce sur quoi je travaille en ce moment,
il s'agit d'un algorithme léger d'amélioration d'image (autre qu'un filtre de bell ou de lanczos qui restent pas mal mais souvent trop lents pour l'utilisation que je veux en faire) , qui pourrait être utilisé à l'upload sur des sites qui proposent d'afficher des photos, je suis aussi actuellement sur deux ou trois projets qui sont donc liés à cette idée ce qui génère une masse de travail(fun) supplémentaire dans mon boulot de barbus.
J'ai aussi réuni une petite équipe pour bosser autour d'un concept (voir plus haut) qui pourra avoir le succès escompté :
Jeremy Castan , Romain Menard et Jean Daniel Boutet m'accompagneront donc dans cette petite expérience que je mettrais en ligne dans quelques mois, nous miserons sur un lancement du tonnerre de dieu !
A très bientôt j'espère !
Pour vous faire une petite idée de ce sur quoi je travaille en ce moment,
il s'agit d'un algorithme léger d'amélioration d'image (autre qu'un filtre de bell ou de lanczos qui restent pas mal mais souvent trop lents pour l'utilisation que je veux en faire) , qui pourrait être utilisé à l'upload sur des sites qui proposent d'afficher des photos, je suis aussi actuellement sur deux ou trois projets qui sont donc liés à cette idée ce qui génère une masse de travail(fun) supplémentaire dans mon boulot de barbus.
J'ai aussi réuni une petite équipe pour bosser autour d'un concept (voir plus haut) qui pourra avoir le succès escompté :
Jeremy Castan , Romain Menard et Jean Daniel Boutet m'accompagneront donc dans cette petite expérience que je mettrais en ligne dans quelques mois, nous miserons sur un lancement du tonnerre de dieu !
A très bientôt j'espère !
Inscription à :
Articles (Atom)