Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >使用 WPAD/PAC 和 JScript在win11中进行远程代码执行1

使用 WPAD/PAC 和 JScript在win11中进行远程代码执行1

原创
作者头像
franket
发布于 2022-04-23 11:21:51
发布于 2022-04-23 11:21:51
8K0
举报
文章被收录于专栏:技术杂记技术杂记

开发

了解 JScript VAR 和字符串

由于在这篇博文的其余部分中,我们将大量讨论 JScript VAR 和字符串,因此在深入了解这些漏洞的工作原理之前先描述这些内容是很有用的。

JScript VAR 是一个 24 字节(在 64 位版本上)结构,它表示一个 JavaScript 变量,并且本质上与此 MSDN 文章中描述的 VARIANT 数据结构相同。在大多数情况下(足以跟踪漏洞利用),它的内存布局如下所示:

抵消

尺寸

描述

0

2

变量类型,3 表示整数,5 表示双精度,8 表示字符串等。

8

8

根据类型,立即数或指针

16

8

大多数类型未使用

例如,我们可以用 VAR 表示一个双精度数,在前 2 个字节中写入 5(表示双精度类型),后跟偏移 8 处的实际双精度值。最后 8 个字节将不使用,但它们如果从该 VAR 复制另一个 VAR 的值,则将被复制。

JScript 字符串是类型为 8 的 VAR 类型和偏移量 8 处的指针。指针指向此处(https://msdn.microsoft.com/en-us/library/windows/desktop/ms221069(v=vs.85%29.aspx)描述的 BSTR 结构。在 64 位版本上,BSTR 布局如下所示:

抵消

尺寸

描述

0

4

没用过

4

4

以字节为单位的字符串长度,不包括最后的空字符

8

长度+2

字符串字符(16 位)后跟一个空字符

String VAR 直接指向字符数组,这意味着,要获得 String 的长度,需要将指针减 4 并从那里读取长度。请注意,BSTR 由 OleAut32.dll 处理并分配在单独的堆上(即与用于其他 JScript 对象的堆不同)。

释放 BSTR 也与大多数对象不同,因为在调用 SysFreeString 时,它不是直接释放 BSTR,而是首先将字符串放入由 OleAut32.dll 控制的缓存中。这个机制在 JavaScript 中的堆风水中有详细描述。

第 1 阶段:信息泄漏

infoleak 的目的是获取我们完全控制其内容的内存中字符串的地址。在这一点上,我们不会泄露任何可执行模块地址,这将在稍后发布。相反,我们的目标是击败高熵堆随机化,并使漏洞利用的第二阶段可靠,而无需使用堆喷射。

对于信息泄漏,我们将在 RegExp.lastParen 中使用这个错误。要了解这个错误,让我们首先仔细看看 jscript!RegExpFncObj 的内存布局,它对应于 JScript RegExp 对象。在偏移量 0xAC RegExpFncObj 包含 20 个整数的缓冲区。实际上这些是 10 对整数:对的第一个元素是输入字符串的开始索引,第二个元素是结束索引。每当带有 RegExp 参数的 RegExp.test、RegExp.exec 或 String.search 遇到捕获组(RegExp 语法中的括号)时,匹配的开始和结束索引都存储在这里。显然,缓冲区中只有 10 个匹配项的空间,因此只有前 10 个匹配项存储在此缓冲区中。

但是,如果 RegExp.lastParen 被调用并且有超过 10 个捕获组,RegExpFncObj::LastParen 会很乐意使用捕获组的数量作为缓冲区的索引,从而导致越界读取。这是一个 PoC:

 var r= new RegExp(Array(100).join('()'));

 ''.search(r);

 警报(RegExp.lastParen);

2 个索引(我们称它们为start_indexend_index )在缓冲区边界之外读取,因此可以任意大。假设第一次越界访问不会导致崩溃,如果这些索引中的值大于输入字符串的长度,那么将发生第二次越界访问,这允许我们读取a 在输入字符串的范围之外。像这样越界读取的字符串内容将在一个可以检查的字符串变量中返回给调用者。

我们将要使用第二次越界读取,但首先我们需要弄清楚如何将受控数据放入start_indexend_index 。好在看RegExpFncObj的布局,在索引缓冲区结束后还有我们控制的数据:RegExp.input值。通过将 RegExp.input 设置为整数值并使用由 41 组空括号组成的 RegExp,当 RegExp.lastParen 被调用时,start_index将为 0,而end_index将是我们写入 RegExp.input 的任何值。

如果我们让一个输入字符串与一个被释放的字符串相邻,那么通过读取输入字符串的边界,我们可以获得堆元数据,例如指向其他空闲堆段的指针(红黑中的Left,Right和Parent节点堆块树,请参阅Windows 10 段堆内部了解更多信息)。图 1 显示了信息泄漏时的相关对象。

图 1:堆信息泄漏布局

我们使用 20000 字节长的字符串作为输入,以便它们不会被分配到低碎片堆上(LFH 只能用于 16K 字节或更小的分配),因为 LFH 的堆元数据不同并且不包括Windows 10 段堆中的有用指针。此外,LFH 引入了随机性,这会影响我们将输入字符串放置在已释放字符串旁边的能力。

通过从返回的字符串中读取堆元数据,我们可以获得一个已释放字符串的地址。然后,如果我们分配一个与释放的字符串大小相同的字符串,它可能会被放置在这个地址,我们就实现了我们的目标,即我们知道我们控制其内容的字符串的内存地址。

整个信息泄露过程如下所示:

  1. 分配 1000 个 10000 个字符的字符串(注意:10000 个字符 == 20000 个字节)。
  2. 每隔一秒免费一次。
  3. 触发信息泄漏错误。使用剩余的字符串之一作为输入字符串并读取 20080 个字节。
  4. 分析泄漏的字符串并获取指向已释放字符串之一的指针。
  5. 使用特制内容分配 500 个与已释放字符串(10000 个字符)长度相同的字符串。

特制琴弦的内容现阶段不重要,但在下一阶段会很重要,所以会在此进行说明。另请注意,通过检查堆元数据,我们可以轻松确定进程正在使用哪个堆实现(段堆与 NT 堆)。

图像 2 和 3 显示了在信息泄漏前后使用堆历史查看器创建的堆可视化。绿色条纹代表分配的块(被字符串占用),灰色条纹代表分配的块,然后被稍后再次分配的释放(我们释放并在触发信息泄漏错误后重新分配的stings),白色条纹代表从未分配的数据(守卫页)。您可以看到随着时间的流逝如何分配字符串,然后释放其中一半(灰色),稍后再次分配(条纹变为绿色)。

我们可以看到,每 3 次这样大小的分配后都会有保护页。我们的漏洞利用永远不会真正触及任何这些保护页面(它读取的数据太少超出了字符串的末尾),但在 1/3 的情况下,在输入字符串之后不会有空闲字符串infoleak,因此预期的堆元数据将丢失。然而,我们可以很容易地检测到这种情况,或者使用另一个输入字符串触发 infoleak 错误,或者静默中止漏洞利用(注意:到目前为止,我们没有触发任何内存损坏)。

图 2:堆图:显示堆随时间的演变

图 3:泄露指向字符串的指针的分步说明。

第 2 阶段:溢出

在漏洞利用的第 2 阶段,我们将使用这个堆溢出漏洞在 Array.sort 中。如果 Array.sort 的输入数组中的元素数大于 Array.length / 2,JsArrayStringHeapSort(如果未指定比较函数则由 Array.sort 调用)将分配一个相同大小的临时缓冲区作为当前数组中的元素数(注意:可以小于array.lenght)。然后它将尝试检索从 0 到 Array.length 的每个数组索引的相应元素,如果该元素存在,则将其添加到缓冲区并转换为字符串。如果数组在 JsArrayStringHeapSort 的生命周期内没有改变,这将正常工作。但是,JsArrayStringHeapSort 将数组元素转换为可以触发 toString() 回调的字符串。如果在其中一个 toString() 回调中元素被添加到之前未定义的数组中,

为了更好地理解这个错误及其可利用性,让我们仔细看看我们将溢出的缓冲区的结构。已经提到该数组将具有与当前输入数组中的元素数相同的大小(准确地说,它将是元素数 + 1)。数组的每个元素的大小将是 48 字节(在 64 位构建中),具有以下结构:

抵消

尺寸

描述

0

8

将偏移量 16 处的原始 VAR 转换为字符串后指向字符串 VAR 的指针

8

4

当前元素的索引 (int)

16

24

VAR 保存原始数组元素

40

4

int 0 或 1 取决于偏移 16 处的 VAR 类型

在 JsArrayStringHeapSort 期间,检索索引 < array.length 的数组的每个元素,如果定义了该元素,则会发生以下情况:

  1. 数组元素在偏移量 16 处读入 VAR
  2. 原始的 VAR 被转换为字符串 VAR。指向字符串 VAR 的指针被写入偏移量 0。
  3. 在偏移量 8 处,写入数组中当前元素的索引
  4. 根据原始 VAR 类型,在偏移量 40 处写入 0 或 1

看临时缓冲区的结构,很多我们并没有直接控制。如果数组成员是一个字符串,那么在偏移量 0 和 24 处我们将有一个指针,当取消引用时,在偏移量 8 处包含另一个指向我们控制的数据的指针。然而,这比在大多数情况下对我们有用的间接级别要大一级。

但是,如果数组的成员是双精度数,那么在偏移量 24(对应于原始 VAR 的偏移量 8)处,该数字的值将被写入,并且它直接在我们的控制之下。如果我们创建一个与在阶段 1 中获得的指针具有相同双精度表示的数字,那么我们可以使用溢出来用指向我们直接控制的内存的指针覆盖缓冲区结束后某处的指针。

现在问题变成了,我们可以用这种方式覆盖什么来推进漏洞利用。如果我们仔细研究对象在 JScript 中是如何工作的,那么其中一个可能的答案就会出现。

每个对象(更具体地说,一个 NameList JScript 对象)都有一个指向哈希表的指针。这个哈希表只是一个指针数组。当访问 Object 的成员元素时,将计算元素名称的哈希值。然后,取消引用对应于哈希最低位的偏移量的指针。这个指针指向一个对象元素的链表,并且遍历这个链表,直到我们到达一个与请求元素同名的元素。如图 4 所示。

图 4:JScript 对象元素内部

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
C 语言知识点总结篇
Debug 和 Release 版本比较 Debug 附加了许多调试信息,主要用于调试,故文件大; Release 是经过优化后的版本,去掉了调试信息,代码进行了优化,故文件较小,且编译速度快过 Debug,用于发布平台的配置管理器的设置; 32 位与 64 位 32 位,地址为 32 位,最大使用内存 4G,只能运行 32 位的数据; 64 位,地址为 64 位,既可以运行 32 位的数据,也可以运行 64 位的数据; 指针 指针是个量,对应一块内存区域; 指针存储的是某个内存单元的地址; 访问方式: 1
村雨遥
2022/06/15
6030
C 语言知识点总结篇
利用WPAD/PAC与JScript实现Windows 10远程代码执行
简介 Project Zero团队在google发表了一篇关于利用WPAD/PAC和JScript在本地网络中实现Windows10远程代码执行的博客,笔者根据博客复现了漏洞,现在把利用过程以及一些值得注意的地方拿出来和大家分享。 博客中介绍了此漏洞在WPAD服务中的利用过程,而本文主要针对此漏洞在IE浏览器中的利用。由于IE浏览器无论是在32位系统还是64位系统中,默认情况下始终是使用32位版本去访问页面,所以本文所有的利用过程都是针对32位IE。 漏洞介绍 在处理如下(1)处的调用时,如果Array.s
安恒信息
2018/04/09
8780
利用WPAD/PAC与JScript实现Windows 10远程代码执行
使用 WPAD/PAC 和 JScript在win11中进行远程代码执行3
请注意,当元素的名称小于 4 个字节时,它与 VAR(元素值)存储在相同的结构中。否则,将有一个指向元素名称的指针。名称长度 <=4 对我们来说就足够了,所以我们不需要详细说明。
franket
2022/04/23
2.1K0
C/C++静态代码安全检查工具
静态代码安全检查工具是一种能够帮助程序员自动检测出源程序中是否存在安全缺陷的软件。它通过逐行分析程序的源代码,发现软件中潜在的安全漏洞。本文针对 C/C++语言程序设计中容易存在的多种安全问题,分别分析了问题的根源,给出了具体可行的分析及检测方法。最后通过对静态代码安全检查工具优缺点的比较,给出了一些提高安全检查效果的建议。
用户7886150
2021/02/19
1.8K0
理解对C++裸指针释放后重用的问题
本文将以Android 2.2-2.3上的一个zergRush漏洞为例,分析指针释放后重用的问题。 zergRush是Android 2.2-2.3上的一个漏洞,主要问题就在于指针的释放后重用。 zergRush利用了libsysutils库提供的Framework套接字的通用接口。 程序从套接字收到的消息中出抽取出的文本命令会导致栈缓冲区溢出,进而造成释放后重用问题。 具体地,是vold后台程序调用了libsysutils.so,bug出在FrameworkListener.cpp的dispa
felix
2018/06/08
1.8K0
【CSAPP】AttackLab
《CSAPP》是指计算机系统基础课程的经典教材《Computer Systems: A Programmer's Perspective》,由Randal E. Bryant和David R. O'Hallaron编写。该书的主要目标是帮助深入理解计算机系统的工作原理,包括硬件和软件的相互关系,其涵盖了计算机体系结构、汇编语言、操作系统、计算机网络等主题,旨在培养学生系统级编程和分析的能力。
SarPro
2024/02/20
3291
【CSAPP】AttackLab
redis内部数据结构详解
redis内部有 简单动态字符串、链表、字典、跳跃表、整数集合、压缩列表六种数据结构。
一点博客
2023/02/20
7420
redis内部数据结构详解
可靠的远程代码执行(3)
前面我们也提到过OOB访问对象上的虚方法后的几条指令被调用。这通过 vtable 取消引用照常发生。这是再次提醒的代码:
franket
2021/07/09
5.1K0
【翻译】看我如何利用PHP的0day黑掉Pornhub并获得2W美刀奖励
在分析了Pornhub使用的平台之后,我们在其网站上检测到了unserialize函数的使用,其中的很多功能点(例如上传图片的地方等等)都受到了影响,例如下面两个URL:
ChaMd5安全团队
2019/10/31
2K0
面试官不讲武德,居然让我讲讲蠕虫和金丝雀!
  蠕虫是一种可以自我复制的代码,并且通过网络传播,通常无需人为干预就能传播。蠕虫病毒入侵并完全控制一台计算机之后,就会把这台机器作为宿主,进而扫描并感染其他计算机。当这些新的被蠕虫入侵的计算机被控制之后,蠕虫会以这些计算机为宿主继续扫描并感染其他计算机,这种行为会一直延续下去。蠕虫使用这种递归的方法进行传播,按照指数增长的规律分布自己,进而及时控制越来越多的计算机。
嵌入式与Linux那些事
2021/04/20
1.3K0
cJSON,c语言的JSON库!
cJSON的目标是成为您能够完成工作的“最愚蠢(最便捷)”的解析器。它是一个C文件和一个头文件。
小锋学长生活大爆炸
2020/08/13
4.5K0
cJSON,c语言的JSON库!
在 C# 中使用 Span<T> 和 Memory<T> 编写高性能代码
原文地址:https://www.codemag.com/Article/2207031/Writing-High-Performance-Code-Using-SpanT-and-MemoryT-in-C
痴者工良
2022/09/23
3.2K0
在 C# 中使用 Span<T> 和 Memory<T> 编写高性能代码
开心档之Node.js Buffer(缓冲区)
但在处理像TCP流或文件流时,必须使用到二进制数据。因此在 Node.js中,定义了一个 Buffer 类,该类用来创建一个专门存放二进制数据的缓存区。
爱学iOS的小麦子
2023/02/09
1.2K0
堆和栈的区别
一、预备知识—程序的内存分配 一个由c/C++编译的程序占用的内存分为以下几个部分 1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。 2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。 3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态
Angel_Kitty
2018/04/08
1.3K0
JavaScript是如何工作的:深入V8引擎&编写优化代码的5个技巧
JavaScript 引擎是执行 JavaScript 代码的程序或解释器。JavaScript 引擎可以实现为标准解释器,或者以某种形式将 JavaScript 编译为字节码的即时编译器。
Javanx
2019/10/12
1.7K0
JavaScript是如何工作的:深入V8引擎&编写优化代码的5个技巧
面试总结-C++
堆、栈、自由存储区、全局/静态存储区、常量存储区 自由存储区存储malloc申请的内存 (1)从静态存储区域分配 。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如 全局变量, static 变量 。 (2)在栈上创建 。在执行函数时, 函数内局部变量的存储单元都可以在栈上创建 ,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集。 (3)从堆上分配 , 亦称动态内存分配 。程序在运行的时候用 malloc 或 new 申请任意多少的内存,程序员自己负责在何时用 free 或 delete 释放内存。动态内存的生存期由程序员决定,使用非常灵活,但问题也最多。
小二三不乌
2018/08/02
2.2K0
如何隐藏钩子:rootkit 的管理程序2
考虑到分配的寻址可预测性,两个 可以在多个测试中进行观察: 1. 两个分配都按 16 页对齐,添加了 0x20 字节的标头 启用整页堆设置(或默认设置为 0x8)。 2. 两种分配的内存地址都是高度可预测的。 事实上,两个分配的地址会因测试而异 'just' 大约 0x1'000'000 字节,这在 0x19'000'000+0x12'000'000 几乎连续受控内存的术语 空间: ; 为便于阅读而编辑的 windbg 脚本日志 ; 通过重新启动应用程序并记录相同的分配产生 ; 显示两
franket
2022/03/21
4.6K2
【Linux】文件操作函数 (详解)
🔥 每个系统都有自己的专属函数,我们习惯称其为系统函数。系统函数并不是内核函数,因为内核函数是不允许用户使用的,系统函数就充当了二者之间的桥梁,这样用户就可以间接的完成某些内核操作了。 如:open、close、lseek、read、write这些系统IO函数又被称为不带缓冲的IO (unbuffered IO)。术语不带缓冲指的是每个read和write都调用内核中的一个系统调用,因此也常叫做系统IO,与之相对应的还有标准IO(fopen、fread、fwrite、fclose等)。 应用层程序编写如下:
IsLand1314
2024/11/19
3060
【Linux】文件操作函数 (详解)
Nebula漏洞利用包CVE-2016-0189漏洞利用分析
1. 引言 在最近的一年里, 漏洞利用工具包(EK/Exploit Kit)市场风云变幻。2016年六月初,曾经极为猖獗的Angler EK 销声匿迹,Neutrino EK 迅速填补了空白。随后短短不到3个月时间,Neutrino EK 又转为地下,RIG EK继而成为最流行的漏洞利用工具包。今年3月初,RIG又淡出视线,而迎来了新的Nebula EK。 Nebula EK包中对CVE-2016-0189的漏洞利用,比其它漏洞利用包的漏洞利用方有了一定改进,这里进行一下深入分析。 所用工具: IE11(调
FB客服
2018/02/24
1.6K0
Nebula漏洞利用包CVE-2016-0189漏洞利用分析
放大零点击漏洞
Zoom 是一个视频会议平台,在整个大流行期间广受欢迎。与我调查过的其他视频会议系统不同,一个用户发起呼叫,其他用户必须立即接受或拒绝,Zoom 呼叫通常是提前安排好的,并通过电子邮件邀请加入。过去,我没有优先审查 Zoom,因为我认为任何针对 Zoom 客户端的攻击都需要用户多次点击。然而,最近在 Pwn2Own 上披露了针对 Windows Zoom 客户端的零点击攻击 ,表明它确实具有完全远程的攻击面。以下帖子详细介绍了我对 Zoom 的调查。
Khan安全团队
2022/01/19
1.3K0
相关推荐
C 语言知识点总结篇
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档