cabecera blog BlackArrow

De exploit N-day a Kerberos EoP en entornos Linux

Introducción

En una de sus operaciones, el Red Team logra la ejecución de comandos en una página web perimetral, como usuario no privilegiado. En este artículo describe el análisis y explotación de una vulnerabilidad (CVE-2018-1685) que permite la lectura arbitraria de ficheros, pero de la que no se conocen detalles públicos. Finalmente, se expondrá un método para convertir este tipo de vulnerabilidades (lectura de ficheros) en el compromiso total del sistema (ejecución de comandos), en caso de máquinas Linux integradas en Directorio Activo mediante Kerberos.

Vulnerabilidad de elevación de privilegios (EOP)

La máquina comprometida, se trata de un servidor Red Hat actualizado, por lo que se descarta la elevación de privilegios mediante un exploit de kernel. Tras las típicas comprobaciones rutinarias, se detectan varios ejecutables con SUID, propiedad del usuario “root”:

 /home/db2test/sqllib/adm:
 total 5.3M
 drwxr-sr-x.  2 db2test db2test  112 Oct  8 10:29 .
 drwxrwsr-t. 19 db2test db2test 4.0K Oct  8 10:32 ..
 -r-sr-xr-x.  1 db2test db2test 152K Oct  8 10:29 db2audit
 -r-

s

r-xr-x.  1 root    db2test  19K Oct  8 10:29 

db2cacpy

 -r-xr-xr-x.  1 db2test db2test 195K Oct  8 10:29 db2cap
 -r-

s

r-x---.  1 root    db2test  32K Oct  8 10:29 

db2iclean

 -r-

s

r-x---.  1 root    db2test  87K Oct  8 10:29 

db2licm

 -r-xr-xr-x.  1 db2test db2test 120K Oct  8 10:29 db2set
 -r-sr-sr-x.  1 db2test db2test 4.7M Oct  8 10:29 db2trc    

El usuario “db2test” parece estar relacionado con una instalación de pruebas de DB2, un sistema de gestión de bases de datos de IBM. Tras una rápida búsqueda en Google, se encuentra un boletín de seguridad relacionado con uno de estos ejecutables (db2cacpy), publicado por el fabricante.

CVE-2018-1685 description
Descripción CVE-2018-1685
Workarounds and Mitigations
Workarounds y mitigaciones

A pesar de que no se ofrecen detalles de la vulnerabilidad, se pueden destacar dos pistas interesantes:

  • Permite a un usuario local leer cualquier fichero del sistema.
  • En la sección de «Workarounds», se indica que al borrar este binario se perderá la capacidad de añadir nuevos puertos al fichero /etc/services, cuando se agregan nuevas bases de datos utilizando el «Asistente de configuración».

Con esta información en mano, el Red Team procede a la búsqueda del fallo.

CVE-2018-1685: en busca de la vulnerabilidad

Lo primero es descargar el ejecutable para poder analizarlo localmente. Además, es necesario descargar también unas 10 librerías de DB2, para poder hacer funcionar la herramienta.

Tras un análisis estático inicial, podemos desentrañar su funcionamiento. El binario recibe 2 argumentos por línea de comandos, sobre los que realiza una comprobación para cada uno de ellos, antes de que el programa continúe.

Primer check

Se comprueba, de forma un tanto ofuscada, que este primer argumento corresponda con una clave que podemos encontrar en texto claro en el segmento “.rodata”.

First check disassembly
Decompilado del primer check

Segundo check

En este caso, se comprueba que el segundo argumento comience con la cadena /tmp/services., probablemente porque algún otro componente de DB2 genera archivos que siguen este patrón.

Decompilado del segundo check
Decompilado del segundo check

Vulnerabilidad

Si estas dos comprobaciones se cumplen, la herramienta copia el fichero indicado (en el segundo parámetro) a /etc/services, sobrescribiéndolo. Un posible pseudocódigo, simplificado, podría ser el siguiente:

func main(argc, argv[]) {
   init_db2()

   if (argc is 3)
   {
      if (argv[1] equals HARDCODED_KEY) {
         if (argv[2] startsWith "/tmp/services.") {
            copy_file(argv[2], "/etc/services")
         }
      }
   }
}

¿Cómo aprovechar esto para leer ficheros arbitrarios? A través de path traversal. Si en /tmp creamos un directorio “services.” (o que comience así), podríamos por ejemplo desencadenar la copia del fichero /tmp/services./../../etc/shadow, cumpliendo el segundo check.

En este repositorio podéis encontrar un exploit funcional, que además se encarga de restaurar el fichero /etc/services original tras la explotación. Es posible que la clave (primer check) varíe dependiendo de la versión o instalación de DB2 (no hemos podido comprobarlo).

Lectura del fichero /etc/shadow
Lectura del fichero /etc/shadow

De lectura arbitraria a ejecución como root

Al tratarse de un servidor Linux integrado en Directorio Activo mediante Kerberos, lo primero que se hace es comprobar si en /tmp hay TGTs (ficheros ccache) vigentes (para su reutilización), pero todos se encuentran caducados. Por tanto, se busca una vía que no depende de la interacción de los usuarios: el archivo keytab.

En el keytab siempre se encuentran las claves de la cuenta de máquina (por defecto /etc/krb5.keytab en Red Hat). Las claves de una cuenta de máquina, se pueden aprovechar para forjar tickets para sus servicios (TGS).

Para extraer las claves del keytab, se hace uso de un script conjuntamente con el exploit de DB2.

Extracción de claves del keytab
Extracción de claves del keytab

A continuación, mediante la utilidad ticketer.py de impacket se construye un TGS para el servicio SSH del propio servidor (SPN “host”) a nombre de un usuario del dominio que tenga privilegios de administración en la máquina.

Forja de un TGS de kerberos a nombre de un administrador del servidor
Forja de un TGS a nombre de un administrador del servidor

Finalmente, se utiliza el ticket generado para conectar vía SSH, autenticando mediante Kerberos.

Ejecución de comandos como root
Ejecución de comandos como “root”

Conclusión

En este artículo, hemos visto cómo un atacante puede aprovecharse de un fallo conocido, para el cual no existe exploit o detalles públicos. Por ello, es importante incidir en la temprana aplicación de todo parche de seguridad y no sólo cuando el exploit sale a la luz (un ejemplo de esto es la publicación de Zerologon, donde las empresas no vieron la criticidad del mismo hasta que el exploit circulaba por GitHub, meses después).