为什么可以't通过“;数据执行防止”;

why can't Javascript shellcode exploits be fixed via "data execution prevention"?

本文关键字:数据 执行 为什么 通过      更新时间:2023-09-26

维基百科的"堆喷"文章表明,许多javascript漏洞利用都涉及将外壳代码定位在脚本的可执行代码或数据空间内存中的某个位置,然后让解释器跳到那里执行它。我不明白的是,为什么解释器的整个堆不能被标记为"数据",这样DEP就不能阻止解释器执行shell代码了?同时,javascript派生的字节码的执行将由虚拟机完成,虚拟机不允许它修改属于解释器的内存(这在似乎执行机器代码的V8上不起作用,但可能在使用某种字节码的Firefox上起作用)。

我想以上听起来很琐碎,可能实际上正在做一些类似的事情。因此,我正试图了解推理中的缺陷,或者现有解释器实现中的缺陷在哪里。例如,当javascript请求内存时,解释器是否依赖于系统的内存分配,而不是实现自己的内部分配,从而使区分属于解释器和javascript的内存变得过于困难?或者,为什么基于DEP的方法不能完全消除外壳代码?

要回答您的问题,我们首先需要定义数据执行预防实时编译JIT喷洒

数据执行保护是一种安全功能,禁止从不可执行的内存区域执行代码。DEP可以通过诸如NX位的硬件机制和/或通过添加运行时检查的软件机制来实现。

实时(JIT)编译器是动态编译器,可在运行时将字节码转换为机器码。目标是将解释代码的优势与编译代码的速度相结合。只有当在编译中花费的额外时间可以通过编译代码的预期性能增益来摊销时,它才应该编译方法。[1]

JIT喷涂是强制JIT引擎编写许多带有嵌入式外壳代码的可执行页面的过程。

[….]

例如,诸如"var x=0x41414141+0x442424242;"之类的Javascript语句可能会被编译为在可执行映像中包含两个4字节常量(例如,"mov eax,0x41414141;mov ecx,0x42424242,add eax,ecx")通过在这些常量中间开始执行,可以显示出完全不同的指令流

[….]

关键的见解是JIT是可预测的,并且必须将一些常量复制到可执行页面。给定一个统一的语句(如长和或任何重复模式),这些常量可以对小指令进行编码,然后控制流到下一个常量的位置。[2]

在这个答案的范围之外,必须使用高级技术来找到JIT喷射块的地址并触发该漏洞。

现在应该很清楚

如果攻击者的代码是由JIT引擎生成的,那么它也将驻留在可执行区域中。换句话说,DEP不参与JIT编译器发出的代码的保护。[3]

参考

[1] Java实时编译器的动态优化框架

[2] 解释器开发:指针推理和JIT喷涂

[3] JIT喷涂和缓解