[ Linux ] Antivirus et les fichiers temporaires PHP !
Hello les geek !
Sachez d’abord qu’il existe plusieurs antivirus fonctionnant sous Linux (que ce soit un desktop ou un serveur, son fonctionnement reste le même) comme par exemple McAfee, Kaspersky, Clamav et d’autres… Je ne vais pas débattre sur le choix du meilleur antivirus sous Linux, ce n’est pas le but de cet article. D’ailleurs je trouve qu’avoir un antivirus sur un serveur ne sert pas à grand chose étant donné les différentes méthodes d’attaques. Vous croyez vraiment qu’un antivirus vous protègera d’une faille XSS ?
Dans cet article je souhaite plutôt présenter le fonctionnement de l’antivirus (via le scan en temps réel, livescan pour les intimes) face à l’upload d’un fichier temporaire. Tous les tests effectués dans cet article ont été réalisés sur mon serveur dédié. Sur cet environnement j’utilise CentOS (7.2), un service Nginx (1.9) et du PHP-FPM (5.6) avec des configurations de base sans restrictions (sauf quelques uns, faut pas être bête non plus). Le DocumentRoot comporte un simple fichier PHP affichant un message :
[root@djerfy-fx:/datas/sites/www.testintrusion.com/tmp]# cat ../www/index.php
<?php printf(« Welcome to » . $_SERVER[‘HTTP_HOST’]); ?>
J’ai donc modifié mon fichier « /etc/hosts » afin que le site « www.testintrusion.com » pointe sur mon serveur (pas la peine de faire des tests d’injections, le host n’existe plus à l’heure actuelle), j’ai ensuite fais quelques requêtes de type POST envoyant un fichier « command.txt » qui comporte un simple « <?php phpinfo() ?>« . Pour ce faire, j’ai utilisé le module « Postman – REST Client » que l’on retrouve sur Chrome mais vous pouvez faire la même chose avec Curl 🙂
Voici quelques retours de mes logs du site de test :
[root@djerfy-fx:/datas/sites/www.testintrusion.com/tmp]# tail -n10 /datas/logs/nginx/www.testintrusion.com/access.log
xxx.xxx.xxx.xxx http – [09/Mar/2016:11:46:00 +0100] RQ= »POST / HTTP/1.1″ S= »200″ B= »63″ RF= »- » UA= »Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36″ T= »0.000″ P= »31750″ RA= »127.0.0.1″ H= »www.testintrusion.com »
xxx.xxx.xxx.xxx http – [09/Mar/2016:11:46:00 +0100] RQ= »POST / HTTP/1.1″ S= »200″ B= »63″ RF= »- » UA= »Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36″ T= »0.000″ P= »31750″ RA= »127.0.0.1″ H= »www.testintrusion.com »
xxx.xxx.xxx.xxx http – [09/Mar/2016:11:46:00 +0100] RQ= »POST / HTTP/1.1″ S= »200″ B= »63″ RF= »- » UA= »Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36″ T= »0.001″ P= »31750″ RA= »127.0.0.1″ H= »www.testintrusion.com »
xxx.xxx.xxx.xxx http – [09/Mar/2016:11:46:00 +0100] RQ= »POST / HTTP/1.1″ S= »200″ B= »63″ RF= »- » UA= »Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36″ T= »0.000″ P= »31750″ RA= »127.0.0.1″ H= »www.testintrusion.com »
Suite à ces requêtes POST (avec le fichier), il est possible de voir que cela a généré des fichiers temporaires bien que la page ne gère pas du tout ce genre de chose :
[root@djerfy-fx:/datas/sites/www.testintrusion.com/tmp]# while true; do ll | grep -vi ‘^total’; done
-rw——- 1 www.testintrusion.com www.testintrusion.com 1.6K Mar 9 11:45 phpJZq80p
-rw——- 1 www.testintrusion.com www.testintrusion.com 1.6K Mar 9 11:46 phppUvENm
-rw——- 1 www.testintrusion.com www.testintrusion.com 1.6K Mar 9 11:46 phpdZWpD7
^C
Plus précisément voici la capture d’un trace effectué à ces moments, je donne quelques détails en dessous :
[pid 31971] 1457520536.610611 <… accept resumed> {sa_family=AF_LOCAL, NULL}, [2]) = 4 <1.982046>
[pid 31971] 1457520536.610873 times({tms_utime=0, tms_stime=0, tms_cutime=0, tms_cstime=0}) = 764739882 <0.000147>
[pid 31971] 1457520536.611205 poll([{fd=4, events=POLLIN}], 1, 5000) = 1 ([{fd=4, revents=POLLIN}]) <0.000037>
[pid 31971] 1457520536.611430 read(4, « \1\1\0\1\0\10\0\0 », 8) = 8 <0.000105>
[pid 31971] 1457520536.611711 read(4, « \0\1\0\0\0\0\0\0 », 8) = 8 <0.000114>
[pid 31971] 1457520536.611942 read(4, « \1\4\0\1\4\267\1\0 », 8) = 8 <0.000110>
[pid 31971] 1457520536.612184 read(4, « \0170SCRIPT_FILENAME/datas/sites/www.testintrusion.com/www/index.php\f\0QUERY_STRING\16\4REQUEST_METHODPOST\fDCONTENT_TYPEmultipart/form-data; boundary=—-WebKitFormBoundaryfFFV5TTavl9fz055\16\4CONTENT_LENGTH1795\v\nSCRIPT_NAME/index.php\v\1REQUEST_URI/\f\nDOCUMENT_URI/ind »…, 1208) = 1208 <0.000033>
[pid 31971] 1457520536.612324 read(4, « \1\4\0\1\0\0\0\0 », 8) = 8 <0.000014>
[pid 31971] 1457520536.612443 setitimer(ITIMER_PROF, {it_interval={0, 0}, it_value={60, 0}}, NULL) = 0 <0.000031>
[pid 31971] 1457520536.612550 rt_sigaction(SIGPROF, {0x7f8069cd0cb0, [PROF], SA_RESTORER|SA_RESTART, 0x7f8066fdf670}, {0x7f8069cd0cb0, [PROF], SA_RESTORER|SA_RESTART, 0x7f8066fdf670}, 8) = 0 <0.000013>
[pid 31971] 1457520536.613643 rt_sigprocmask(SIG_UNBLOCK, [PROF], NULL, 8) = 0 <0.000012>
[pid 31971] 1457520536.613709 read(4, « \1\5\0\1\1\204\4\0 », 8) = 8 <0.000012>
[pid 31971] 1457520536.613756 read(4, « ——WebKitFormBoundaryfFFV5TTavl9fz055\r\nContent-Disposition: form-data; name=\ »name\ »; filename=\ »command.txt\ »\r\nContent-Type: text/plain\r\n\r\n<?php phpinfo(); ?> »…, 388) = 388 <0.000012>
[pid 31971] 1457520536.613804 read(4, « \0\0\0\0 », 4) = 4 <0.000011>
[pid 31971] 1457520536.613849 read(4, « \1\5\0\1\5\177\1\0 », 8) = 8 <0.000011>
(1) [pid 31971] 1457520536.613891 read(4, « n/<?php phpinfo(); ?> »…, 1407) = 1407 <0.000011>
[pid 31971] 1457520536.613942 read(4, « \0 », 1) = 1 <0.000011>
[pid 31971] 1457520536.613999 getcwd(« / », 4096) = 2 <0.000014>
(2) [pid 31971] 1457520536.614055 open(« /datas/sites/www.testintrusion.com/tmp/phpC8hOXf », O_RDWR|O_CREAT|O_EXCL, 0600) = 5 <0.000059>
(3) [pid 31971] 1457520536.614161 write(5, « <?php phpinfo(); ?> »…, 1610) = 1610 <0.000032>
(4) [pid 31971] 1457520536.614233 close(5) = 0 <0.000016>
[pid 31971] 1457520536.614372 getcwd(« / », 4095) = 2 <0.000014>
[pid 31971] 1457520536.614421 chdir(« /datas/sites/www.testintrusion.com/www ») = 0 <0.000014>
[pid 31971] 1457520536.614471 setitimer(ITIMER_PROF, {it_interval={0, 0}, it_value={60, 0}}, NULL) = 0 <0.000012>
[pid 31971] 1457520536.614519 fcntl(3, F_SETLK, {type=F_RDLCK, whence=SEEK_SET, start=1, len=1}) = 0 <0.000014>
[pid 31971] 1457520536.614575 stat(« /datas/sites/www.testintrusion.com/www/index.php », {st_dev=makedev(8, 5), st_ino=10231697, st_mode=S_IFREG|0644, st_nlink=1, st_uid=0, st_gid=0, st_blksize=4096, st_blocks=8, st_size=61, st_atime=2016/03/09-11:43:44, st_mtime=2016/03/09-11:42:48, st_ctime=2016/03/09-11:42:48}) = 0 <0.000014>
[pid 31971] 1457520536.614749 chdir(« / ») = 0 <0.000012>
[pid 31971] 1457520536.614798 times({tms_utime=0, tms_stime=0, tms_cutime=0, tms_cstime=0}) = 764739882 <0.000012>
[pid 31971] 1457520536.614852 brk(0) = 0x7f806bcda000 <0.000012>
[pid 31971] 1457520536.614897 brk(0x7f806bd1a000) = 0x7f806bd1a000 <0.000015>
[pid 31971] 1457520536.614950 brk(0) = 0x7f806bd1a000 <0.000011>
[pid 31971] 1457520536.614991 brk(0x7f806bd5a000) = 0x7f806bd5a000 <0.000012>
[pid 31971] 1457520536.615080 brk(0) = 0x7f806bd5a000 <0.000011>
[pid 31971] 1457520536.615122 brk(0) = 0x7f806bd5a000 <0.000011>
[pid 31971] 1457520536.615163 brk(0x7f806bcda000) = 0x7f806bcda000 <0.000022>
[pid 31971] 1457520536.615217 brk(0) = 0x7f806bcda000 <0.000011>
[pid 31971] 1457520536.615271 setitimer(ITIMER_PROF, {it_interval={0, 0}, it_value={0, 0}}, NULL) = 0 <0.000012>
[pid 31971] 1457520536.615339 fcntl(3, F_SETLK, {type=F_UNLCK, whence=SEEK_SET, start=0, len=0}) = 0 <0.000013>
[pid 31971] 1457520536.615395 write(4, « \1\6\0\1\0~\2\0Content-Encoding: gzip\r\nVary: Accept-Encoding\r\nContent-type: text/html\r\n\r\n\37\213\10\0\0\0\0\0\0\3\vO\315I\316\317\315MU(\311W(//\327+I-.\311\314+)*-\316\314\317\323\3J\1\0_\177\177d!\0\0\0\0\0\1\3\0\1\0\10\0\0\0\0\0\0\0\0\0\0 », 152) = 152 <0.000016>
[pid 31971] 1457520536.615450 shutdown(4, SHUT_WR) = 0 <0.000011>
[pid 31971] 1457520536.615491 recvfrom(4, « \1\5\0\1\0\0\0\0 », 8, 0, NULL, NULL) = 8 <0.000012>
[pid 31971] 1457520536.615538 recvfrom(4, « », 8, 0, NULL, NULL) = 0 <0.000010>
[pid 31971] 1457520536.615582 close(4) = 0 <0.000017>
(5) [pid 31971] 1457520536.615632 unlink(« /datas/sites/www.testintrusion.com/tmp/phpC8hOXf ») = 0 <0.000044>
[pid 31971] 1457520536.615743 setitimer(ITIMER_PROF, {it_interval={0, 0}, it_value={0, 0}}, NULL) = 0 <0.000052>
[pid 31971] 1457520536.615849 accept(0, ^CProcess 31969 detached
Vous avez sans doute remarqué que certaines lignes en gras (bleu) et précédées d’un numéro, donc voici quelques détails sur ces lignes :
- Lecture du fichier se trouvant dans la requête HTTP, ici il s’agit d’un simple fichier texte contenant un phpinfo
- L’environnement PHP créé un fichier temporaire, à ce moment il est encore vide
- Nos données (notre phpinfo) sont écrites dans le fichier temporaire
- Le fichier temporaire est fermé
[antivirus] Une fois que le fichier est fermé (donc écrit sur le disque), il est alors scanné par l’antivirus qui le supprime (ou qui le place en quarantaine) - Le fichier temporaire est supprimé (pas géré, pas les droits, il existe de multiple raison)
Dans ces tests il s’agit d’un simple fichier contenant un phpinfo mais j’aurais très bien pu envoyer un fichier malveillant, le résultat aurait été le même sauf que PHP n’aurait pas réussi à le supprimer puisque l’antivirus l’aurait déjà fait dès lors où le fichier a été écrit (4). Selon la configuration de l’antivirus, vous êtes alors alerté une intrusion/malware sur votre serveur, et cela sans forcement avoir une faille sur votre service.
J’espère vous avez fournis quelques éclaircissement sur le fonctionnement des fichiers temporaire avec un antivirus.
Si vous avez des suggestions ou des configurations au top, n’hésitez pas les proposer dans les commentaires !
++