UAM: Reverseando la MOVida malagueña

Introducción

Descargamos el binario de la web del reto, lo descomprimimos y comprobamos su hash. Lo primero que nos llama la atención es la información que nos muestra readelf:

readelf -h Thestral_6ee87b9724dcf5c41ebba4cd578841be
ELF Header:
Magic: 7f 45 4c 46 01 02 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2’s complement, big endian
Version: 1 (current)
OS/ABI: UNIX – System V
ABI Version: 0
Type: <unknown>: 200
Machine: <unknown>: 0x300
Version: 0x1000000
Entry point address: 0x1c830408
Start of program headers: 872415232 (bytes into file)
Start of section headers: 1352047616 (bytes into file)
Flags: 0x0
Size of this header: 13312 (bytes)
Size of program headers: 8192 (bytes)
Number of program headers: 1536
Size of section headers: 10240 (bytes)
Number of section headers: 5120
Section header string table index: 4864
readelf: Warning: The e_shentsize field in the ELF header is larger than the size of an ELF section header
readelf: Error: Reading 52428800 bytes extends past end of file for section headers
readelf: Warning: The e_phentsize field in the ELF header is larger than the size of an ELF program header
readelf: Error: Reading 12582912 bytes extends past end of file for program headers

Estamos ante un binario de 32 bits, formato ELF, y los datos de la cabecera no son correctos. Simplemente viendo los valores en los campos Type y Machine, ya nos da la pista de lo que hay que corregir: el byte que indica la endianness del binario (fijémonos que readelf lo interpreta como big endian, cuando x86 es little endian). Editamos el byte en el offset 0x5 y lo cambiamos de 0x2 a 0x1 (https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header):

00000000: 7f45 4c46 0102 .ELF..

00000000: 7f45 4c46 0101 .ELF..

Con este cambio, readelf ya nos interpreta los bytes de la manera correcta. Ahora podremos usar el binario dentro de una sesión de depuración con gdb:

readelf -h Thestral_6ee87b9724dcf5c41ebba4cd578841be
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2’s complement, little endian
Version: 1 (current)
OS/ABI: UNIX – System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x804831c
Start of program headers: 52 (bytes into file)
Start of section headers: 10262096 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 6
Size of section headers: 40 (bytes)
Number of section headers: 20
Section header string table index: 19

Buscando cadenas

Antes de analizar el binario dentro de r2, ejecutamos una pasada del comando strings para ver que nos encontramos:

UAM{
m0v3
_me_
1n_7
t0_7
h3_h
0gw4
rts_
cR3w
sch0
_:P}
Mmmmm sorry man.. But that’s not the secret 🙁
Yay!! That was the secret! 😀
Incorrect length! 🙁
Do you know what’s the secret? Tell me the secret:
UAM{this_is_not_the_flag_lol_xd_:P}

Aparte de lo que parecería ser una flag falsa, vemos partes de lo que podría ser una flag correcta. Si nos fijamos bien en los primeros caracteres, parecería que nos falta “0l” de “sch00l”. Eso es algo muy fácil de ver; buscamos cadenas con 3 caracteres, a ver si suena la flauta:

UAM{
pUt
m0v3
_me_
1n_7
t0_7
h3_h
0gw4
rts_
cR3w
sch0
_:P}
0l}

Efectivamente, nos aparece “0l}” y la cadena “pUt”. Esto tiene toda la pinta de ser los caracteres de la flag correcta.

Empieza la MOVida

Lanzamos r2 y nos ponemos a analizar el binario. Tras un rato mirando el código desensamblado de algunas de las funciones del programa, ya nos damos cuenta de que algo no cuadra. ¡Todo son MOVs! Encontramos la explicación en las propias cadenas:

/home/asegura/tools/movfuscator/build//crtd.o

Una rápida búsqueda en Google nos muestra que este binario ha sido ofuscado utilizando Movfuscator. Aparentemente, hay un proyecto de un desofuscador, Demovfuscator. A pesar de ser muy tentador usar el desofuscador, dedicaremos un tiempo a entender los principios de Movfuscator leyendo su paper y usándolo para localizar patrones en el código con códigos simples de ejemplo.

Analizando la MOVida y casi muriendo en el acto

Sabemos, tras leer el paper sobre el ofuscador, que lo primero que hace es registrar 2 handlers para las señales SIGILL y SISGEV. Para cambiar el flujo de ejecución dentro del propio binario, movfuscator usa excepciones de tipo “Illegal Instruction”, mientras que para ejecutar instrucciones externas genera excepciones de tipo “Segmentation Fault”. Para seguir el control del flujo de llamadas a funciones externas la cosa es tan sencilla como usar, por ejemplo, strace y alimentar el programa con cualquier entrada:

echo “LALALALA”|strace ./Thestral_6ee87b9724dcf5c41ebba4cd578841be

Nos interesan las señales SISGEV. Observamos esto:

— SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} — ; printf();
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x8), …}) = 0
brk(NULL) = 0x8c8d000
brk(0x8cae000) = 0x8cae000
brk(0x8caf000) = 0x8caf000
write(1, “Do you know what’s the secret? T”…, 52Do you know what’s the secret? Tell me the secret:
) = 52
— SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} — ; fgets();
fstat64(0, {st_mode=S_IFIFO|0600, st_size=0, …}) = 0
read(0, “LALALALA\n”, 4096) = 9
— SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} — ;strlen();
— SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} — ;printf();
write(1, “Incorrect length! :(\n”, 21Incorrect length! 🙁
) = 21
— SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} — ;exit(-1);
exit_group(-1) = ?
+++ exited with 255 +++

Con una entrada de una longitud inferior a la que espera el programa, vemos diferentes llamadas a la libc justo después de cada segmentation fault. Vamos a usar r2 para intentar determinar los diferentes control path del programa dependiendo de su entrada:

Asignando el handler sa_dispatch para saltar a funciones externas.

El código anterior, en el punto de entrada del binario, registra el handler “sa_dispatch” para procesar la señal 0xb (11, SIGSEGV), Segmentation Fault. Echamos un vistazo rápido a dicho método, que no tiene mayor complicación:

Salto al offset indicado en “external” para ejecutar una llamada externa.

Este código recupera el valor real de la pila sobre el registro ESP, y luego salta a la dirección almacenada en “external”, que apuntará a un dirección válida de una función externa al programa (llamadas a la libc). Recordemos que estamos en arquitectura x86, y los parámetros se pasan por la pila. Después de leer sobre movfuscator, sabemos que éste utiliza 2 pilas virtuales (la virtual stack y la virtual discard stack) pero en el caso de las llamadas a la libc, ésta necesitará acceso a la pila real del programa. Por eso se restaura en la primera línea del método “sa_dispatch”.

Seguir, pues, el control del flujo del programa en cuanto a llamadas externas es fácil. Podemos simplemente ver que valores literales se ponen en “external” mediante instrucciones “mov”, y luego identificar dichos offsets con llamadas a la libc. Así tendremos una idea de lo que está haciendo el programa:

Usando r2, podemos ver claramente que estos OFFSETS se corresponden con las funciones de la libc en la @plt siguientes:

Sabiendo esto, ya sabemos que, si introducimos un código con una longitud diferente de la deseada, el flujo del programa será:

0x0804d597: printf(Tell me the secret.) main
0x0804d87f: fgets(secret) main
0x0804daa1: strlen(secret) == <expected_len> ? main
No:
0x0804df84: printf(Longitud Incorrecta) main
0x0804e14c: exit(-1) main ok

Debemos descubrir, primero de todo, la longitud que espera el programa.

Comprobación de la longitud del secreto

Sabemos que movfuscator asigna valores mediante literales. Por ejemplo, una asignación en lenguaje C del tipo:

int a= 0x23;

Se traduce, tras compilar con movfuscator, en:

mov dword [loc.R2], 0x23

Donde R2 es un virtual register de movfuscator (sí, no tan solo tiene 2 pilas virtuales, el muy cabr….). Sabiendo esto, miramos en la función main si hay algún valor literal asignado a R2:

Buscando literales sobre el Virtual Register R2.

Sabemos que la longitud de la cadena debe ser mayor que 0, y probablemente mayor que 1 carácter ;-). Así que el valor 0x23 (35) es un muy buen candidato. Si observamos la flag falsa, tiene precisamente 35 caracteres:

Longitud de la flag falsa, 35 caracteres.

Probamos a alimentar el programa con la flag falsa. De paso, lo ejecutamos dentro de strace para ver las diferencias del flujo de ejecución con respecto al primer intento:

echo “UAM{this_is_not_the_flag_lol_xd_:P}”|strace ./Thestral_6ee87b9724dcf5c41ebba4cd578841be

El resultado, esta vez, nos confirma que 35 es la longitud de la clave (sin incluir el carácter de nueva línea \x0a). Pero también vemos cosas interesantes con strace:

(…)

— SIGILL {si_signo=SIGILL, si_code=ILL_ILLOPN, si_addr=0x80553dc} —
— SIGILL {si_signo=SIGILL, si_code=ILL_ILLOPN, si_addr=0x80553dc} —
— SIGILL {si_signo=SIGILL, si_code=ILL_ILLOPN, si_addr=0x80553dc} —
— SIGILL {si_signo=SIGILL, si_code=ILL_ILLOPN, si_addr=0x80553dc} —
— SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} — ; printf();
write(1, “Mmmmm sorry man.. But that’s not”…, 47Mmmmm sorry man.. But that’s not the secret 🙁
) = 47
— SIGILL {si_signo=SIGILL, si_code=ILL_ILLOPN, si_addr=0x80553dc} —
— SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} — ;exit(1);
exit_group(1) = ?
+++ exited with 1 +++

Hay un montón de SIGILLs. Sabemos, por el paper de movfuscator, que SIGILL se usa para cambiar el control de flujo dentro del binario. Sabemos también que el código debe de estar ejecutando algún tipo de comparación con nuestra entrada y, tal vez, las cadenas que hemos visto con el comando string. Usando el parámetro -i de strace, podemos añadir OFFSETS a cada llamada y, así, podemos verificar un poco más lo que hace el programa con las llamadas externas. Vemos, por ejemplo, que la llamada a exit(1) no la ejecuta main, sino la función _dispatch:

[080553dc] — SIGILL {si_signo=SIGILL, si_code=ILL_ILLOPN, si_addr=0x80553dc} —  ; Salto a dispatch.
[08048898] — SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} — ; exit(1)
[f7fa6069] exit_group(1) = ?
[????????] +++ exited with 1 +++

La llamada a exit(1) cuando la clave no es válda la ejecuta dispatch(), no main().

El secreto

Hacer reversing de esto es un suicidio, pero tiene algo de divertido también. Apoyándome en el propio paper del proyecto y leyendo sobre otros CTFs similares (https://x0r19x91.github.io/blog/2019-03-14-utctf-mov/, https://x0r19x91.github.io/blog/2019-04-09-swamp-future-fun/), se va entendiendo la lógica del ofuscador. Sabemos que SIGILL desvía la ejecución DENTRO del binario. Sabemos que, cuando la longitud de la clave NO es la correcta, tras la llamada a fgets() hay una llamada a strlen() y finalmente una llamada a printf() y a exit(-1). No hay desvío del flujo de ejecución dentro del programa en absoluto (no hay SIGILLs). En cambio, si la longitud es la correcta, sí:

[0804d895] — SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} — ; fgets()
[f7f80069] fstat64(0, {st_mode=S_IFIFO|0600, st_size=0, …}) = 0
[f7f80069] read(0, “UAM{this_is_not_the_flag_lol_xd_”…, 4096) = 36
[0804dab7] — SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} — ; strlen(input);
[080553dc] — SIGILL {si_signo=SIGILL, si_code=ILL_ILLOPN, si_addr=0x80553dc} —

Tras este SIGILL, siguen otros. Esto indica que el código está ejecutando la comparación. Por supuesto, movfuscator tiene su propia ALU implementada mediante porrón de tablas 1D y 2D en memoria. Comparar cadenas se traduce en un puro trámite de comparar 2 valores numéricos, pero estamos en 32 bits. No podemos comparar valores numéricos más gordos que 4 bytes de una sola pasada, hay que “trozeralos”. Por eso las “cadenas” que hemos visto con el comando strings, en realidad, se usan dentro de movfuscator como valores numéricos literales de 4 bytes, y no como direcciones de memoria que apuntan a dichas cadenas. Sabiendo esto, buscamos literales sobre algún registro virtual R* que contenga, por ejemplo, “UAM{“:

Buscamos “UAM{” como literal.

En el OFFSET 0x0804e4a3 tenemos el literal 0x7b4d4155 (recordemos que x86 es little endian). Sabiendo esto, vamos a buscar todos los literales sobre el registro virtual R3:

Todos los literales encontrados con el comando strings, se asignan al registro virtual R3.

r2 nos revela que hay una función dentro del binario, strcmp(), que a priori parecería ser la encargada de comparar nuestra entrada, de algún modo, con los valores anteriores. Las comparaciones y los saltos condicionales en movfuscator implican, por regla general, evaluar alguna expresión, activar el flag virtual ZF y asignar el valor a b0. Dependiendo del valor de b0, se ejecutará o no un salto. Recordemos que, al ser todo instrucciones MOV, se ejecutan todas las instrucciones SIEMPRE, da igual la entrada del programa. Es dependiendo de los valores indicados que se usará la virtual discard stack para que la ejecución no afecte al comportamiento del programa, o la virtual stack, para que sí lo haga. Esto es muy importante a tener en cuenta, de lo contrario uno se vuelve majareta entendiendo porqué ciertos valores acaban repitiéndose cuando intenta analizar de manera dinámica la ejecución del programa XD.

Consideramos que la función strcmp() debe comparar 9 partes de nuestra entrada de 4 bytes cada una. Sabemos que son 9 porque buscamos referencias a ZF en la función main() (que llama a strcmp() para comparar cada parte):

Se realizan un total de 10 comparaciones en main que pueden desviar el flujo del programa.

La primera comprobación es la longitud de la entrada. Por eso vemos 10 referencias a ZF. Para estar seguros de esto, podemos usar gdb para alterar la ejecución del programa incluso si la longitud no es 35:

gdb -nx -q ./Thestral_6ee87b9724dcf5c41ebba4cd578841be
Reading symbols from ./Thestral_6ee87b9724dcf5c41ebba4cd578841be…(no debugging symbols found)…done.
(gdb) handle SIGILL nostop
Signal Stop Print Pass to program Description
SIGILL No Yes Yes Illegal instruction
(gdb) handle SIGSEGV nostop
Signal Stop Print Pass to program Description
SIGSEGV No Yes Yes Segmentation fault
(gdb) b * 0x0804dd18
Breakpoint 1 at 0x804dd18

Desactivamos temporalmente el punto de interrupción y ejecutamos el binario hasta que nos pide la entrada:

(gdb) dis
(gdb) r

Interrumpimos la ejecución con CTRL+c y activamos de nuevo el breakpoint. Continuamos con la ejecución del programa e introducimos una cadena de longitud != 35, por ejemplo: “BIRRA”:

(gdb) en
(gdb) c
Continuing.
BIRRA

Una vez el programa se interrumpa en nuestro breakpoint, alteramos el valor del registro AL por 0x1, desactivamos el punto de interrupción y continuamos la ejecución:

Breakpoint 1, 0x0804dd18 in main ()
(gdb) i r al
al 0x0 0
(gdb) set $al = 1
(gdb) dis
(gdb) c

Y voilà! Hemos demostrado que teníamos razón:

Program received signal SIGSEGV, Segmentation fault.
Mmmmm sorry man.. But that’s not the secret 🙁

Program received signal SIGILL, Illegal instruction.

Program received signal SIGSEGV, Segmentation fault.
[Inferior 1 (process 22936) exited with code 01]

El secreto no tan secreto.

Seguimos reverseando con r2, fijándonos en bloques principales y usando nuestros pobres conocimientos sobre el ofuscador para intentar localizar lugares dentro del código que sean clave. Nos fijamos en la función strcmp(). Sabemos que R3 se usa en main para inicializar todos los valores de 4 bytes identificados como partes del secreto (algunas partes más que deducibles ya). Tras analizar a grosso modo la función strcmp(), vemos que en el OFFSET 0x0804bd98 el valor del registro virtual R3 es guardado en el registro EDX. Usando GDB, escribimos un pequeño script:

set pagination off
handle SIGILL nostop
handle SIGSEGV nostop
shell rm -rf gdb.txt
set logging on
 
break * 0x0804bd9e
  commands
    silent
    i r edx
    c
  end
 
r
set logging off
shell cp gdb.txt gdb-run.txt
# Obtener salida de caracteres comparados con exito:
shell cat gdb-run.txt |grep -v "0x86"|grep -E "^edx"|awk '{ print $2 }'|xargs|xxd -p -r|rev;echo ""
q

Alimentamos el programa con una flag errónea, y:

echo “UAM{aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa”|gdb -q -x bp_flag.txt -nx Thestral_6ee87b9724dcf5c41ebba4cd578841be|tail -1
aaaaUAM{UAM{

Probamos con otra flag sin “UAM{“:

echo “AAA{aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa”|gdb -q -x bp_flag.txt -nx Thestral_6ee87b9724dcf5c41ebba4cd578841be|tail -1
AAA{

¡Vaya! Tenemos un oráculo. Como a estas alturas ya estaba algo agotado, escribí un sencillo script en bash que se apoyase en el script de gdb para extraer la flag a partir de los literales guardados en R3:

#!/bin/bash
 
# Todas las cadenas obtenidas con strings -3 y con r2 mov~R3:
flag=("UAM{" "pUt\0" "m0v3" "_me_" "1n_7" "t0_7" "h3_h" "0gw4" "rts_" "cR3w" "sch0" "_:P}" "0l}")
 
# GDB script:
gdbs="bp_flag.txt"
 
# Binario:
binary="Thestral_6ee87b9724dcf5c41ebba4cd578841be"
 
# Argumento pasado al programa:
arg=""
 
# Elementos del array flag-1:
flagl=${#flag[@]}
flagle=`expr $flagl - 1`
 
# 35 as de padding:
padding="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
 
# Bucle para ir obteniendo la clave partida en 9 partes:
for i in  ${!flag[@]};
do
	# Elemento anterior concatenado con nuevo elemento:
	argtmp=${arg}${flag[$i]}
	# Padding hasta la longitud de 35 caracteres:
	argpadded=`printf "%s" ${argtmp} "${padding:${#argtmp}}"`
 
	# Lanzamos GDB y guardamos la ultima linea con los elementos
	# del array reflejados:
	echo "Probando $argpadded"
	out=`echo "${argpadded}"|gdb -q -x $gdbs -nx $binary|tail -1`
 
	# Si el elemento añadido "i" esta en la salida junto con bytes
	# de padding "aaa" delante, es un elemento de la flag. En el
	# caso de que ya no hay padding, bastará con saber si la ejec.
	# del binario nos retorna "Yay":
	if [ ${argtmp} == ${argpadded} ]; then
		# Ya no tenemos padding, lanzamos gdb con esta flag
		# y esperamos el "Yay":
		out=`echo "${argpadded}"|gdb -q -x $gdbs -nx $binary|grep "Yay"` &amp;&amp; arg=${argtmp}
	else
		outt=`echo $out|tail -1`
		echo $outt|grep -E "aaa${flag[$i]}" &amp;&amp; arg=${argtmp}
	fi
 
done
 
# Cuando salimos del bucle, mostramos el valor de arg:
echo "La flag es: ${arg}"
 
# Lanzamos el binario con la flag para comprobar:
echo ${arg}|./${binary}
exit $?

Y, ejecutando el script, obtenemos el secreto no tan secreto. De hecho, esto se podría haber resuelto sin ni siquiera analizar el binario mediante un poco de scripting y prueba y error generando las posibles entradas y alimentando el programa directamente, sin leer sobre movfuscator ni hacer reversing:

Apoyándonos en GDB y el breakpoint de strcmp(), obtenemos la flag mediante el oráculo.

El tiempo que tarda en resolver la flag es de unos 8 segundos en mi ordenador, cuando aproximaciones con el ataque de tipo “perf” son mucho más lentas y tediosas.

real 0m8.015s
user 0m4.933s
sys 0m3.399s

La flag es: UAM{m0v3_me_t0_7h3_h0gw4rts_sch00l}.

 

Lazy mode

El siguiente script de Python obtiene la clave correcta sin necesidad de hacer reversing, tan sólo obteniendo las cadenas con strings -3 y probando la flag falsa para saber que la longitud de la flag es de 35 caracteres:

import itertools
from pwn import *
 
# Cadenas obtenidas con strings -3:
flag = [ "pUt","m0v3","_me_","1n_7","t0_7","h3_h","0gw4","rts_","cR3w","sch0" ]
 
# Las 3 cadenas siguientes las dejamos fuera de las combinaciones. 
# UAM{ esta claro que es la primera cadena de la flag.
# La ultima solo puede ser o 0l} o _:P}:
fs = "UAM{"
fe = [ "0l}","_:P}" ]
 
# Longitud de la clave obtenida con R2:
l = 0x23
 
# binario:
binary = "./Thestral_6ee87b9724dcf5c41ebba4cd578841be"
 
# Generamos todas las posibles combinaciones de longitud 35 y la enviamos al
# programa:
for L in range(0, len(flag)+1):
    for subset in itertools.combinations(flag, L):
        f = fs + ''.join(subset)
        # Probar concatenando la parte final:
        for i in fe:
            f+=i
            if len(f)==l:
                # Probamos contra el programa:
                print "Probando: " + f
                r = process(binary)
                r.recvline()
                # Enviamos la flag:
                r.sendline(f)
                # Si tenemos "Yay!!" en la respuesta, esa es la flag:
                if "Yay!!" in r.recvline():
                    print "[*] La flag es: " + f
                    r.close
                    sys.exit(0)
                r.close()

La ejecución del script nos da la flag correcta:

python brute.py SILENT=1
Probando: UAM{m0v3_me_1n_7t0_7h3_h0gw40l}_:P}
Probando: UAM{m0v3_me_1n_7t0_7h3_hrts_0l}_:P}
Probando: UAM{m0v3_me_1n_7t0_7h3_hcR3w0l}_:P}
Probando: UAM{m0v3_me_1n_7t0_7h3_hsch00l}_:P}
Probando: UAM{m0v3_me_1n_7t0_70gw4rts_0l}_:P}
Probando: UAM{m0v3_me_1n_7t0_70gw4cR3w0l}_:P}
Probando: UAM{m0v3_me_1n_7t0_70gw4sch00l}_:P}
Probando: UAM{m0v3_me_1n_7t0_7rts_cR3w0l}_:P}
Probando: UAM{m0v3_me_1n_7t0_7rts_sch00l}_:P}
Probando: UAM{m0v3_me_1n_7t0_7cR3wsch00l}_:P}
Probando: UAM{m0v3_me_1n_7h3_h0gw4rts_0l}_:P}
Probando: UAM{m0v3_me_1n_7h3_h0gw4cR3w0l}_:P}
Probando: UAM{m0v3_me_1n_7h3_h0gw4sch00l}_:P}
Probando: UAM{m0v3_me_1n_7h3_hrts_cR3w0l}_:P}
Probando: UAM{m0v3_me_1n_7h3_hrts_sch00l}_:P}
Probando: UAM{m0v3_me_1n_7h3_hcR3wsch00l}_:P}
Probando: UAM{m0v3_me_1n_70gw4rts_cR3w0l}_:P}
Probando: UAM{m0v3_me_1n_70gw4rts_sch00l}_:P}
Probando: UAM{m0v3_me_1n_70gw4cR3wsch00l}_:P}
Probando: UAM{m0v3_me_1n_7rts_cR3wsch00l}_:P}
Probando: UAM{m0v3_me_t0_7h3_h0gw4rts_0l}_:P}
Probando: UAM{m0v3_me_t0_7h3_h0gw4cR3w0l}_:P}
Probando: UAM{m0v3_me_t0_7h3_h0gw4sch00l}_:P}
Probando: UAM{m0v3_me_t0_7h3_hrts_cR3w0l}_:P}
Probando: UAM{m0v3_me_t0_7h3_hrts_sch00l}_:P}
Probando: UAM{m0v3_me_t0_7h3_hcR3wsch00l}_:P}
Probando: UAM{m0v3_me_t0_70gw4rts_cR3w0l}_:P}
Probando: UAM{m0v3_me_t0_70gw4rts_sch00l}_:P}
Probando: UAM{m0v3_me_t0_70gw4cR3wsch00l}_:P}
Probando: UAM{m0v3_me_t0_7rts_cR3wsch00l}_:P}
Probando: UAM{m0v3_me_h3_h0gw4rts_cR3w0l}_:P}
Probando: UAM{m0v3_me_h3_h0gw4rts_sch00l}_:P}
Probando: UAM{m0v3_me_h3_h0gw4cR3wsch00l}_:P}
Probando: UAM{m0v3_me_h3_hrts_cR3wsch00l}_:P}
Probando: UAM{m0v3_me_0gw4rts_cR3wsch00l}_:P}
Probando: UAM{m0v31n_7t0_7h3_h0gw4rts_0l}_:P}
Probando: UAM{m0v31n_7t0_7h3_h0gw4cR3w0l}_:P}
Probando: UAM{m0v31n_7t0_7h3_h0gw4sch00l}_:P}
Probando: UAM{m0v31n_7t0_7h3_hrts_cR3w0l}_:P}
Probando: UAM{m0v31n_7t0_7h3_hrts_sch00l}_:P}
Probando: UAM{m0v31n_7t0_7h3_hcR3wsch00l}_:P}
Probando: UAM{m0v31n_7t0_70gw4rts_cR3w0l}_:P}
Probando: UAM{m0v31n_7t0_70gw4rts_sch00l}_:P}
Probando: UAM{m0v31n_7t0_70gw4cR3wsch00l}_:P}
Probando: UAM{m0v31n_7t0_7rts_cR3wsch00l}_:P}
Probando: UAM{m0v31n_7h3_h0gw4rts_cR3w0l}_:P}
Probando: UAM{m0v31n_7h3_h0gw4rts_sch00l}_:P}
Probando: UAM{m0v31n_7h3_h0gw4cR3wsch00l}_:P}
Probando: UAM{m0v31n_7h3_hrts_cR3wsch00l}_:P}
Probando: UAM{m0v31n_70gw4rts_cR3wsch00l}_:P}
Probando: UAM{m0v3t0_7h3_h0gw4rts_cR3w0l}_:P}
Probando: UAM{m0v3t0_7h3_h0gw4rts_sch00l}_:P}
Probando: UAM{m0v3t0_7h3_h0gw4cR3wsch00l}_:P}
Probando: UAM{m0v3t0_7h3_hrts_cR3wsch00l}_:P}
Probando: UAM{m0v3t0_70gw4rts_cR3wsch00l}_:P}
Probando: UAM{m0v3h3_h0gw4rts_cR3wsch00l}_:P}
Probando: UAM{_me_1n_7t0_7h3_h0gw4rts_0l}_:P}
Probando: UAM{_me_1n_7t0_7h3_h0gw4cR3w0l}_:P}
Probando: UAM{_me_1n_7t0_7h3_h0gw4sch00l}_:P}
Probando: UAM{_me_1n_7t0_7h3_hrts_cR3w0l}_:P}
Probando: UAM{_me_1n_7t0_7h3_hrts_sch00l}_:P}
Probando: UAM{_me_1n_7t0_7h3_hcR3wsch00l}_:P}
Probando: UAM{_me_1n_7t0_70gw4rts_cR3w0l}_:P}
Probando: UAM{_me_1n_7t0_70gw4rts_sch00l}_:P}
Probando: UAM{_me_1n_7t0_70gw4cR3wsch00l}_:P}
Probando: UAM{_me_1n_7t0_7rts_cR3wsch00l}_:P}
Probando: UAM{_me_1n_7h3_h0gw4rts_cR3w0l}_:P}
Probando: UAM{_me_1n_7h3_h0gw4rts_sch00l}_:P}
Probando: UAM{_me_1n_7h3_h0gw4cR3wsch00l}_:P}
Probando: UAM{_me_1n_7h3_hrts_cR3wsch00l}_:P}
Probando: UAM{_me_1n_70gw4rts_cR3wsch00l}_:P}
Probando: UAM{_me_t0_7h3_h0gw4rts_cR3w0l}_:P}
Probando: UAM{_me_t0_7h3_h0gw4rts_sch00l}_:P}
Probando: UAM{_me_t0_7h3_h0gw4cR3wsch00l}_:P}
Probando: UAM{_me_t0_7h3_hrts_cR3wsch00l}_:P}
Probando: UAM{_me_t0_70gw4rts_cR3wsch00l}_:P}
Probando: UAM{_me_h3_h0gw4rts_cR3wsch00l}_:P}
Probando: UAM{1n_7t0_7h3_h0gw4rts_cR3w0l}_:P}
Probando: UAM{1n_7t0_7h3_h0gw4rts_sch00l}_:P}
Probando: UAM{1n_7t0_7h3_h0gw4cR3wsch00l}_:P}
Probando: UAM{1n_7t0_7h3_hrts_cR3wsch00l}_:P}
Probando: UAM{1n_7t0_70gw4rts_cR3wsch00l}_:P}
Probando: UAM{1n_7h3_h0gw4rts_cR3wsch00l}_:P}
Probando: UAM{t0_7h3_h0gw4rts_cR3wsch00l}_:P}
Probando: UAM{m0v3_me_1n_7t0_7h3_h0gw4rts_0l}
Probando: UAM{m0v3_me_1n_7t0_7h3_h0gw4cR3w0l}
Probando: UAM{m0v3_me_1n_7t0_7h3_h0gw4sch00l}
Probando: UAM{m0v3_me_1n_7t0_7h3_hrts_cR3w0l}
Probando: UAM{m0v3_me_1n_7t0_7h3_hrts_sch00l}
Probando: UAM{m0v3_me_1n_7t0_7h3_hcR3wsch00l}
Probando: UAM{m0v3_me_1n_7t0_70gw4rts_cR3w0l}
Probando: UAM{m0v3_me_1n_7t0_70gw4rts_sch00l}
Probando: UAM{m0v3_me_1n_7t0_70gw4cR3wsch00l}
Probando: UAM{m0v3_me_1n_7t0_7rts_cR3wsch00l}
Probando: UAM{m0v3_me_1n_7h3_h0gw4rts_cR3w0l}
Probando: UAM{m0v3_me_1n_7h3_h0gw4rts_sch00l}
Probando: UAM{m0v3_me_1n_7h3_h0gw4cR3wsch00l}
Probando: UAM{m0v3_me_1n_7h3_hrts_cR3wsch00l}
Probando: UAM{m0v3_me_1n_70gw4rts_cR3wsch00l}
Probando: UAM{m0v3_me_t0_7h3_h0gw4rts_cR3w0l}
Probando: UAM{m0v3_me_t0_7h3_h0gw4rts_sch00l}
[*] La flag es: UAM{m0v3_me_t0_7h3_h0gw4rts_sch00l}

 

@Disbauxes