Fuzzing experiments I or... I have no idea what I'm doing

Introduction

Hello! In today’s post I’ll explain my first steps in the fuzzing world. I’ll detail the steps I took to fuzz some code part of the open source code released by TP-Link for the TL-WR841N Router.

Disclaimer: This blog post will be very basic and just cover the fundamentals. No bugs were found but I learned a lot :)

Having the idea of experimenting a bit with fuzzing, I decided to focus my attention towards one of the TL-WR841N services. Specifically the router’s UPnP daemon, running on port TCP and UDP 1900. Doing a quick check, I issued an HTTP request to that port and to my surprise, it answer back with a 404, page not found error.

Based on this, I proceeded to download the GPL code for the router and take a look at it.

The router is using the The Portable SDK for UPnP* Devices (libupnp) version 1.6.19.

As this is not the latest version and as far as I know no one fuzzed it before, seemed as a good target.

The Router’s code for the libupnp library is similar to the official one, but it has some patches applied. Based on this, I decided to use it instead of the official version.

Compiling the router’s library code

My first task was to compile the code provided by the vendor to perform some basic testing and get and overal idea if I was going to be able to achieve any useful results.

For this, I performed these steps:

  1. Download GPL code from TP-Link’s website
  2. Go to TL-WR841NV14/apps/public/upnp_libs
  3. To avoid errors in the next step, open the Makefile file and comment out (with #) lines 60, 65, and 70. Save and close the file.
  4. Open a terminal and execute make
  5. If everything goes well you’ll see some output and at the end of the process you’ll have three libraries: libixml.so, libthreadutil.so, libupnp.so

Writing a basic test program importing a function from libupnp

My next step was to write a really simple test program using an imported function from libupnp.so. The idea behind this was to perform the same task that I needed for fuzzing (that is, calling a function from the library using an external program) but in a simpler way.

For that I chose to call function get_sdk_info.

This function simply expects a buffer and a size and writes the library version in it.

To create this program I followed these steps:

  1. I created a new directory tests inside TL-WR841NV14/apps/public/upnp_libs/src

  2. Create a new file get_sdk_info_example.c with the following content

/*
This simple example will use an exported function from
`lipupnp.so`, `get_sdk_info` thats defined in
`httpreadwrite.h`

Compile it with: `gcc -Wall -I ../inc -o get_sdk_info_example
get_sdk_info_example.c -L ../ -lupnp -lixml -lthreadutil`
*/

#include <stdio.h>
#include "httpreadwrite.h"

int main(){
    char buffer[200];
    get_sdk_info(buffer, sizeof(buffer));
    printf("%s\n", buffer);
    return 0;
}
  1. Compile it with: gcc -Wall -I ../inc -o get_sdk_info_example get_sdk_info_example.c -L ../ -lupnp -lixml -lthreadutil

Note for newcomers like myself: GCC expects the name of the library without the prefix lib and without the .so extension for the -l parameter, hence the names “upnp, ixml, and threadutil.

  1. Add the path where the libraries are stored to the LD_LIBRARY_PATH environment variable and export it
  2. Test the program:
./helloWorld

Linux/5.4.0-54-generic, UPnP/1.0, Portable SDK for UPnP devices/1.6.19

At this point I was able to confirm that the call worked and I started working on a simple program to call the function I wanted to fuzz.

Fuzzing http_RecvMessage

As explained in the introduction I decided to fuzz the function in charge of parsing HTTP requests in libupnp. After taking a look at the code I found the function called http_RecvMessage which receives a buffer expected to be an HTTP request and parses it in other words this was te function I was looking for. My next task was to modify it a bit to be able to fuzz it with AFL++. For that I had to modify to make it expect data from a buffer and not a socket, as Antonio Morales explained in his Fuzzing sockets blog post series.

I uploaded three patch files in this repository, that you can use to apply the same changes I did.

I also changed other parts of the code that called this function to reflect the change made to the function’s parameters.

Our function modified to be fuzzed will have the following signature:

int http_RecvMessage(
	IN char raw_buffer[],
	IN int raw_buffer_size,
	OUT http_parser_t *parser,
	IN http_method_t request_method,
	IN OUT int *timeout_secs,
	OUT int *http_error_code);

Defining macros in GCC with command line arguments

To learn a bit more I used a macro, AFL_FUZZING, to tell the GCC compiler to include my changes, only if the macro was defined. When calling GCC to compile our libraries we need to pass -DAFL_FUZZING as parameter. Doing it in this way we avoid having to define our macro in different files.

I included this in the Makefile that is shared along the patch files.

Writing a simple program to call our modified version of http_RecvMessage

The only thing remaining was to write a simple program calling this modfied function:

/*
Calls our modified http_RecvMessage reading an HTTP request from a file
*/

#include <stdio.h>
#include <stdlib.h>

#include "httpreadwrite.h"
#include "httpparser.h"

int main(int argc, char *argv[]){
    char buffer[2 * 1024];
    int content_size = 0;
    http_parser_t parser;
    int timeout = 5;
    int http_error_code;
    int ret_code;

    int fd;
    if ((fd = open(argv[1], O_RDONLY)) == -1) {
        printf("Error opening the file");
        exit(1);
    }
    content_size = read(fd, buffer, sizeof(buffer));
    ret_code = http_RecvMessage(buffer, content_size, &parser, \
    HTTPMETHOD_UNKNOWN, &timeout, &http_error_code);
    return 0;
}

Compiling everything with afl-clang-fast and starting the fuzzer

Once I had all the different parts ready, I only needed to glue them together. The last step was to compile everything with afl-clang-fast and start the fuzzer. To compile the code I modified both Makefiles (the one that came with the code and other simpler I wrote for my test programs) and added the following line:

#CC=<path_to_afl_plusplus>/afl-clang-fast

With that we are overriding the default CC variable that defines what compile will be used, to use AFL++’s compiler. With that done, I executed make and waited until the process finished.

The last step was to execute the fuzzer:

./afl-fuzz -i tplink-wr841/fuzzing/in/ -o tplink-wr841/fuzzing/out/ -- TL-WR841NV14/apps/public/upnp_libs/tests/test_call_http_RecvMessage -d @@

As this was a simple test my corpus was just a file with an HTTP request. A real fuzzing campaign will need a real corpus for testing.

Another important point is that this should be performed with AFL++ persistent mode as far as I understand as it will provide an important bonus on performance.

References

  • Defining macros in GCC.

  • Fuzzing Sockets, Antonio Morales - https://securitylab.github.com/research/fuzzing-sockets-FTP/

  • @ Modifier in Makefiles, Stack Overflow - https://stackoverflow.com/questions/3477292/what-do-and-do-as-prefixes-to-recipe-lines-in-make

  • AFL++ - https://github.com/AFLplusplus/AFLplusplus

  • Makefile tutorial - https://makefiletutorial.com/#getting-started

  • Fuzzing Universal Plug and Play, Eleanor Van Looy - https://www.esat.kuleuven.be/cosic/publications/thesis-376.pdf

Written on May 22, 2021