Latest Tweets

Script for NUMA systems

Preamble

On modern NUMA systems, it’s always a good thing to know the total number of physical processors (nodes), the total number of real cores per processor, and if HT is enabled, the total number of virtual cores per processor (which is, of course, twice the number of real cores per socket). At the same time, it would be great to be able to disable HT for a particular physical processor on the fly. This simple BASH script does precisely that.

Using the script

Install numactl before running the script. If numactl is not found, the script will tell you so and exit:

sudo apt-get install numactl

The script can report the real and virtual cores per socket along with the total number of physical processors installed on the system. It works perfectly well for systems that only have 1 socket, of course, so no NUMA in this case.:

cores.sh -h
Usage: /usr/bin/cores.sh [-t] [-c CPU] [-h]
		 -t, reports total number of physical processors (nodes) and quits.
		 -c CPU, reports total and real cores for physical processor CPU.
		 -r CPU, reports real cores for physical processor CPU separated with commas.
		 -d CPU, disables HT on the given CPU (requires root).
		 -h, show this help message.
  Example: /usr/bin/cores.sh -t
           /usr/bin/cores.sh -c 2
           sudo /usr/bin/cores.sh -d 0

To get the total number of cores for, say, physical processor 1 on a 4-socket system, run:

cores.sh -c 1
Total physical processors on this system: 4
Total Cores for processor 1: 1 5 9 13 17 21 25 29 33 37 41 45 49 53 57 61 65 69 73 77
Virtual Cores for processor 1:  41 45 49 53 57 61 65 69 73 77 
Real Cores for processor  1:  1 5 9 13 17 21 25 29 33 37

You can disable HT for a particular socket as well. The number of cores that will be disabled are shown in the “Virtual Cores” row. Say, you want to disable HT for CPU0 on a 1-socket system; run:

 sudo cores.sh -d 0
Total physical processors on this system: 1
Total Cores for processor 0: 0 1 2 3 4 5 6 7
Virtual Cores for processor 0:  4 5 6 7 
Real Cores for processor  0:  0 1 2 3
We are about to disable HT on physical cpu: 0
CPU cores to be disabled:  4 5 6 7 
Are you sure? [yn]

If you are completely sure, type “y” and press <ENTER>. Otherwise, type any other key and press <ENTER>.

You can run the script using the “-r” flag in order to output the real cores for a particular physical processor to pass it directly to numactl. Let’s imagine you want to run a 10-core simulation using mpirun on a 4-socket NUMA system. Each physical node has 10 real cores and 10 virtual cores due to HT. You want to run this simulation on node 3 (CPU4):

cores.sh -r 3
Total physical processors on this system: 4
Real Cores for processor  3:  3,7,11,15,19,23,27,31,35,39

Now, you can pass the string of real cores to numactl and run your simulation like this:

numactl --physcpubind=3,7,11,15,19,23,27,31,35,39 mpirun -np 10 \
> --report-bindings binary arguments

Or you can do it using this one-liner instead:

numactl --physcpubind=`cores.sh -r 3|tail -1|cut -d":" -f2|tr -d " "` \
>  mpirun -np 10 --report-bindings binary arguments

To make sure your simulation is running on the chosen cores/sockets, you can run the following command (replace PID with the proper one):

cat /proc/<PID>/status |grep Cpus_allowed_list
Cpus_allowed_list:	4-7

Get the script (cores.sh)

You can download the script from HERE.

Integrating the IHaveBeenPwned API into Linux PAM

Introduction

I was writing another 4-page article for Linux User and Developer about Public APIs when I came out with the idea of showing the readers how to leverage the IHaveBeenPwned API using a Linux PAM module. The idea was to use their new “Pwned Passwords API v2” with the K-Anonymity feature.

Writing the module

Writing a Linux PAM module is relatively easy. Doing it the right way (i.e.: avoiding common programming mistakes, adhering to good PAM-developing practises, and so on) is quite another thing altogether. There are certain things to consider; writing a buggy PAM module can easily lead to a total system lock-down or even a total system take-over. For starters, you must ensure that you overwrite any memory you have dynamically allocated before freeing it (see http://www.linux-pam.org/Linux-PAM-html/mwg-see-programming-sec.html#mwg-see-programming-sec-token). This module is used whenever a user runs the “passwd” command or some application performs a call to the putspent() function in order to change a user’s password.

This module performs the following actions:

  1. It asks for the current UNIX password to authenticate the user.
  2. If the users is authenticated, it asks for a new password.
  3. It computes its SHA1 and then generates a call to the IHaveBeenPwned API.
  4. If there is any kind of error communicating with the API, and if the option “enforceonerror” is set, the module returns an error and ends. No password is changed.
  5. If there is any kind of error communicating with the API and the “enforceonerror” option is not set, it jumps to step 8.
  6. If the call to the API succeeds, it performs a simple search for the whole hash in a local buffer.
  7. If the hash is found, it prints an error message telling the user so and returns an error. No password is changed.
  8. If the hash is not found, it tells the user so and asks for the new password again for confirmation.
  9. If both passwords match up, the password is stacked for the next module to process (pam_unix.so).

The hash is computed using OpenSSL and the API call is performed with Curl3. That’s why this module must be linked against libopenssl (-lssl) and libcurl3 (-lcurl3).

Testing the module

I released my module’s source code some days ago on GitHub. Clone, build and install the module as described in the README.md file. I have tested it on Debian Wheezy, Debian Jessie, Debian Stretch and Ubuntu 16.0.6 distros so far. Consider installing a Virtual Machine and testing the module there first. Once the module is enabled, you can run the “passwd” command to change your password the usual way. Try some well-known pwned passwords such as mariobros, princesspeach, heyjude! and so on.

My module in action with some logging.

Future work

I’m now in the process of serious code reviewing, to make sure everything is in order. There are some bits that are quite redundant, and then prone to error. So I’m trying to simplify the code as much as possible. Bear in mind that I’m a newbie when it comes to writing Linux PAM modules, so feel free to comment on my project and open issues on Github ;-).

Happy hacking!

CTF Una-Al-Mes La casa de papel 1ª parte. Write-up

Obtención de los códigos web

Abrimos la página web del CTF: http://34.253.233.243/lacasadepapel/episodio1/puerta.php. Observamos un sencillo formulario web con dos cajas de texto, “Código 1” y “Código 2”. Antes de hacer pruebas a lo loco, comprobamos el código fuente de la página:

El código fuente de la página del CTF nos revela un archivo interesante: “login.js”

El archivo JavaScript “login.js” parece ser importante. Lo abrimos y nos encontramos con una única función, llamada conexion, que nos dará los dos códigos tras un sencillo proceso de parseado:

function conexion(){
    var Password = 
        "unescape%28String.fromCharCode%252880%252C%2520108%252C%25" +
        "2097%252C%2520110%2529%29:KZQWYZLOMNUWC===";
    for (i = 0; i < Password.length; i++)
    {
        if (Password[i].indexOf(code1) == 0)
        {
            var TheSplit = Password[i].split(":");
            var code1 = TheSplit[0];
            var code2 = TheSplit[1];
        }
    }
}

El código anterior nos muestra como se generan los dos códigos a partir de la cadena “Password”. El terminador que los separa es “:”. Por lo tanto, para el código2 basta coger todos los caracteres después de “:”:

KZQWYZLOMNUWC===

Siendo todo mayúsculas, y con la terminación “===” parecería que estamos ante una codificación Base32. Decodificamos:

$ echo -n “KZQWYZLOMNUWC===”|base32 -d
Valencia

Para el primer código lo que haremos es coger todos los caracteres antes del “:”. Tenemos esto:

unescape%28String.fromCharCode%252880%252C%2520108%252C%252097%252C%2520110%2529%29

Basta con darse cuenta de que los caracteres que empiezan con % están usando la codificación hexadecimal en HTML. Sabiendo esto, basta con convertirlos a sus correspondientes valores ASCII y nos queda:

unescape(String.fromCharCode(80, 108, 97, 110))

Básicamente tenemos una llamada JavaScript simple, que nos devolverá “Plan”.

Rellenamos los dos campos del formulario web con “Plan” y “Valencia”, y obtenemos el password del ZIP:

El password del ZIP tras descubrir como generar Código1 y Código2

Reversing del ejecutable

Descargamos el archivo ZIP y usamos el password “PR0F3SOR&R10” para descomprimirlo. Obtenemos un ejecutable para consola en Windows de 64 bits:

$ file episodio1.exe
episodio1.exe: PE32+ executable (console) x86-64, for MS Windows

Lo ejecutamos con Wine64:

$ wine64 episodio1.exe
System_Date: 05/16/18
Wrong date R3m0!

————-HINT———————
‘La persistencia de la memoria…’
————————————–
Press any key to continue…

Bien, ahora tenemos 2 maneras diferentes de resolver el reto. Parece evidente que el programa comprueba la fecha del sistema, y si no es la que espera, nos muestra el mensaje de error y el “HINT”. La primera manera de resolverlo es, pues, encontrando la fecha correcta a partir del HINT. La segunda es, lógicamente, haciendo reversing. Elegimos la segunda por ser esto un CTF de seguridad informática.

Análisis con radare

Ejecutamos un primer análisis con radare y buscamos la función main:

r2 -A episodio1.exe
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze len bytes of instructions for references (aar)
[x] Analyze function calls (aac)
[x] Use -AA or aaaa to perform additional experimental analysis.
[x] Constructing a function name for fcn.* and sym.func.* functions (aan)
— Setup dbg.fpregs to true to visualize the fpu registers in the debugger view.
[0x00401500]> afl~main
0x004011b0 44 834 -> 813 sym.__tmainCRTStartup
0x00401530 5 595 -> 527 sym.main
0x0040e960 3 28 -> 24 sym.__main
0x00419d50 1 6 sym.__getmainargs
0x00452d40 1 29 sym.std::domain_error::domain_error_std::stringconst__
0x00452d60 1 36 sym.std::domain_error::_domain_error__
0x00452d90 1 15 method.std::domain_error.~domain_error()
0x0046d410 2 99 -> 139 sub.std::domain_error.domain_error_std::stringconst___410

Cuánta porquería, está claro que esto fue escrito en C++ (puag). Vamos directos al OFFSET de la función main, pasamos al modo visual, hacemos algo de zoom y observamos el simple flujo del programa:

[0x00401500]> s sym.main
[0x00401530]> VV

El flujo del programa. Como se puede apreciar, lo ideal sería “caer” en el nodo de la izquierda.

En la figura anterior, si el flujo del programa cae en el nodo de la izquierda, obtendremos el mensaje de “Congratulations!!, Stealing Money $$$”.  Es lo que nos interesa, sin duda. ¿Cómo llega aquí? Fácil; se hace una comparación de fecha. Si la fecha no es la esperada, saltamos al nodo de la derecha en la figura anterior. ¿Qué fecha és esa? Simplemente recorremos la figura anterior hacia atrás, y observamos que la fecha está hard-codeada dentro del ejecutable:

[0x004015f2]> s sym.main
[0x00401530]> pd 20

La fecha está hard-codeada dentro del binario: 01/23/89″.

La fecha se encuentra en el OFFSET apuntado por “str.01_23_89”, y es “01/23/89”. Esto está en formato americano, con el mes y el día intercambiados. Así que la fecha del sistema debería ser: “23/01/1989”.

A partir de aquí, podemos resolver el reto de al menos de 2 maneras diferentes:

  1. Cambiamos la fecha de nuestra VM para que sea 23/01/1989.
  2. Parcheamos la instrucción de salto tras la comparación de fechas para que el flujo del programa caiga en el nodo de la derecha, sin importar la fecha de nuestro sistema.

Método 1: Cambio de la fecha (pa gandules ;-))

Cambiamos la fecha y ejecutamos de nuevo el binario para obtener la FLAG:

Obtención de la flag, método 1: Cambiamos la fecha del sistema.

Método 2: Parcheamos la instrucción de salto (sólo un poco más de trabajo)

Revisamos dónde se hace la comparación de fechas y qué instrucción de salto se ejecuta. Bastará con parchear dicha instrucción de salto para caer siempre en el nodo de la izquierda:

La comparación de fechas y el salto; si la fecha no es válida, se ejecutará el salto hacia el OFFSET 0x401677, el nodo de la derecha.

Bastará parchear el JE por un JNE y pelillos a la mar. Así que obtenemos el OFFSET de dicha instrucción y lo cambiamos. Primero debemos salir de radare y ejecutarlo de nuevo con “-w” para poder escribir sobre el binario:

$ r2 -w -A episodio1.exe

Nos situamos en la instrucción JE 0x401677:

[0x00000000]> s `/c je 0x401677~[0]`
[0x004015ec]> pd 1
| ,=< ;– hit0_0:
| ,=< 0x004015ec 0f8485000000 je 0x401677

Parcheamos el JE por un JNE; comprobamos que el cambio se ha producido, y salimos de Radare:

[0x004015ec]> wa jne 0x401677
Written 6 bytes (jne 0x401677) = wx 0f8585000000
[0x004015ec]> pd 1
| ,=< ;– hit0_0:
| ,=< 0x004015ec 0f8585000000 jne 0x401677
[0x004015ec]> q

El binario ya está parcheado, así que simplemente lo ejecutamos en nuestro equipo sin cambiar su fecha:

Obtención de la FLAG mediante parcheo de binario.

La flag, por supuesto, es:

UAM{e30f35ad8d9cb6efc0778539a669fa85}

Además, si utilitzamos la web http://md5decrypt.net/en/, y intentamos crackear el MD5, obtenemos precisamente: 01/23/89:

La flag es, en realidad, el MD5 de la cadena “01/23/89”.

Toni Castillo

@disbauxes