sábado, 17 de septiembre de 2011

Writeup level3 del wargame de la NoCon Name 2011

Al loguearnos vemos un binario arbitraje y su codigo fuente. Cuando ejecutamos el binario vemos que nos suelta un montón de líneas y al terminar con Ctrl + C nos dice que estamos perdiendo dinero. WTF! ESTO HAY QUE SOLUCIONARLO PRONTO QUE ESTAMOS EN CRISIS Y NO PUEDE SER!.

Miramos el fuente y vemos una bonita explicación (aunque todavía estoy preguntándome de dónde sale el 0.76...) de lo que es el arbitraje y cómo las hienas ganan dinero con ello. Mirando ya el código en si, vemos que el programa se queda generando un valor aleatorio para usdollar, britishpound y francs aleatoriamente e imprimiendo los valores, y que cuando mandemos la señal SIGINT se comprobará si la multiplicación de estos tres valores es mayor que 1 y en tal caso imprimirá el fichero password.txt. En caso contrario nos dirá que estamos perdiendo dinero.

Probando muchas veces puede ocurrir que usdollar y britishpound (los cuales nunca tendrán un valor por encima de 1) sean lo bastante grandes (cercanos lo más posible a 1) como para que al multiplicarlos por francs (que suele valer por encima de uno con cierta frecuencia... concretamente un 30'5551317% de las veces, pero no estamos en clase de probabilidad y estadística) el resultado sea superior a 1, que es lo que buscamos. Veamos que tal está el lector con herramientas de UN*X... sed -e '/^Probando muchas veces puede ocurrir\(.*\)$/Scripteando ocurrirá\1/' $ESTE_PARRAFO.

Así que vamos a ello, un poco de bash (almost) ninja magic:

#!/bin/bash

# Fichero temporal donde se va a volcar la salida de arbitraje.
tmp_file=`mktemp --tmpdir=/var/tmp`

# Comenzamos un bucle infinito donde lo que se hace es lanzar en
# background una instancia de arbitraje redireccionando su stdout
# al fichero temporal. Luego se le envia SIGINT y se comprueba si
# perdió dinero, en cuyo caso vuelve a intentarlo. Si no fue así
# se imprime el final del fichero temporal, donde se habrá escrito
# la contraseña de level3 y se termina la ejecución.
for ((;;)); do
    ./arbitraje 1>$tmp_file &
    sleep 0.001

    # MATAR!
    sync
    kill -INT $!

    egrep "perdiendo dinero" $tmp_file 1>/dev/null
    if [[ $? -eq 1 ]]; then
        tail $tmp_file
        exit 0
    fi
done

El comentario en el script creo que es bastante autoexplicativo. Hemos creado un script que estará todo el rato lanzando arbitrajes, matándolos y comprobando si ha ocurrido lo que esperamos, hasta que lo consigamos. Como es un ordenador el que ejecuta este proceso lo hará muy rápido con lo que esperamos que el tiempo de "prueba error" se reduzca drásticamente.

$ chmod 700 script.sh
$ ./script
...
>2'+<74FR}8i

Después de unos pocos segundos se nos imprime la contraseña del siguiente nivel :).

El lector habrá notado un par de líneas un poco extrañas en el script, concretamente un sleep y un sync. El sleep es debido a que después de la creación de arbitraje quién se ejecuta no es arbitraje sino el script, con lo que directamente matará a arbitraje sin que este se ejecute (realmente podría ocurrir que el kernel justo interrumpiera a script.sh antes de ejecutar el kill y sched() decidiera introducir a arbitraje... pero eso es poco probable y no vamos a entrar en internals del kernel porque ahora no es el momento). El sleep lo que va a provocar precisamente es que el sistema saque de la CPU a script.sh y meta a arbitraje y ya empezará a escupir información.

La otra línea extraña es sync. Si no ejecutamos sync y debido a la naturaleza buffereada de las escrituras al fichero, ocurrirá que aún no se habrán escrito todos los datos en el fichero y las últimas líneas no aparecerán, con lo que no encontrará "perdiendo dinero" y se ejecutará el tail de un fichero que lo más probable es que no tenga la contraseña al final (curiosamente entre egrep y tail sí que se llega a terminar la escritura del fichero, y tail si que muestra el "perdiendo dinero". Haciendo un sync antes del kill, obligamos al sistema a escribir todo lo que hay en los bufferes, entre otras cosas lo que arbitraje haya escrito en el fichero temporal, de esta forma nos aseguramos que egrep y tail se ejecuten sobre el fichero correcto y no parte del mismo.

Puedes bajarte el pdf aquí.

No hay comentarios:

Publicar un comentario