# 🏌️ BGGP3 - How to crash a famous JS engine for fun

Contents

So this summer - and it has been this for the past 2 years - the famous Binary Golfing Grand Prix took place online for it’s 3rd edition, and of course I decided to give it a try.

After getting to try my best at golfing binaries (see my golfing posts), I had to race this competition for fun and learn a lot about fuzzing - as I have never fuzzed before.

## What is fuzzing?

Fuzzing a binary is like bruteforcing a binary’s input (cmd args, input file…) in order to get an odd behaviour, a bug or even the holy crash.

There are a lot of tools in order to help users to fuzz a binary and optimize the results (execs/s, payload mutation, harnesses…) and they are pretty easy to use.

The first tutorials online and my own knowledge led me to the famous AFL, or more exactly it’s big brother AFL++. So I will go with this tool for this grand prix in order to familiarize myself with it.

## Chosing target

Spoiler

Looking by curiosity what are all the known JavaScript engines (and there are a lot of them), one caught my attention: Espruino.

I thought this project was in the spirit of the minimalism, and thus wanted to see if it was enough to avoid crashes.

Especialy design for embeeded devices and IoT, still maintained after more than 7 years, this project was a good practice for fuzzing.

## Instrumentation

Note
For this fuzzing project, I used the AFL++ Docker container, mapping the code of the target in /src.

The first step for fuzzing, we have to prepare the target binary. ALF uses a custom GCC in order to optimize results and explore the binary. We have to build the binary from source and patch the Makefile.

 1 2 3 4 5  --- a/Makefile +++ b/Makefile @@ -1,8 +1,12 @@ - CC = gcc + CC = afl-gcc 

In more complex project, you will have to also change the compiler to alf-clang-fast++, add some compilation flags for optimizations, and even have to patch the main() {} function for AFL.

On compilation you should see some warnings/infos from AFL:

I will copy the built binary in /usr/local/bin/, and create a new directory for this fuzzing:

 1 2 3  cd $HOME mkdir in # our inputs for the fuzzer mkdir out # outputs of the fuzzer (crashes, test queue...)  ## Minimizing test cases The next step is to get good test cases to speed up the process of fuzzing. The fuzzer will base its mutations on those test cases, so the more unique tests you have, the better. By chance, most projects have good tests in their /tests/ directory, so let’s copy them to our inputs:  1  cp /src/tests/*.js in/  Once again, for optimizations, it is a good practice to minimize the test cases, it can save a lot of time during fuzz.  1 2 3 4 5  mkdir min # our minimized inputs afl-cmin -i in -o min --$TARGET @@ # minify the tests for the target # the '@@' stands for the input file # ie. for the target /bin/cat, we would use: # afl-cmin -i in -o min -- /bin/cat @@ 

After running the command (this will take a while if you have hundreds of cases) we now have a lot more efficient test cases in our min dir.

## Fuzzing

Now that we have our test cases ready, let’s get to fuzing!

As simple as that:

### Act III: anger

After trying dozens of projects to fuzz, I started to be a bit angry, or more precisely frustrated. I was trying to fuzz a binary to get a crash, but I got nothing for the past week. Angry at myself that I couldn’t setup a simple fuzzing lab.

### Act IV: bargaining

In order to save myself of myself, I started to try a lot of things, with my newly gained experience in fuzzing, I decided to go back to my original idea: radare2.

With that, I also read the manual and all the options for AFL++ in order to get better results, I even asked online for help, of course SoEasY DMed me to help. He wasted some time with me, and we supposed that the low amount of exec/s was due to the fact that I start r2 in interactive mode, and the process limit itself to a certain amount of threads, so the time the process kill itself in order to spawn a new one, it limits a lot the number of execs.

He also asked me to try other binaries of the radare2 suite, even to write a harness for a specific function to fuzz.

### Act V: depression

Even with those tweaks and tries, there were no improvements in my results after 5 days of fuzzing. 😢

I decided to take a break for days.

### Act VI: testing

After my break I wanted to know why I did not have any results with my fuzzing. And for me the obvious reason was an issue of the famous 8th layer of the OSI model: the keyboard-chair interface.

For my previous choices, either it was a bad target, or I did things wrong.

### Act VII: acceptance

The only way forward for me was to find an other target, and see if I get a crash easily.

Now that you have the past history of the project, see the real fuzzing journey.

## Conclusion

I made 11th out of 33 and I am very happy about that

Here you will find the final results including all the submitted entries for this year!