Kudos for the first validated exploit!

88 views
Skip to first unread message

Brad Chen

unread,
Dec 13, 2008, 11:42:43 AM12/13/08
to native-cli...@googlegroups.com, native-clie...@googlegroups.com

I'm please to announce that the first Native Client exploit from outside Google has been submitted as Issue 23 to the project site. User defend.the.world found an inner-sandbox escape due to a defect in the validator. The validator was checking for calls through registers, as in this two-byte call:
83 e2 e0                and    $0xffffffe0,%edx
ff d2                   call   %edx

but erroneously permitting similar calls through memory using this addressing mode:
83 e2 e0                and    $0xffffffe0,%edx
ff 12                   call   *(%edx)
The and mask required by the validator aligns the address in the register, but not the address in the memory location pointed to by the register, thereby allowing a control transfer to an arbitrary byte location in the untrusted text segment. For example, it could transfer control to a syscall instruction embedded in the middle of an instruction previously identified by the validator.

Fixing this defect is relatively simple via a patch to ncv/ncvalidate.c to restrict the addressing modes allowed for this kind of call or jump:
bash-3.2$ diff -Naur ORIG/ncvalidate.c ncvalidate.c
--- ORIG/ncvalidate.c   2008-12-12 22:28:16.000000000 -0800
+++ ncvalidate.c        2008-12-12 22:38:04.000000000 -0800
@@ -482,6 +482,10 @@
     /* check all the opcodes. */
     if (jmpopcode[0] != 0xff) break;
     if ((modrm_reg(mrm) != 2) && (modrm_reg(mrm) != 4)) break;
+    /* Issue 32: disallow unsafe call/jump indirection */
+    /* example:    ff 12     call (*edx)               */
+    /* Reported by defend.the.world on 11 Dec 2008     */
+    if (modrm_mod(mrm) != 3) break;
     if (oropcode[0] != 0x81) break;
     if (andopcode[0] != 0x81) break;
     /* check modrm bytes of or and and instructions */
@@ -536,6 +540,10 @@
     /* In GROUP5, 2 => call, 4 => jmp */
     if (jmpopcode[0] != 0xff) break;
     if ((modrm_reg(mrm) != 2) && (modrm_reg(mrm) != 4)) break;
+    /* Issue 32: disallow unsafe call/jump indirection */
+    /* example:    ff 12     call (*edx)               */
+    /* Reported by defend.the.world on 11 Dec 2008     */
+    if (modrm_mod(mrm) != 3) break;
     if (targetreg == kReg_ESP) break;
     if (andopcode[0] != 0x83) break;
     /* check modrm bytes of or and and instructions */
bash-3.2$

Note that we are fixing both the five and 14-byte versions of ValidateIndirect, even though only the five-byte version is used. This fix will be included in our next set of downloads.

Congratulations to defend.the.world!

Brad Chen

dan

unread,
Dec 15, 2008, 5:08:37 AM12/15/08
to Native Client Discuss
Nice breakout. Any idea why ncval reports it as unsafe though ?


D:\nacl\googleclient\native_client\scons-out\opt-win\staging>ncval d:
\test\nacl\
haha_release.nexe
...
***MODULE d:\test\nacl\haha_release.nexe IS UNSAFE***

Analysis Summary:
94332 Checked instructions
12378 checked jump targets
561 calls/jumps need dynamic checking (0.59%)

Problems:
0 illegal instructions
0 bad jump targets
0 illegal unprotected indirect jumps (including ret)
0 instruction alignment defects
0 segmentation errors
0 bad prefix
0 bad instruction length
0 missing full stop
0 internal errors
0 bad cpu
Validated d:\test\nacl\haha_release.nexe
d:\test\nacl\haha_release.nexe: 0.000000 0.015000


Cheers,
Daniel


On 13 déc, 17:42, Brad Chen <bradc...@google.com> wrote:
> I'm please to announce that the first Native Client exploit from outside
> Google has been submitted as Issue
> 23<http://code.google.com/p/nativeclient/issues/detail?id=23>to the

Brad Chen

unread,
Dec 15, 2008, 11:22:44 PM12/15/08
to native-cli...@googlegroups.com
The command-line validator is not being very helpful in this case. Someplace in the middle of the output you omitted, it said something about multiple text sections, which it doesn't like, because it's worried about holes. When the validator is invoked by sel_ldr, it turns out that the sections have already been loaded into memory, and are passed in for validation as a single contiguous region.

Brad Chen

dan

unread,
Dec 16, 2008, 4:52:27 AM12/16/08
to Native Client Discuss
Ok, thanks Brad.

Is it just me or is this exploit actually using the nacljmp as it
appears in the research paper ?

and %eax, 0xffffffe0
jmp *(%eax)

At the same time, the research paper states “we disallow memory
addressing modes on indirect jmp and call instructions“. So it looks
like the nacljmp in the research paper should be:

and %eax, 0xffffffe0
jmp %eax

The rest of my random thoughts have been posted here:
http://indefinitestudies.org/2008/12/15/a-first-look-at-google-native-clients-inner-sandbox/

Cheers,
Dan

Brad Chen

unread,
Dec 16, 2008, 1:16:25 PM12/16/08
to native-cli...@googlegroups.com
Maybe this explains why I've always liked hexadecimal. Sadly there are two different common assembler syntaxes for x86 and I can't keep them straight. Thanks for pointing out this inconsistency. We will fix this when we next revise the paper.

Brad

Bennet Yee (余仕斌)

unread,
Dec 16, 2008, 1:31:39 PM12/16/08
to native-cli...@googlegroups.com
on a linux system, so using gas:

$ i=dan.s; cat $i; as $i
        .globl foo
foo:    and %eax, 0xffffffe0
        jmp %eax
dan.s: Assembler messages:
dan.s:3: Error: suffix or operands invalid for `jmp'
$ i=dan2.s; cat $i; as $i
        .globl foo
foo:    and %eax, 0xffffffe0
        jmp (%eax)
dan2.s: Assembler messages:
dan2.s:3: Warning: indirect jmp without `*'
$ i=dan3.s; cat $i; as $i
        .globl foo
foo:    and %eax, 0xffffffe0
        jmp *(%eax)
$

-bsy



On Tue, Dec 16, 2008 at 1:52 AM, dan <reynaud...@gmail.com> wrote:
>
--
bennet s yee
i usually don't capitalize due to mild tendonitis


David Sehr

unread,
Dec 16, 2008, 3:09:58 PM12/16/08
to native-cli...@googlegroups.com
Dan,

Bennet and I just confirmed your insight that our paper contained a typographical error.  What we intended to convey was that the accepted instruction sequence for a nacljmp should be:
        and %eax, 0xffffffe0
        jmp *%eax
rather than

        and %eax, 0xffffffe0
        jmp *(%eax)

The former makes no memory reference to compute the target address, while the latter does.  We will update the paper accordingly in an upcoming release.

Thank you again!

David
Reply all
Reply to author
Forward
0 new messages