北京新闻频道

usdt otc(www.caibao.it):一个有关 V8 破绽的细节剖析 (三)

来源:北京新闻网 发布时间:2021-03-13 浏览次数:

USDT第三方支付平台

菜宝钱包(caibao.it)是使用TRC-20协议的Usdt第三方支付平台,Usdt收款平台、Usdt自动充提平台、usdt跑分平台。免费提供入金通道、Usdt钱包支付接口、Usdt自动充值接口、Usdt无需实名寄售回收。菜宝Usdt钱包一键生成Usdt钱包、一键调用API接口、一键无实名出售Usdt。

一个有关 V8 破绽的细节剖析 (一)

一个有关 V8 破绽的细节剖析 (二)

现在,TurboFan可以以此为条件来响应地修改sea of nodes graph,那么它有什么用呢?它实验优化MaybeGrowFastElements节点,然则这样做异常小心。它知道作为推测性优化编译器,它所做的假设可能是错误的。通过确立一个新的CheckBounds节点,可以防止这种错误假设。

在if语句中,我们在[4]处看到此CheckBounds节点的确立。有几个参数转达给这个新节点,然则我们在这里只体贴index和length参数。凭证CheckBounds节点的事情方式,我们知道到达此新确立的CheckBounds节点时,TurboFan将检查以确保索引的现实值(在这种情形下,x == 7)小于或即是长度的值(在本例中,为一个NumberConstant局限(2,2))。显然7不小于或即是2,因此执行将返回给注释器,而且所有希望都将丢失,除非首先由于该错误导致CheckBounds节点从来没有插入到sea of nodes graph中。

此函数确实存在一个错误,Sergey在Bugtracker中简短地讨论了它,因此有需要更深入地研究它。该错误在标有[5]的行上,其中用两个参数挪用ReplaceWithValue,即当前节点(即MaybeGrowFastElements节点)和elements节点,这是LoadField[ 8]节点和MaybeGrowFastElements节点之间solid 边缘 的value output。这是corrupting_array的后备存储。

LoadField 和MaybeGrowFastElements之间的Value 边缘

这里的问题是ReplaceWithValue现实上接受四个参数:

真正应该发生的是挪用带有Check_bounds作为Node *效果参数的ReplaceWithValue(node,elements,check_bounds)。由于check_bounds从未传入,因此Node *效果参数最终为nullptr,这使其成为[1]处的传入效果input node(在本例中,这是另一个CheckBounds节点,与长度 1024举行对照)。请记着,节点图海洋上的效果边缘是虚线,而值和控制边缘是实线。 MaybeGrowFastElements节点周围的边缘如下所示:

MaybeGrowFastElements边缘

[2]处的for循环遍历MaybeGrowFastElements节点的每个输出边缘,并将该边缘的“input node”替换为作为参数传入的响应节点。例如,传入的Node *值参数是LoadField [ 8]节点(value input 边缘1),该节点将加载corrupting_array的元素指针。 MaybeGrowFastElements的唯一value output 边缘就是通向StoreElement节点的那条边缘,因此,当for循环在该Value 边缘上迭代时,情形如下:

现实错误发生在[3],这里的边缘变量是MaybeGrowFastElements节点与StoreField [ 12]和EffectPhi节点之间的效果输出边缘。我们希望将此边缘的input node(当前为MaybeGrowFastElements节点)替换为确立的新CheckBounds节点,由于当这一切发生的时刻,新的CheckBounds节点会有影响输出自己之间的边缘和StoreField( 12)和EffectPhi节点。

为什么具有这种效果的输出边缘云云主要?好吧,若是新的CheckBounds节点具有到另一个节点的输出效果边缘,它会告诉TurboFan,在这个新的CheckBounds节点完成其事情之前,其他节点无法做任何需要做的事情。它告诉TurboFan这个CheckBounds节点很主要。请记着,效果边缘是TurboFan若何确定需要特定执行顺序的节点的顺序。

现在,Node *效果参数已设置为链接到MaybeGrowFastElements节点的先前CheckBounds节点,而不是新确立的CheckBounds节点。这意味着StoreField [ 12]和EffectPhi节点最终将其MaybeGrowFastElements节点的效果边缘替换为先前Checkbounds节点的效果边缘。

由于新的CheckBounds节点没有任何效果输出边缘,因此TurboFan最终以为这是一个无用的CheckBounds节点(若是该节点的现实输出对其他任何节点都没有影响,为什么还要检查任何界限?)。

一旦ReplaceWithValue返回,则Replace(check_bounds)挪用将MaybeGrowFastElements节点替换为新的CheckBounds节点。由于新的CheckBounds节点没有用果输出边缘,因此将其删除,如下所示:

删除GrowFastElements

具有重影效果(ghost effect )的CheckBounds节点是新的CheckBounds节点,由于没有任何效果输出边缘,因此已将其删除。可以看到它未来自另一个CheckBounds节点的索引与常数2(这是corrupting_array的长度)举行对照,然则没有其他节点使用它,因此它被以为是冗余的,因此被删除了。

毗邻到StoreElement节点的另一个CheckBounds节点是起到检查作用,以确保x小于length 1024的节点。由于x = 7一定小于length 1024,因此很喜悦让我们无限制地接见corrupting_array [x]。另外该数组也不会增进,由于已删除了MaybeGrowFastElements节点,而且引擎不会埋怨x = 7大于corrupting_array.length = 2,由于应该测试该工具的CheckBounds节点已被删除,越界写入已经实现!

越界写入的详细历程

现在我们已经超出了特定索引的界限(在本例中,x = 7),Sergey选择7一定是有缘故原由的,我们知道corrupting_array是在corrupted_array之前界说的,而且由于V8堆简直定性性子,corrupted_array总是在corrupting_array之后放置。由于我们在末尾处以损坏的长度返回了corrupted_array,以是对下索引7的越界写入操作笼罩了corrupted_array的length属性是有意义的。在GDB中,我们可以通过./d8——allow-native -syntax运行以下代码来看到这一点:

在GDB中运行这个,在遇到断点后向上转动,复制corrupted_array的地址并在它之前查看几组quadwords:

注重,我们从地址中减去1,由于在V8中,指针的最后位总是设置为1。

这里有几点需要注重:

,

Usdt第三方支付接口

菜宝钱包(www.caibao.it)是使用TRC-20协议的Usdt第三方支付平台,Usdt收款平台、Usdt自动充提平台、usdt跑分平台。免费提供入金通道、Usdt钱包支付接口、Usdt自动充值接口、Usdt无需实名寄售回收。菜宝Usdt钱包一键生成Usdt钱包、一键调用API接口、一键无实名出售Usdt。

,

1.V8堆中的所有指针均为32位,然则每个数组中的0.1位指针都示意为它们的64位的IEEE-754 0x3fb9999999999999999a的十六进制示意,这是我同时使用x/wx和x/gx查看堆的部门缘故原由,由于这可以更清晰地领会堆。

2.若是你在厥后备存储器的界限之外跟踪ruptinging_array的索引,你会注重到,corrupted_array的元素指针是索引7的低32位,而length属性是索引7的高32位。特定值索引7处的值为0x178308792cfc处的0x2424242400000000值。

3.由于corrupting_array是一种HOLEY_DOUBLE_ELEMENTS类型的数组,因此我们对其执行的任何超出局限的写入操作都市将64位值写入所选的索引。 Sergey将length_as_double设置为0x2424242400000000的浮点示意形式。之以是将高位设置为较大的值,是由于他想笼罩length属性,该属性正好是此索引的高32位。

这里的一个大问题是,当笼罩length属性时,我们也必须笼罩elements指针。若是你要注重的话,你会注重到%DebugPrint在实验打印出有关corrupted_array的信息时现实上会导致分段错误。这样做的缘故原由是由于元素指针已被笼罩为NULL,以是在作废引用时,就会泛启程序运行溃逃(segfault)。

你可能想知道,引擎若何知道后备存储的位置?现在接见corrupted_array的任何索引一定会导致segfault,由于它将实验接见元素指针,我想这似乎是由于corrupted_array是一个已知长度的“快速”数组(我们将其分配为1)。由于从未修悔改此长度(使用越界写入举行修改不会盘算在内),因此引擎始终在其自身之前以已知偏移量分配其FixedDoubleArray后备存储。引擎可能将此偏移量缓存在某个位置,然则我不确定该若何事情。你只需要知道,只要你不再次通过JavaScript扩展数组的长度,笼罩指向NULL的elements指针就不会造成任何问题。

我们的剖析差不多完成了,不外需要注释一下最后一行:

为什么Sergey选择在包装器数组中同时返回corrupting_array和corrupted_array?若是你仅通过返回corrupted_array来试验看法证实,就会注重到看法证实不再起作用(corrupted_array的长度永远不会被笼罩)。

让我们快速查看一下GDB,使用--allow-natives-syntax标志在GDB中运行以下代码:

注重到这里的区别了吗?corrupting_array的现实JSArray工具消逝了!这里我们只有corrupting_array的后备存储,索引为0和1的为[0.1,0.1] ,然后是用于corrupted_array的后备存储,最后是用于corrupted_array的JSArray工具。由于这个缘故原由,defected_array的长度所在的越界索引现在位于corrupting_array的索引5处,而不是索引7处。不外我们仍然可以看到发生越界写入,然则它位于错误的索引处。

在注释为什么corrupting_array的JSArray工具消逝之前,主要的是要注重这个特定的场景仍然是可行使的。现实上,它用一个简朴得多的语句替换了当前看似庞大的return语句,从而简化了Trigger函数。我们只需要将x设置为5而不是7,同时将typer类型x作为局限Range(0, 1)。

一种可能的方式是:

我们修改了乘法和减法,使得我们能够将x设置为5,而Typer仍然使用Range(0,1)输入最终的Math.max挪用。若是你实验使用这种看法验证,就会发现它确实有用,并为我们简化了返回声明。

现在,为什么corrupting_array的JSArray工具消逝了?也许它被TurboFan优化了?为了明白这一点,我们必须看看最后一个优化阶段——逃避剖析阶段。

逃避剖析

Tobias Tebbi有一个关于这个阶段的精彩演讲,但简朴地说,V8使用了逃避剖析阶段来确定它是否可以优化任何未从函数中逃避的已分配工具。在本例中,“逃避函数”仅意味着通过返回语句或外部作用域中的变量等从函数中返回。

在我们修悔改的看法证实案例中,TurboFan准确地推断出corrupting_array现实上不需要分配。它可以分配后备存储,在索引x上举行一个越界写入操作,然后竣事。现实的corrupting_array不会在函数中的其他任何地方使用,也不会从函数中返回(因此也没有从函数中逃出)。若是你不从函数中返回corrupted_array,这就是corrupting_array的JSArray工具消逝的缘故原由。

若是要在sea of nodes图中查看此图,只需对照负载删除阶段和逃避剖析阶段的图形即可。你会注重到,删除负载阶段具有一个分外的Allocate [Array,Young]节点,该节点在逃避剖析阶段不存在。这是应该为corrupting_array分配JSArray工具的节点,而且已对其举行优化。

来自第一个POC的相同开发原语

之前我提到过,只要稍微修改一下Trigger函数,就可以从第一个看法证实中获得相同的行使原语。请注重,在“设置”部门中,我提到了一种无需任何编译器优化即可构建刊行版本的方式。若是你实验在禁用编译器优化的情形下运行以下代码,则将需要很长时间才气完成。若是你想实验一下,建议使用编译器优化函数编译默认刊行版。

第一个看法证实的代码如下所示:

破绽行使

这个由@r4j0x00编写的破绽已经被行使了n天。另有许多其他博客文章,形貌了一旦实现了云云壮大的行使原语,若何在V8中执行代码,因此,我不会详细先容该主题。以下是可用于往后阶段执行代码的一样平常步骤列表:

1.实行addrof原语:立刻在corrupted_array之后分配一个工具,我们称其为泄露工具。将要泄露其地址的工具设置为内联属性,以泄露方式使用,并使用corrupted_array越界读取此属性的地址。

2.在32位V8堆上实现绝对的r/w原语:数组具有32位元素指针。确立一个具有PACKED_DOUBLE_ELEMENTS类型的数组,该数组在堆上的corrupted_array之后存在。使用来自corrupted_array的越界写入操作,修改这个新数组的elements指针,指向随便32位地址。现在,你可以使用此新数组对V8堆中的随便32位地址读取和写入64位double值。

3. 在64位地址空间上实现绝对r/w原语:V8中的TypedArray工具使用64位的后备存储指针。在堆上的corrupted_array之后确立一个BigUint64Array,并使用corrupted_array的越界写入将BigUint64Array的后备存储指针修改为随便64位地址。然后,你可以使用BigUint64Array读取和写入随便64位地址。

4.实现代码执行:加载WebAssembly模块,泄露WebAssembly实例工具的地址,使用32位随便读取原语泄露RWX页面的地址(此地址存储在实例工具上),替换RWX中的代码使用64位随便r / w原语包罗shellcode的页面,最后挪用WebAssembly函数。

本文翻译自:https://www.elttam.com/blog/simple-bugs-with-complex-exploits/,content:
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片