Como llevo algunas noches de insomnio me ha dado por refrescar, tras algunos años olvidados en un cajón, aspectos de monitorización de usuarios en Solaris (Solaris 10, para ser exactos); y la verdad es que de lo que conocía -dejé de administrar máquinas Solaris “en serio” en su versión 7- a lo que me he encontrado en las nuevas versiones del operativo, hay alguna que otra diferencia que sorprende gratamente, y es que a pesar de que ahora sea un producto de Oracle, Solaris sigue siendo Solaris :)
Como siempre, para generar trazas “en serio” de la actividad de los usuarios podemos utilizar el Basic Security Module, habilitado mediante bsmconv(1M) y que nos dirá hasta qué usuario pestañea demasiado delante de la consola :) ¿Problemas? Alguno que otro… para empezar, requerimos reiniciar el sistema, cosa que ya de por sí a nadie le gusta mucho… y para continuar, tenemos el problema histórico del volumen de datos que generamos: por muy bien que configuremos el módulo de auditoría, incluso si lo hacemos por usuario, la cantidad de registros que se almacenan en la máquina no deja de ser considerable… y lo peor de todo: la marcha atrás tras habilitar BSM en nuestro sistema implica de nuevo detener servicios (la orden bsmunconv hay que lanzarla en runlevel 1).
Aunque BSM es la solución correcta y definitiva si necesitamos un registro de auditoría al detalle, me ha sorprendido en Solaris 10 DTrace, un framework que permite monitorizar en tiempo real y sin parada de sistema determinados aspectos tanto del núcleo como del espacio de usuario; este framework incorpora un lenguaje de programación propio (“D”), que nos permite registrar, de forma sencilla, actividad en el sistema de cara a detectar problemas, a “tunear”, o simplemente a monitorizar determinada actividad en la máquina (accesos a un fichero, cambios en inodos, etc.). Por supuesto, para esto último no es tan completo como BSM -que insisto, es la solución correcta-, pero nos puede servir para sacarnos de más de un apuro en cuanto a conocer qué hacen nuestros usuarios.
Un ejemplo de monitorización sencilla: ¿qué órdenes ejecuta un determinado usuario? Mediante dtrace(1M), es trivial obtener esta información: ponemos “vigilantes”, generadores de información, en las llamadas al sistema exec() y familia, y la condición de que el UID del usuario que usa estas llamadas – que pasaremos como argumento al programa- sea uno en concreto; si esto se cumple, imprimimos la información que nos interesa:
# cat t.d
syscall::exec:return, syscall::exece:return
/ uid==$1 /
{
printf("%s %-20Y %S\n", probefunc, walltimestamp, curpsinfo->pr_psargs);
}
# dtrace -s prueba.d 100
dtrace: script 'prueba.d' matched 2 probes
CPU ID FUNCTION:NAME
0 108 exece:return exece 2010 Jun 9 18:54:17 ls
0 108 exece:return exece 2010 Jun 9 18:54:28 more prueba.d
#
Seguro que el código se puede mejorar, ya lo sé :) Más cosas que nos pueden interesar de la actividad de un usuario: archivos abiertos, conexiones de red…todo esto es bastante sencillo obtenerlo mediante dtrace(1M), sus probes y las condiciones adecuadas; podemos poner todo junto, y en bonito (para que nos muestre la información más legible, básicamente) en un script que invocaremos desde línea de órdenes:
# cat luser.d
#pragma D option quiet
/*
* Ejecucion de ordenes
*/
syscall::exec:return, syscall::exece:return
/ uid==$1 /
{
printf("%s %-20Y %S\n", probefunc, walltimestamp, curpsinfo->pr_psargs);
}
/*
* Acceso a FS
*/
syscall::open:entry, syscall::creat:entry,
syscall::open64:entry, syscall::creat64:entry,
syscall::unlink:entry, syscall::rename:entry
/ uid==$1 && strstr(stringof(copyinstr(arg0)), "/proc") == NULL /
/* Nos quitamos de la condicion el acceso a procfs */
{
printf("%s %Y %s\n", probefunc, walltimestamp, stringof(copyinstr(arg0)));
}
/*
* Acceso a red / TCP
*/
::tcp_send_data:entry
{
self->lport=((unsigned int) args[0]->tcp_tcph->th_lport[0] < <8) + (unsigned int) args[0]->tcp_tcph->th_lport[1];
dig1=(unsigned int) args[0]->tcp_tcph->th_fport[0];
dig2=(unsigned int) args[0]->tcp_tcph->th_fport[1];
dig1=dig1< <8;
self->rport=((unsigned int) args[0]->tcp_tcph->th_fport[0] < <8) + (unsigned int) args[0]->tcp_tcph->th_fport[1];
srcaddr=(unsigned int) (args[0]->tcp_ipha->ipha_src);
dstaddr=(unsigned int) (args[0]->tcp_ipha->ipha_dst);
self->octect[0]=srcaddr>>3*8 & 0xFF;
self->octect[1]=srcaddr>>2*8 & 0xFF;
self->octect[2]=srcaddr>>1*8 & 0xFF;
self->octect[3]=srcaddr>>0*8 & 0xFF;
self->octect[4]=dstaddr>>3*8 & 0xFF;
self->octect[5]=dstaddr>>2*8 & 0xFF;
self->octect[6]=dstaddr>>1*8 & 0xFF;
self->octect[7]=dstaddr>>0*8 & 0xFF;
self->ok=1;
}
::tcp_send_data:entry
/ self->ok && uid==$1 /
{
printf("%s %Y %d.%d.%d.%d:%d -> %d.%d.%d.%d:%d\n", probefunc,walltimestamp,self->octect[0],self->octect[1],self->octect[2],self->octect[3], self->lport,self->octect[4],self->octect[5],self->octect[6],self->octect[7],self->rport);
self->ok=0;
}
#
Al invocarlo mediante dtrace(1M), la salida que obtendremos será similar a la siguiente -con muchos más datos que habrá que filtrar, no estoy ahora para pulir el código que, insisto, es un simple ejemplo y tendrá N fallos y mejoras-):
tcp_send_data 2010 Jun 9 19:00:37 192.168.1.2:22 -> 192.168.1.5:37963
tcp_send_data 2010 Jun 9 19:00:38 192.168.1.2:22 -> 192.168.1.5:37964
tcp_send_data 2010 Jun 9 19:00:38 192.168.1.2:22 -> 192.168.1.5:37963
exece 2010 Jun 9 19:00:38 cat /home/toni/fbsd-como\0
open 2010 Jun 9 19:00:38 /var/ld/ld.config
open 2010 Jun 9 19:00:38 /lib/libc.so.1
open 2010 Jun 9 19:00:38 /platform/SUNW,Ultra-5_10/lib/libc_psr.so.1
Así, mediante dtrace(1M), y de una forma muy sencilla, estamos en disposición de monitorizar muchísimas acciones -en este caso de un usuario concreto- que pueden servirnos para incrementar considerablemente la seguridad de nuestros sistemas Solaris desde el punto de vista de monitorización de la actividad (aparte de para resolver algún problema en las máquinas). Por supuesto, con un ratito de búsqueda en Google tendremos acceso a un montón de ejemplos de programas en D que podemos adaptar y aprovechar para crear un luser.d en condiciones :)
En definitiva, dtrace(1M) es una herramienta que no conocía más que de oídas y que, a poco que he empezado a tocarla, me ha sorprendido muy gratamente (tanto por su capacidad como por su sencillez) para la monitorización de ciertas actividades concretas del sistema o de nuestros usuarios, sin necesidad de meternos en el “gran” BSM… además, puede ser muy útil en aquellos casos en los que BSM no esté habilitado de antemano, por ejemplo si nos enfrentamos a un análisis forense de una Solaris comprometida… en fin, que seguiremos informando :) Por cierto, ¿alguien se anima a explicarnos algo similar en Linux, Windows, AIX, etc.? Sé que Dtrace se ha migrado -o se está migrando- a BSD, pero no sé si tenemos algo de capacidades similares en otros entornos (es que ya no soy técnico :)