Apacolypse Now: Exploiting Windows Ten Inward A Local Network Alongside Wpad/Pac In Addition To Jscript
by Ivan Fratric, Thomas Dullien, James Forshaw as well as Steven Vittitoe
Intro
Many widely-deployed technologies, viewed through 20/20 hindsight, seem similar an strange or unnecessarily risky idea. Engineering decisions inward information technology are oftentimes made amongst imperfect information as well as nether fourth dimension pressure, as well as some oddities of the information technology stack tin best live explained amongst “it seemed similar a proficient thought at the time”. In the personal persuasion of some of the authors of this post, WPAD (“Web Proxy Auto Discovery Protocol” - as well as to a greater extent than specifically “Proxy Auto-Config”), is 1 of these oddities.
At some dot inward the real early on days of the Internet - prior to 1996 - engineers at Netscape decided that JavaScript was a proficient linguistic communication to write configuration files in. The final result was PAC - a configuration file format that plant every bit follows: The browser connects to a pre-configured server, downloads the PAC file, as well as executes a particular Javascript component subdivision to determine proper proxy configuration. Why not? It sure is to a greater extent than expressive as well as less verbose than (let’s say) XML, as well as seems a reasonable way to furnish configurations to many clients.
PAC itself was coupled amongst a protocol called WPAD - a protocol that makes it unnecessary for the browser to withdraw hold a pre-configured server to connect to. Instead, WPAD allows the reckoner to query the local network to determine the server from which to charge the PAC file.
Somehow this technology scientific discipline ended upward beingness an IETF draft which expired inward 1999, as well as now, inward 2017, every Windows machine volition inquire the local network: “Hey, where tin I discovery a Javascript file to execute?”. This tin come about via a number of mechanisms: DNS, WINS, but - perchance most interestingly - DHCP.
In recent years, browser exploits withdraw hold mutated from beingness primarily DOM-oriented to targeting Javascript engines directly, so the mere advert that nosotros tin teach Javascript execution over the network without the browser was motivating. An initial investigation revealed that the JS Engine responsible for executing these configuration files was jscript.dll - the legacy JS Engine that also powered IE7 as well as IE8 (and is still reachable inward IE11 inward IE7/8 compatibility fashion if appropriate script attributes are used). This is both proficient as well as bad - on the 1 hand, it agency that non every Chakra põrnikas is automatically a local network remote attack, but on the other hand, it agency that some pretty onetime code volition live responsible for executing our Javascript.
Security researchers withdraw hold previously warned about the dangers of WPAD. But, every bit far every bit nosotros know, this is the offset fourth dimension that an assault against WPAD is demonstrated that results inward the consummate compromise of the WPAD user’s machine.
Windows is sure non the solely slice of software that implements WPAD. Other operating systems as well as applications practice every bit well. For instance Google Chrome also has a WPAD implementation, but inward Chrome’s case, evaluating the JavaScript code from the PAC file happens within a sandbox. And other operating systems that back upward WPAD don’t enable it yesteryear default. This is why Windows is currently the most interesting target for this variety of attack.
Web Proxy Auto-Discovery
As mentioned above, WPAD volition query DHCP as well as DNS (in that order) to obtain a URL to connect to - evidently LLMNR as well as Netbios tin also live used if no response from DNS is available. Some peculiarities of WPAD-over-DNS enable surprising assault vectors.
Attack scenario: Local network via DHCP
In the most mutual scenario, a machine volition query the local DHCP server using pick code 252. The DHCP server replies amongst a string - similar “http://server.domain/proxyconfig.pac”, which specifies a URL from which the configuration file should live fetched. The customer as well as then proceeds to fetch this file, as well as execute the contents every bit Javascript.
In a local network, an aggressor tin just impersonate the DHCP server - either yesteryear ARP games or yesteryear racing the legitimate DHCP. The aggressor tin as well as then furnish a URL where the malicious Javascript file is hosted.
Attack scenario: Remote over the network via privileged seat as well as DNS
Aside from the local-network assault scenario, the fact that lookup for WPAD may also come about via DNS creates a secondary assault scenario. Many users configure their computers to perform DNS lookups against 1 of the public, globally visible DNS servers (such every bit 8.8.8.8, 8.8.4.4, 208.67.222.222 as well as 208.67.220.220). In such a scenario, a machine volition transportation DNS queries (such every bit wpad.local) to the server which sits exterior of the local network. An aggressor inward a privileged seat on the network (e.g. a gateway, or whatever other upstream host) tin monitor the DNS queries as well as spoof a reply, directing the customer to download as well as execute a malicious Javascript file.
Setups similar these seem to live mutual - according to this Wikipedia entry, a nontrivial proportion of the traffic that the DNS root servers watch are .local requests.
Attack scenario: Remote over the network via malicious wpad.tld
A particular oddity of WPAD is that it recursively walks the local machine scream to discovery domains to query. If a machine is called “laptop01.us.division.company.com”, the next domains are supposedly queried inward order:
- wpad.us.division.company.com
- wpad.division.company.com
- wpad.company.com
- wpad.com
This has (according to this Wikipedia entry) inward the yesteryear led to people registering wpad.co.uk as well as redirecting traffic to an online auction site. Further quoting from that entry:
Through the WPAD file, the aggressor tin dot users' browsers to their ain proxies as well as intercept as well as modify all of World Wide Web traffic. Although a simplistic create for Windows WPAD treatment was applied inward 2005, it solely fixed the occupation for the .com domain. Influenza A virus subtype H5N1 presentation at Kiwicon showed that the ease of the basis was still critically vulnerable to this safety hole, amongst a sample domain registered inward New Zealand for testing purposes receiving proxy requests from all over the province at the charge per unit of measurement of several a second. Several of the wpad.tld domain names (including COM, NET, ORG, as well as US) at nowadays dot to the customer loopback address to assist protect against this vulnerability, though some names are still registered (wpad.co.uk).
Thus, an administrator should brand sure that a user tin trust all the DHCP servers inward an organisation as well as that all possible wpad domains for the organisation are nether control. Furthermore, if there's no wpad domain configured for an organisation, a user volition croak to whatever external location has the next wpad site inward the domain hierarchy as well as utilisation that for its configuration. This allows whoever registers the wpad subdomain inward a particular province to perform a man-in-the-middle attack on large portions of that country's network traffic yesteryear setting themselves every bit a proxy for all traffic or sites of interest.
The IETF draft, on the other hand, explicitly asks for clients to solely allow “canonical” (e.g. non-top-level domains). We withdraw hold non investigated to what extent clients implement this, or if second-level domains (such every bit .co.uk) are the culprit inward the historical cases of traffic redirection.
Either way: Bugs inward the Javascript engine nether consideration tin live exploited remotely via the network if 1 manages to register wpad.$TLD for a given organization’s TLD, provided said TLD is non explicitly blacklisted yesteryear the customer implementation. Given that the IETF draft from 1999 refers to a listing of TLDs from 1994 (RFC1591), it is unlikely that clients withdraw hold been updated to reverberate the proliferation of novel TLDs.
Our attempts to register wpad.co.$TLD for a diversity of TLDs were non (yet) successful.
Bugs
We spent some fourth dimension looking for bugs inward jscript.dll as well as employed both manual analysis as well as fuzzing. JScript initially posed some challenge because a lot of “features” useful for triggering bugs inward JavaScript engines can’t live used inward JScript, just due to it beingness likewise onetime to back upward them. For example:
- There are no multiple arrays types (int array, float array etc.). Thus confusing 1 array type for some other is non possible.
- There are non every bit many optimizations (“fast paths”) every bit inward the newer, faster JavaScript engines. These fast paths are oftentimes the source of bugs.
- It is non possible to define a getter/setter on a generic JavaScript object. It is possible to telephone yell upward defineProperty but solely on DOM objects which doesn’t piece of work for us every bit in that location won’t live a DOM inward the WPAD process. Even if in that location were, a lot of JScript functions volition just neglect when called on a DOM object amongst a message “JScript object expected”.
- It is impossible to modify an object’s epitome 1 time it is created (i.e. in that location is no “__proto__” property).
However, JScript does endure from to a greater extent than “old-school” vulnerability classes such every bit use-after-free. JScript’s garbage collector is described inward this onetime MSDN article. JScript uses a non-generational mark-and-sweep garbage collector. Essentially, whenever a garbage collection is triggered, it marks all the JScript objects. Then it scans them starting from a laid of “root” objects (sometimes also referred to every bit “scavengers”) as well as clears the grade from all the objects it encounters. All the objects that are still marked teach deleted. One recurring occupation is that local variables on the stack aren’t added to the listing of root objects yesteryear default, pregnant that a programmer needs to recollect to add together them to the garbage collector’s root list, peculiarly if those variables refer to objects that tin live deleted during the function’s lifetime.
Other possible types of vulnerabilities include buffer overflows, uninitialized variables etc.
For fuzzing, nosotros used the grammar-based Domato fuzzing engine as well as wrote a novel grammar specifically for JScript. We identified interesting built-in properties as well as functions to add together to the grammar yesteryear looking at EnsureBuiltin methods of diverse JScript objects. The JScript grammar has been added to the Domato repository here.
Between fuzzing as well as manual analysis nosotros identified 7 safety vulnerabilities. They are summarized inward the tabular array below:
Vulnerability class | Vulnerabilities affecting IE8 mode | Vulnerabilities affecting IE7 mode |
Use-after-free | ||
Heap overflow | ||
Uninitialized variable | ||
Out-of-bounds read | ||
Total | 7 | 5 |
At the fourth dimension of publishing this spider web log post, all the bugs withdraw hold been fixed yesteryear Microsoft.
The tabular array breaks downward the vulnerabilities yesteryear degree as well as compatibility fashion required to trigger them. JScript inward WPAD is equivalent to running a script inward IE7 compatibility mode, which agency that, although nosotros flora 7 vulnerabilities, “only” five of them tin live triggered inward WPAD. However, the other vulnerabilities tin still live used against Internet Explorer (including IE11) when set into IE8 compatibility fashion yesteryear a malicious webpage.
Exploit
Understanding JScript VARs as well as Strings
Since inward the residue of this blogpost we’re going to verbalise nearly JScript VARs as well as Strings a lot, it is useful to depict these earlier going deeper into how the exploits work.
JScript VAR is a 24-byte (on 64-bit builds) construction that represents a JavaScript variable as well as is essentially the same every bit the VARIANT information construction described inward this MSDN article. In most cases (sufficient to follow the exploit) its retention layout looks similar this:
Offset | Size | Description |
0 | 2 | Variable type, 3 for integer, five for double, 8 for string etc. |
8 | 8 | Depending on the type, either an immediate value or a pointer |
16 | 8 | Unused for most types |
For example, nosotros tin stand upward for a double precision number yesteryear a VAR that has five written inward the offset 2 bytes (indicating the double type), followed yesteryear an actual double value at offset 8. The in conclusion 8 bytes are going to live unused but they are going to live copied around if a value of some other VAR is copied from this VAR.
A JScript string is a type of VAR that has the type 8 as well as a pointer at offset 8. The pointer points into a BSTR construction described here. On 64-bit builds BSTR layout looks similar this:
Offset | Size | Description |
0 | 4 | Unused |
4 | 4 | String length inward bytes non counting the nada grapheme at the end |
8 | length+2 | String characters (16-bit) followed yesteryear a nada character |
A String VAR points direct to the grapheme array, which agency that, to obtain a String's length, the pointer needs to live decremented yesteryear iv as well as the length read from there. Note that BSTRs are handled yesteryear OleAut32.dll as well as are allocated on a dissever heap (i.e. a different heap than is beingness used for other JScript objects).
Freeing of BSTRs is also different than for most objects because, instead of direct freeing a BSTR, when SysFreeString is called, it offset puts a string inward a cache controlled yesteryear OleAut32.dll. This machinery is described inward particular inward Heap Feng Shui inward JavaScript.
Stage 1: Infoleak
The purpose of the infoleak volition live to obtain the address of a string inward retention whose content nosotros fully control. We won’t live leaking whatever executable module addresses at this point, that volition come upward later. Instead, the goal is to defeat high-entropy heap randomization as well as brand the 2nd phase of the exploit reliable without having to utilisation heap spraying.
For the infoleak we’re going to utilisation this bug inward RegExp.lastParen. To empathise the põrnikas let’s offset convey a closer human face at the retention layout of jscript!RegExpFncObj which corresponds to the JScript RegExp object. At offset 0xAC RegExpFncObj contains a buffer of twenty integers. Actually these are 10 pairs of integers: the offset chemical constituent of the pair is the start index into the input string as well as the 2nd chemical constituent is the destination index. Whenever RegExp.test, RegExp.exec or String.search amongst a RegExp parameter run into a capturing grouping (parentheses inward the RegExp syntax), the start as well as destination index of the jibe are stored here. Obviously inward the buffer in that location is infinite for solely 10 matches, so solely the offset 10 matches are stored inward this buffer.
However, if RegExp.lastParen is called as well as in that location were to a greater extent than than 10 capturing groups, RegExpFncObj::LastParen volition happily utilisation the number of capturing groups every bit an index into the buffer, leading to out-of-bounds read. Here is a PoC:
var r= novel RegExp(Array(100).join('()'));
''.search(r);
alert(RegExp.lastParen);
The 2 indices (let’s telephone yell upward them start_index as well as end_index) are read exterior the bounds of the buffer as well as tin thence live made arbitrarily large. Assuming this offset out-of-bounds access doesn’t drive a crash, if the values inward those indices are larger than the length of the input string, as well as then a second out-of-bounds access is going to occur which allows us to read a exterior the bounds of the input string. The string content read out-of-bounds similar this is going to live returned to the caller inward a String variable where it tin live examined.
This 2nd out-of-bounds read is what we’re going to use, but offset nosotros demand to figure out how to teach controlled information into start_index as well as end_index. Fortunately, looking at the layout of RegExpFncObj, in that location is information nosotros command after the destination of the index buffer: RegExp.input value. By setting RegExp.input to an integer value as well as using a RegExp composed of 41 sets of empty parentheses, when RegExp.lastParen gets called, start_index is going to live 0 as well as the end_index is going to live whatever value nosotros wrote to RegExp.input.
If nosotros brand an input string next to a freed string, as well as then yesteryear reading after the bounds of input string, nosotros tin obtain the heap metadata such every bit the pointers to the other complimentary heap segments (Left, Right as well as Parent node inward the red-black tree of heap chunks, watch Windows 10 Segment Heap Internals for to a greater extent than information). Image 1 shows the relevant objects at the 2nd of infoleak.
Image 1: Heap infoleak layout
We are using 20000 bytes-long strings every bit input inward gild for them not to live allocated on the Low Fragmentation Heap (LFH tin solely live used for allocations of 16K bytes as well as smaller) since the heap metadata for the LFH is different as well as does non include useful pointers inward Windows 10 Segment Heap. Additionally, LFH introduces randomness that would touching our powerfulness to identify the input string next to a freed string.
By reading the heap metadata out of the returned string, nosotros tin obtain an address of a freed string. Then, if nosotros allocate a string of the same size every bit the freed string, it mightiness live placed at this address as well as nosotros achieved our goal, that is nosotros know the address of retention of a string whose content nosotros control.
The whole infoleak procedure looks similar this:
- Allocate M 10000-character strings (note: 10000 characters == 20000 bytes).
- Free every 2nd one.
- Trigger the information leak bug. Use 1 of the remaining strings every bit an input strings as well as read 20080 bytes.
- Analyze the leaked string as well as obtain the pointer to 1 of the freed strings.
- Allocate 500 strings of the same length every bit the freed strings (10000 characters) amongst a specially crafted content.
The content of the specially crafted strings is non of import at this stage, but volition live of import inward the next one, so it volition live described there. Also depository fiscal establishment annotation that, yesteryear examining heap metadata, nosotros tin easily determine which heap implementation the procedure is using (Segment Heap vs NT heap).
Images 2 as well as 3 present heap visualization created using Heap History Viewer at the fourth dimension around the infoleak. Green stripes stand upward for allocated blocks (occupied yesteryear strings), greyish stripes stand upward for allocated blocks that are as well as then freed yesteryear later on allocated 1 time to a greater extent than (the stings nosotros complimentary as well as and then reallocate after triggering the infoleak bug) as well as the white stripes stand upward for information that is never allocated (guard pages). You tin watch how strings teach allocated every bit the fourth dimension passes, as well as then one-half of them are freed (grey ones) as well as sometime later on teach allocated 1 time to a greater extent than (the stripes croak green).
We tin watch that in that location are going to live guard pages after every 3 allocations of this size. Our exploit is never genuinely going to touching whatever of these guard pages (it reads likewise lilliputian information yesteryear the destination of the string for that to occur) but inward ⅓ of the cases in that location won’t live a complimentary string after the input string for the infoleak so the expected heap metadata volition live missing. We can, however, easily discovery this instance as well as either trigger the infoleak põrnikas using some other input string or silently abort the exploit (note: nosotros didn’t trigger whatever retention corruption upward to this point).
Image 2: Heap Diagram: Showing the development of the heap over time
Image 3: Step-by-step illustration of leaking a pointer to a string.
Stage 2: Overflow
In phase 2 of the exploit we’re going to utilisation this heap overflow bug inward Array.sort. In instance the number of elements inward the input array to Array.sort is larger than Array.length / 2, JsArrayStringHeapSort (called yesteryear Array.sort if a comparing component subdivision isn’t specified) is going to allocate a temporary buffer of the same size every bit the number of elements currently inward the array (note: tin live smaller than array.lenght). It is as well as then going to essay to retrieve the corresponding elements for every array index from 0 to Array.length and, if that chemical constituent exists, add together it to the buffer as well as convert to string. If the array doesn’t modify during the lifetime of JsArrayStringHeapSort, this volition piece of work fine. However, JsArrayStringHeapSort converts array elements into strings which tin trigger toString() callbacks. If during 1 of those toString() callbacks elements are added to the array where they were previously undefined, an overflow is going to occur.
To empathise the põrnikas as well as its exploitability meliorate let’s convey a closer human face at the construction of the buffer we’ll overflow out of. It is already mentioned that the array volition withdraw hold the same size every bit the number of elements currently inward input array (to live exact, it is going to live number of elements + 1). Each chemical constituent of the array is going to live 48 bytes inward size (in a 64-bit build) amongst the next structure:
Offset | Size | Descripion |
0 | 8 | Pointer to a string VAR after the original VAR at offset sixteen is converted to string |
8 | 4 | Index (int) of the electrical flow element |
16 | 24 | VAR holding the original array element |
40 | 4 | int 0 or 1 depending on the type of VAR at offset 16 |
During JsArrayStringHeapSort, each chemical constituent of the array amongst index < array.length is retrieved, as well as if the chemical constituent is defined the next happens:
- The array chemical constituent is read into VAR at offset 16
- The original VAR is converted into a string VAR. Influenza A virus subtype H5N1 pointer to the string VAR is written at offset 0.
- At offset 8, the index of the electrical flow chemical constituent inward array is written
- Depending on the original VAR type, 0 or 1 is written at offset 40
Looking at the construction of the temporary buffer, nosotros don’t command a lot of it directly. If an array fellow member is a string, as well as then at offsets 0 as well as 24 we’re going to withdraw hold a pointer that, when dereferenced, at offset 8 contains some other pointer to the information nosotros control. This is, however, 1 aeroplane of indirection larger than what would live useful to us inward most situations.
However, if a fellow member of array is a double precision number, as well as then at offset 24 (corresponding to offset 8 into the original VAR) the value of that number is going to live written as well as it is direct nether our control. If nosotros create a number amongst the same double representation every bit the pointer obtained inward Stage 1, as well as then nosotros tin utilisation our overflow to overwrite a pointer somewhere after the destination of the buffer amongst a pointer to the retention nosotros direct control.
Now the enquiry becomes, what tin nosotros overwrite inward this way to advance the exploit. One of the possible answers presents itself if nosotros convey a closer human face at how Objects piece of work inward JScript.
Each Object (more specifically, a NameList JScript object) is going to withdraw hold a pointer to a hashtable. This hashtable is just an array of pointers. When a fellow member chemical constituent of an Object is accessed, a hash of the scream of the chemical constituent is computed. Then, a pointer at the offset corresponding to the lowest bits of the hash is dereferenced. This pointer points to a linked listing of object elements as well as this linked listing is traversed until nosotros reached an chemical constituent amongst the same scream every bit the requested element. This is shown inward picture 4.
Note that, when the scream of the chemical constituent is less than iv bytes, it is stored inward the same construction every bit the VAR (element value). Otherwise, in that location is going to live a pointer to the chemical constituent name. Name lengths <=4 are sufficient for us so nosotros don’t demand to croak into the details of this.
An Object hashtable is a proficient candidate to overwrite because:
- We tin command which elements of it are dereferenced yesteryear accessing the corresponding object members. Elements nosotros overwrite amongst information nosotros don’t command volition just never live accessed.
- We withdraw hold limited command over the hashtable size yesteryear controlling how many members the corresponding object has. For instance a hashtable starts amongst 1024 bytes, but if nosotros add together to a greater extent than than 512 elements to the object, the hashtable volition live reallocated to 8192 bytes.
- By overwriting a hashtable pointer amongst a pointer to information nosotros control, nosotros tin create mistaken JScript vars inward the information nosotros command as well as access them just yesteryear accessing the corresponding object members.
To perform the overwrite reliably nosotros practice the following:
- Allocate as well as complimentary a lot of retention blocks amongst size 8192. This volition plow on the Low Fragmentation Heap for resources allotment of size 8192. This volition ensure that the buffer nosotros are inundation out of, every bit good every bit hashtable nosotros are inundation into volition live allocated on the LFH. This is of import because it agency in that location volition live no other allocations of other sizes nearby to spoil the exploit essay (since an LFH bucket tin solely incorporate allocations of a sure size). This inward plow ensures that nosotros volition live overwriting precisely what nosotros desire amongst high reliability.
- Create 2000 objects, each containing 512 members. In this state, each object has a hashtable of 1024 bytes. However, adding just 1 to a greater extent than chemical constituent to 1 of these objects volition drive its hashtable to grow to 8192 bytes.
- Add the 513 chemical constituent to the offset M objects, causing M allocations of 8192-byte hashtables.
- Trigger Array.sort amongst an array amongst length=300 as well as 170 elements. This allocates a buffer of size (170+1)*48=8208 bytes. Due to LFH granularity this object volition live allocated inward the same LFH bucket every bit 8192-byte hashtables.
- Immediately (in the toString() method of the offset array element) add together 513th chemical constituent to the 2nd M objects. This makes us pretty sure that yesteryear at nowadays the variety buffer is neighboring 1 of the hashtables. In the same toString() method also add together to a greater extent than elements to the array which volition drive it to grow out-of-bounds.
Image five shows heap visualization around the address of the variety buffer (red line). You tin watch the variety buffer is surrounded yesteryear allocations of similar size which all correspond to Object hashtables. You tin also observe the LFH randomness inward the feel that subsequent allocations are non necessarily on subsequent addresses, withal this makes no divergence for our exploit.
Image 5: Heap visualization around the overflow buffer
As mentioned previously, nosotros crafted our overflow inward such a way that some of the hashtable pointers of an unlucky JScript object volition teach overwritten amongst pointers into the information nosotros control. Now finally what precisely nosotros set into this information comes into play: nosotros crafted it inward such a way that it contains five (fake) JavaScript variables:
- Variable 1 just contains number 1337.
- Variable 2 is of special type 0x400C. This type basically tells JavaScript that the actual VAR is pointed to yesteryear pointer at offset 8, as well as this pointer should live dereferenced earlier reading or writing this variable. In our case, this pointer points sixteen bytes earlier Variable 1. This basically agency that the in conclusion 8-byte qword of Variable 2 as well as the offset 8-byte qword of Variable 1 overlap.
- Variable 3, Variable iv as well as Variable five are unproblematic integers. What is special nearly them is that they incorporate numbers 5, 8 as well as 0x400C inward their in conclusion 8 bytes, respectively.
Image 6: State of objects after the overflow. Red areas dot where the overflow occurred. Each box inward the bottom row (except those marked every bit ‘...’) corresponds to 8 bytes. Data contained inward ‘...’ boxes is omitted for clarity
We tin access Variable 1 yesteryear just accessing the corrupted object at the right index (let’s telephone yell upward it index1) as well as similarly for Variables 2-5. In fact, nosotros tin discovery which Object nosotros corrupted yesteryear accessing index1 of all objects as well as seeing which at nowadays has the value 1337.
Overlapping Variable 1 as well as Variable 2 has the outcome that nosotros tin modify the type (first WORD) of Variable 1 into five (double), 8 (string) or 0x400C (pointer). We practice this yesteryear reading Variable 2, 3 or iv as well as and then writing the read value into Variable 2. For instance the statement
corruptedobject[index2] = corruptedobject[index4];
Has the outcome that the type of Variable 1 volition live changed into a String (8), spell all other fields of Variable 1 volition stay unchanged.
This layout gives us several real powerful exploitation primitives:
- If nosotros write some variable that contains a pointer into Variable 1, nosotros tin discover the value of this pointer yesteryear changing the type of Variable 1 to double (5) as well as reading it out
- We tin discover (read) retention at an arbitrary address yesteryear faking a String at that address. We tin accomplish this yesteryear offset writing a double value corresponding to the address nosotros desire to read into Variable 1 as well as and then changing the type of Variable 1 toString (8).
- We tin write to an arbitrary address yesteryear offset writing a numeric value corresponding to the address into Variable 1, as well as then changing the type of Variable 1 to 0x400C (pointer) as well as finally writing some information to Variable 1.
With these exploit primitives, unremarkably getting the code execution would live pretty simple, but since we’re exploiting Windows 10 nosotros offset demand to bypass the Control Flow Guard (CFG).
Stage 3: CFG bypass
There are in all likelihood other known bypasses nosotros could withdraw hold used here, but it turns out that in that location are some real convenient bypasses (once aggressor has a read/write primitive) specific to jscript.dll. We are going to exploit the facts that:
- Return addresses are non protected yesteryear CFG
- Some Jscript objects withdraw hold pointers to the native stack
Specifically, each NameTbl object (in Jscript, all JavaScript objects inherit from NameTbl), at offset 24 holds a pointer to CSession object. CSession object, at offset eighty holds a pointer to close the top of the native stack.
Thus, amongst an arbitrary read, yesteryear next a chain of pointers from whatever JScript object, it is possible to retrieve a pointer to the native stack. Then, amongst an arbitrary write, it is possible to overwrite a render address, bypassing CFG.
Stage 4: Getting code execution every bit Local Service
With all the exploit elements inward place, nosotros tin at nowadays croak along to getting the code execution. We are doing it inward these steps:
- Read the address of jscript.dll from a vtable of whatever JScript object
- Read the address of kernel32.dll yesteryear reading the import tabular array of jscript.dll
- Read the address of kernelbase.dll yesteryear reading the import tabular array of kernel32.dll
- Scan kernel32.dll for rop gadgets nosotros are going to need
- Get the address of WinExec from the export tabular array of kernel32.dll
- Leak the stack address every bit explained inward the previous section
- Prepare the ROP chain as well as write it to the stack, starting amongst a render address closest to our leaked stack address.
The ROP chain nosotros are using looks similar this:
[address of RET] //needed to align the stack to sixteen bytes
[address of POP RCX; RET] //loads the offset parameter into rcx
[address of command to execute]
[address of POP RDX; RET] //loads the 2nd parameter into rdx
1
[address of WinExec]
By executing this ROP chain nosotros are calling WinExec amongst a command nosotros specified. For example, if nosotros run the command ‘cmd’ nosotros are going to watch a command prompt beingness spawned, running every bit Local Service (the same user WPAD service runs as).
Unfortunately, from a minor fry procedure running every bit Local Service, nosotros can’t verbalise to the network, but what nosotros tin practice is drib our privilege escalation payload from retention to a disk location Local Service tin write as well as execute it from there.
Stage 5: Privilege escalation
While the Local Service concern human relationship is a service account, it doesn’t withdraw hold administrative privileges. This agency the exploit is quite limited inward what it tin access as well as modify on the system, peculiarly to persist after exploitation or after the scheme has been rebooted. While there’s ever probable to live an unfixed privilege escalation inward Windows nosotros don’t demand to discovery a novel vulnerability to escalate our privileges. Instead nosotros tin abuse a built-in characteristic to escalate from Local Service to the SYSTEM account. Let’s human face at the privileges that the service concern human relationship for WPAD has been granted:
Image 7: Service Access Token’s Privileges showing Impersonate Privilege
We’ve solely got 3 privileges, but the highlighted privilege, SeImpersonatePrivilege is important. This privilege allows the service to impersonate other users on the local system. The argue the service has impersonate privilege is it accepts requests from all users on the local scheme as well as mightiness demand to perform actions on their behalf. However, every bit long every bit nosotros tin teach an access token for the concern human relationship nosotros desire to impersonate nosotros tin teach the total access rights of the token’s user account, including SYSTEM which would give us administrator rights on the local system.
Abusing impersonation is a known number amongst the Windows safety model (you tin discovery to a greater extent than details yesteryear searching for Token Kidnapping). Microsoft withdraw hold tried to teach inward harder to teach an access token for a privileged user but it’s virtually impossible to closed all possible routes. For example, James discovered a vulnerability inward Windows’ implementation of DCOM which allows whatever user to teach access to a SYSTEM access token. While Microsoft fixed the direct privilege escalation vulnerability they didn’t, or perchance couldn’t, create the token kidnapping issue. We tin abuse this characteristic to capture the SYSTEM token, impersonate the token, as well as then completely compromise the system, such every bit installing a privileged service.
There’s an existing implementation of the token kidnapping via DCOM (RottenPotato) withal the implementation was designed for utilisation amongst the Metasploit framework’s getsystem command which we’re non using. Therefore, nosotros implemented our ain simpler version inward C++ which direct spawns an arbitrary procedure amongst a SYSTEM token using the CreateProcessWithToken API. As a bonus nosotros were able to compile it to an executable of 11KiB inward size, much smaller than RottenPotato, which made it easier to drib to disk as well as run from the ROP payload.
Tying it all together
When the WPAD service queries for the PAC file, nosotros serve the exploit file which exploits the WPAD service as well as runs WinExec to drib as well as execute the privilege escalation binary. This binary as well as then executes a command (hardcoded ‘cmd’ inward our case) every bit SYSTEM.
The exploit worked pretty reliably inward our experiments, but it is interesting to depository fiscal establishment annotation that a 100% reliable exploit isn’t required - if the exploit crashes the WPAD service, a novel instance is going to teach spawned when a customer makes some other asking from WPAD service, so an aggressor tin just essay again. There volition live no indication inward the UI that the WPAD service has crashed, although Window Error Reporting volition probable pick upward the crash as well as written report it to Microsoft, provided that the user didn’t disable it.
In fact, our exploit doesn’t create clean upward gracefully as well as volition crash the WPAD service 1 time it runs its payload, so if nosotros maintain serving the exploit PAC file after the service has been exploited, it volition just teach exploited again. You tin watch the outcome of that inward Image 7, which was taken after leaving the exploit server running for some minutes as well as making a lot of HTTP requests inward the victim machine.
Image 7: Did nosotros exit the exploit running for likewise long?
Conclusion
Executing untrusted JavaScript code is dangerous, as well as executing it inward an unsandboxed procedure is fifty-fifty to a greater extent than so. This is truthful fifty-fifty if it’s done yesteryear a relatively compact JavaScript engine such every bit jscript.dll. We identified 7 safety vulnerabilities inward it as well as successfully demonstrated reliable code execution from local network (and beyond) against a fully patched (at the fourth dimension of writing) Windows 10 64-bit amongst Fall Creators Update installed.
Since the bugs are at nowadays fixed, does this hateful nosotros are done as well as tin croak home? Unlikely. Although nosotros spent a fair amount of time, elbow grease as well as compute powerfulness on finding jscript.dll bugs, nosotros brand no claims that nosotros flora all of them. In fact, where in that location are 7 bugs, in that location is probable to live an 8th. So if something doesn’t modify it is quite possible we’ll watch a chain similar this used inward the wild someday (and that is, of course, optimistically assuming that attackers don’t withdraw hold this capability already).
So, what tin Microsoft practice to brand futurity attacks similar this harder:
- Disable WPAD yesteryear default. In fact, spell the other operating systems back upward WPAD, Windows is the solely 1 where it is enabled yesteryear default.
- Sandbox the JScript interpreter within the WPAD service. Since the interpreter needs to execute a JavaScript component subdivision amongst good defined inputs as well as render the output string, sandboxing it should live pretty straightforward. Given the simplicity of the input-output model, it would live dandy if Microsoft introduced a sandbox of comparable restrictiveness to seccomp-strict: Some processes genuinely practice non demand to a greater extent than privileges than “receive a fleck of data”, “perform a fleck of computation”, “return a fleck of data”.
In instance you lot desire to convey activity on your own, the solely way to preclude this type of assault using new, currently unknown vulnerabilities, seems to live to completely disable the WinHttpAutoProxySvc service. Sometimes this can’t live done inward the Services UI (“Startup type” command volition live grayed out) due to other services depending on WPAD, but it tin live done via the corresponding registry entry. Under “HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WinHttpAutoProxySvc” modify the value of “Start” from 3 (manual) to iv (disabled).
These are some of the advices commonly flora online when searching for “disabling WPAD” that did not piece of work to preclude the assault inward our experiments:
- Turning off “Automatically discovery settings” inward Control Panel
- Setting “WpadOverride” registry key
- Putting “255.255.255.255 wpad” inward the hosts file (this is going to halt the DNS variant but probable non the DHCP variant)
Komentar
Posting Komentar