Tras leer la sección anterior seguramente habrá quedado claro que un
correcto esquema de detección de intrusos basado en red es vital para
proteger cualquier sistema; con frecuencia suele ser el punto más importante,
que más ataques detecta, y donde se suelen emplazar la mayoría de
sistemas de detección que existen instalados en entornos reales hoy en
día. No obstante, esta enorme importancia suele degenerar en un error
bastante grave: en muchos entornos los responsables de seguridad, a la hora de
trabajar con IDSes, se limitan a instalar diversos sensores de detección
basados en red en cada segmento a proteger, creyendo que así son capaces
de detectar la mayoría de ataques. Y eso suele generar una falsa
sensación de seguridad grave, ya que a la hora de lanzar ciertos ataques un
pirata puede eludir fácilmente a estos sensores; los sensores de detección
en nuestros segmentos de red son importantes, pero no son la panacea. Para
comprobarlo, volvamos a nuestro ejemplo anterior, en el que un atacante trata
de descubrir vulnerabilidades en nuestros servidores HTTP: si
recordamos dónde nos habíamos quedado, el pirata estaba lanzando un
escaneador de vulnerabilidades web contra el puerto 80 de nuestro servidor
corporativo; el esquema de detección implantado en el cortafuegos no
percibirá nada extraño, pero el sensor ubicado en el segmento donde se
encuentra el servidor sin duda verá patrones que denotan un ataque. Por
ejemplo, en el momento en que el escáner compruebe la existencia en el
servidor de un CGI denominado phf, SNORT generará una alerta
similar a esta:
[**] IDS128 - CVE-1999-0067 - CGI phf attempt [**]
03/10-03:29:59.834996 192.168.0.3:1032 -> 192.168.0.1:80
TCP TTL:56 TOS:0x0 ID:5040 IpLen:20 DgmLen:58 DF
***AP*** Seq: 0x91FA846 Ack: 0x5AD9A72 Win: 0x7D78 TcpLen: 20
Como veremos en el punto siguiente, es posible que al generar este aviso, el
propio sensor decida lanzar una respuesta automática contra la dirección
atacante (por ejemplo, bloquearla en el cortafuegos corporativo). Pero SNORT trabaja basándose en su base de datos de patrones de ataques; en dicha
base de datos habrá una regla como la siguiente:
alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS 80 (msg:"WEB-CGI phf access";\
flags: A+; content:"/phf";flags: A+; nocase; reference:arachnids,128; \
reference:cve,CVE-1999-0067; )
A grandes rasgos, esta regla viene a decir que cuando el sensor detecte una
petición al puerto 80 de nuestro servidor web en cuyo contenido se
encuentre la cadena `/phf' levante la alerta correspondiente; de esta
forma, cuando el atacante solicite el archivo /cgi-bin/phf del servidor,
SNORT `verá' dicha cadena en la petición y generará una alarma.
>Pero qué sucede si el atacante solicita ese mismo fichero pero utilizando
una petición `ofuscada', formada por los códigos ASCII de cada carácter?
Es decir, si en lugar de lanzar una petición como `GET /cgi-bin/phf'
hace una similar a `GET %2f%63%67%69%2d%62%69%6e%2f%70%68%66'.
La respuesta es sencilla: la petición anterior se `decodifica' en el propio
servidor web, o como mucho en un proxy intermedio. Algunos
detectores de intrusos, como RealSecure, son
en teoría capaces de procesar este tipo de tráfico y analizarlo
normalmente en busca de patrones sospechosos, pero otros muchos (SNORT en
este caso) no; así, estos últimos no verán en ningún
momento la cadena `/phf' circulando por la red, y por tanto no
generarán ninguna alarma. Parece entonces evidente que es
necesario un nivel adicional en nuestro esquema de detección: justamente el
compuesto por los sistemas basados en la propia máquina a proteger.
Antes hemos hablado de los tres modelos básicos de IDSes basados en
máquina: verificadores de integridad, analizadores de registros y honeypots. Parece claro que un verificador de integridad en nuestro caso no va
a resultar muy útil para detectar a ese atacante (esto no significa que no
se trate de modelos necesarios y útiles en otras muchas situaciones).
Tendremos por tanto que recurrir a analizadores de logs o a tarros de
miel instalados en la máquina. Si optamos por los primeros, es sencillo
construir un shellscript que procese los archivos generados por el
servidor web - en nuestro caso, aunque igualmente sencillo que procesar
registros del sistema o de otras aplicaciones - en busca de patrones que puedan
denotar un ataque, como el acceso a determinados archivos bajo el DocumentRoot. Si analizamos cualquier CGI Scanner nos podremos hacer
una idea de a qué patrones debemos estar atentos: por ejemplo, intentos de
acceso a CGIs como phf o printenv, a archivos passwd, a
ficheros fuera del DocumentRoot, etc.
Aunque analizar los registros generados por una aplicación en busca de
ciertos patrones sospechosos es una tarea trivial, no lo es tanto el integrar
ese análisis en un esquema de detección de intrusos. Seguramente procesar
la salida de un `tail -f' del archivo de log correspondiente,
enviando un correo electrónico al responsable de seguridad cuando se detecte
una entrada sospechosa es fácil, pero por poner un simple ejemplo, >qué
sucede cuando la máquina se reinicia o el fichero de registros se rota? >Es
necesario volver a entrar y lanzar de nuevo la orden correspondiente para
analizar los logs? Seguramente alguien planteará que se puede
planificar una tarea para que periódicamente compruebe que se está
procesando el archivo, y lance el análisis en caso de que no sea
así...>pero hasta qué punto es esto cómodo? >qué sucede con las
entradas duplicadas? >y con los registros perdidos que no se llegan a procesar?
Evidentemente, no todo es tan sencillo como el simple `tail -f'
anterior.
El análisis de registros generados por el sistema o por ciertas aplicaciones
suele ser una excelente fuente de información de cara a la detección de
actividades sospechosas en nuestros entornos, pero no es habitual aplicar dicho
análisis en un esquema de respuesta automática ante ataques. Es mucho más
común automatizar la revisión de logs para que periódicamente (por
ejemplo, cada noche) se analicen esos registros y se envíe un mensaje de
alerta por correo electrónico a los responsables de seguridad en caso de que
algo anormal se detecte; evidentemente no es un modelo que trabaje en tiempo
real, pero no por ello deja de ser un esquema útil en la detección de
intrusos; el único problema que se presenta a la hora de realizar el
análisis suele ser la decisión de qué patrones buscar en los registros,
algo que depende por completo del tipo de log que estemos analizando.
Aparte de los sistemas de detección basados en el análisis de registros,
otro esquema que podemos - y debemos - implantar en cada máquina son los
honeypots o tarros de miel, mecanismo que nos ha de permitir detectar
ciertos ataques aunque el resto de sensores de nuestro modelo falle. Como antes
hemos comentado, hay diferentes modelos de tarros de miel, desde los simples
detectores de pruebas hasta los complejos sistemas dedicados por completo a esta
tarea; para detectar ataques rutinarios estos últimos suelen ser algo
excesivo e incluso en ocasiones difícil no sólo desde un punto de vista
estrictamente técnico, ya que no siempre podemos dedicar
una máquina entera a `engañar' atacantes, aparte del tiempo necesario para
configurarla correctamente, actualizarla, revisar sus registros, etc. Esquemas
teóricamente más simples pueden incluso resultar más efectivos en la
práctica.
En nuestro caso no vamos a complicarnos mucho la existencia; si recordamos
a nuestro atacante, estaba lanzando un escaneo de vulnerabilidades contra
nuestro servidor web; nuestro IDS basado en red detectará el ataque y
en consecuencia dará la voz de alarma y, adicionalmente, ejecutará una
respuesta automática contra el pirata, bloqueándolo en el cortafuegos
corporativo. Ese atacante ya puede más que sospechar que tenemos un detector
de intrusos basado en red que le impide completar su escaneo, ya que en el
momento que se detecta tráfico sospechoso bloquea por completo a la
dirección origen; por tanto, un paso lógico para él es intentar un
análisis de vulnerabilidades `camuflado', bien mediante una simple
codificación de peticiones bien mediante un complejo stealth scan. De
nuevo, buscará la existencia de CGIs vulnerables, como /cgi-bin/phf o
/cgi-bin/printenv, y en este caso SNORT será incapaz de detectar
el ataque. Pero forzosamente a nuestro servidor web han de llegar estas
peticiones, por lo que >qué mejor forma de detectar al pirata que en la
propia máquina? No tenemos más que situar en el directorio donde se ubican
nuestros CGIs un programa que nos informe si alguien intenta acceder a él,
tan simple como el siguiente shellscript:
anita:~# cat /web/cgi-bin/phf
#!/bin/sh
/bin/echo "Pirata desde "$REMOTE_ADDR""|mailx -s "Ataque PHF" root
/bin/echo "Content-type: text/html"
/bin/echo ""
/bin/echo "<HTML><CENTER>Sonrie a la camara oculta...</CENTER></HTML>"
anita:~#
Evidentemente la `decepción' del sistema anterior en un atacante durará
unos pocos segundos, ya que es inmediato para éste detectar que se trata de
una simple trampa; si queremos algo más elaborado, tampoco es difícil
conseguirlo: podemos simular el comportamiento de diferentes CGIs con
vulnerabilidades conocidas de una forma muy sencilla. Por ejemplo, existen
diferentes `imitaciones' de CGIs vulnerables que aparentan un problema de
seguridad pero que en realidad se trata de sistemas de decepción más o
menos eficaces; en http://www.eng.auburn.edu/users/rayh/software/phf.html podemos encontrar una
versión muy interesante del CGI phf, capaz de simular los ataques más
habituales contra el programa original de
una forma bastante creíble - aunque no perfecta -. Además en este
caso el código en Perl es fácilmente modificable, con lo que podemos
desde adecuarlo a nuestros sistemas hasta mejorar su simulación; si lo
hacemos, es muy posible que mantengamos `entretenidos' incluso a piratas con
conocimientos por encima de la media de atacantes (esto lo digo por
experiencia). También podemos construirnos nuestros propios CGIs que
aparenten ser vulnerables, en muchos casos simplemente con unos conocimientos
básicos de programación en shell o en Perl; por ejemplo, el
código siguiente simula el CGI printenv, proporcionando información
falsa sobre el sistema que parece útil para un atacante, y avisando por correo
electrónico a los responsables de seguridad del sistema cuando alguien
accede al programa:
anita:/# cat /web/cgi-bin/printenv
#!/usr/bin/perl
$SECUREADDRESS="root";
$mailprog = '/usr/lib/sendmail';
print "Content-type: text/html\n\n";
print "SERVER_SOFTWARE = Apache/1.3.12<br>";
print "GATEWAY_INTERFACE = CGI/1.2<br>";
print "DOCUMENT_ROOT = /usr/local/httpd/htdocs<br>";
print "REMOTE_ADDR = $ENV{'REMOTE_ADDR'}<br>";
print "SERVER_PROTOCOL = $ENV{'SERVER_PROTOCOL'}<br>";
print "SERVER_SIGNATURE = <br><i>Apache/1.3.9 Server at \
$ENV{'SERVER_NAME'}</i><br><br>";
print "REQUEST_METHOD = GET<br>";
print "QUERY_STRING = $ENV{'QUERY_STRING'}<br>";
print "HTTP_USER_AGENT = $ENV{'HTTP_USER_AGENT'}<br>";
print "PATH = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:\
/usr/local/bin<br>";
print "HTTP_ACCEPT = image/gif, image/x-xbitmap, image/jpeg<br>";
print "HTTP_CONNECTION = Keep-Alive<br>";
print "REMOTE_PORT = $ENV{'REMOTE_PORT'}<br>";
print "SERVER_ADDR = $ENV{'SERVER_ADDR'}<br>";
print "HTTP_ACCEPT_LANGUAGE = en<br>";
print "SCRIPT_NAME = /cgi-bin/printenv<br>";
print "HTTP_ACCEPT_ENCODING = gzip<br>";
print "SCRIPT_FILENAME = /usr/local/httpd/cgi-bin/printenv<br>";
print "SERVER_NAME = $ENV{'SERVER_NAME'}<br>";
print "REQUEST_URI = /cgi-bin/printenv<br>";
print "HTTP_ACCEPT_CHARSET = iso-8859-1, utf-8<br>";
print "SERVER_PORT = $ENV{'SERVER_PORT'}<br>";
print "HTTP_HOST = $ENV{'HTTP_HOST'}<br>";
print "SERVER_ADMIN = webmaster<br>";
# Enviamos correo
open (MAIL, "|$mailprog $SECUREADDRESS") or die "Can't open $mailprog!\n";
print MAIL "To: $SECUREADDRESS\n";
print MAIL "From: PRINTENV Watcher <$SECUREADDRESS>\n";
print MAIL "Subject: [/CGI-BIN/PRINTENV] $ENV{'REMOTE_HOST'} $action\n\n";
print MAIL "\n";
print MAIL "--------------------------------------------------------\n";
print MAIL "Remote host: $ENV{'REMOTE_ADDR'}\n";
print MAIL "Server: $ENV{'SERVER_NAME'}\n";
print MAIL "Remote IP address: $ENV{'REMOTE_ADDR'}\n";
print MAIL "HTTP Referer: $ENV{'HTTP_REFERER'}\n";
print MAIL "Query String: $ENV{'QUERY_STRING'}\n";
print MAIL "\n--------------------------------------------------------\n";
close(MAIL);
exit;
anita:/#
© 2002 Antonio Villalón Huerta