Unpacking the WPAD/PAC and JScript Exploit: A Deep Dive Into Windows 10 Local Network Vulnerabilities

It’s fascinating how seemingly innocuous web technologies can become potent tools for attackers. Recently, the Project Zero team at Google shed light on a rather intricate exploit targeting Windows 10 within a local network, leveraging WPAD/PAC files and JScript. While the initial reports and translations offer a glimpse, the mechanics can feel a bit like navigating a maze. That’s where this analysis comes in, aiming to demystify the process, even if it means wrestling with some complex concepts myself.

At its heart, this exploit unfolds in several stages, but the real magic, and the focus here, lies in the first two: memory disclosure and creating an overflow. The ultimate goal is code execution, often achieved by first leaking a controllable memory address, then manipulating another vulnerability to create an overflow, taking control of the instruction pointer (EIP), escalating privileges, and finally employing techniques like Return-Oriented Programming (ROP).

So, what exactly are WPAD and PAC? PAC, or Proxy Auto-Config, is essentially a JavaScript file that tells browsers how to automatically select a proxy server for a given URL. WPAD (Web Proxy Auto-Discovery Protocol) is the mechanism that helps discover the location of this PAC file, often through DNS or DHCP services. The crucial part for this exploit? PAC files are written in JavaScript, and that’s where the vulnerabilities lie.

Stage One: Leaking a Controllable Heap Address

The first hurdle is to get our hands on a memory address that we can influence. This is achieved through a vulnerability in RegExp.lastParen. Imagine this: you have a regular expression that’s designed to match a very specific pattern. In JScript, the RegExp object has an internal buffer that stores indices for each match. The problem arises when the number of matches exceeds the capacity of this buffer. When RegExp.lastParen is then accessed, it tries to use the number of matches as an index into this buffer, leading to an out-of-bounds read.

By carefully crafting a regular expression and setting RegExp.input to a specific integer, we can manipulate RegExp.lastParen to reveal an address. The strategy involves allocating large strings to ensure they land in a predictable memory region, then selectively freeing some to create gaps. Triggering the RegExp.lastParen vulnerability then leaks the address of one of these freed strings, giving us a pointer to the heap metadata. This address is then used to ensure subsequent allocations point to something we can control, setting the stage for the next phase.

Stage Two: Crafting an Overflow with Array.sort

This is where things get really interesting. The second stage exploits a vulnerability within the Array.sort method in JScript. When Array.sort is invoked, it internally uses a function called JsArrayStringHeapSort. This function allocates temporary arrays to help with the sorting process. The vulnerability kicks in when the array’s size unexpectedly increases during the sorting, specifically after a custom toString() method is called on an object within the array. This causes the temporary allocation to overflow.

During JsArrayStringHeapSort, elements are read into a temporary structure. For string elements, pointers to the string are stored. For double-precision floating-point numbers, the actual value is stored directly. The exploit aims to overwrite critical data structures, particularly the hash table pointers of JScript objects. By carefully orchestrating memory allocations and deallocations, the exploit ensures that the overflow buffer created by Array.sort is adjacent to a JScript object’s hash table.

The overflow allows us to overwrite the hash table pointer of a JScript object with a controlled pointer. This is achieved by manipulating specific variables within the overflowed structure. One variable can be made to point to another, and by changing its type, we can effectively read or write arbitrary memory locations. This is the linchpin for further exploitation, allowing us to leak addresses or even write arbitrary values to memory.

The Path Forward: From Leak to Execution

While stages three and four delve into bypassing Control Flow Guard (CFG) and preparing for code execution using ROP chains, the initial two stages are the foundation. They demonstrate a clever interplay of JavaScript engine quirks and memory management to achieve a critical foothold: a controllable memory address and the ability to overwrite essential data structures. It’s a stark reminder of how deep security vulnerabilities can run, often hidden within the very features designed to make our online experience smoother.

Leave a Reply

Your email address will not be published. Required fields are marked *