Escalado de privilegios – Apache/OHS, permisos y granularidad insuficiente
16/12/2015 -
El errante viaje del profesional que se dedica a la consultoría esta repleto de curiosidades, poder ver tantas casas diferentes, métodos, preocupaciones y un sinfín de quehaceres hace que las pequeñas partes homogéneas resalten dentro de esa heterogeneidad. Normativas, estándares, auditorías de seguridad, cada cual más ensortijada.
En lo que a la parte de seguridad atañe, la costumbre más global es:
- Acceso root prohibido.
- Auditar todos los accesos o “switch” entre usuarios.
- Guardar todo el historial.
- Bits uid, gid, desactivados (muchas veces no puedes ni usar el ping).
- Particiones “comunes” montadas con noexec.
- etc.
La mayoría de estos aspectos son razonables, de hecho, particularmente opino que todavía podría elevarse el modo “paranoico”; pero en muchas ocasiones los árboles no nos dejan ver el bosque. En abundantes sistemas nos podemos encontrar que por un lado, se lleva una excelente tarea de auditoría, prevención y seguridad, pero por el otro se descuidan aspectos muy básicos: las ‘capabilities‘ de seguridad que nos proporciona el sudo y su dejada configuración.
Desventuradamente he tenido la ocasión de encontrarme, de manera recurrente, una configuración insuficientemente granulada de las reglas de sudo que permiten autenticas “atrocidades”; éstas quizá pueda atribuirse a descuidos, desidia, comodidad, desconocimiento…
Presentamos un escenario real, donde un usuario sin prácticamente permisos, puede llegar a maximizarlos de una manera mayúscula a partir de una mala configuración del sudoers.
Como de costumbre, adentrémonos a la parte práctica:
Sistema con usuario de servicio sin privilegios (o por ejemplo, operador), sin posibilidad de root, en una máquina con un apache corriendo por el puerto 80, sin privilegios para modificar la configuración del servicio pero con la posibilidad de levantar, parar o reiniciar el proceso.
La primera cosa sobrante a destacar, es que se debería evitar utilizar servicios que tengan que asociarse a puertos privilegiados (inferiores a 1024) ya que esto obliga a levantar el proceso de escucha con usuario privilegiado; maneras de evitarlo hay varias, establecer una capa frontal con un balanceador (o similar), mapeo de puertos, iptables, etc.
Comprobamos como está el apache (httpd):
Vemos que el proceso padre con PID 1725 está levantado con un uid de root y los procesos hijo como apache. Esto es necesario, como se ha comentado, para poder hacer el bind al puerto 80:
No tenemos privilegios para modificar la configuración original del apache:
Para poder arrancar, parar, reiniciar (entre otros) el proceso tenemos asignada la regla de sudo siguiente:
Y aquí está el gran problema! Factor muy peligroso, el uso del asterisco-wildcard como comodín en el sudo.
Esto nos permite ejecutar, como root, el binario /usr/sbin/httpd y todo lo que venga detrás. La configuración radica en que el httpd acepta unas cuantas combinaciones posibles para gestionarlo: start, restart, graceful, graceful-stop y stop; son las únicas que deberíamos tener derecho. Y seguir el principio del mínimo privilegio.
Vamos a ver como podemos aprovechar esa ocasión. Si miramos las opciones que tenemos:
Vamos a centrarnos con las opciones que nos permitan aprovechar el binario del httpd con la regla de sudo existente, una de las que llama la atención es la de file:
Como hemos mencionado, no podemos modificar la configuración original del Apache, pero con la opción “-f” podemos especificar un fichero de configuración alternativo, que podemos ubicar en cualquier directorio donde si tengamos permisos y hacer que el httpd lo cargue. ¿Tenemos permiso para ello? Por supuesto! El sudo, al utilizar el asterisco nos permite pasarle cualquier parámetro al proceso.
De manera opcional, podemos hacer una copia del httpd.conf original en el directorio home del usuario (o en el que sea):
Con la opción “-f” podremos indicar un fichero de configuración alternativo para el httpd, que será el que hemos ubicado en nuestra home, pero ¿que hacemos con él? ¿Cómo podemos aprovechar esta opción?
De entrada, al utilizar el sudo, nos permitirá levantar el servicio de Apache donde el proceso padre será root con la configuración que nosotros le proporcionemos. Cuando el proceso padre levanta, carga la configuración, donde parte de ella encontramos la carga de los módulos dinámicos (shared objects):
Esos módulos son procesados y ejecutados por el proceso padre, y cada uno tiene un sinfín de posibilidades que permiten al Apache dotarse de una gran potencia y versatilidad.
Aprovecharemos el flujo de ejecución del proceso de root, para crear un modulo propio que nos permita explotar el escenario y poder escalar privilegios.
Para desarrollar y compilar el modulo necesitaremos el binario apxs (APache eXtenSion tool). Si no lo tenemos en la máquina podemos descargar las fuentes de Apache y compilarlas, y en caso de no tener herramientas de compilación podemos construir el modulo en otra máquina que si podamos y subir el .so resultante. Se recomienda la lectura de la página oficial para la programación de módulos.
Descargamos las fuentes de la misma versión, descomprimimos, creamos el MakeFile gracias al autotools, compilamos e instalamos. No es necesaria una configuración estricta, sólo nos interesa el apxs.
Nos ubicamos en el directorio del apxs y le indicamos que genere el módulo en base a la plantilla genérica de ejemplo:
Nos habrá generado el código:
Código fuente aquí.
Al procesarse el módulo con permisos de super usuario, aprovecharemos para hacer una llamada a una shell a través de la función system de la librería stdlib en C. Con esto “desviaremos” el flujo lógico del Apache para obtener una shell con privilegos de root.
Situaremos la llamada en la función de registro del hook:
Código fuente aquí.
Compilaremos el módulo:
Se ubica en:
Añadimos la carga del módulo que hemos creado en el fichero personalizado de configuración (alternativamente, podríamos usar un httpd.conf vacío y añadir solamente la línea de LoadModule sin necesidad de copiar la configuración original) de apache ubicado en nuestra home:
Ahora sacamos partido del sudo y ejecutamos el proceso con el fichero de configuración nuestro. No es necesario levantar el Apache, pues estando parado, si le pasamos igualmente la opción de stop (o hacemos un syntax check con el “-t“, etc.), también realiza la carga de los módulos, cumpliendo nuestro objetivo:
Hemos obtenido nuestra shell con permisos de root!
Este proceso es extrapolable a configuraciones con OHS donde se usa el setuid en el fichero .apachectl y en muchas otras configuraciones, que pese a no utilizar un puerto privilegiado, continúan levantándose con permisos de root.
Hay que ser especialmente cuidadoso con la creación de reglas de sudo, de manera que se aplique la máxima granularidad posible para evitar los inconvenientes expuestos.
Una regla de ejemplo sería del estilo:
wls ALL = (root) NOPASSWD:/usr/sbin/httpd start, /usr/sbin/httpd stop, /usr/sbin/httpd restart, /usr/sbin/httpd graceful
O utilizando el script de servicio en el init.d. Aunque lo ideal siempre es prescindir de configuraciones que necesiten permisos adicionales.