Un blog de Seguridad Informática, desde un punto de vista tecnológico

Más reciente

Write Up 5h311 – Final CTF NCN 2014

Buenas,

Para continuar con la saga de write-up’s iniciada en el anterior post con @julianvilas, hoy os pondremos la solución a otro de los retos que tuvimos el placer de testear.

Se trata de un fichero llamado “5h311”, que al ejecutarlo se abre un servicio en local en el Puerto 6969, que la conectarnos muestra lo siguiente:

Ejecución 5h311

Parece ser un acceso por consola que permite una serie de comandos, concretamente “cat”, “echo”, “env”, “exit”, “help”, “ls”, “set” y “unset”.

Si hacemos ls encontramos que el flag se encuentra en el mismo directorio del binario, pero al hacer un “cat flag.txt” podemos observar que no disponemos de privilegios para accede .

Permission Denied

Bueno pues nos ponemos manos a la obra y abrimos el programa con IDA para ver que es lo que nos esconde.

Buscamos en IDA las ocurrencias del comando “cat” con la búsqueda de Strings (ALT+T), con la finalidad de identificar la sección de código donde se están gestionando los comandos:

String put

Como resultado, en la sección .rodata podemos observar el vector que incluye los comandos que son printados por pantalla.

comandos

Pero observando unas direcciones de memoria más abajo, se pueden observar de nuevo los comandos asignados a unos offsets, pero con la peculiaridad que aparece un nuevo comando que no nos ha listado el comando HELP, el comando “Puts”.

puts command

Miramos las Xrefs del offset correspondiente a “aPuts” (x Key):

xrefs puts

Miramos de analizar la primera ocurrencia, que parece ser que se está empleando dentro de una función.

Antes de nada un apunte, observando el programa desde la View Graph, ya se observa algo raro, como si se hubiera ofuscado con algún tipo de programa, debido a que todos los paths van a parar a un mismo punto como se observa en la siguiente imagen:

graph

Procedemos a analizar el bloque de código que emplea el offset de “puts”, y observamos que se realizan una serie de comparaciones:

puts code

Concretamente hace una comparación de dos offsets con una llamada a strcmp y verifica mediante el siguiente cmp si son iguales, en ese caso activa el ZF.

Antes de continuar refrequemos que hace el opcode “setz”:

  • The setz sets the byte in the destination operand to 1 if the Zero Flag (ZF) is set, otherwise sets the operand to 0.

Después mediante la instrucción “setz”, se setea el valor de “bl” a 1 si ZF vale 1, es decir bl valdrá 1 si el resultado del strcmp es que son iguales.

Posteriormente mediante la instrucción “test”, se modifica otra vez el ZF en función del resultado del registro bl. (Empezamos a observar algo de redundancia aquí, por lo que la hipótesis de que se ha empleado algún tipo de programa para ofuscar el código es cada vez más firme :P)

Finalmente se mueven de nuevo los dos valores comparados en el strcmp, y se ejecuta la instrucción cmovz (al parecer sin valor alguno debido a que solo se ejecuta si ZF=1, es decir, si ecx y eax ya son iguales).

Como podéis ver, una locura para al final solo acabar realizando una comparación xD Por lo que antes de ingresar en un psiquiárico, procederemos a realizar un análisis dinámico partiendo del bloque de código identificado.

Cuando el proceso recibe una conexión al puerto 6969, éste crea un nuevo proceso hijo mediante la syscall ‘clone’ y le pasa el control al mismo para que continúe su ejecución. Para poder debugear el proceso hijo sin que el padre nos moleste (al cabo de un tiempo envia un SIGALARM y nos mata el proceso), empleamos la instrucción “catch” de GDB para que, una vez cree el proceso hijo, podamos pausar su ejecución, y de esta forma poder debugear el proceso hijo con calma.

 

gdb debug

 

 

Añadimos un breakpoint a la dirección del bloque de código donde hemos observado el offset del ‘puts’, y ejecutamos la instrucción para ver que ocurre. Observamos que no  se observa ningún cambio, por lo que el flujo de ejecución no pasa por ahí. (ouch!) Continuemos con el análisis pues.

putsdoesnotork

Observando más detenidamente el código y continuando con la búsqueda de cadenas de texto interesantes como los comandos encontramos una zona de memoria donde se definen los offsets de las funciones asociadas a cada comando de la shell analizada:

commands

En la imagen se muestran los offsets de las funciones ya renombrados.

Usando la funcionalidad de cross-reference vemos que el primero de estos offsets es llamado desde otro punto del código:

xrefs

 

 

En ese punto se aprecia el acceso a este offset con un desplazamiento dinàmico con el valor almacenado en [eax*8]. Esto permite con el valor de eax recorrer la zona de memoria que contiene los punteros a las funciones de cada comando. Más tarde este offset guardado en el registro eax será llamado con call eax.

Captura de pantalla 2014-10-31 a la(s) 11.40.01

 

Tirando del hilo veremos que el valor de eax viene condicionado supuestamente por el valor del comando introducido por el usuario, mediante el offset “off_804E848”.

Captura de pantalla 2014-10-31 a la(s) 11.46.07

Vemos que este valor parece venir de la función _fgets. Aunque de momento, debido a que el flujo del código esta ofuscado con la implementación de una máquina de estados, no podemos estar seguros de todas estas conjeturas. Deberemos por lo tanto ejecutar el análisis de forma dinámica para estar seguros.

Captura de pantalla 2014-10-31 a la(s) 12.08.57

Para analizar todos los valores comentados anteriormente de forma dinámica, utilizaremos gdbserver para debuggar cómodamente  de forma remota y poder indicar los breakpoints directamente desde IDA.

GDBServer

Luego en IDA seleccionamos el Debugger de tipo GDB server y configuramos la ip y el puerto:

IDA GDB Config

 

Ya podemos a priori centrarnos en el comportamiento de los comandos que más nos interesen, en este caso ‘cat’, ‘set’, y el misterioso ‘puts’. Para ello prepararemos el entorno para debuggar y pondremos breakpoints en los puntos más interesantes.

Focalizando en las funciones cat, set, i puts vemos que todas están implementadas ofuscando el flujo del código con una máquina de estados. Por lo tanto buscaremos las llamadas mas interesantes para poner breakpoints. Para verificar que no se nos escapa nada y por donde podemos empezar a mirar, sacamos un grafo de llamadas desde cada función que nos interesa con Graphview.

Captura de pantalla 2014-10-31 a la(s) 12.27.40Captura de pantalla 2014-10-31 a la(s) 12.28.17Captura de pantalla 2014-10-31 a la(s) 12.27.57

 

 

 

 

 

 

 

 

Ponemos los breakpoints en las llamadas empleadas en cada una de las funciones anteriormente mostradas en los callgraphs (strcmp, fopen, fgets, strncpy), con la finalidad de identificar, por ejemplo, las comparaciones realizadas en cada una de las llamadas a “strcmp”,  y empezamos a jugar.

En la función “cat” observamos se emplea una llamada a fopen para abrir el fichero a leer y que el valor de dicho fichero esta hardcodeado a “flag.txt”, por lo que solo se podrá abrir un fichero con dicho nombre.

Captura de pantalla 2014-10-31 a la(s) 12.30.13

Captura de pantalla 2014-10-31 a la(s) 12.31.24

En la función “set” observamos que las variables de entorno se guardan en memoria empezando en el offset dword_804e8a8 sumando un desplazamiento de 0x100 bytes (por lo que resulta en 804e9a8) y que el numero de variables de entorno se guarda en el offset dword_804e8a4.

Captura de pantalla 2014-10-31 a la(s) 12.32.00

 

Podemos ver como en las direcciones de memoria anteriormente comentadas se almacenan las variables de entorno seteadas con el comando “SET”, (variable en 0x804e8a8 y valor en un offset de 0x100, concretamente en 0x804e9a8).

EnvVars

 

EnvVars_command

 

En la función “puts” observamos que recorre las variables definidas con set (incluso recorre las que se han “eliminado” con unset pero que aún siguen en la memoria pero sin la primera letra) y compara su valor con la cadena “puts”.

Captura de pantalla 2014-10-31 a la(s) 12.35.58

 

Si una de las variables se llama “puts” entonces compara su valor con “printf”.

Captura de pantalla 2014-10-31 a la(s) 12.36.48

 

Probamos el comportamiento creando una variable de entorno que se llame puts y que su valor sea printf y luego invocamos a puts. Como podemos ver, parece que se hemos conseguido una escalada de privilegios o algo parecido.

Captura de pantalla 2014-10-31 a la(s) 12.37.36

 

Probando ahora el comando cat con un fichero cualquiera del directorio desde donde ejecutamos la shell vemos que nos devuelve “error: permission denied”

Captura de pantalla 2014-10-31 a la(s) 12.38.58

Pero si recordamos que el valor de “flag.txt” está hardcodeado en el binario, miremos de probar pues de modificar el fichero de nuestro entorno local a dicho nombre. Volvemos a provar y ya podemos mostrar el contenido de flag.txt!

Captura de pantalla 2014-10-31 a la(s) 12.51.08

 

En este caso esta prueba no logramos resolverla dentro del tiempo del CTF. Pudimos resolverlo con calma luego desde casa 😛

Solo queda dar gracias al staff de las NCN por la originalidad de los juegos!

 

Post escrito con la colaboración de “Pau Rodriguez”, miembro activo de 0xb33r$ 🙂

Solución HIDDENtation – Final CTF NCN 2014

Buenas,

hoy hemos tenido el placer de participar en la final del CTF de las No cON Name por segundo año consecutivo y, antes de explicaros nuestra solución a uno de los retos (que no conseguimos terminar a tiempo ;( ), nos gustaría dar las gracias a la organización; ya que se han currado un montón las pruebas (tanto las de la final como las de las quals) con el único objetivo de hacernos pasar un buen rato. Gracias de verdad, porque ha sido muy divertido! 🙂

El reto que vamos a explicaros se llama HIDDENtation, y el texto que describía el reto decía tal que así: “Dig deep into the file and find the flag.”. Este texto venía acompañado por un archivo, que es en el que se centra el juego.

En un primer vistazo al archivo vemos algo tal que así:

hexdump

 

 

Por lo que parece que se trate de una imagen de un volumen cifrado con LUKS (estándar de cifrado de discos duros en Linux). El tema es que el comando “file” no ha identificado el fichero como tal, así que procedemos a analizar si la estructura del archivo es correcta. Para ello utilizamos una plantilla para el “010 Editor” para analizar el format de volúmenes LUKS.

Al ejecutar la plantilla vemos que nos da un error que dice que el archivo no es LUKS, ya que no se corresponde su firma. Así que pasamos a mirarnos el estándar de LUKS para ver cual es su firma, donde nos dice que la cabecera de la partición empieza con el siguiente magic: “{’L’,’U’,’K’,’S’,0xBA,0xBE}”, y en nuestro caso en vez de una ‘S’ había una ‘s’ minúscula. Una vez modificada esa letra, volvemos a aplicar el template y vemos como ahora sí lo reconoce:

Cabecera LUKS

 

curioseando un poco el fichero vemos que en la sección de padding de caracteres aparece el siguiente texto: “Try … most common passwd in …”, donde los “…” son dos números hexadecimales: 0x19 (25) y 0x07dd (2013). Así que nos vamos a preguntarle a Google y encontramos esto.

Utilizando el siguiente comando

cryptsetup luksOpen hiddentation volume1

 

intentamos descifrar el volumen con los 25 passwords sin éxito :(. Así que parece que tocaba trabajar más en los headers.

Después de pelearnos con el estándar vemos que nos faltaría arreglar las secciones de los key-slots en el header.

Key-slots

 

En este caso vemos :

  1. que los ocho que hay están desactivados (“00 00 DE AD”), cuando tendría que haber al menos uno activo (en el que supone que está la clave con la que se cifran los datos protegida con la passphrase correspondiente a uno de los 25 passwords más comunes en 2013),
  2. que los campos donde se indican los offset de los KeyMaterials no parecen estar correctamente calculados. Para estar bien calculados deberían cumplir la fórmula round_up(key_length * stripes / sector_size); en este caso: (32*4000) /512 = 250, por lo que tomamos 256 (0x100).

Así que ya que parece que el key-slot8 es “el bueno”, pues marcamos este slot como ENABLED (0x00AC71F3) y retocamos los 8 offsets, quedando algo tal que así:

LUKS OK

 

Ahora nos disponemos a probar otra vez los 25 passwords y tenemos éxito con el número 18: “shadow”.

Así que ahora vemos qué pinta tiene el disco:

fdisk

 

 

Y vemos que la tabla de particiones es GPT, y que fdisk no soporta GPT. Procedemos a utilizar parted:

Gparted

 

Y aparecen tres particiones, una XFS, una EXT2 y una FAT32. Haciendo uso de los dispositivos de loop las vamos montando una a una. Por ejemplo:

losetup -o 44040192 /dev/loop2 /dev/mapper/volume1

donde indicamos el offset de la partición, el dispositivo de loop a utilizar y el volumen de disco. Este caso concreto es el de la tercera partición (tras buscar en la primera y la segunda no encontramos el flag).

Y al montar la tercera nos aparece un fichero que se llama “flag.txt”. Quedaba un minuto para que se acabase el CTF y con toda el ansia procedemos a abrir el fichero para encontrarnos un “It’s inside this partition, but hidden ;)”. Agggggggghhhh xD

Bien, después de analizar la partición con el autopsy, no vimos nada relevante en cuanto a ficheros borrados. Utilizando el comando testdisk vemos que en el mismo volumen hay una partición NTFS borrada previamente.

NTFS

 

La extraemos del siguiente modo:

dd if=/dev/loop2 of=ntfs2 skip=69632 count=34816

la montamos y vemos que hay un “readme.txt”. Abrimos y…. “You are very near, but it’s even more hidden!”. Mekagüen!! esta gente está loca! ;***, jajaja

De nuevo autopsy, esta vez sobre la partición NTFS y encontramos esto:

ADS

 

Un fichero flag.txt borrado (que no contiene el flag) pero con un Alternate Data Stream que contiene esa secuencia codificada en ROT13. La decodificamos y voilà, ahora sí tenemos flag “NCNd986942b809daa32a6987a7422771a53f59e5a1f02ed700cce43c5196aba749e” (pero el CTF ya ha acabado xD).

Pues parece que si que había que “Dig deeper” para encontrar la bandera ;).

Genial la prueba, muy muy currada. Gracias de nuevo staff de las NcN!! 🙂

acONOnado con el nuevo servicio de Wi-Fi gratis de ONO

Andaba yo tranquilamente viendo la televisión un rato, cuando veo un fantástico anuncio de la compañía ONO en la televisión en la que se ofrece a los clientes móviles acceso a Internet de alta velocidad mediante Wi-Fi. Rápidamente caí en la cuenta de que esta misma semana (que estaba experimentando problemas con la Wi-Fi de mi casa) había visto una red Wi-Fi rara: “_AUTO_ONOWiFi”, y me temía lo peor…

Al acceder a la página de ONO para consultar acerca del servicio me he encontrado perlas como esta:

Captura de pantalla 2014-07-04 a la(s) 19.30.53

 

 

Vaya, un servicio que pueden utilizar incluso no clientes… mmm, cómo lo ofrecerán, habrán puesto antenas por ahí? veamos más… por ejemplo las condiciones legales del servicio…

Captura de pantalla 2014-07-04 a la(s) 19.35.21

WTF! Red doméstica formada gracias a la reconfiguración de los cable módems de nuestros clientes!!!! seguro que les habrán avisado…

pues no! resulta que mi cable módem era uno de los bonitos que estaba ofreciendo este servicio por la cara, y sin avisarme previamente… desde luego que mis días como cliente de ONO están contados.

Si sois usuarios de ONO chequead que vuestro cable módem no esté publicando una Wi-Fi con el SSID mencionado antes, y si lo está y no estáis de acuerdo (yo desde luego NO cedo MI INFRAESTRUCTURA sin haber dado NINGÚN TIPO DE  CONSENTIMIENTO PREVIO y SIN HABER SIDO NOTIFICADO), podéis solicitar la baja en la propia página de ONO. Yo comprobé de forma fácil que mi cable módem era un “lila” porque la intensidad de la Wi-Fi “pa la peña” esa era la misma que la de mi Wi-Fi; sin complicarme más apagué mi cable módem para ver desaparecer ambas Wi-Fi a la vez: la de mi casa y la otra de mi casa que ONO utiliza para invitar a navegar a la gente.

Captura de pantalla 2014-07-04 a la(s) 19.41.30

He ido tan rápido y malhumorado a deshabilitarlo que no me ha dado ni tiempo a pegarle un vistazo a lo que se podía hacer desde ahí…

Captura de pantalla 2014-07-04 a la(s) 19.43.31

 

Los muy majos además te ponen la desactivación del 2º SSID desde “Mis productos”, en fin…

Después de deshabilitarlo he googleado un poco y había gente que lo advertía ya desde hace tiempo.

Espero que no os hayan dado el palo como me lo han dado a mí.

Buen fin de semana!

 

“Kicking around SCADA!” en RootedCON 2014

Los pasado días 6, 7 y 8 de Marzo se celebró en Madrid la V edición de las RootedCON. En ella, nuestro compañero Juan Vázquez (@_juan_vazquez_) y yo mismo (@julianvilas) tuvimos la oportunidad de presentar el resultado del trabajo de investigación sobre SCADA que llevábamos realizando los últimos meses.

La ponencia se tituló “Tú a Boston Barcelona y yo a California Tejas. A patadas con mi SCADA!”, y en ella explicamos las vulnerabilidades que encontramos en el producto Yokogawa CENTUM CS3000, un Sistema de Control Distribuido (DCS/SCADA) desplegado en más de 7.600 instalaciones a lo largo del mundo (según el fabricante), utilizado en refinerías, petroquímicas, sector energético, oil&gas, y un largo etcétera de entornos considerados infraestructuras críticas.

Se encontraron vulnerabilidades a nivel de configuración del entorno / software base, a nivel de diseño de los protocolos (ausencia de cifrado, autenticación, control de integridad, etc.), y a nivel de implementación. Estas últimas se corresponden con los advisories publicados por el fabricante y por el ICS-CERT (CVE-2014-0781, CVE-2014-0783, CVE-2014-0784), vulnerabilidades provocadas por desbordamientos de buffer en el stack y en el heap que permiten ejecución remota de código, para las cuales ya se han publicado tanto parches como pruebas de concepto (exploits) en Metasploit Framework.

También hicimos una demostración de posibles acciones de post-explotación una vez comprometido el sistema, en la que troyanizábamos las comunicaciones entre las estaciones de operación (HIS) y el controlador (FCS). Para finalizar la charla contamos también los resultados de escanear internet gracias a la colaboración de Rapid7 y su proyecto Sonar, que realiza este tipo de escaneos.

Podéis ver las slides de la charla en Slideshare, y tan pronto como la organización de RootedCON publique los vídeos actualizaremos el post.

Agradecer desde aquí a la RootedCON y a todos sus asistentes el habernos permitido pasar un tan buen momento.

Saludos!

Solución reto Australia – Final CTF NcN 2013

A continuación la solución al reto de Australia, que por desgracia no nos dio tiempo a resolver en el mismo CTF, pero que hemos resuelto posteriormente y ahora os exponemos.

Al acceder a la IP del servidor correspondiente al país “Australia”, se podía descargar un binario para proceder a su análisis. El binario era un ejecutable de Linux (ELF), que pedía introducir una clave que, principalmente, consistía en el flag que debíamos introducir para obtener la puntuación del juego.

Screen Shot 2013-11-30 at 10.11.14 AM

En el CTF optamos por hacer un reversing estático del programa con IDA, y para ganar tiempo, se obtuvo el código C mediante el empleo de HexRays:

signed int __cdecl main()
{
 signed int result; // eax@2
 int v1; // [sp+1Ch] [bp-4h]@1
print_header();
 v1 = malloc(goodboy_len);
 if ( v1 )
 {
 sub_80481A0();
 if ( fgets(v1, goodboy_len - 1, stdin[0]) )
 {
 if ( check_buffer(v1, goodboy_len - 2) )
 puts("Winner! Post your flag.");
 else
 fwrite("Sorry, that is not correct.\n", 1, 28, stderr);
 result = 0;
 }
 else
 {
 fwrite("Could not read user input.\n", 1, 27, stderr);
 free(v1);
 result = 2;
 }
 }
 else
 {
 fwrite("Could not allocate buffer.\n", 1, 27, stderr);
 result = 1;
 }
 return result;
}
signed int __cdecl check_buffer(int a1, unsigned int a2)
{
 unsigned int i; // [sp+Ch] [bp-4h]@1
for ( i = 0; i < a2; ++i )
 {
 if ( not_flag[i] != (*(_BYTE *)(a1 + i) ^ 0xCC) )
 return 0;
 }
 return 1;
}

Si analizamos el código, se puede observar que el resultado del programa depende del valor de retorno de la función check_buffer(), en la cual el valor del flag XOR’ed con el valor 0xCC debe ser igual al array “not_flag”:

 not_flag[i] != (*(_BYTE *)(a1 + i) ^ 0xCC)

Por lo que para calcular el valor del flag, no hay más que conmutar la función XOR:

0xCC ^ not_flag[i] != (*(_BYTE *)(a1 + i)  

Cabe considerar que la entrada se comprueba BYTE a BYTE, pero eso ya lo analizaremos con detalle más adelante.

Después de varios intentos, pudimos comprobar que el flag no era correcto, por lo que algo fallaba.

Por lo que vamos a utilizar GDB para hacer un análisis dinámico y ver realmente que es lo que se estaba fallando.

Desensamblamos la función check_buffer:

Screen Shot 2013-11-30 at 10.43.11 AM

Analizamos el punto donde se realiza la XOR:

Screen Shot 2013-11-30 at 10.52.05 AM

El BYTE con el cual se realiza una XOR con la entrada del usuario se almacena en la posición -0x7(%ebp).

El siguiente código corresponde al cálculo del valor  que será utilizado para la operación XOR:

0x08048433 <+25>: movl $0xcd000000,-0xc(%ebp) --> -0xc(%ebp) = 0xcd000000
[...]
0x0804843c <+34>: mov -0xc(%ebp),%eax --> EAX = 0xcd000000
0x0804843f <+37>: shr $0x18,%eax --> Shift_Right(EAX,0x18) EAX = 0xCD
0x08048442 <+40>: mov %al,-0x7(%ebp) --> -0x7(%EBP) = 0xCD
0x08048445 <+43>: movzbl -0x7(%ebp),%eax --> %eax = 0xCD
0x08048449 <+47>: and $0xf,%EAX--> %eax = 0xd
0x0804844c <+50>: mov %al,-0x5(%ebp) --> -0x5(%ebp) = 0x0d
0x0804844f <+53>: movzbl -0x7(%ebp),%eax --> %eax = 0xcd
0x08048453 <+57>: and $0xfffffff0,%eax --> %eax = 0xc0
0x08048456 <+60>: mov %al,-0x6(%ebp) --> -0x6(%ebp) = 0xc0
0x08048459 <+63>: movzbl -0x6(%ebp),%eax --> %eax = 0xc0
0x0804845d <+67>: mov %eax,%edx --> %edx = 0xc0
0x0804845f <+69>: shr $0x4,%dl --> %dl (0-7bit) = 0xc
0x08048462 <+72>: movzbl -0x5(%ebp),%eax --> %eax = 0x0d
0x08048466 <+76>: shl $0x4,%eax --> %eax = 0xd0
0x08048469 <+79>: add %edx,%eax --> %eax = 0xdc
0x0804846b <+81>: mov %al,-0x7(%ebp) -->0x7(%ebp) = 0xdc

Con GDB no es necesario realizar todos los cálculos, sino únicamente con insertar un breakpoint en el punto en el que se realiza la XOR y ver qué hay almacenado en el registro %eax:

Screen Shot 2013-11-30 at 11.04.07 AM

Por lo que, en lugar de hacer una XOR con el valor 0xCC como se indicaba en el código, realmente se hace una XOR con el valor 0xDC.

Llegados a este punto, únicamente nos queda definir el formato mediante el cual se ha de introducir el flag. 

Según el código analizado, los valores introducidos por el usuario se almacenan en el registro %eax como resultado de la operación XOR, y los valores son comparados byte a byte mediante el uso del registro %al.

Screen Shot 2013-11-30 at 1.23.41 PM

Screen Shot 2013-11-30 at 11.04.07 AM

Los valores son comparados en formato hexadecimal, en cambio los valores son obtenidos de la entrada del usuario mediante la función fgets, por lo que los datos son obtenidos en formato ASCII. Por este motivo, para obtener los valores del flag hay que hacer una XOR del byte de la variable “not_flag” con el valor 0xDC y hacer una conversión a ASCII, tal y como se muestra a continuación:

Screen Shot 2013-11-30 at 1.35.17 PM

Así que para finalizar, solo hay que obtener los bytes de la variable “not_flag”:

Screen Shot 2013-11-30 at 1.38.48 PM

Y automatizar el proceso para obtener el valor del flag:

#!/usr/bin/ruby
not_flag = [0xeb, 0xe8, 0xbf, 0xe4, 0xea, 0xbe, 0xba, 0xe4, 
 0xe5, 0xea, 0xe8, 0xea, 0xe8, 0xee, 0xe9, 0xba, 
 0xea, 0xe8, 0xeb, 0xba, 0xbf, 0xba ,0xeb, 0xea,
 0xe8, 0xef, 0xbd, 0xba, 0xed, 0xe9, 0xba, 0xee,
 0xe9, 0xed, 0xbe, 0xed, 0xe4, 0xea, 0xbe, 0xba, 
 0xe9, 0xe4, 0xbd, 0xea, 0xb8, 0xe9, 0xb8, 0xbf, 
 0xeb, 0xb9, 0xbe, 0xe4, 0xbe, 0xba, 0xe5, 0xbf, 
 0xba, 0xbf, 0xe5, 0xb8, 0xec, 0xe8, 0xbf, 0xb8]
puts "Solucion: "
not_flag.each { v | 
 p (0xdc ^ v).chr
}
puts

Y finalmente, podremos verificar que el flag introducido es correcto 🙂

Screen Shot 2013-11-30 at 1.45.23 PM

Disfrutamos mucho del CTF. Esperamos ansiosos poder participar en otro bien pronto.

Saludos!

Solución reto China – Final CTF NcN 2013

Hace unos días tuvimos la suerte de poder participar en la final del CTF de las No cON Name 2013, organizado por el Security Staff de Facebook.

La verdad, estuvo genial organizado y realmente nos divertimos mucho. ¡Felicidades Facebook & NcN staff! Enhorabuena también a los otros participantes, y en especial a los ganadores 🙂

En el concurso se publicaron un conjunto de servidores, cada uno de ellos correspondiente con un país.

Cada servidor/país podía ser una base o un flag:

  • Las bases contenían retos que podían ser resueltos una vez por cada equipo.
  • Los flags contenían algún tipo de vulnerabilidad que permitía a los equipos capturarlo (el flag). Los puntos se otorgaban por el tiempo que el equipo tuviese en su poder el flag. Básicamente los flags consistían en escribir en el fichero “/tmp/SCORE_POINTS” del servidor en cuestión, el nombre del equipo.

En este post os vamos a explicar como pudimos capturar el flag de China! 🙂

Al realizar un escaneo de puertos contra el servidor, éste presentaba abiertos los puertos 80 y 12345. El segundo era el utilizado por la organización para monitorizar los flags, así que procedimos a acceder al puerto 80.

Imagen

Y esto era lo que nos encontramos. Lo primero que hicimos, tirar de google translate para traducir el texto en chino. Básicamente era un formulario de login. Al probar a autenticarse, daba un error en el usuario/contraseña, y las pruebas de inyección realizadas no dieron resultado.

Por lo que procedimos a examinar con más detalle las peticiones y respuestas intercambiadas. Para ir al grano, el punto interesante era el proceso de autenticación:

Imagen

Y ¿qué era lo interesante de este caso?

  1. Un token AntiCSRF en el formulario de autenticación nos pareció un poco raro. Este tipo de tokens se utiliza en formularios que permiten hacer algún tipo de modificación
  2. El token AntiCSRF, tiene pinta de algo codificado (desde luego no de un hash)

Procedimos a su decodificación:

Imagen

Lo que nos indicaba que era un archivo binario, nos revelaba un path con un archivo .py, nos mostraba un hash y la palabra secret. Volcamos el contenido en un fichero y ejecutamos el comando file:

python 2.7 byte-compiled

Por lo que procedimos a decompilarlo:

Imagen

Básicamente lo que contenía era una asignación de una variable, siendo el path un metadato del fichero. Por lo que construimos nuestro propio python:

Imagen

Generamos un fichero byte-compiled (.pyc):

Captura de pantalla 2013-11-07 a la(s) 00.19.04

Lo codificamos en base64:

Captura de pantalla 2013-11-07 a la(s) 00.24.28

Y finalmente hacemos tampering de la petición cambiando el token AntiCSRF por el que hemos generado nosotros, y voilà! habíamos capturado la bandera de China 🙂

Esperamos poder subir en los próximos días alguna solución más 🙂

Un saludo!

Write-up del 2º Reto del CTF de la No cON Name 2013

Buenas a todos!

Vamos a cerrar el fin de semana y ésta cadena de posts exponiendo la solución al segundo reto del CTF de las NoConName 2013 que se celebró el pasado fin de semana.

El juego consistía en una aplicación Android (.APK) que debía ser descargada de la pagina oficial del CTF.

Una vez instalada en el emulador o dispositivo, a nuestro pesar observamos que ésta no se ejecutaba correctamente, dando lugar a un error desconocido de entrada.

Rascando los ficheros de log del dispositivo mediante la aplicación CatLog, pudimos observar que algo no funcionaba correctamente en la aplicación, concretamente se mostraba el mensaje de error que se muestra a continuación:

screenshot-1380333703143

Efectivamente, parecía que había algún tipo de error producido por un fichero Manifest.xml mal generado.

Para obtener el fichero Manifest.xml primero hay que decompilar el código fuente de la aplicación. Para ello se utilizó la herramienta APKTOOL:

Una vez instalada la herramienta en el sistema, obtener el decompilado de la aplicación , y consecuentemente el fichero Manifest.xml, ejecutando lo siguiente:

root@bt:~/Desktop# apktool d level.apk
I: Baksmaling...
I: Loading resource table...
I: Loaded.
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: /root/apktool/framework/1.apk
I: Loaded.
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
I: Done.
I: Copying assets and libs...
root@bt:~/Desktop#

A continuación se muestra el fichero Manifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest android:versionCode="1" android:versionName="1.0" package="com.facebook_ctf.challenge"
 xmlns:android="http://schemas.android.com/apk/res/android">
 <application android:theme="@style/AppTheme" android:label="@string/app_name" android:icon="@drawable/ic_launcher">
 <activity android:label="@string/title_activity_main" android:name="com.facebook_ctf.challenge.MainActivity">
 <intent-filter>
 <action android:name="android.intent.action.MAIN" />
 <category android:name="android.intent.category.LAUNCHER" />
 </intent-filter>
 </activity>
 <activity android:label="@string/title_activity_main" android:name="com.facebook_ctf.challenge.MainActivity" />
 </application>
</manifest>

Cómo se puede observar, hay dos MainActivity definidas, lo cual ocasiona un conflicto que evita que la aplicación pueda ser iniciada correctamente. Eliminando una de las dos líneas que definen el MainActivity será suficiente para que la aplicación sea ejecutada correctamente.

Una vez modificado el fichero Manifest.xml, hay que volver a recompilar la aplicación. Para ello volvímos a utilizar la herramienta APKTOOL pero ahora además es necesario el empleo de JARSIGNER para generar la firma:

root@bt:~/Desktop# apktool b level-smali level-modified.apk
I: Checking whether sources has changed...
I: Checking whether resources has changed...
I: Building apk file...
root@bt:~/Desktop# java -jar signapk.jar testkey.x509.pem testkey.pk8 ../level-modified.apk ../level-modified-signed.apk

Al instalar de nuevo la aplicación, ya pudimos ver de que se trataba:

screenshot-1380334377050

La aplicación básicamente funciona de la siguiente forma: Dispone de un botón con la etiqueta “Gimme Gimme!” mediante el cual, cuando se hace TAP sobre él, se muestra una imágen en la aplicación. Concretamente en la aplicación original se muestra de forma aleatória una de las imágenes almacenadas en la carpeta resource de la aplicación:

Screen Shot 2013-10-06 at 8.34.46 PMNo hace falta mucha ingeniería inversa para poder comprobar que las imágenes que se muestran son fragmentos de un código QR que, tal como ya os habréis imaginado, habrá que reconstruir. Así que, Let’s go!

Mediante el proceso de decompilado anteriormente mencionado, también se obtiene el código Dalvik de la aplicación que procederemos a comentar a continuación. No obstante, con la finalidad de poder comprender mejor el funcionamiento de la aplicación, antes de meternos en detalle en el código Smali, primero se procedió a pasar el código almacenado en el fichero classes.dex a Java para sacar un poco de luz al asunto.

Para esta tarea se hizo uso de la herramienta DEX2JAR:

  • DEX2JAR – http://code.google.com/p/dex2jar/

El uso de la herramienta es bastante simple. Solamente es necesario descomprimir el fichero APK (p.ej. con el comando unzip) y posteriormente ejecutar lo siguiente con el fichero classes.dex obtenido:

/dex2jar-0.0.9.15/d2j-dex2jar.sh classes.dex

Mediante la ejecución de dicha herramienta, en conjunto con el uso de JD-GUI, fue posible obtener el código fuente en JAVA, donde se pudo observar cómo en la clase MainActivity se pinta la imágen escogida aleatoriamente. Concretamente se realiza en la función “yaaaay()” mediante la variable “localBitmap17”:

int i = new Random().nextInt(localArrayList.size());
   makeMeHappyAgain(makeMeHappy(localBitmap1, localBitmap2, localBitmap3, localBitmap4), makeMeHappy(localBitmap5, localBitmap6, localBitmap7, localBitmap8), makeMeHappy(localBitmap9, localBitmap10, localBitmap11, localBitmap12), makeMeHappy(localBitmap13, localBitmap14, localBitmap15, localBitmap16));
   Bitmap localBitmap17 = (Bitmap)localArrayList.get(i);
   this.secret.setImageBitmap(localBitmap17);

La función “makeMeHappyAgain”, analizando el código se observó que era la responsable de maquetar el código QR correctamente (bueno casi, pero eso lo veremos más adelante :-P), por lo que por el momento, únicamente había que modificar el código Smali para que en lugar de pintar por pantalla la imagen aleatória almacenada en “localBitmap17”, se pintara el resultado de la llamada a la función “makeMeHappyAgain”:

Screen Shot 2013-09-28 at 4.20.42 AM

En la imágen anterior, se puede apreciar cómo se modificó el código Smali original para que en la última llamada al método virtual “setImageBitmap”, en lugar de utilizar el valor “v1”,  se utilizara el valor “v4” que es la variable resultado de la llamada a la función “makeMeHappyAgain”, definido por la  instrucción “move-result-object v4”.

Aunque a simple vista, una vez recompilado el código y ejecutado de nuevo parece ser que el código QR se genera correctamente, realmente no fue así 😦

Hay  dos imágenes que no están correctamente posicionadas, lo cual no nos permitía escanear correctamente el QR y obtener la clave del reto. Para ello hay que hacer otra modificación del código Smali para hacer swap de las imágenes “c.png” (0x7f040002) y “g.png” (0x7f040006). Para obtener la relación entre las imágenes y sus correspondientes  identificadores Hex hay que consultar el fichero “public.xml” almacenado en la carpeta  de los resources (res) de la aplicación.

A continuación se muestra el código resultante de dicha modificación:

Screen Shot 2013-09-28 at 4.22.51 AM

Finalmente, una vez recompilada, refirmada y reinstalada la aplicación se puede observar el código QR generado correctamente:

welldone

Y posteriormente, una vez escaneado, obtuvimos la SECRET KEY del Reto:

screenshot-1380333471692

Solo nos queda felicitar a los 12 equipos que se han clasificado en la final que se celebrará el día 1 de Noviembre en el congreso NoConName 2013:

Screen Shot 2013-10-06 at 8.16.14 PM

……y decir que logramos clasificarnos en 7º posición 😉

Así que nos vemos en la final!

Reto 1 del CTF de las No cON Name 2013

Hola a todos, hola a tothom!

Mi nombre es Ignasi M. (ny4nyi) y he tenido el placer de ser invitado a participar en este blog. Es todo un honor. Espero que todo lo que pueda aportar os sea útil y disfrutéis!

Sobretodo, dar las gracias a Julian y a todo el equipo por darme esta oportunidad de poder participar con gente tan grande.

Ahora, a por materia.

El primer reto del CTF NoConName 2013 consistía en una página web que solicita una clave secreta para superar el reto.

Paso 1

La primera aproximación fue probar un número aleatorio para estudiar el comportamiento normal de la página. Obviamente, se produce un error de “Clave incorrecta” y se sigue en la misma página inicial (ya hubiera sido la ostia acertar a la primera ).

Una vez se conoce el comportamiento estándar de la página, se realizó un estudio del código fuente de la misma, y se encuentra lo siguiente:

   <head>

    <title>NcN 2013 Registration Quals</title>

    <link rel=”stylesheet” href=”../res/main.css” type=”text/css” media=”screen”/>

    <link href=’../res/UbuntuMono.css’ rel=’stylesheet’ type=’text/css’>

    <meta content=”Javier Marcos @javutin” name=”author” />

    <script type=”text/javascript” src=”crypto.js”></script>

  </head>

La página carga un “js” de nombre “crypto.js” que es el responsable de realizar la validación. Resaltar que al tratarse de un “js” se ejecuta en el navegador del cliente, no en servidor. Por lo tanto, el siguiente paso a seguir es realizar un estudio del código del “js” y entender su lógica/funcionamiento para identificar la posible manera de evadir o hallar la clave secreta de forma exitosa.

Se accede al archivo “cryto.js” para obtener su código fuente. Es algo tan bonito como esto:

var_0x52ae=[“\x66\x20\x6F\x28\x38\x29\x7B\x63\x20\x69\x2C\x6A\x3D\x30\x3B\x6B\x28\x69\x3D\x30\x3B\x69\x3C\x38\x2E\x6C\x3B\x69\x2B\x2B\x29\x7B\x6A\x2B\x3D\x28\x38\x5B\x69\x5D\x2E\x73\x28\x29\x2A\x28\x69\x2B\x31\x29\x29\x7D\x67\x20\x74\x2E\x75\x28\x6A\x29\x25\x76\x7D\x66\x20\x70\x28\x68\x29\x7B\x68\x3D\x68\x2E\x71\x28\x30\x29\x3B\x63\x20\x69\x3B\x6B\x28\x69\x3D\x30\x3B\x69\x3C\x77\x3B\x2B\x2B\x69\x29\x7B\x63\x20\x35\x3D\x69\x2E\x78\x28\x79\x29\x3B\x6D\x28\x35\x2E\x6C\x3D\x3D\x31\x29\x35\x3D\x22\x30\x22\x2B\x35\x3B\x35\x3D\x22\x25\x22\x2B\x35\x3B\x35\x3D\x7A\x28\x35\x29\x3B\x6D\x28\x35\x3D\x3D\x68\x29\x41\x7D\x67\x20\x69\x7D\x66\x20\x6E\x28\x38\x29\x7B\x63\x20\x69\x2C\x61\x3D\x30\x2C\x62\x3B\x6B\x28\x69\x3D\x30\x3B\x69\x3C\x38\x2E\x6C\x3B\x2B\x2B\x69\x29\x7B\x62\x3D\x70\x28\x38\x2E\x71\x28\x69\x29\x29\x3B\x61\x2B\x3D\x62\x2A\x28\x69\x2B\x31\x29\x7D\x67\x20\x61\x7D\x66\x20\x42\x28\x39\x29\x7B\x63\x20\x32\x3B\x32\x3D\x6E\x28\x39\x2E\x64\x2E\x65\x29\x3B\x32\x3D\x32\x2A\x28\x33\x2B\x31\x2B\x33\x2B\x33\x2B\x37\x29\x3B\x32\x3D\x32\x3E\x3E\x3E\x36\x3B\x32\x3D\x32\x2F\x34\x3B\x32\x3D\x32\x5E\x43\x3B\x6D\x28\x32\x21\x3D\x30\x29\x7B\x72\x28\x27\x44\x20\x64\x21\x27\x29\x7D\x45\x7B\x72\x28\x27\x46\x20\x64\x20\x3A\x29\x27\x29\x7D\x39\x2E\x47\x2E\x65\x3D\x6E\x28\x39\x2E\x64\x2E\x65\x29\x3B\x39\x2E\x48\x2E\x65\x3D\x22\x49\x22\x2B\x6F\x28\x39\x2E\x64\x2E\x65\x29\x3B\x67\x20\x4A\x7D”,”\x7C”,”\x73\x70\x6C\x69\x74″,”\x7C\x7C\x72\x65\x73\x7C\x7C\x7C\x68\x65\x78\x5F\x69\x7C\x7C\x7C\x73\x74\x72\x7C\x66\x6F\x72\x6D\x7C\x7C\x7C\x76\x61\x72\x7C\x70\x61\x73\x73\x77\x6F\x72\x64\x7C\x76\x61\x6C\x75\x65\x7C\x66\x75\x6E\x63\x74\x69\x6F\x6E\x7C\x72\x65\x74\x75\x72\x6E\x7C\x66\x6F\x6F\x7C\x7C\x68\x61\x73\x68\x7C\x66\x6F\x72\x7C\x6C\x65\x6E\x67\x74\x68\x7C\x69\x66\x7C\x6E\x75\x6D\x65\x72\x69\x63\x61\x6C\x5F\x76\x61\x6C\x75\x65\x7C\x73\x69\x6D\x70\x6C\x65\x48\x61\x73\x68\x7C\x61\x73\x63\x69\x69\x5F\x6F\x6E\x65\x7C\x63\x68\x61\x72\x41\x74\x7C\x61\x6C\x65\x72\x74\x7C\x63\x68\x61\x72\x43\x6F\x64\x65\x41\x74\x7C\x4D\x61\x74\x68\x7C\x61\x62\x73\x7C\x33\x31\x33\x33\x37\x7C\x32\x35\x36\x7C\x74\x6F\x53\x74\x72\x69\x6E\x67\x7C\x31\x36\x7C\x75\x6E\x65\x73\x63\x61\x70\x65\x7C\x62\x72\x65\x61\x6B\x7C\x65\x6E\x63\x72\x79\x70\x74\x7C\x34\x31\x35\x33\x7C\x49\x6E\x76\x61\x6C\x69\x64\x7C\x65\x6C\x73\x65\x7C\x43\x6F\x72\x72\x65\x63\x74\x7C\x6B\x65\x79\x7C\x76\x65\x72\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x7C\x79\x65\x73\x7C\x74\x72\x75\x65″,””,”\x66\x72\x6F\x6D\x43\x68\x61\x72\x43\x6F\x64\x65″,”\x72\x65\x70\x6C\x61\x63\x65″,”\x5C\x77\x2B”,”\x5C\x62″,”\x67″];eval(function (_0x7038x1,_0x7038x2,_0x7038x3,_0x7038x4,_0x7038x5,_0x7038x6){_0x7038x5=function (_0x7038x3){return (_0x7038x3<_0x7038x2?_0x52ae[4]:_0x7038x5(parseInt(_0x7038x3/_0x7038x2)))+((_0x7038x3=_0x7038x3%_0x7038x2)>35?String[_0x52ae[5]](_0x7038x3+29):_0x7038x3.toString(36));};if(!_0x52ae[4][_0x52ae[6]](/^/,String)){while(_0x7038x3-)_0x7038x6[_0x7038x5(_0x7038x3)]=_0x7038x4[_0x7038x3]||_0x7038x5(_0x7038x3);} ;_0x7038x4=[function (_0x7038x5){return _0x7038x6[_0x7038x5];} ];_0x7038x5=function (){return _0x52ae[7];} ;_0x7038x3=1;} ;while(_0x7038x3–){if(_0x7038x4[_0x7038x3]){_0x7038x1=_0x7038x1[_0x52ae[6]]( new RegExp(_0x52ae[8]+_0x7038x5(_0x7038x3)+_0x52ae[8],_0x52ae[9]),_0x7038x4[_0x7038x3]);} ;} ;return _0x7038x1;} (_0x52ae[0],46,46,_0x52ae[3][_0x52ae[2]](_0x52ae[1]),0,{}));

Como se puede ver, el código del “js” esta ofuscado (lastima, habrá que currar más). Ha de quedar claro que esta ofuscado, NO cifrado.

Si se disecciona el código, a grandes rasgos se puede detectar lo siguiente:

  • Una variable de nombre “var_0x52ae” : Parece ser un vector donde el valor de cada posición está representado en código hexadecimal. Recordar que si un valor se escribe como “\x” significa que se representa en sistema hexa.
  • Una función eval: Definición purista, “Si el argumento es una expresión, eval () evalúa la expresión. Si el argumento es una o más sentencias JavaScript, eval () ejecuta las sentencias.”
  • La definición de funciones: Por ejemplo, “function (_0x7038x1,…)”
  • La llamada de funciones: Por ejemplo, “(_0x52ae[0],46,46,_0x52ae[3])”

Aclarar que en las definiciones de las funciones se ven nombres de parámetros tal que “_0x_7038x1” pero se desconoce su valor. Esto es porque en una declaración de función se puede dar cualquier nombre al parámetro, que luego éste recibirá el valor del parámetro usado en la llamada. En resumen, cuando se llame a la función, el valor del parámetro será el siguiente:

_0x7038x1=_0x52AE[0]=”\x66…..\7D”.

Paso 2

Para desofuscar el código js se pueden utilizar diferentes recursos online en la red, o simplemente, modificar la función “eval” por una función “alert” que se encargara de imprimir en una ventana la representación del código sin ofuscar, ya que interpretara todos los valores hexadecimales posibles como caracteres.

El resultado es el siguiente:

Imagen

El código sin ofuscar es:

Function simpleHash(str) {

var i, hash = 0;

for (i = 0; i < str.length; i++) {

hash += (str[i].charCodeAt() * (i + 1))

}

return Math.abs(hash) % 31337

}

 function ascii_one(foo) {

foo = foo.charAt(0);

var i;                              

for (i = 0; i < 256; ++i) {

var hex_i = i.toString(16);

if (hex_i.length == 1) hex_i = “0” + hex_i;

hex_i = “%” + hex_i;

hex_i = unescape(hex_i);

if (hex_i == foo) break

}

return i

}

 function numerical_value(str) {

var i, a = 0,

b;

for (i = 0; i < str.length; ++i) {

b = ascii_one(str.charAt(i));

a += b * (i + 1)

}

return a

}

function encrypt(form) {

var res;

res = numerical_value(form.password.value);

res = res * (3 + 1 + 3 + 3 + 7);

res = res >>> 6;

res = res / 4;

res = res ^ 4153;

if (res != 0) {

alert(‘Invalid password!’)

} else {

alert(‘Correct password :)’)

}

form.key.value = numerical_value(form.password.value);

form.verification.value = “yes” + simpleHash(form.password.value);

return true}

Paso 3

La lógica general de este código es la siguiente:

  1. La función “numerical_value” recibe el valor o cadena “X” que introduce el usuario en la página web y retorna un valor resultado que es la suma de cada carácter de la cadena X en su correspondiente valor decimal ASCII multiplicado por el resultado de la suma del valor de la posición del carácter en la cadena X +1
  2. La función “encryp” se encarga primero de aplicar varias operaciones sobre el valor retornado por la función “numerical_value” y después compara este valor “final” con 0. Si la comparación es cierta, el password (cadena “X”) introducida por el usuario es correcta.
  3. Estudiando con más detalle la función “encrypt” se determina que el valor “final” ha de estar entre el siguiente rango de valores :62540-62554.

Ya con esta información clara el último paso es introducir, mediante técnicas de “brute forcing”, una cadena de valores/caracteres que después de ser tratada por la función “numerical_value” de un valor que pertenezca al rango deseado.

En este caso se encontró la siguiente cadena:

ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZNR

Se introdujo esta cadena en la página web y tachan!:

Congrats! you passed the level! Here is the key:

23f8d1cea8d60c5816700892284809a94bd00fe7347645b96a99559749c7b7b8

Twitter: @Ny4nyi

Bypassing iOS 7 lockscreen with Siri

Hola a todos,

mi nombre es Álex Soler y he tenido el placer que ser invitado a aportar todo lo que pueda y más a la comunidad de (in)seguridad a través de este blog. Así que espero no decepcionaros 🙂

A raíz de las múltiples vulnerabilidades de bypass del lock screen que tanta fama han ganado en las distintas versiones de iOS publicadas, se nos ocurrió estudiar este fenómeno más en detalle y comprobar qué grados de libertad ofrece una vulnerabilidad de este tipo.

Para empezar a calentar, procedimos a analizar las últimas vulnerabilidades de bypass publicadas en la primera release de iOS 7, concretamente las que hacen referencia a los identificadores CVE-2013-5160 y CVE-2013-5161.

La primera vulnerabilidad (CVE-2013-5160) permite que cualquier persona con acceso al dispositivo pueda realizar llamadas sin conocer el código de desbloqueo del mismo. mediante el uso de la funcionalidad de llamadas de emergencia.

La segunda vulnerabilidad (CVE-2013-5161) permite acceder a las fotos realizadas mediante una combinación de teclas realizada en la vista “Temporizador”. Concretamente consiste en habilitar la vista en la que aparece la opción “Apagar” y posteriormente cancelarlo a la vez que se presiona dos veces el botón “Home”, cómo si quisiéramos abrir el listado de aplicaciones abiertas en el dispositivo. A continuación se abrirá la vista del listado de aplicaciones abiertas y se permitirá acceder a información personal del teléfono cómo por ejemplo las fotos o los contactos.

Vamos a centrarnos en la segunda para lo que realmente precede en la presente entrada de blog. En el siguiente vídeo puede observarse cómo se explota la vulnerabilidad mencionada:

En el anterior vídeo se puede observar cómo es posible acceder tanto a las fotos como a los contactos como bien prometía la descripción de la vulnerabilidad, no obstante, cabe destacar tal como se observa en el vídeo que aunque sí se dispone de acceso a la agenda de contactos, no es posible acceder a los respectivos números de teléfono.

Pero esto no nos supone un problema, en este caso podremos recurrir a nuestra gran amiga/amante en el mundo iOS: SIRI.

 siri

Curiosamente muchos usuarios de iPhone hacen uso de esta magnífica funcionalidad que permite hacer uso de nuestro dispositivo sin ni siquiera tocar una tecla. Algunos ejemplos indicados en la propia ayuda son los siguientes:

  • Abre Fotos
  • Abrir aplicación Contactos
  • Abre Fotos
  • Llamar
  • Etc…

Algunas funcionalidades del Siri, como por ejemplo acceder a la aplicación contactos o ver los correos, te piden el correspondiente código PIN. No obstante, como es de suponer, otras no.

En el siguiente vídeo, se puede observar cómo es posible acceder a la agenda (incluídos los números de teléfono) a través de Siri. El truco consiste en nombrar una cadena de texto que se encuentre dentro de un contacto existente en la agenda. (por ejemplo, la cadena “No Se” haría referencia a contactos como “Sergio”):

En la versión de iOS 6, el acceso a los contactos se rige al puro estilo “Brute Force”, probando cadenas que estén contenidas en los contactos e ir llamándoles para obtener sus números. En cambio en la versión de iOS 7 la tarea es mucho más simple, dado que a través del botón “Otros” podremos acceder a la agenda al completo.

Recientemente ya se ha reproducido el mismo problema mediante otras técnicas de Bypass combinadas con el uso de Facetime:

http://thehackernews.com/2013/09/another-iphone-lockscreen-bypass.html

Cómo solución a este tipo de problemas, lo más sensato es deshabilitar el uso de Siri en el screen lock como se muestra a continuación, algo que personalmente pienso debería estar deshabilitado por defecto:

photo

Así que, ¿Seguís confiando en Siri?

CTF de la No cON Name 2013 (write-up)

Buenas a todos,

después de algún tiempo sin nuevas entradas en el blog, hemos pensado que una buena forma de regresar sería publicando nuestras soluciones a los retos de la ronda clasificatoria del primer CTF que se organiza en las conferencias No cON Name, en este año 2013.

Esta ronda de clasificación ha consistido en la resolución de un juego de estilo “Jeopardy”, consistente en 3 niveles. El primero de ellos relacionado con Web, el segundo con Android y el tercero con reversing de binarios.

Imagen

 

En este post describiremos cómo solucionamos el nivel 3, en el que se entregaba un binario de tipo ELF de 64 bits. Al ejecutarlo mostraba lo siguiente:

De forma que al escribir, el programa finalizaba indicando el siguiente mensaje:

Para resolver el desafío hicimos un desensamblado del binario, y analizamos su comportamiento. En primer lugar el programa imprimía por pantalla el texto que hemos podido ver anteriormente:

Imagen

 

A continuación entraba en un bucle de 10 iteraciones, en el que se van leyendo los caracteres introducidos por el usuario y se comparan con el contenido de la variable “facebookctf_rocks”. Esta variable es un array de DWORDs, en las que el byte más significativo de cada DWORD contiene el valor que va a comparar con el carácter introducido por el usuario, y los otros 3 bytes de la DWORD son ceros.

Imagen

 

El contenido de la variable “facebookctf_rocks” es el siguiente:

20 00 00 00

53 00 00 00

55 00 00 00

52 00 00 00

50 00 00 00

52 00 00 00

49 00 00 00

53 00 00 00

45 00 00 00

21 00 00 00

Y teniendo en cuenta lo explicado anteriormente, se corresponde con la cadena “\x20\x53\x55\x52\x50\x52\x49\x53\x45\x21”, o lo que es lo mismo ” SURPRISE!” (con un espacio al principio). 

Si introducimos esa cadena, el programa muestra el siguiente mensaje:

 

Una forma alternativa de obtener la clave (sin introducir el texto), es analizar la parte final del binario, en la que se aprecian tres caminos diferentes: que se haya presionado la tecla de salida (call seeyaaaa), que se haya introducido un carácter que no es el esperado (call game_over), o que se haya introducido la cadena esperada (call success).

Imagen

 

Por lo que si debugueamos el programa y modificamos el EIP por la dirección de memoria donde se llama a la función “success” (0x000000000040117B), obtendremos el mismo resultado. 

En breve publicaremos la solución de los otros 2 niveles 🙂

Saludos!!