Resources

People often ask me "How did you learn how to hack?" The answer: by reading. This page is a collection of the blog posts and other articles that I have accumulated over the years of my journey. Enjoy!

Corruption via MathSpace on Firefox Browser- 1703

Manfred Paul - ZDI post by Hossein LotfiPosted 7 Months Ago
  • Browsers need to be fast - I mean, really fast. So, running JavaScript isn't always fast enough. Modern browsers perform Just-in-Time (JIT) compilations of JavaScript to native code, making it faster. This introduces an interesting yet incredibly complicated set of vulnerabilities to consider. This post is a Firefox JIT bug in the Pwn2Own competition.
  • The Ion JIT compiler uses a function called ExtractLinearSum to convert a value into a linear sum expression. For instance, (x+(2+3)) - (-3) can be transformed into x+8. This type contains three parameters: This type contains three parameters:
    1. Value node
    2. MathSpace - an enum with the three values Modulo, Infinite and Unknown that will wrap around the integer space, bail if wrapping is needed and the final one is a default value.
    3. Recursive counter for stack depth exhaustion issues
  • The function ExtractLinearSum is used multiple places in the Ion compiler, one of which is folding or simplifying the linear expressions. The function TryEliminateBoundsCheck is trying to merge bounds checks on the same object to simplify things. For instance, array[i+4]; array[i+7] will generate two bounds checks. To do this, it will create a bounds check object that can keep track of what's going on, eventually leading to a value of 7 being checked on the length.
  • Although the usage of the MathSpace is useful, it's not rigorously verified. In the case of bounds checks, this seems pretty important! Module makes sense in some math cases but doesn't make sense in the case of bounds checks - infinite does. So, what if we can find a way to make the numbers being used in this operation of type Modulo on a bounds check?
  • The following code triggers the bug when i is slightly less than 2^32: array[(i+5)|0]; array[(i+10)|0]. The |0 is used to force this to be 32 bits. The check will overflow because of the MathSpace being set to Modulo, leading to a faulty bounds check. This is only possible with really large arrays, requiring typed arrays to be practically feasible.
  • Getting the write to happen in the proper location only requires fiddling with the minimum and maximum sizes in funky ways to trick the minimum/maximum counting for the bounds. To make this useful to exploit for an OOB read or OOB write, a useful object must be found in the huge address space. They found that Map objects were nice for getting a addrOf and fakeObj primitive. Once there, exploitation is trivial.
  • It appears that this bug was found via manual source code review. Even though JavaScript engines are heavily fuzzed and reviewed, there are still great bugs lurking in unusual places. Overall, great write-up for somebody who knows nothing about browser engines!