Tool Learning 1 - Use Fuzzilli on Real Targets

Fuzzing Real Targets

In this post, I start using Fuzzilli on its currently supported targets and record some background notes on Swift.

Fuzzing Preparation

My Ubuntu environment is shown below:

Install Clang

The required version is >=4.0; I installed clang-10. I had installed this part before, but I ran into some problems after installing Swift.

The clang path pointed to the Swift installation folder, so I reinstalled Clang and added clang to update-alternative --config. Using sudo ln may also solve this issue, but I did not try it.

1
2
$ sudo apt-get install clang-10 #or just simply install clang
$ sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-10 99 --slave /usr/bin/clang++ clang++ /usr/bin/clang++-10 #the number larger will stand for higher priority

The llvm-dev is also needed:

1
$ sudo apt install llvm-dev

To switch to a different clang version:

1
$ sudo update-alternatives --config clang

To remove the link and its slave:

1
2
$ sudo update-alternatives --display clang #or clang++ or others
$ sudo update-alternatives --remove clang /usr/bin/clang-10 #depends on the message show in the commandline

Do not install it like this, because it is easier to make mistakes:

1
2
3
$ sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-10 10000
$ sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-10 10000
$ sudo update-alternatives --install /usr/bin/llvm-config llvm-config /usr/bin/llvm-config-10 10000

Swift may already include clang, so installing clang separately might not be necessary. I am not fully sure, so I am keeping these clang installation notes here.

Install Swift

Make sure the package index and installed packages are up to date:

1
$ sudo apt update && sudo apt upgrade

Install the dependencies for Swift. I did not run this step, but it may be needed in a new Docker container or freshly installed system.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ sudo apt install binutils git gnupg2 libc6-dev libcurl4 libedit2 libgcc-9-dev libpython2.7 libsqlite3-0 libstdc++-9-dev libxml2 libz3-dev pkg-config tzdata zlib1g-dev

#or try this (from https://swift.org/getting-started/#installing-swift)

$ sudo apt-get install \
binutils \
git \
libc6-dev \
libcurl4 \
libedit2 \
libgcc-5-dev \
libpython2.7 \
libsqlite3-0 \
libstdc++-5-dev \
libxml2 \
pkg-config \
tzdata \
zlib1g-dev

Download toolchains from the Swift download page. For example, I chose swift-5.4.2-RELEASE-ubuntu18.04.tar.gz. Then extract the file into a folder such as /home/user_name/:

1
$ tar -xvzf swift-5.4.2-RELEASE-ubuntu18.04.tar.gz -C ~

Add the path to ~/.bashrc and source it, or restart the environment:

1
2
$ echo "PATH=~/swift-5.4.2-RELEASE-ubuntu18.04/usr/bin:$PATH" >> ~/.bashrc
$ source ~/.bashrc

To verify Swift, you can enter:

1
$ swift --version

If the output looks like the screenshot below, Swift has been installed successfully.

Test Swift

To test Swift on the command line, enter swift; the terminal will launch a shell called REPL (Read-Eval-Print-Loop). I ran into the following errors when entering REPL:

After removing libc6-dbg, the error message was gone.

1
$ sudo apt remove libc6-dbg

Type the following code to check whether Swift works:

1
2
3
4
let name = "LinuxConfig"
import Glibc // imports GNU C Library
var ln = random() % 100
print("hello,",name,"your lucky number is", ln)

After testing, you can exit with ctrl + d, :quit, or :q.

Build Fuzzilli

1
2
3
$ git clone https://github.com/googleprojectzero/fuzzilli.git
$ cd fuzzilli
$ swift build -c release -Xlinker='-lrt'

If it builds successfully, we can begin to fuzz the JavaScript engine.

Begin Fuzzing

After setting up the Swift and clang environment, Fuzzilli can be tried on the following JavaScript engines.

Fuzzing on JavaScriptCore

JavaScriptCore is the JS engine implemented in Safari. First, download the source code and patch it using Fuzzilli's patch.

1
2
3
4
5
$ git clone https://github.com/WebKit/webkit
$ git checkout xxxxx #This is optional if needed
$ patch -p1 < /The/Path/to/webkit.patch #Patch on the current folder
$ cp /The/Path/to/fuzzilli/Targets/JavaScriptCore/fuzzbuild.sh ./
$ ./fuzzbuild.sh # Begin building

After this, we can start running Fuzzilli:

1
2
$ sysctl -w 'kernel.core_pattern=|/bin/false' #Run this if this is first time to use fuzzilli to fuzz
$ swift run -c release -Xlinker='-lrt' FuzzilliCli --profile=jsc /The/Path/to/webkit/FuzzBuild/Debug/bin/jsc #See also swift run FuzzilliCli --help

The following error may appear on the command line:

1
$ error: root manifest not found

If so, run this command first:

1
$ swift package init --type executable

However, this does not always work. The "root manifest not found" error occurs because the project lacks package.swift. I eventually found the solution: clone the whole project inside Fuzzilli instead of somewhere else. In other words, all source code for a specific JavaScript engine, such as JavaScriptCore, should be under /Path/to/fuzzilli/Targets/xxx. This ensures that package.swift exists in the root folder of fuzzilli.

Therefore, I cloned WebKit under ~/coding_env/fuzzilli/Targets/JavaScriptCore and executed the following command under ~/coding_env/fuzzilli/Targets/JavaScriptCore/webkit:

1
$ swift run -c release -Xlinker='-lrt' FuzzilliCli --profile=jsc FuzzBuild/Debug/bin/jsc #under fuzzilli's folder, in .../fuzzilli/Targets/JavaScriptCore/webkit

Fuzzing begins. Initialization takes some time.

Once fuzzing starts, the console looks like this:

After fuzzing, we can perform crash analysis using gdb.

Fuzzing QuickJS

QuickJS is an embeddable JS engine. Use the following command to build it, or follow this link to download the code matching the version in Targets/QJS/REVISION.

1
2
3
4
5
6
7
$ cd fuzzilli/Targets/QJS # Make sure this is under the fuzzilli directory
$ git clone https://github.com/bellard/quickjs.git
$ cd quickjs
$ git checkout xxx -b fuzz #This depends! Refer to the REVISION under fuzzilli/Targets
$ cp ../Patches/Fuzzilli-instrumentation-for-QJS.patch ./
$ patch -p1 < Fuzzilli-instrumentation-for-QJS.patch #Patch the current project, this may take some time to patch
$ make #official repo say we should use "make qjs" here

I encountered some issues here, so I think this should be built on macOS (which uses clang as the default compiler):

The build on Ubuntu failed, and I am still figuring out why and how to fix it. It seems clang is not supported for building QuickJS on Ubuntu. GCC is the default compiler, but GCC does not support -fsanitize-coverage=trace-pc-guard; only clang supports it.

On Ubuntu, if you build using make qjs (following the instructions here), the error is different.

It seems very close to success, but I am stuck here.

Fuzzing V8

V8 is the open-source JS engine used in Chrome. First, we need to fetch the source code, so install depot_tools first.

1
$ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git

Add depot_tools to the front of your PATH (you will probably want to put this in your ~/.bashrc or ~/.zshrc). Assuming you cloned depot_tools to /path/to/depot_tools:

1
$ export PATH=/path/to/depot_tools:$PATH

Update depot_tools by running the following command in your terminal:

1
$ gclient

Now, get the V8 source code, including all branches and dependencies:

1
2
3
4
5
$ cd fuzzilli/Targets/V8 # Make sure this is under the fuzzilli directory
$ mkdir ~/v8
$ cd ~/v8
$ fetch v8 #This may take some time, grasp a coffee and wait
$ cd v8

If you want to update the code, you can use the following command:

1
2
$ git pull
$ gclient sync

Done. Now go to the v8 directory, copy fuzzbuild.sh into the v8 root directory, and execute it from there.

The build succeeded. Run this command to begin fuzzing:

1
2
3
4
$ cd .. 
$ mkdir out #make a directory to store output
$ cd v8
$ swift run -c release -Xlinker='-lrt' FuzzilliCli --profile=v8 --storagePath=../out out/fuzzbuild/d8 #The storagePath used to store the fuzzing result

Now it works.

Note: sanitizer coverage for v8 is currently not supported on macOS as it is missing from v8's custom clang toolchain.

Fuzzing Duktape

Duktape is an embeddable JavaScript engine. First, fetch the code from GitHub:

1
2
3
4
$ cd fuzzilli/Targets/duktape # Make sure this is under the fuzzilli directory
$ git clone https://github.com/svaarala/duktape
$ cd duktape
$ make duk-fuzzilli

The executable will be named duk-fuzzilli and will be located in the duktape directory. However, I got stuck after running make duk-fuzzilli.

Fuzzing SpiderMonkey

SpiderMonkey is an open-source JS engine implemented in Firefox. First, clone the repo and run the script in Fuzzilli.

1
2
$ cd fuzzilli/Targets/Spidermonkey # Make sure this is under the fuzzilli directory
$ git clone https://github.com/mozilla/gecko-dev # This may take some time

After copying fuzzbuild.sh from Targets/Spidermonkey to the gecko-dev/js/src directory, run it:

1
2
3
4
5
$ cd Targets/Spidermonkey/gecko-dev
$ git checkout xxx # Switch to the Firefox branch
$ cd gecko-dev/js/src
$ cp /The/Path/to/fuzzilli/Targets/Spidermonkey/fuzzbuild.sh ./
$ ./fuzzbuild.sh # Run from the gecko-dev root; rustc may be needed, and this may take some time

fuzzbuild_OPT.OBJ/dist/bin/js will be the JavaScript shell for the fuzzer.

1
2
$ mkdir out #In gecko-dev/js/src
$ swift run -c release -Xlinker='-lrt' FuzzilliCli --profile=spidermonkey --storagePath=out/ fuzzbuild_OPT.OBJ/dist/bin/js

Happy hacking!

Fuzzing JerryScript

JerryScript is a lightweight JavaScript engine for the Internet of Things. To fetch the code:

1
2
$ cd fuzzilli/Targets/Jerryscript # Make sure this is under the fuzzilli directory
$ git clone https://github.com/jerryscript-project/jerryscript

Then apply the patch and run fuzzbuild.sh. Note that rustc may be needed for this step.

1
2
3
4
5
$ cd jerryscript # Make sure this is under fuzzilli/Targets/Jerryscript/jerryscript
$ git checkout 0f0041d720adfd83012e59435c2f1b555c1234d5 # Optional; check the REVISION file in the Targets folder
$ patch -p1 < /The/Path/to/jerryscript.patch # Patch the current folder; this fails if the checkout is not at the right commit.
$ cp /The/Path/to/fuzzilli/Targets/Jerryscript/fuzzbuild.sh ./
$ ./fuzzbuild.sh # Begin building

./build/bin/jerry will be the JavaScript shell for the fuzzer.

1
2
$ mkdir out # In Targets/Jerryscript/jerryscript
$ swift run -c release -Xlinker='-lrt' FuzzilliCli --profile=jerryscript --storagePath=out/ ./build/bin/jerry

Now we can begin fuzzing.

Swift Basic Knowledge (Optional)

Swift uses SPM (Swift Package Manager) to set up a new package project. Create a new folder called swift_test and use this command to initialize it:

1
$ swift package init --type executable --name helloworld #swift build --init

An executable Swift package called helloworld will be generated in this folder.

We can run it by building and executing it.

This creates a basic Command line tool.

Fuzzilli in Docker (Optional)

For this part, refer to this document. An available Docker image can be found here.

Install Rust (Optional)

1
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh #Choose 1 after this

The output message is shown below:

All tools, including rustc, cargo, and rustup, will be located in ~/.cargo/bin. Add this directory to the PATH environment variable. Run rustc --version to check whether Rust has been installed. To uninstall it, run rustup self uninstall.