Skip to content

Latest commit

 

History

History

README.md

BlazeCTF2018 Blazefox

Original challenge Gecko-dev commit: be1b849fa2645d5be11f2a80315837ef6a88c469, although patch was modified to be applicable to latest SpiderMonkey version as of the time this writeup was written (JavaScript-C90.0a1). Challenge is available over 0vercl0k's repository here

Analyzing the patch

If we check the patch, we see the following:

--- a/js/src/builtin/Array.cpp	2021-05-19 08:43:50.526955220 -0700
+++ b/js/src/builtin/Array.cpp	2021-05-19 08:59:36.383191816 -0700
@@ -151,6 +151,16 @@
   return ToLength(cx, value, lengthp);
 }
 
+static MOZ_ALWAYS_INLINE bool BlazeSetLengthProperty(JSContext* cx, HandleObject obj, uint64_t* lengthp) {
+        if (obj->is<ArrayObject>()) {
+                obj->as<ArrayObject>().setLength(length);
+                obj->as<ArrayObject>().setCapacityInt32(length);
+                obj->as<ArrayObject>().setInitializedLengthInt32(length);
+                return true;
+            }
+        return false;
+}
+
 // Fast path for array functions where the object is expected to be an array.
 static MOZ_ALWAYS_INLINE bool GetLengthPropertyInlined(JSContext* cx,
                                                        HandleObject obj,
@@ -1503,6 +1513,22 @@
     return DenseElementResult::Success;
   }
 
+  bool js::array_blaze(JSContext* cx, unsigned argc, Value* vp) {
+            CallArgs args = CallArgsFromVp(argc, vp);
+            RootedObject obj(cx, ToObject(cx, args.thisv()));
+            if (!obj)
+                    return false;
+
+                if (!BlazeSetLengthProperty(cx, obj, 420))
+                    return false;
+
+                //uint64_t l = obj.as<ArrayObject>().setLength(cx, 420);
+
+                args.rval().setObject(*obj);
+            return true;
+}
+
+
   auto setElementMaybeHole = [](JSContext* cx, HandleNativeObject obj,
                                 uint32_t index, const Value& val) {
     if (MOZ_LIKELY(!val.isMagic(JS_ELEMENTS_HOLE))) {
@@ -3582,6 +3608,7 @@
     JS_INLINABLE_FN("shift", array_shift, 0, 0, ArrayShift),
     JS_FN("unshift", array_unshift, 1, 0),
     JS_FNINFO("splice", array_splice, &array_splice_info, 2, 0),
+    JS_FN("blaze",            array_blaze,      0,0),
 
     /* Pythonic sequence methods. */
     JS_SELF_HOSTED_FN("concat", "ArrayConcat", 1, 0),
@@ -4237,3 +4264,6 @@
 
   return SetLengthProperty(cx, obj, length);
 }
+
+
+
--- a/js/src/builtin/Array.h	2021-05-19 08:43:50.526955220 -0700
+++ b/js/src/builtin/Array.h	2021-05-19 09:01:56.870722172 -0700
@@ -81,7 +81,7 @@
                                       HandleShape shape);
 
 extern bool ToLength(JSContext* cx, HandleValue v, uint64_t* out);
-
+extern bool array_blaze(JSContext* cx, unsigned argc, js::Value* vp);
 extern bool GetLengthProperty(JSContext* cx, HandleObject obj,
                               uint64_t* lengthp);
 
--- a/js/src/vm/ArrayObject.h	2021-05-19 08:43:53.422928009 -0700
+++ b/js/src/vm/ArrayObject.h	2021-05-19 09:04:07.373414299 -0700
@@ -40,6 +40,14 @@
                   !denseElementsAreFrozen());
     getElementsHeader()->length = length;
   }
+  
+  void setCapacityInt32(uint32_t length) {
+    getElementsHeader()->capacity = length;
+  }
+  
+  void setInitializedLengthInt32(uint32_t length) {
+    getElementsHeader()->initializedLength = length;
+  }
 
   // Make an array object with the specified initial state.
   static inline ArrayObject* createArray(JSContext* cx, gc::AllocKind kind,
@@ -59,6 +67,7 @@
       ArrayObject* obj, HandleShape shape, AutoSetNewObjectMetadata& metadata);
 };
 
+
 }  // namespace js
 
 #endif  // vm_ArrayObject_h

Basically ArrayObjects have a property called blaze, that extends the dimensions of the Array to 420.