Page 210 - 《软件学报》2021年第8期
P. 210

2492                                   Journal of Software  软件学报 Vol.32, No.8,  August 2021

                 本节将对现有浏览器内存攻防研究工作进行总结分析.
                 5.1   代码注入攻击及防御
                 5.1.1    攻击方案
                    针对浏览器的代码注入攻击通常利用了 JIT 编译器的特性.首先,JIT 编译器将在运行时将 JIT 代码写入内
                 存页中,这意味着 JIT 代码页在某些时候需要设置为可写.Gong 等人                  [18] 发现,Chrome 中的 JIT 代码页是同时具
                 备写与可执行权限的,据此实现了代码注入攻击.具体来说,Gong 等人首先利用 Chrome 的 V8JavaScript 引擎中
                 的漏洞来获取对任意内存地址的读写权限,其后分析 Chrome 代码来追踪到 JIT 代码的入口地址,最后通过对该
                 地址的内存页的重写来注入恶意代码.更进一步地,Song 等人                  [17] 认为,应对代码注入攻击的传统 W^X(不能同时
                 可写与可执行)方式在浏览器环境中是无用的.W^X 通过限制内存页的权限不能同时为可写与可执行来抵抗代
                 码注入攻击,然而,浏览器中 JIT 编译器产生新代码或优化现有 JIT 代码时,必须将 JIT 代码页短时间内更改为可
                 写,这个短暂的时间窗口可以被敌手利用来将恶意代码注入到 JIT 内存页中.
                    其次,JIT 编译器生成 JIT 代码的一些规则也能用来发起代码注入攻击.Blazakis 等人                   [19] 提出的 JITSpraying
                 攻击能够利用 JIT 编译器忽略大常数的特性,来在 JIT 代码中注入所需的代码.图 10 展示了 JITSpraying 攻击的
                 原理.具体来说,攻击者 frame 的 JavaScript 代码可以定义一个含有大常数的变量,如:
                                          var a=(0x11223344^0x44332211^0x44332211).
                    该代码被 JIT 编译器编译后的二进制代码在图 10 中进行了标注,其中,对变量 a 赋值的大常数直接存在于
                 JIT 代码中.若攻击者 frame 利用控制流劫持漏洞使得程序跳转到 JIT 代码的第 2 个字节执行,此后浏览器执行
                 的程序逻辑将被篡改.所以,攻击者 frame 可以通过合理地组织 JavaScript 大常数来在 JIT 代码中注入恶意代码.
                 为增大控制流跳转到注入代码特定地址的概率,JITSpraying 攻击要求攻击者 frame 重复地注入大量的代码页,
                 这一操作被称作为 Spraying.
                                      JavaScript代码  var a = (0x11223344^0x44332211^0x44332211)
                                                         注入的        JIT编译器进行编译
                                                         大常数
                                       正常执行时的
                                       二进制代码

                                                                    利用控制流漏洞从第二
                                                                    字节开始执行
                                       攻击后执行的
                                       二进制代码

                                 Fig.10    Example of injecting code into browsers by JITSpraying attack
                                     图 10   通过 JITSpraying 攻击向浏览器中注入代码的示例
                 5.1.2    防御方案
                    与传统环境中的应对代码注入攻击方案相同,浏览器环境中也首先需要对 JIT 代码页采用 W^X 方案.Chen
                 等人 [112] 提出了 JITDefender 系统,来在 JIT 编译器中增加 W^X 机制.JITDefender 机制能够标识 JIT 代码的两个
                 时间点:JIT 编译器生成 JIT 代码与 JIT 代码开始被执行.JITDefender 的工作流是在第 1 个时间点时将 JIT 代码
                 页权限设置为可写但不可执行,在第 2 个时间点将 JIT 代码页设置为可执行但不可写.
                    Crane 等人 [113] 设计了 Readactor 架构来实现仅可执行内存页.Readactor 设计了对应的编译器来将未修改的
                 源代码进行转换,其中实现了分离代码和数据来消除对代码页的读访问、随机化代码布局与设计跳板代码
                 (trampoline)来隐藏代码指针等操作.基于该编译器,一个应用程序的代码页将不需要有读写权限.Readactor 之后
                 利用 Intel 处理器所提供的扩展页表(extended page tables,简称 EPT)来实现硬件限制的仅可执行内存页.目前,
                 主流浏览器已经实施了对 JIT 代码的 W^X          [114] 保护.
                    尽管 JITDefender 与 Readactor 在浏览器中实现了 W^X,但 JIT 编译器在生成 JIT 代码与执行 JIT 代码之间
   205   206   207   208   209   210   211   212   213   214   215