Notes d’apprentissage§

Tout ce qu’un programme demande au noyau (ouvrir un fichier, créer un processus, envoyer un signal) passe par un appel système (syscall). Observer les syscalls d’un processus, c’est voir ce qu’il fait réellement, au-delà de son nom.

Modèle mental : le syscall, frontière entre programme et noyau.

processus (espace utilisateur)
      │  open(), read(), execve(), kill(), socket()...   ← syscalls

   noyau (espace privilégié) ── exécute l'opération, renvoie un code

Un syscall comme kill(666, SIGTERM) signifie « envoyer le signal SIGTERM au PID 666 ». Surveiller ces appels permet de repérer un comportement interdit par une politique de sécurité.

strace : tracer les syscalls en direct.

strace -p <PID>            # s'attacher à un processus en cours et voir ses syscalls
strace -f commande         # tracer une commande ET ses processus enfants (-f = follow)
strace -e trace=kill -p PID  # ne montrer que les syscalls "kill"
strace -c -p PID           # résumé statistique par syscall

On laisse tourner quelques secondes pour capturer les appels périodiques. Ici, seul collector2 émet un kill(...) — c’est le coupable.

Identifier puis neutraliser un processus :

ps aux | grep collector             # PID + chemin de l'exécutable
ls -l /proc/<PID>/exe               # chemin réel de l'exécutable (lien)
kill <PID>                          # SIGTERM : demande d'arrêt propre
kill -9 <PID>                       # SIGKILL : arrêt forcé (si SIGTERM ignoré)
rm /bin/collector2                  # supprimer le binaire

Les signaux courants : SIGTERM (15, arrêt propre, par défaut), SIGKILL (9, tue sans recours), SIGHUP (1, souvent « recharge ta config »), SIGSTOP/SIGCONT (suspendre/reprendre).

Pièges :

Énoncé§

Solve this question on: web-srv1

There was a security alert which you need to follow up on. On server web-srv1 there are three processes: collector1collector2, and collector3. It was alerted that any of these might run periodically the per custom policy forbidden syscall kill.

End the process and remove the executable for those where this is true.

You can use strace -p PID

Solution§

We should check the server for the mentioned processes:

ssh web-srv1
root@web-srv1:~$ ps aux | grep collector
root        3611  0.0  0.0 101924   624 ?        Sl   13:23   0:00 /bin/collector1
root        3612  0.0  0.0 101916   612 ?        Sl   13:23   0:00 /bin/collector2
root        3613  0.0  0.0 101928   616 ?        Sl   13:23   0:00 /bin/collector3

Now we investigate the kernel syscalls of collector1:

root@web-srv1:~$ strace -p 3611 # your PID will be different!
restart_syscall(<... resuming interrupted read ...>) = -1 ETIMEDOUT (Connection timed out)
futex(0x4d4bb0, FUTEX_WAKE_PRIVATE, 1)  = 1
futex(0xc0000324c8, FUTEX_WAKE_PRIVATE, 1) = 1
futex(0x4d7460, FUTEX_WAIT_PRIVATE, 0, {tv_sec=0, tv_nsec=999999757}) = -1 ETIMEDOUT (Connection timed out)
futex(0x4d4bb0, FUTEX_WAKE_PRIVATE, 1)  = 1
futex(0xc0000324c8, FUTEX_WAKE_PRIVATE, 1) = 1
futex(0x4d7460, FUTEX_WAIT_PRIVATE, 0, {tv_sec=0, tv_nsec=999999756}) = -1 ETIMEDOUT (Connection timed out)
futex(0x4d4bb0, FUTEX_WAKE_PRIVATE, 1)  = 1
futex(0xc0000324c8, FUTEX_WAKE_PRIVATE, 1) = 1
futex(0x4d7460, FUTEX_WAIT_PRIVATE, 0, {tv_sec=0, tv_nsec=999999699}) = -1 ETIMEDOUT (Connection timed out)
futex(0x4d4bb0, FUTEX_WAKE_PRIVATE, 1)  = 1
futex(0xc0000324c8, FUTEX_WAKE_PRIVATE, 1) = 1
...

After watching for a while, there don’t seem to be any kill syscalls. Next one is collector2:

root@web-srv1:~$ strace -p 3612
restart_syscall(<... resuming interrupted read ...>) = -1 ETIMEDOUT (Connection timed out)
futex(0x4d2db0, FUTEX_WAKE_PRIVATE, 1)  = 1
kill(666, SIGTERM)                      = -1 ESRCH (No such process)
futex(0xc0000324c8, FUTEX_WAKE_PRIVATE, 1) = 1
futex(0x4d5660, FUTEX_WAIT_PRIVATE, 0, {tv_sec=0, tv_nsec=999999449}) = -1 ETIMEDOUT (Connection timed out)
futex(0x4d2db0, FUTEX_WAKE_PRIVATE, 1)  = 1
kill(666, SIGTERM)                      = -1 ESRCH (No such process)
futex(0xc0000324c8, FUTEX_WAKE_PRIVATE, 1) = 1
futex(0x4d5660, FUTEX_WAIT_PRIVATE, 0, {tv_sec=0, tv_nsec=999999593}) = -1 ETIMEDOUT (Connection timed out)
futex(0x4d2db0, FUTEX_WAKE_PRIVATE, 1)  = 1

kill(666, SIGTERM) # there we go!

Gotcha! Seems like collector2 is one bad process. Still we need to check the last one, collector3:

root@web-srv1:~$ strace -p 3613
restart_syscall(<... resuming interrupted read ...>) = -1 ETIMEDOUT (Connection timed out)
futex(0x4d5bb0, FUTEX_WAKE_PRIVATE, 1)  = 1
futex(0xc0000324c8, FUTEX_WAKE_PRIVATE, 1) = 1
futex(0x4d8460, FUTEX_WAIT_PRIVATE, 0, {tv_sec=0, tv_nsec=999999731}) = -1 ETIMEDOUT (Connection timed out)
futex(0x4d5bb0, FUTEX_WAKE_PRIVATE, 1)  = 1
futex(0xc0000324c8, FUTEX_WAKE_PRIVATE, 1) = 1
futex(0x4d8460, FUTEX_WAIT_PRIVATE, 0, {tv_sec=0, tv_nsec=999999722}) = -1 ETIMEDOUT (Connection timed out)
futex(0x4d5bb0, FUTEX_WAKE_PRIVATE, 1)  = 1
futex(0xc0000324c8, FUTEX_WAKE_PRIVATE, 1) = 1
futex(0x4d8460, FUTEX_WAIT_PRIVATE, 0, {tv_sec=0, tv_nsec=999999635}) = -1 ETIMEDOUT (Connection timed out)
futex(0x4d5bb0, FUTEX_WAKE_PRIVATE, 1)  = 1
futex(0xc0000324c8, FUTEX_WAKE_PRIVATE, 1) = 1
futex(0x4d8460, FUTEX_WAIT_PRIVATE, 0, {tv_sec=0, tv_nsec=999999641}) = -1 ETIMEDOUT (Connection timed out)
futex(0x4d5bb0, FUTEX_WAKE_PRIVATE, 1)  = 1
futex(0xc0000324c8, FUTEX_WAKE_PRIVATE, 1) = 1
...

Seems like only collector2 should be terminated. First we run ps again to see the binary path:

root@web-srv1:~$ ps aux | grep collector2
root        3612  0.0  0.0 101916   612 ?        Sl   13:23   0:00 /bin/collector2
root@web-srv1:~$ kill 3612 # your PID will be different!
root@web-srv1:~$ ps aux | grep collector2
root@web-srv1:~$ rm /bin/collector2