allisonleathomas / google-security-research

Automatically exported from code.google.com/p/google-security-research
0 stars 0 forks source link

Windows Kernel ATMFD.DLL unlimited out-of-bounds stack manipulation via BLEND operator #180

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
The `blend` operator - as described in "The Type 2 Charstring Format, 18 March 
1998" - is supposed to take n + 1 parameters from the operand stack, with the 
16-bit signed value "n" being passed as the first argument. The implementation 
of the operator found in the Adobe Type Manager Font Driver (ATMFD.DLL) in the 
Windows kernel does not expect that value to be negative and mishandles this 
corner case, leading to catastrophic consequences for system security.

Specifically, the `blend` handler does perform some validation checks against 
"n" in order to check that the (again, signed) number is not greater than the 
current size of the stack, or that the stack pointer is not already out of 
stack bounds when entering the code:

---
      case cf2_cmdBLEND:
        if ( op_sp < &op_stk[1] || op_sp > &op_end )
...
        if ( !master_designs && &op_sp[n] >= &op_end )
...
        if ( &op_stk[n * master_designs] > op_sp )
...
        op_sp = DoBlend(op_sp,
                        font->weight_vector,
                        font->master_designs,
                        n);

---

A negative 16-bit number passes all of the above checks and is further provided 
as the last parameter to the "DoBlend" function. When confronted with such a 
number, that function shifts the operand stack pointer up by the following 
number of bytes:

-n * (master_designs - 1) * 4

This condition is badly dangerous because of the fact that the 48-item long 
operand stack is implemented as a regular array on the interpreter function's 
stack, thus being able to shift the operand stack pointer out of bounds gives 
the power to manipulate the regular kernel stack in any desired way. An 
attacker is able to illegally add a maximum value of 32768 * 15 * 4 = 1966080 
(0x1E0000) to the stack pointer; on the other hand, by setting "master_designs" 
to 2 (in case of ATMFD.DLL, this can be achieved by inserting a PostScript 
array "WeightVector" with two elements into the font dict), one is able to 
shift the pointer with great accuracy (any multiply of 4). For example, if the 
return address of the interpreter function is positioned 128 dwords ahead of 
the "op_stk" array, the two instructions below will set "op_sp" to that address:

-128 blend

At first glance it is not trivial to turn the condition into an arbitrary stack 
manipulation primitive, because the standard opcodes used for pushing values to 
the stack do check that "op_sp" has not gone beyond the "op_stk" memory area. 
However, various operators which write to the stack but don't increase "op_sp" 
(because they also take parameters from the stack) don't perform such checks, 
and so can be used to manipulate the data under any "op_sp". These operators 
are:

1) not
2) neg
3) abs
4) sqrt
5) index
6) div
7) add
8) sub
9) mul
10) get

In particular, a sequence of `put`, `blend`, and several `sqrt` followed by 
`get` instructions can be used to successfully manipulate the data on stack in 
any desired way. This is not just about reading and writing - the CharString 
can perform arithmetic operations such as addition or subtraction, thus it is 
possible to build a full ROP chain on the kernel stack and reliably hijack 
ring-0 code execution solely from within the font VM, with no external help. 
This is very similar to a FreeType vulnerability exploited by comex in his iOS 
jailbreak [1], only here the attacker gets even more control over the control 
flow, because the entire kernel stack is fully controlled.

The vulnerability is reproducible with Type1 fonts. It is not reproducible (to 
our current knowledge) with OpenType fonts, because it requires the number of 
master designs in the font to be non-zero. The attached testcase ("poc.pfm" + 
"poc.pfb") crashes a fully patched Windows 8.1 32-bit, by using the following 
charstring for letter 'a':

/a ## -| { -349 blend exch endchar } |-

together with a "WeightVector" of length 2. This causes the "op_sp" pointer to 
be shifted forward by 0x574 bytes (4 bytes ahead of the interpreter function's 
return address), and further dereferenced by the `exch` operator. Therefore, 
the following crash occurs due to an attempt to execute a non-executable stack 
address (as the return address and stack frame pointer are exchanged), when the 
font is opened with the standard Windows Font Viewer utility:

---
ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY (fc)
An attempt was made to execute non-executable memory.  The guilty driver
is on the stack trace (and is typically the current instruction pointer).
When possible, the guilty driver's name (Unicode string) is printed on
the bugcheck screen and saved in KiBugCheckDriver.
Arguments:
Arg1: 97ebf6a4, Virtual address for the attempted execute.
Arg2: 11dd2963, PTE contents.
Arg3: 97ebf56c, (reserved)
Arg4: 00000002, (reserved)

---

A full crash log can be found in the "crash.txt" file. All 32-bit versions of 
Windows up to 8.1 are affected by the vulnerability. While the faulty 
expression in C code remains the same for both 32 and 64-bit architectures, the 
"n * master_designs" factor is cast to a 32-bit unsigned integer, causing the 
entire bounds check expression to evaluate to "true" on 64-bit platforms, if 
"n" is a negative 16-bit number:

---
if ( (unsigned __int64)((char *)&op_stk + 4 * (unsigned int)(n * 
master_designs)) > op_sp )
{
  v111 = (__int64)"op_stk + inst->lenWeightVector*nArgs <= op_sp";

---

On the other hand, the vulnerability can be successfully exploited in sandboxed 
environments, if the win32k lock-down option is not in force. Typically 
installing a font in the system would require file system access; however, it 
is also possible to achieve the goal through an undocumented 
win32k!NtGdiAddRemoteFontToDC system call, which can load font resources 
consisting of multiple files from memory.

References:
[1] http://esec-lab.sogeti.com/post/Analysis-of-the-jailbreakme-v3-font-exploit

Original issue reported on code.google.com by mjurc...@google.com on 20 Nov 2014 at 10:30

Attachments:

GoogleCodeExporter commented 8 years ago

Original comment by mjurc...@google.com on 4 Dec 2014 at 4:36

GoogleCodeExporter commented 8 years ago

Original comment by mjurc...@google.com on 11 Dec 2014 at 10:19

GoogleCodeExporter commented 8 years ago
This bug is subject to a 90 day disclosure deadline. If 90 days elapse without 
a broadly available patch, then the bug report will automatically become 
visible to the public.

The message was communicated to the vendor while reporting the vulnerability.

Original comment by mjurc...@google.com on 6 Feb 2015 at 11:28

GoogleCodeExporter commented 8 years ago

Original comment by mjurc...@google.com on 24 Mar 2015 at 10:07

GoogleCodeExporter commented 8 years ago

Original comment by cev...@google.com on 1 Apr 2015 at 12:11

GoogleCodeExporter commented 8 years ago

Original comment by mjurc...@google.com on 20 Apr 2015 at 2:08

GoogleCodeExporter commented 8 years ago

Original comment by mjurc...@google.com on 12 Jun 2015 at 4:03