Elevación de privilegios en Apache HTTP
Un error no controlado al intentar acceder fuera de los límites de un array, permitiría a un atacante local elevar privilegios y ejecutar código con permisos de administrador en el popular servidor HTTP Apache.
El módulo de MultiProcesamiento (MPM), que se ejecuta como root, administra una cola de procesos menos privilegiados (www-data) que son utilizados para gestionar las peticiones HTTP. Estos “workers”, comparten los resultados en una zona de memoria compartida (SHM) a la que tienen acceso total de escritura y lectura. En esta zona de la memoria se muestra, entre otra información, el PID de cada worker y la petición que atendió cada uno.
(gdb) p *ap_scoreboard_image
$3 = {
global = 0x7f4a9323e008,
parent = 0x7f4a9323e020,
servers = 0x55835eddea78
}
(gdb) p ap_scoreboard_image->servers[0]
$5 = (worker_score *) 0x7f4a93240820
Ejemplo de la memoria compartida asociada al worker con PID 19447:
(gdb) p ap_scoreboard_image->parent[0]
$6 = {
pid = 19447,
generation = 0,
quiescing = 0 ‘\000’,
not_accepting = 0 ‘\000’,
connections = 0,
write_completion = 0,
lingering_close = 0,
keep_alive = 0,
suspended = 0,
bucket = 0 <- index for all_buckets } (gdb) ptype *ap_scoreboard_image->parent
type = struct process_score {
pid_t pid;
ap_generation_t generation;
char quiescing;
char not_accepting;
apr_uint32_t connections;
apr_uint32_t write_completion;
apr_uint32_t lingering_close;
apr_uint32_t keep_alive;
apr_uint32_t suspended;
int bucket; <- index for all_buckets
}
Cuando Apache se reinicia de forma “suave”, el proceso principal mata los workers antiguos y los reemplaza por nuevos. En este punto, se produce una lectura del array ‘all_buckets‘:
(gdb) p $index = ap_scoreboard_image->parent[0]->bucket
(gdb) p all_buckets[$index]
$7 = {
pod = 0x7f19db2c7408,
listeners = 0x7f19db35e9d0,
mutex = 0x7f19db2c7550
}
(gdb) ptype all_buckets[$index]
type = struct prefork_child_bucket {
ap_pod_t *pod; ap_listen_rec *listeners; apr_proc_mutex_t *mutex; <--
}
(gdb) ptype apr_proc_mutex_t
apr_proc_mutex_t {
apr_pool_t *pool; const apr_proc_mutex_unix_lock_methods_t *meth; <-- int curr_locked; char *fname; …
}
(gdb) ptype apr_proc_mutex_unix_lock_methods_t
apr_proc_mutex_unix_lock_methods_t {
… apr_status_t (*child_init)(apr_proc_mutex_t **, apr_pool_t *, const char *); <-- …
}
Esta lectura no comprueba los límites del array, lo que puede ser aprovechado por un atacante para cambiar el índice de ‘all_buckets‘, apuntar a la memoria compartida y hacerse con el control de de la estructura ‘prefork_child_bucket‘ al reiniciar, lo que podría resultar en una llamada a una función arbitraria con privilegios de administrador.
Esta vulnerabilidad sólo puede ser explotada si el atacante tiene permisos para subir archivos y ejecutar scripts que no sean de confianza (PHP, CGI, etc) en el servidor. Un tipo de configuración muy habitual en servidores compartidos.
El investigador de seguridad Charles Fol ha publicado una prueba de concepto que permite explotar esta vulnerabilidad.
Recomendamos actualizar cuanto antes a la versión de Apache 2.4.39 que soluciona esta vulnerabilidad.
Más información:
CARPE (DIEM): CVE-2019-0211 Apache Root Privilege Escalation
https://cfreal.github.io/carpe-diem-cve-2019-0211-apache-local-root.html