¿Y ahora qué? Algunas ideas para seguir formándose

Ahora con la llegada del buen tiempo es el momento de que los recién graduados en informática escojan entre las opciones disponibles para seguir formándose. Desde este blog queremos aportar nuestro granito de arena recordando algunas de las opciones disponibles:

Por otra parte, existen otras certificaciones no-universitarias que son más que interesantes:

  • Offensive Security Certified Professional. Consta del curso “Penetration Testing with Backtrack”, cuya duración y precio es variable. Durante el curso, el alumno tendrá acceso a una red de ordenadores (averiguar cuántos es parte del curso), dónde se practicarán todas las fases de un pentest, atacando sin distinguir entre servidores, máquinas de cliente, y distintos sistemas operativos. Desde la experiencia, es posible sacárselo en 2 meses, aunque depende de lo agobiado que quiera y pueda ir cada uno. Los precios oscilan entre los 750 $ (1 mes) y 1100 $ (3 meses). Una vez finalizado el curso, el alumno tiene un periodo de 3 meses para realizar el examen de certificación, que dura 24 horas y en el que debe hacerse con el control de varias máquinas. Finalizadas las 24 horas, tiene otras 24 horas para realizar y entregar el informe. Un curso extremadamente divertido, dónde dormir no es una opción.
  • Cracking the perimeter. Es la versión avanzada del curso anterior. Para acceder es necesario superar unas pruebas de admisión, y desembolsar entre 1200 y 1500 $, dependiendo de si se opta por realizarlo en uno o dos meses. En este caso, la duración del examen es de 48 horas.
  • Cursos prácticos también son los ofrecidos por www.securitytube.net. Son cursos prácticos bastante asequibles económicamente. Personalmente, me gustan los de desarrollo en Python y ensamblador. También ofrecen de manera gratuita un curso (sin certificación) de Metasploit.

Y cómo siempre está la opción de la autoformación, de la que se ha hablado largo y tendido. Por suerte hoy día existen multitud de sites que ofrecen CTF (Capture The Flags), máquinas virtuales y multitud de documentación de forma totalmente gratuita y desinteresada.

Entiendo que nos dejamos muchas certificaciones (y muy buenas) en el tintero, pero con esta entrada sólo pretendíamos acercar a la gente al mundillo de la seguridad. Por este motivo, no hemos indicado ninguna certificación que requiera su renovación, como pueden ser SANS, CEH, CISSP, y un largo etc.

Hacia rutas salvajes

Mucho se está hablando últimamente de VPN anónimas, y en este post no pretendo descubrir las américas a nadie, pero aún así espero que le pueda ser de utilidad a alguien.

Para ponernos en situación, tengo un servidor contratado en un proveedor extranjero que me ofrece varios servicios, entre ellos una VPN (openVPN) que me permite navegar con una IP extranjera. Hasta aquí ningún misterio, para redirigir todo el tráfico basta con añadir las siguientes opciones a la configuración del servicio:

ifconfig-push IPCliente 255.255.255.0
push "dhcp-option DOMAIN ejemplo"
push "dhcp-option DNS DNS1"
push "route IPRedInterna 255.255.255.0"
push "redirect-gateway def1”

Y ejecutar los siguientes comandos:

echo "1" > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -s IPVPNInterna/24 -o enp1s0 -j MASQUERADE

Sin embargo, como hago uso de cierto tipo de servicios que no están permitidos por mi proveedor, me he visto obligado a recurrir a servicios de VPN anónima (“Internet Private Access” en este caso). Lo cual también permite que mis saltos realicen un segundo salto y que viajen cifrados a dos países distintos antes de salir into the wild, además de burlar el límite de número de distintos dispositivos conectados a la vez (3 en este caso) permitidos por Internet Provider Access.

Entrando en harina, si alguien conecta con la VPN de InternetPrivateAccess con la configuración que ofrecen por defecto de manera remota, lo primero que le va a pasar es que perderá el acceso total a su servidor, ya que se modifican las rutas y los paquetes viajan de vuelta por una salida diferente. Para evitar este comportamiento, antes de conectar nada, vamos a crear la tabla de rutas. En el fichero /etc/iproute2/rt_tables , pondremos:

1 services

Y crearemos un script que se ejecute al arranque del sistema:

#!/bin/bash

ip route add RedServidor/24 dev enp1s0 src IPPublicaServidor table services
ip route add default via GatewayServidor dev enp1s0 table services
ip rule add from IPPublicaServidor/32 table services
ip rule add to IPPublicaServidor/32 table services
ip rule add fwmark 1 table services

ip route flush cache

De este modo, todas las conexiones que lleguen a la IP pública del servidor no pasarán por la VPN de Internet Provider Access, lo que nos permitirá seguir ofreciendo servicios (siempre y cuando funcionen a través de TCP).

Para redirigir el tráfico desde una VPN hasta la otra, bastará con ejecutar:

iptables -t nat -A POSTROUTING -s  IPVPNInterna/24 -o tun1 -j MASQUERADE
# Sólo si antes hemos añadido la ruta anterior: 
iptables -t nat -D POSTROUTING -s IPVPNInterna/24 -o enp1s0 -j MASQUERADE 

Como bonus, decir que es posible abrir puertos en la VPN de Internet Private Access con un software que han desarrollado ellos, pero que por desgracia no tiene soporte para sistemas GNU/Linux. No obstante, se puede realizar un pequeño apaño:

$ cat /home/USUARIO/.pia_client

ID= #Resultado de ejecutar head -n 100 /dev/urandom | md5sum | tr -d " -" 
PORT= #Puerto que nos abre la API de Internet Private Access 
IP="IP” # IP asignada por Internet Private Access

El siguiente script se debe añadir en el crontab (con ejecutarse cada 30 minutos, bastaría):

#!/bin/bash

CONFIG=/home/USUARIO/.pia_client

. $CONFIG

function getIP {

        NEWIP=""

        while true; do
                NEWIP=$(ip addr show dev tun1 | grep inet | awk '{print $2}')
                if [ "$NEWIP" != "" ]; then
                        break;
                fi
                sleep 10
        done

        echo $NEWIP

}

function closePort {
        iptables -D INPUT -i tun1 -p tcp -m tcp --dport $PORT -j ACCEPT
        iptables -D INPUT -i tun1 -p udp -m udp --dport $PORT -j ACCEPT
}

function openPort {
        iptables -A INPUT -i tun1 -p tcp -m tcp --dport $NEWPORT -j ACCEPT
        iptables -A INPUT -i tun1 -p udp -m udp --dport $NEWPORT -j ACCEPT
}

function getPort {
        NEWPORT=$(sudo -u USUARIO -- curl -d 
              "user=USUARIOIPV&pass=PASSWORDIPV&client_id=$ID&local_ip=$NEWIP" 
              https://www.privateinternetaccess.com/vpninfo/port_forward_assignment 2>/dev/null);
        NEWPORT=$(echo $NEWPORT | awk -F'[{:}]' '{print $3}')
        echo $NEWPORT 
}

function replaceConfig {
        sed -i.bak "s/^PORT=.*$/PORT=$NEWPORT/" $CONFIG || exit
        sed -i.bak "s/^IP=.*$/IP=\"$NEWIP\"/" $CONFIG || exit
       #Acciones que queremos hacer tras abrir un puerto
}


NEWIP=$(getIP)
NEWPORT=$(getPort)
if [ "$NEWIP" != "$IP" -o "$NEWPORT" != "$PORT" ]; then
        closePort
        openPort
        replaceConfig
fi

De este modo, cada 30 minutos se verificará que la IP de la VPN y el puerto que nos natea la API son el mismo, y en caso de que cambien se cerrará el puerto viejo y se abrirá el nuevo. No hay que olvidarse de reiniciar aquellas aplicaciones que dependan de los puertos nateados.

Cómo ganar en juegos Android… mediante reverse engineering

Hace unos meses, empecé a jugar a un juego de la plataforma Android. El caso es que como perdía más rondas que ganaba, decidí utilizar métodos menos ortodoxos: utilizar la ingeniería inversa para hacerme con el control de los datos de la aplicación, ganando en todo momento cualquier turno. Así pues, en un primer momento mi compañero David Lladró y yo, tratamos de descifrar las comunicaciones que se establecían entre la aplicación y el servidor.

Para ello, extrajimos el fichero “classex.dex” (el fichero ejecutable de la máquina virtual Dalvik que utiliza Android) del “apk” (el fichero mediante el cual se distribuyen e instalan las aplicaciones de Android) y lo convertimos a “jar” (el tipo de fichero en el que se empaquetan las clases compiladas de Java) mediante la herramienta “dex2jar”. A continuación, con la herramienta “jdgui”, descompilamos el fichero “jar”, y obtuvimos el código Java de la aplicación… o eso creíamos, ya que las funciones que generaban las claves de cifrado y descifrado estaban ofuscadas y fue imposible obtenerlas.

Ya de noche, y tras estar todo el día dándole vueltas, me propuse realizar el segundo asalto a la aplicación (qué paciencia hay que tener para aguantarme). Esta vez, decidí centrar mis esfuerzos en la lógica del programa, estudiar todo los procedimientos que se llevan a cabo en una partida, los tiempos… y esas pequeñas cosas que, de controlarlas, permitan tener una ventaja sobre el adversario y ganarle.

Apoyándome en el pseudo-código descompilado anteriormente (aún quitando los fragmentos ofuscados, el código no era ni mucho menos funcional), encontré que en la clase dónde se gestionan los diálogos de la aplicación había algo muy interesante:

ClaseTurno{
     ...
     diálogo.opciónPulsada(opciónSeleccionada);
     ...
}

De este código se podía entender que se almacena mi jugada en una variable de la clase diálogo, y que después se enviará (presumiblemente, cifrada mediante la clave que no fuimos capaces de conseguir al principio) al servidor para que este facilite la siguiente jugada. También pude comprobar que en la clase existía un atributo llamado “correcta”, que por el nombre, supuse que almacenaría el identificador de la jugada válida.

A estas alturas, seguro que el lector ve por dónde van a ir los tiros… Si en la memoria del teléfono ya tengo almacenado el valor de la jugada que me hace ganar, ¿qué me impide modificar la aplicación para que siempre se envíe el valor de dicho atributo, ignorando el valor que haya facilitado?

Sin embargo, existía un problema: como ya he dicho, el código descompilado no era en absoluto funcional. Por lo que no se me ocurrió otra idea que bajar un nivel y comenzar a jugar con el código smali (el lenguaje ensamblador para la máquina virtual Dalvik). Para ello, volví otra vez al fichero apk, y con la herramienta “apktool” (que más tarde nos permitirá reconstruir la aplicación a partir de los ficheros obtenidos), extraje todos los ficheros smali que componían la aplicación.

Ya con la estructura smali en mano, surgió un nuevo problema: el código anterior sobrescribía un método de una clase padre, que a su vez estaba incluida en otra clase (la propia del fichero Java), por lo que el compilador de Dalvik había separado todas estas clases en ficheros de tipo “NombreClase$$N.smali”, donde $N es un número de fichero. Tras un rato, identifiqué el código que se correspondía con el fragmento mostrado anteriormente:

iget-object v0, p0, ClaseTurno$5;->this$0:ClaseTurno;

iget-object v0, v0, ClaseTurno;->diálogo;

iget v1, p0, ClaseTurno$5;->opciónSeleccionada:I

invoke-interface {v0, v1}, diálogo;->opciónPulsada(I)V

Para entender este código, debemos saber que el registro p0 es la referencia a “this”, que es utilizado como dirección base para cargar una referencia a la clase principal en el registro v0, que a continuación es sobrescrito con una referencia a diálogo. Siguiendo el mismo procedimiento, en el registro v1 se carga la variable opciónSeleccionada, para a continuación ejecutar una llamada a la función opciónPulsada que está almacenada en v0, pasándole como único parámetro el registro v1.

Llegados a este punto, sólo tuve que hacer los siguientes cambios para conseguir que independientemente de la opción pulsada, siempre se enviase al servidor la opción que me hace ganar:

iget-object v0, p0, ClaseTurno$5;->this$0:ClaseTurno;

iget-object v0, v0, ClaseTurno;->diálogo;

iget-object v1, p0, ClaseTurno$5;->this$0:ClaseTurno;

iget v1, v1, ClaseTurno;->correcta:I

invoke-interface {v0, v1}, diálogo;->opciónPulsada(I)V

De manera similar al código smali anterior, ahora en v1 cargamos la referencia a la clase principal, que es donde está almacenado el atributo correcta, y a continuación sobrescribimos el registro con dicho atributo. De este modo, siempre se llamará al método opciónPulsada pasándole como parámetro el atributo “correcta”, lo que hará que se envíe la respuesta correcta independientemente de nuestra elección.

Para poder ejecutar la aplicación, sólo hace falta reensamblar el apk con “apktool”, y firmarlo con una clave que nosotros hayamos generado (el manual del desarrollador de Android da buenos ejemplos sobre cómo hacerlo) para que se pueda instalar en cualquier teléfono Android que esté soportado por la aplicación original.

Cómo hemos podido ver en esta entrada, la aplicación ha sido vulnerada porque el servidor remoto no realizaba ninguna comprobación, ya que se delegaban en el cliente. Aunque puede parecer trivial, este error es común en aplicaciones que utilicen una arquitectura cliente-servidor como son las aplicaciones web. Por tanto, como corolario recordar que las comprobaciones siempre se deben realizar en el lado del servidor, independientemente de si el cliente las realiza o no.

Antes de finalizar el post, me gustaría aclarar que el código mostrado aquí ha sido modificado por respeto a los derechos de los autores de la misma. Y aunque todo lo mostrado ya no funciona, puesto que nos pusimos en contacto con los desarrolladores de la aplicación para darles tiempo a arreglar este error, somos conscientes de que existen otros que permitirían realizar comportamientos similares. Aún así, desde aquí me gustaría agradecer la profesionalidad y deportividad con la que se tomaron todo este asunto.

El cifrado sin control, no sirve de nada

 

Últimamente, tanto en auditorías que realizamos, como en código que encuentro en la red, hay una cosa que me llama poderosamente la atención, y es el mal uso (o uso incompleto) de las funciones de criptografía. Por lo general, el procedimiento que suelen seguir los desarrolladores que no están en contacto con el mundo de la seguridad, suelen consistir en coger un método que venga con la API del lenguaje o en una librería de terceros, buscar el  método que  implementa el algoritmo de cifrado de turno, rellenar la firma del método y almacenar la salida.

Sin embargo, el uso correcto del cifrado, como todo lo que es crítico en esta vida, no es algo que se deba hacer a las bravas: además del algoritmo de cifrado, es necesaria la utilización de más algoritmos para la gestión de la autenticidad del mensaje y de la clave.

Pongamos que por ejemplo, Bob desea enviarle un mensaje a Alice mediante un programa que realiza un cifrado de clave: Bob introduce la clave y los datos que quiere cifrar, y el programa se encarga del resto. Pero, exactamente, ¿qué debería hacer el programa?

En primer lugar, el programa debe  obtener algunos bytes aleatorios (o lo más aleatorios posible), para generar un salt que se utilizará junto a la contraseña, con el fin de dificultar ataques basados en tablas Rainbow.

A continuación, generará la clave de cifrado mediante un algoritmo de derivación de claves, como PBKDF2. Para ello utiliza la contraseña proporcionada por Bob, el salt generado antes, el número de iteraciones que debe realizar el algoritmo, la longitud que debe tener la clave derivada y una función pseudo-aleatoria, como es HMAC, para obtener la clave que se utilizará en el cifrado. En el caso de utilizar AES-256, la longitud necesaria de la clave será de 32 bytes (256 bits). Sin embargo, el programa generará una clave mayor,  de 64 bytes, que se cortará en 2 claves de 32 bytes. De éste modo, se habrá obtenido la clave que se utilizará para cifrar los datos, y la clave que se utilizará en HMAC, tal y como detallamos a continuación.

HMAC es un algoritmo que permite verificar la integridad de los datos y la autenticidad de un mensaje. Para asegurarnos de que todos los datos no han sufrido cambios, “hmacquearemos” los datos utilizados hasta ahora: el número de iteraciones de PBKDF2, la longitud de la clave de PBKDF2, la longitud del salt, el salt, la longitud del nonce (ya llegaremos a él) y el nonce. De estos datos, junto a la segunda clave derivada antes con PBKDF2, y un algoritmo de hash (SHA-512, por ejemplo), obtendremos los datos que nos servirán para comprobar la integridad y autenticidad de los datos. Pero, espera ¿no deberíamos también añadir el mensaje cifrado a la función HMAC? Sí, pero como todavía no lo tenemos, no lo podemos añadir, por lo que a medida que vayamos cifrando los datos deberemos actualizar el valor del resultado de HMAC.

Con todo esto, ya podemos empezar a cifrar los datos. Para ello, podemos utilizar AES-256-CTR, ya que no requiere padding (AES-CBC requiere que la longitud de los datos sean múltiplos de 16, por lo que se ha de añadir morralla en caso de que no sea así), aunque requiere de un contador, que utiliza un nonce (secuencia de datos pseudo-aleatorios) y un contador de bloques inicial) en vez de un IV (Initialization Vector).

Para que los datos se puedan descifrar, el resultado del cifrado será un paquete de datos (al estilo de un paquete de red) que deberá contener: el número de iteraciones realizadas por PBKDF2, el tamaño de la clave derivada, la longitud del salt, la longitud del nonce, la longitud del texto cifrado, el resultado de HMAC, el salt, el nonce y el texto cifrado.

Para descifrar los datos, el algoritmo es similar: se deriva la contraseña proporcionada, y se genera el HMAC  de todos los datos con los que hemos hecho el HMAC anteriormente, y que vienen incluidos en el paquete de datos cifrado. Una vez finalizada la generación de HMAC,  podemos comprobar que la longitud del texto cifrado es la misma que la indicada en el paquete, y que el resultado de ambos HMAC tienen el mismo valor. En el caso de que la verificación falle, puede darse por varios motivos: la contraseña es incorrecta, los datos han sido modificados, etc., pero en ningún caso se deberá seguir con el descifrado.

Una vez que todo ha sido verificado correctamente, con la clave de cifrado derivada, podemos, por fin, descifrar los datos.

Como nota, decir que existen unas librerías de Google, Keyczar (disponible para Java, Python y C++), cuyo propósito es evitar al desarrollador pasar por todo este infierno, con la seguridad de que está utilizando la criptografía correctamente.

Violent Python

Hoy me gustaría hacer una review de un libro que comencé hace unas semanas y que me ha parecido de lo más interesante: Violent Python. Su autor, TJ O’Connor, es un paracaidista del ejército estadounidense con una larga ristra de certificaciones de seguridad a sus espaldas, entre las que destacan el GIAC Security Expert (GSE) y el Offensive Security Certified Expert (OSCE). En la escritura del libro ha contribuido también Robert Frost, militar y graduado en ciencias de la computación, y ha sido editado por Mark Bagget, instructor certificado de SANS y consultor y fundador de In Depth Defense, INC., entre otros.

Con estos currículos, cuando alguien coge el libro por primera vez piensa que no puede decepcionar, y tras haberlo leído, puedo confirmar que no lo hace. El libro cubre multitud de temas: test de penetración, análisis forense, análisis de tráfico, seguridad en wireless, seguridad en páginas web y evasión de antivirus… todos desde un punto de vista más práctico que teórico, lo cual es de agradecer.

Todos los capítulos tienen su parte de “historia del abuelo cebolleta”, donde expone un caso real que marcó un antes y después en la seguridad informática, como cuando Kevin Mitnick entró en los sistemas de Shimomura, o cuando HD Moore ayudó al Pentágono en la identificación de qué IP estaba buscando vulnerabilidades en sus sistemas. Mediante estos relatos, el autor consigue motivar al lector para, a continuación, mostrarle la implementación de dichos ataques (o soluciones a problemas) en Python, con una sintaxis clara y comprensible.

Aunque no todo podría ser bueno: el libro hace un uso intensivo de librerías externas, que en algunos casos, no están lo suficientemente mantenidas ni probadas. Personalmente, también esperaba más contenido en la sección de Bluetooth, ya que es una tecnología sobre la que el autor ha realizado varias publicaciones, y a la que se le podría sacar mucho partido con los smartphones. Hablando de los mismos, puede que una sección en la que se hablase de Python en Android, mediante por ejemplo la librería python-for-android (Py4A), fuese de gran utilidad: es más versátil llevar encima un móvil o tablet que un portátil, y se podrían utilizar como plataforma de ejecución de varios de los programas implementados en el libro.

En definitiva, el libro atrapa de principio a fin y es altamente recomendable para todos aquellos que estamos interesados en el mundo de la seguridad informática. El texto, aunque en inglés, está muy bien explicado, y no hace falta tener grandes conocimientos de Python para poder sacarle jugo, puesto que el código, además de efectivo, es extremadamente simple, mostrando todo el potencial que se puede sacar a Python.

No cON Name: FreePBX for fun and profit!

No cON Name, para el que no lo sepa, es una asociación sin ánimo de lucro cuyo principal objetivo, entre otros, es fomentar los mecanismos de la seguridad informática. Las conferencias comenzaron en un pub de Mallorca en el año 1999, dónde se juntaron 15 personas del “underground” español. No obstante, fue en el año 2002 cuando se inscribió como asociación sin ánimo de lucro.

Han pasado 13 años desde esa primera edición, y el pasado 2 y 3 de noviembre, en el CosmoCaixa de Barcelona, se realizó su novena edición. Personalmente, era la segunda No cON a la que asistía y tenía grandes expectativas por ver qué habían preparado. Se realizaron charlas que tocaron multitud de temas: malware, data harvesting, ciberseguridad, ipv6, nfc, android… Temas, que como se puede ver, son de manifiesta actualidad. Tan familiar era el ambiente, que los ponentes Pedro Laguna y Juan Garrido, en su charla “Data exfiltration, the ninja way” decidieron incluso realizar una charla en pijama.

Una de las charlas que más me gustó, quizás porque me recordó a algunas de las pruebas que se pueden encontrar en el curso “Penetration Testing with Backtrack”, fue la “FreePBX for fun and profit!”, por Jose Luis Verdeguer (@pepeluxx).

FreePBX es una distribución GNU/Linux que tiene como objetivo facilitar la instalación del software de centralita telefónica Asterisk.

En la charla, partiendo del acceso al panel de FreePBX, el ponente mostró como se puede tomar el control del sistema. Para ello, se basó completamente en fallos de diseño del sistema y en errores de configuración. Algo muy destacable, porque no se convirtió en una charla del estilo “buscamos un exploit, lo compilamos, lo ejecutamos, y ya somos el administrador de la máquina”, sino que únicamente mirando en las “tripas” de la distribución se pudieron realizar acciones realmente interesantes.

Partiendo del acceso al panel de FreePBX, Verdeguer consiguió escribir una shell en el sistema mediante la modificación del dialplan, aunque para ello tuvo que codificarla en hexadecimal. Como codificar y escribir la shell puede ser un proceso tedioso, lo automatizó mediante un script en Perl que realizaba todo el proceso.

Aprovechando la shell “reversa” que acababa de crear, accedió al sistema como el usuario asterisk, que utilizó posteriormente para acceder a MySQL puesto que por defecto no tiene asignada ninguna contraseña. No obstante, aun en el caso de que el administrador de la máquina se la hubiese asignado, el atacante la puede encontrar en el fichero de configuración “/etc/freepbx.conf”, por lo que de poco sirve en realidad asignársela. Algo similar ocurre con la configuración del Apache, donde el usuario asterisk también puede realizar “defacements”, al ser propietario de todo el panel web.

A continuación, @pepeluxx se propuso troyanizar el propio asterisk, para lo que modificó la configuración del mismo (que para variar, también es propiedad del usuario asterisk) para cargar los módulos desde un directorio donde tuviera permiso de escritura. Una vez modificado y compilado el código fuente del módulo (disponible en Internet ya que Asterisk es software libre), se pudo comprobar cómo en el proceso de compilación se inserta un hash en el propio módulo, con objeto de evitar que asterisk ejecute módulos que provengan de distintas compilaciones. No obstante, debido a que quizá sea un control que no ha sido pensado en la seguridad sino en garantizar el funcionamiento correcto del sistema, mediante el comando strings es posible el valor del hash, por lo que haciendo uso de un editor hexadecimal resulta sencillo sobreescribir dicha cadena por una válida.

En un entorno real, todas las modificaciones descritas se podrían realizar por parte del atacante para por ejemplo ganar dinero mediante la venta de llamadas, que aunque para él serían gratuitas, no lo serían tanto para el propietario del sistema. Para acabar la charla, se hizo un breve repaso a otras distribuciones que facilitan la instalación de asterisk, conteniendo todas ellas vulnerabilidades similares a las explicadas anteriormente.

Desde estas líneas me gustaría agredecer a la asociación No cON Name su dedicación y calidad del evento, esperando poder asistir a una nueva edición el año que viene.

Forense en discos SSD

Estaba haciendo el otro día mis pinitos con django, cuando por una negligencia, borré una aplicación que ya tenía terminada. La web no era compleja, tenía pocas líneas de código y creía que la podría volver a tener en menos de un día, pero sin embargo, vi la ocasión como una oportunidad para aprender a hacer una recuperación de datos en un disco SSD.

La configuración del disco de este equipo es la siguiente: particionado GPT con varias particiones formateadas con ext4 (nada de LVM). Mi experiencia previa en este tipo de casos siempre ha sido utilizar las herramientas más conocidas en entornos GNU/Linux: sleuthkit, autopsy, testdisk y photorec (éstas dos últimas suelen venir en el mismo paquete), dd, grep

Volviendo al caso, nada más darme cuenta de lo que había hecho intenté mantener la calma y seguir lo que suele ser mi procedimiento estándar: montar la partición en la que estaba el proyecto como sólo lectura y crear una imagen de la partición con la herramienta ‘dd‘, de manera que las nuevas interacciones con el disco no sobreescriban ningún dato.

Creada la imagen, mi primera opción fue testdisk, un software de análisis forense y recuperación de datos que me ha dado muy buenos resultados en el pasado. No obstante, en esta ocasión me decía que la partición estaba corrupta, por lo que no podía recuperar el contenido del disco. A día de hoy, desconozco si fue por un error mío en las múltiples opciones que ofrece testdisk, o si bien por el contrario esta herramienta no se lleva bien con discos SSD o con particiones GPT.

Tras un primer intento fallido, probé suerte con sleuthkit y autopsy. En esta ocasión, todo iba como la seda. Tras establecer los parámetros iniciales del caso, empecé a “jugar” con las opciones de autopsy:

No obstante, parecía que el procedimiento iba para rato, ya que la imagen de disco tenía cierto tamaño y estaba almacenada en un disco duro externo USB. Como no me apetecía estar delante del PC sin hacer nada un viernes de madrugada, cancelé los procesos de sleuthkit y me puse a utilizar photorec.

Con photorec la cosa cambió: en cuestión de segundos, estaba recuperando multitud de ficheros, algunos de ellos borrados hacía meses. Como iba para rato, pero había podido comprobar que estaba haciendo su tarea, decidí dejar el proceso ejecutándose y continuar la mañana siguiente. Cual fue mi sorpresa al día siguiente al ver que photorec había encontrado unos cuantos miles de ficheros de tipo texto (extensiones txt, java (en este equipo nunca he programado en Java), html, py…).

Dado el gran número de ficheros, nada mejor que un poco de grep y unas cuantas expresiones regulares para encontrar el directorio y los ficheros que me interesaban. Al ser código en python, empleé sentencias que serían únicas de python, como import, nombres de variables que recordaba, tags html…

Al cabo de unas cuentas horas, pese a que parecía que había recuperado casi la totalidad del proyecto y que si faltaba algo podría recodificarlo, había una cosa extraña: el número de ficheros que tenía ahora del proyecto era más del triple del número de ficheros que tenía originalmente. Tras ojear los ficheros para poder cambiarles el nombre por el original (photorec tiene una pega: cambia el nombre del fichero por caracteres alfanuméricos, e incluso hay veces que no detecta correctamente la extensión del fichero), vi que muchos ficheros se correspondían con el mismo y que muchos otros no estaban completos.

Descarté en seguida que se tratara de copias de seguridad: no había considerado que fuese necesario crear una copia de seguridad para un proyecto como éste. Además, ¿qué sería de la vida sin pequeñas emociones? (N.d.E.: niños, no hagáis caso a este insensato)

Mirando los ficheros detenidamente, pude ver como los ficheros se correspondían a versiones viejas de los mismos, como si cuando hubiese hecho un cambio y lo hubiese guardado en disco, se creara un nuevo fichero y se borrase el viejo, almacenándose cada uno en secciones diferentes del disco. También había unos cuantos ficheros parciales, en los que se veían funciones del código pero no todas las que coexistían en el mismo fichero.

Tras indagar un poco, pude discernir entre “versiones”, realizar varias pruebas en la aplicación y ver que líneas tenía que añadir, borrar o modificar para tener la aplicación tal y como la tenía antes. No obstante, se me planteaban nuevas cuestiones. ¿Guarda eclipse varias versiones del mismo fichero? ¿Es cosa del Sistema Operativo? ¿Es por utilizar un disco SSD?

Como muchos lectores ya se habrán imaginado, el causante de este comportamiento es la forma en la que el disco SSD almacena los datos. Sin embargo, me gustaría dejar los detalles técnicos para una próxima entrega, más técnica y menos teórica que la actual.

Nos vemos en la próxima!

La moneda electrónica (II): Soluciones actuales

Siguiendo con la serie de entradas de “La moneda electrónica” que comenzó Samuel hace un par de días, hoy vamos a hacer un repaso de los formas de pago digital que existen en la actualidad, las tecnologías que existen detrás de ellas y los inconvenientes que presentan, especialmente aquellos relacionados con la seguridad.

Tal y como podemos observar en el día a día, en las transacciones diarias, el pago en efectivo es el rey. Pero, ¿y si pudiéramos eliminar todo el dinero en metálico y sustituirlo por un dispositivo que ya utilicemos, de manera que la transición no suponga un cambio brusco?

Como vimos en la entrada anterior, parece que el móvil es la respuesta a todas estas incógnitas. No obstante, la solución adoptada en Kenia, dónde se utilizan SMS para realizar nuevas transferencias abre algunas preguntas de seguridad: ¿es realmente un método seguro? ¿Pueden cometerse robos mediante técnicas conocidas, como por ejemplo un ataque de estación de base falsa o SMS Spoofing?

[Read more…]