Wednesday, April 18, 2018

Building a Proxy Fuzzer for the MQTT protocol in a nutshell with Polymorph framework


This post shows how easy you can build a fuzzer for the MQTT protocol by using the Polymorph framework.

I will start by assuming that the reader knows the MQTT protocol. For those who do not know it, you can find more information here. The first thing we will do is prepare the environment where we will perform the fuzzing, in this case, it will be very simple, a Kali Linux machine in which we will install the following dependencies:

Polymorph framework
apt-get install build-essential python-dev libnetfilter-queue-dev tshark tcpdump python3-pip wireshark
pip3 install --process-dependency-links polymorph

apt-get install mosquitto mosquitto-clients

sudo apt-get install gcc make git wget 
git clone && cd radamsa && make && sudo make install

With all this installed, we are ready to start!

Before starting the construction of the fuzzer, we are going to test our mosquitto installation in localhost. To do this, we are going to open two terminals and execute a client that is going to publish to a certain topic and another in which we will run the mosquito broker. In the following image you can see the commands and the result.

Well, now that we have tested the communication between both clients, we are going to open Polymorph and begin with the capture and modification of MQTT packets in real time. 

In our particular case, we are going to fuzz the topic field of the MQTTPublish packets, notice that the modification of any other field would be done in exactly the same way. Also, for simplicity, we are going to modify MQTT packets that implement the IPv4 protocol. Sometimes you will see that Polymorph captures the MQTT protocol over IPv6, to temporarily disable IPv6 you can use the following command over the loopback interface:

sudo sh -c 'echo 1 > /proc/sys/net/ipv6/conf/loopback/disable_ipv6'

Having said that, we are going to access the Polymorph main interface, to do that, we only have to introduce the polymorph command from a Linux terminal.

Once here, let´s start with the construction of the fuzzer. As in this case we will not need to intercept the communication between two machines because the client and the broker will be in localhost, we do not need to use any spoofing technique. We can simply use the capture command to start the packet sniffing process.

Our goal at this point is to capture one of the packets that we want to modify, so that the framework converts it into a template and we can work on it. Therefore, while the tool is sniffing packets, we place ourselves in our MQTT client and send an MQTTPublish message to the broker.

Once this is done, we use Ctr-C to finish the sniffing process in Polymorph and use the show command to show the captured packets on the screen.

As you can see, most of the packets include a last Raw layer, which means that, at first glance, they have not been interpreted/dissected correctly by the primary dissectors. With the dissect command, we use more advanced dissectors that give us a representation of the part of the packets that have not been represented.

Now that we have a more concrete representation of all the bytes of the packets that we have captured, what we must do is choose the template that corresponds to the packet that we want to modify. We can use the wireshark command to open this application and perform a more detailed filtering. Once the template is selected, we access it using the template command.

Right now, we are in the context of the selected template. With the show command we can see the different layers and fields that it has, as well as the type of them. The template concept is the most important abstraction of the framework, and it is what allows the user to access the captured packets in real time using simple syntax in the code he writes to perform complex processing on them. Furthermore, it is the container in which all the conditional functions and structures of the framework are stored when we save a session.

At this point, the conditional functions come into play (preconditions, postconditions and executions). When the user enters the intercept command in the template interface, the machine that hosts Polymorph will stop forwarding the packets at the kernel level and start sending those packages to the tool to be processed before being forwarded. The conditional functions defined by the user will be executed in each of the intercepted packets. 

Let's see a simple example of how these functions work, we are going to add the following precondition to our current template using the command precs -a test_condition.

if you are using the default editor, pico, remember not to mix tabs and spaces, better use only spaces to indent the code. (You can specify another editor that is in your PATH using the option -e):

Enter "y" to keep the code on disk and enter precs -s to visualize the added precondition.

Now, introduce the intercept command with the next iptables rule (by default the framework will set a forward rule):

Look how all the packets that flow through the machine are processed by the tool in real time and the precondition we have added is executed on each of them. We can test it just by sending a MQTTPublish message from one MQTT client to the other.

The conditional functions are another important abstraction of the framework and work as follows. When a packet is intercepted in real time, the conditional functions defined by the user are executed on it following a certain order, first the preconditions are executed in the order in which the user has added them to the template, then the executions and finally the postconditions. If at any point of the execution of any of the three types of conditional functions the value None is returned by one of them, the execution chain is broken and the packet is forwarded as it is at that moment. On the other hand, if the packet that is received as an argument is returned, the chain of execution of conditions continues. Remember that the packet that is received as argument is the packet that has been intercepted in real time at that moment.

Once this is understood, we are going to exit the intercept mode in Polymorph by entering Ctr-C (in this way, the machine that hosts Polymorph only forwards the packets without passing them through the tool). After that, we are going to add the following preconditionsexecutions and postconditions, which, I insist, when we start intercepting will be executed on each of the packets that are intercepted. To eliminate the test precondition that we added before, use precs -d test_condition.


Two preconditions have been added using the commands:

precs -a global_vars -e editor
precs -a filter_mqttpublish -e editor

The first precondition, global_vars, is creating a global variable that will remain constant for all intercepted packets. It will be used to store all the test cases that we will use to fuzz the MQTTPublish packets.

On the other hand, the second precondition, filter_mqttpublish, will filter the incoming packets so that they only continue executing the rest of the conditional functions those whose msgtype field is equals to 48. Notice that thanks to the template abstraction, Polymorph knows the position that the msgtype field occupies within the bytes of the intercepted packet, and therefore, the user can access it much more easily.

We are going to add one execution function that is a bit longer than the precondition, but it remains simple. The piece of code shown below performs the following tasks:
  1. Transforms the intercepted packet into a Scapy representation. We do this to be able to interact more easily with the fields of the MQTT layer, especially with the lengths, which are encoded. I wrote the MQTT specification for Scapy a while ago, you can find it here.
  2. We check if fuzzing values ​​remain in our list of test cases. The list is stored in the global variable created above. If the list is empty, we invoke Radamsa to generate more test cases and we stored them in the global variable.
  3. Finally, we use Scapy to insert the fuzzing value in the topic field of the packet and we eliminate that value from our list, so that it is not inserted twice. In addition, we recalculate the control fields, such as lengths and chksums.

That's all we need to build a Proxy Fuzzer for the MQTT protocol using Polymorph!

To put it into operation, we will create two directories in the PATH from which we have run Polymorph, one called valid_cases and another called fuzz_cases. These directories will be used by Radamsa to read valid test cases and mutate them in cases that may unravel in a possible vulnerability. We can add some valid cases like the following ones.

Once this is done we simply go to the template interface in Polymorph and enter the intercept -ipt "iptables -A INPUT -j NFQUEUE --queue-num 1" command. After that, we go to our MQTT client and publish a message, preferably with a long value so that there are no problems with the sequence numbers of the TCP/IP session.

We can observe how the packet is modified in real time and the value produced by Radamsa is introduced. What we could do now is making a simple loop in Bash and let it test a significant number of test values. Also, the most common thing would be that we run the application that we are testing under a debugger, so we can capture the exceptions that occur and analyze them.

Finally, we can use the save command from the template interface to export the template and import it into Polymorph in another machine, so you can share it with your colleagues!

Friday, April 13, 2018

Polymorph: Modificando paquetes ICMP en tiempo real


En este post vamos a ver lo sencillo que sería modificar el contenido de paquetes pertenecientes al protocolo ICMP utilizando Polymorph.

Lo primero de todo, vamos a instalar la herramienta y a establecer el entorno de pruebas. Para empezar todos en el mismo punto, vamos a utilizar el despliegue con Docker que incorpora Polymorph:

cd polymorph
docker-compose up -d

Una vez ejecutados los commandos se empezará a formar el entorno, cuando termine, accedemos a las tres máquinas mediante:

docker exec -ti polymorph bash
docker exec -ti bob bash
docker exec -ti alice bash

Las tres maquinas se encuentran en la misma red, que tiene una estructura muy sencilla:
  • Polymorph:
  • Alice:
  • Bob: 

Vamos a instalar la utilidad traceroute en la máquina bob, y vamos a ejecutarlo para ver la ruta que siguen los paquetes hasta alice:

apt-get install traceroute

Como podéis ver, el primer y ultimo salto es alice:

Nos situamos en la maquina polymorph, y desde cualquier parte ejecutamos el comando polymorph, esto abrirá la herramienta. Una vez abierta, vamos a utilizar el módulo de arp spoofing para interceptar la comunicación entre alice y bob:

Si ahora nos situamos en bob y volvemos a ejecutar el comando traceroute, veremos que la comunicación pasa por la máquina polymorph:

Ya tenemos la comunicación interceptada entre las dos máquinas legítimas, ahora los paquetes están fluyendo por la máquina polymorph y siendo reenviados. Vamos a poner la herramienta a hacer sniffing con el objetivo de capturar un paquete ICMP, para ello utilizamos el comando capture y tras ejecutarlo, haremos un ping desde bob a alice o viceversa.

Utilizamos Ctr-C para terminar el proceso de sniffing, y automáticamente la herramienta genera una plantilla para cada uno de los paquetes capturados. Podemos verlo mediante el comando show.

Como inciso, recalcar que esta primera disección y generación de la plantilla se hace con los disectores de Scapy, que muchas veces no serán capaces de diseccionar algunos protocolos complejos, para utilizar disectores más avanzados sobre las plantillas, utilizaríamos el comando dissect.

Volviendo al ejemplo, vamos a buscar entre las plantillas una que se corresponda con el paquete que queremos modificar y vamos a acceder a ella mediante el comando template:

Ahora estamos en el contexto de una plantilla, y podemos realizar modificaciones sobre ella. El concepto de plantilla es importante, es lo que le permite al usuario acceder en tiempo real a paquetes de distintos protocolos mediante una sintaxis sencilla. Vamos a verlo con el ejemplo.
Si ejecutamos el comando show, podemos ver el contenido de la plantilla generada a partir del paquete, en este caso, vamos a modificar el campo load de la capa RAW, que es donde se encuentran los datos.

En este punto es donde entran en juego las funciones condicionales (precondiciones, postcondiciones y ejecuciones). Cuando el usuario, en el contexto de la plantilla introduzca el comando intercept, la máquina polymorph dejará de reenviar los paquetes a nivel del kernel y comenzará a enviar esos paquetes a la herramienta para que los procese antes de que sean reenviados, sobre cada uno de los paquetes que pasen por la máquina,  se ejecutarán las funciones condicionales que hayamos definido. Vamos a ver un ejemplo sencillo, vamos a añadir la siguiente precondición a nuestra plantilla actual mediante el comando precs -a condición_prueba. 

Si utilizais el editor por defecto, pico, recordad no meter tabulaciones y espacios mezclados, mejor tabular el código con espacios. (podéis indicar otro editor que este en el path con la opción -e):

Introducimos "y" para mantenerla en disco e introducimos precs -s para ver la precondición añadida.

Ahora introducimos el comando intercept:

Fijaros como todos los paquetes que fluyen a través de la máquina son procesados por la herramienta y se ejecuta la precondición que hemos añadido, como estamos interceptando la comunicación entre la máquina alice y bob, si hacemos un ping de una a otra, los paquetes pasan por la máquina polymorph y la herramienta ejecuta la precondición sobre ellos.

Una vez entendido esto, vamos a salir del modo interceptar con Ctr-C (de tal forma que la máquina polymorph únicamente reenvie los paquetes sin pasarlos por la herramienta) y vamos a añadir las siguientes precondiciones, ejecuciones y postcondiciones, que, insisto, cuando estemos interceptando se ejecutarán sobre todos los paquetes que se intercepten (para eliminar la precondición de prueba precs -d condición_prueba). 

Si utilizais el editor por defecto, pico, recordad no meter tabulaciones y espacios mezclados, mejor tabular el código con espacios. (podéis indicar otro editor que este en el path con la opción -e)
  • Precondición
  • Ejecución
  • Postcondición 

Las funciones condicionales funcionan de la siguiente forma, primero se ejecutan las precondiciones en el orden en el que las hayamos metido, después las ejecuciones y por último las postcondiciones. Si algún punto de la ejecución de cualquiera de las tres se devuleve el valor None, se rompe la cadena de ejecución y se reenvía el paquete tal cual esté en ese momento, si por el contrario, se devuelve el paquete que se recibe como argumento, la cadena de ejecución de condiciones continúa. El paquete que se recibe como arguemento es el paquete que se ha interceptado en tiempo real en ese momento.

En este caso hemos añadido una precondición que dice: 
"si en el paquete que llegue existe una capa IP con un campo proto con el valor 1 (que indica que se trata de un paquete ICMP), retorna el paquete y continua ejecutando funciones condicionales, en el caso contrario retorna None y reenvía el paquete sin ejecutar nada más."

La ejecución dice: 
"en la capa RAW y el campo load del paquete que ha pasado la precondición introdúceme este nuevo valor. Si os fijais en la plantilla cuado ejecutamos el comando show, el tipo del campo load es hex, es muy importante que los tipos que se asignan o comparan sean los mismo, sino se producirá un error de tipos."

Por último la postcondición dice:
"el paquete que me llega después de ejecutar la precondición y ejecución sobre él, transfórmamelo a un paquete scapy, recalculame los campos de control para que quede consistente, vuelve a asignarlo a la variable paquete de polymorph y retornalo para que sea reenviado."

Como ya no hay más condiciones después de la postcondición el paquete se reenvía.

Una vez añadidas las funciones, vamos a la máquina bob e instalamos tcpdump mediante apt-get install tcpdump y ejecutamos el siguiente comando.

Una vez que tcpdump este escuchando, vamos a alice y enviamos un ping a bob, (aun no hemos ejecutado el comando intercept en la máquina polymorph), en bob deberíamos ver el contenido de los paquetes.

Ahora vamos a la máquina polymorph y ejecutamos el comando intercept, regresamos a alice y hacemos un ping a bob, fijaros como no se pierde ningún paquete pero el contenido del ICMP que recibe bob es el introducido por el atacante.

Una vez terminado, podemos pulsar Ctr-C para salir del modo intercept en la herramienta y con el comando save guardar la plantilla, que podremos intercambiar o transportar a otro pc. Para importarla en la herramienta utilizamos la sentencia polymorph -t plantilla.json desde la consola de comandos.