Clave Única es un sistema desarrollado por el gobierno chileno para autenticar y autorizar a los ciudadanos a usar una variedad de servicios gubernamentales. Según su documentación técnica usa OpenID Connect 1.0 y también se describe su funcionamiento interno en detalle.

Desde el punto de vista legal, hay un documento especificando su alcance. Cito como se estipula en la sección V. CONCLUSIONES..

La utilización de “ClaveÚnica” tendrá la misma validez y efectos jurídicos que

tendría si los actos, contratos o declaraciones fueran efectuados por escrito y suscritos

a través de una firma manuscrita.

Entonces, cualquier vulnerabilidad que presente no solo afecta a un ciudadano como un usuario dentro de un sistema, sino que también puede tener efectos legales que lo perjudiquen. En esta investigación describiré una serie de vulnerabilidades en la plataforma Clave Única, las cuales tras ser reportadas no han sido completamente solucionadas.

PD: Siendo que no soy experto en OpenID Connect, cualquier corrección es bienvenida.

Petición de ejemplo

Cada servicio crea una petición acorde a la información que necesita, por lo tanto todas las peticiones hacia Clave Única no son iguales. Lo que si, hay algunos campos que son comunes como (más información puede ser consultada aquí):

openid.identity: http://specs.openid.net/auth/2.0/identifier_select

openid.assoc_handle: valor generado por el servicio gubernamental para autenticar que la petición fue realizada por él. Corresponde al paso 1 de la guía.

openid.return_to: URL a la que Clave Única devuelve el control después de una autenticación correcta.

openid.realm: parámetro opcional que define el dominio.

openid.mode: checkid_setup

openid.ns: http://specs.openid.net/auth/2.0

Por lo visto, la información requerida sobre el ciudadano se agrega al namespace openid.ns u openid.ax . En ejemplo, se tomará la petición creada por un sitio del Indap a Clave Única.

https://www.claveunica.cl/autenticacion/openid?openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.assoc_handle=5149ecec9e5cbaa36eeb4aae0a8ea403da5fbe5b&openid.return_to=http%3A%2F%2Fmi.indap.cl%2Findex.aspx%3Fdnoa.userSuppliedIdentifier%3Dhttps%253A%252F%252Fwww.claveunica.cl%252Fautenticacion%252Fopenid&openid.realm=http%3A%2F%2Fmi.indap.cl%2F&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.ns.alias3=http%3A%2F%2Fopenid.net%2Fsrv%2Fax%2F1.0&openid.alias3.required=alias1&openid.alias3.mode=fetch_request&openid.alias3.type.alias1=http%3A%2F%2Faxschema.org%2Fperson%2Fguid&openid.alias3.count.alias1=1

Vulnerabilidades

Este reporte resume una serie de vulnerabilidades. Primero, los casos de Cross Site Scripting (XSS) en la página de ingreso de credenciales son críticos ya que un atacante podría usurpar el usuario y contraseña ingresados.

XSS a través del parámetro openid.return_to

Si no está presente el parámetro openid.realm , openid.return_to es reflejado en la página https://www.claveunica.cl/autenticacion/openid , siendo posible inyectar código HTML y Javascript. Reemplazando en nuestra petición de ejemplo ambos parámetros con:

openid.return_to=http%3A%2F%2Fexample.org%2F<script>alert('test')</script>

Se explota correctamente la vulnerabilidad.

XSS a través del parámetro openid.realm

El parámetro openid.realm es reflejado en la página https://www.claveunica.cl/autenticacion/openid , siendo posible inyectar código HTML y Javascript. Sin embargo, no es tan simple como poner nuestro vector de ataque sino que hay una relación entre openid.realm y openid.return_to , la cual es:

openid.realm debe estar contenido en openid.return_to .

Entonces, enviando ambos parámetros iguales podemos explotar la vulnerabilidad:

openid.return_to=http%3A%2F%2Fexample.org%2F<script>alert('test')</script>&openid.realm=http%3A%2F%2Fexample.org%2F<script>alert('test')</script>

XSS a través de ns data

Por lo que entiendo, el namespace openid.ns se utiliza para describir qué datos del ciudadano necesita saber el servicio. Por ejemplo, el sitio del Indap solicita esta información:

openid.ns.alias3=http%3A%2F%2Fopenid.net%2Fsrv%2Fax%2F1.0&openid.alias3.required=alias1&openid.alias3.mode=fetch_request&openid.alias3.type.alias1=http%3A%2F%2Faxschema.org%2Fperson%2Fguid&openid.alias3.count.alias1=1

Lo cual se refleja en la página https://www.claveunica.cl/autenticacion/openid como:

<input type="hidden" name="attributes[person/guid]" value="1" />

Luego de un análisis, el parámetro openid.alias3.type.alias1 no es correctamente incrustado y se da un caso de Cross Site Scripting. Un vector de ataque exitoso sería reemplazar el parámetro por:

openid.alias3.type.alias1=http%3A%2F%2Faxschema.org%2Fperson%2Fguid"><script>alert("test")</script><!--

El mismo tipo de escenario se da con los datos declarados a través de openid.ax como en la petición generada por la Fiscalía Nacional Económica.

Falta de cifrado en openid.redirect_to

Si bien la guía recalca el uso de HTTPS, Clave Única no fuerza a que el parámetro openid.redirect_to use HTTPS, pudiendo utilizar HTTP. El flujo en el escenario anteriormente mencionado se puede graficar como:

Esto posibilita que un atacante haciendo un ataque man-in-the-middle no será capaz de leer el contenido de la petición HTTPS desde el servicio a Clave Única, pero si podrá leer la petición desde Clave Única al servicio y que contiene el código de acceso.

Este caso se encuentra en páginas como Indap que tiene una página de retorno en HTTP: openid.return_to=http://mi.indap.cl/index.aspx

Falta de token de estado

El primer paso de la guía es sobre la creación de un token de estado, sin embargo Clave Única no fuerza su requerimiento. Un ejemplo de esto es la oficina virtual del SAG que en su petición a Clave Única no envía un token de estado (no existe el parámetro openid.assoc_handle ).

Generación de error y divulgación de software

Una petición quitando los parámetros openid.identity y openid.assoc_handle generó los siguientes errores:

A PHP Error was encountered Severity: Notice Message: Undefined index: openid_identity Filename: LightOpenIDProvider/provider.php Line Number: 346

Tomando en cuenta el tipo de error, nombre de fichero y línea, podemos darnos cuenta que Clave Única está usando LightOpenID como biblioteca para gestionar el uso de OpenID. Esto abre la posibilidad de encontrar más vulnerabilidades leyendo el código fuente.

Mitigaciones y Timeline

Esta serie de vulnerabilidades fueron reportadas con la ayuda del CSIRT. Ellos permitieron que mi reporte llegara a los desarrolladores, los cuales no establecieron contacto directo conmigo.

Los casos de Cross Site Scripting fueron parcialmente solucionados con una especie de firewall web (o biblioteca) que filtra y sanitiza ciertos vectores comunes, demostrando el poco entendimiento de cómo solucionar este tipo de vulnerabilidades. La página sigue siendo vulnerable pero momentaneamente no explotable gracias a esta solución de firewall web. Sin embargo, nuevos vectores pueden aparecer a largo plazo que esquiven las reglas del firewall web y la explotación de la vulnerabilidad vuelva a ser exitosa.

Los restantes problemas son producto del no seguimiento de sus propias políticas y la incorrecta configuración de sus servidores. Al parecer no revisten importancia ya que no fueron solucionados.

Hay una serie de cosas que no fueron notificadas, como por ejemplo el hecho de que uno puede autentificar un dominio propio con Clave Única. Si bien no es tan simple como obtener un token en un dominio propio y luego enviarlo a cualquier servicio, esto podría encadenarse con otros errores para dar paso a una vulnerabilidad más ingeniosa.

El tiempo que demoraron en solucionar lo reportado fue alrededor de dos semanas y agradezco la forma eficiente y rápida en que el CSIRT manejo la notificación.