admin管理员组

文章数量:1533913

本文讲的是 破解索尼PS4系列:利用网页漏洞实现相关的ROP攻击(一)

目前关于PS4的黑客攻击还非常的少,但这并不能说明PS4 系统非常安全,黑客不会对其发动攻击。本文的目的就是找出PS4的一系列漏洞,最终来获得PS4的内核执行代码。

PlayStation 4(简称PS4),是索尼电脑娱乐公司(SCE)推出的家用游戏机。是PlayStation游戏机系列的第四代游戏主机。PlayStation 4采用以AMD为基础的x86-64架构处理器(8核)

除了有一个记录良好的架构处理器,PS4中使用的大部分软件都是开源的。最值得注意的是,PS4运行的操作系统上是Orbis OS,这是一款修改版FreeBSD 9.0。FreeBSD是一种类Unix操作系统,是由经过BSD、386BSD和4.4BSD发展而来的Unix的一个重要分支。相比Linux,其授权许可更为宽松,而且PS4是基于x86_64架构,并非上代所采用的Cell,这也使得运行FreeBSD变得更为简单。除此之外,PS4还运行了其他的的开源软件,如Mono VM和WebKit。

WebKit漏洞

WebKit 是 iOS、Wii U、3DS、PS Vita 以及 PS4 当中的浏览器用来渲染网页的开源排版引擎。特别是,PS4的1.76版本固件中的浏览器使用了易受CVE-2012-3748远程代码执行漏洞(含EXPLOIT!)攻击的WebKit 版本,该漏洞会利用JSArray::sort(…) 方法进行堆的缓冲区溢出。

早在2014年,nas和Proxima就宣布,他们已经成功地把Mac OS X Safari的WebKit漏洞利用到PS4的浏览器上,并公开发布了PoC代码,作为入侵PS4的第一个攻击入口。

这样我们就能任意的读写并访问WebKit进程中所包含的任何读取和写入的内容,然后将Webkit模块进行转储,并改写堆栈上的返回地址,最终我们就可以通过这个攻击口控制指令指针寄存器(rip)来实现ROP执行。

此后,人们还在WebKit中发现了许多其他漏洞,这些漏洞可能相继被用作了PS4的攻击入口。

什么是ROP链

与原始设备(如DS)不同,PS4具有控制不同存储区域属性的内核,这也就意味着可以在PS4设备上执行数据执行保护(DEP) ,即DEP可帮助PS4设备防止把数据页当作代码执行,从而有效分离数据与代码。PS4设备实施 DEP 检测从这些位置运行的代码,并在发现执行情况时引发异常。

所以我们就不能将有效载荷复制到内存中并执行它,但是,我们可以执行已经加载到内存中并标记为可执行文件的代码。如果我们不能将自己的代码写入该地址,那么即使跳转到该地址也不能执行,所以我们就必须使用ROP。

面向返回编程(ROP)只是传统堆栈粉碎的一个扩展,不过我们的目的并不只是改写程跳转值,由于ROP其核心思想是在整个进程空间内现存的函数中寻找适合指令片断(gadget),并通过精心设计返回堆栈把各个gadget拼接起来,从而达到恶意攻击的目的。构造ROP攻击的难点在于,我们需要在整个进程空间中搜索我们需要的gadgets,这需要花费相当长的时间。但一旦完成了“搜索”和“拼接”,这样的攻击是无法抵挡的,因为它用到的都是内存中合法的代码,普通的杀毒引擎对ROP攻击是无计可施的。

然后这些gadgets还有一个特征要求就是:他们都是要以一个返回指令作为结尾(如ret指令)。而实际上,这些gadgets的返回指令的作用就是用来对地址链中的下一个gadget进行调用。

在 x86_64 汇编语言中,当执行到一个 ret 指令时,一个 64 位值就会被退栈,并且寄存器也会跳转到这个值,由于我们可以控制堆栈,所以我们就可以让每一个 ret 指令都跳转到下一个gadgets。例如,从0x80000开始,会包含以下指令:

mov rax, 0
ret

而从0x90000开始,指令就会发生变化,如下所示:

mov rbx, 0
ret

如果我们把堆栈上的返回地址相继修改为0x80000和0x90000,那么一旦执行到第一个ret指令,就将跳转到mov rax, 0, ,然后紧接着,下一个ret指令会将 0x90000 退栈,并且跳到mov rbx,0。

ROP链不仅限于地址列表,假设从0xa0000也包含这些指令:

pop rax
ret

我们可以将ROP链中的第一个项目设置为0xa0000,将下一个项目设置为rax的任何所需值。

gadgets也不一定要以 ret 指令结束,我们也可以使用以 jmp 结束的指令:

add rax, 8
jmp rcx

让 rcx 指向ret 指令,ROP 将继续运行:

chain.add("pop rcx", "ret");
chain.add("add rax, 8; jmp rcx");

但是,我们并不是总能找到所需的gadgets,这时,我们就需要用gadgets把其后的指令进行修改。例如,要将r8设置为某个指令,但如果只有gadgets,我们就只能把r9设置为某个虚拟值:

pop r8
pop r9
ret

寻找gadgets

ROP的功能都是用序言和结尾语言构成的:

; Save registers
push    rbp
mov     rbp, rsp
push    r15
push    r14
push    r13
push    r12
push    rbx
sub     rsp, 18h

; Function body

; Restore registers
add     rsp, 18h
pop     rbx
pop     r12
pop     r13
pop     r14
pop     r15
pop     rbp
ret

我们期望找到的gadgets能 将xor rax, rax返回之前的返回值置设置为0:

cmp [rax], r12
ret

x86架构是重要地可变指令长度的CISC(复杂指令集计算机,Complex Instruction Set Computer)。 x86_64上的ROP充分利用了指令集的特点,即任何随机的字节序列都可能被解释为一些有效的x86_64指令集。

为了展示这一点,可以从WebKit模块中看看这个函数的结尾:

000000000052BE0D                 mov     eax, [rdx+8]
000000000052BE10                 mov     [rsi+10h], eax
000000000052BE13                 or      byte ptr [rsi+39h], 20h
000000000052BE17                 ret

假如如果我们从0x52be14开始解码,会出现什么变化呢?

000000000052BE14                 cmp     [rax], r12
000000000052BE17                 ret

即使这段代码从来没有被执行过,它还是在一个被标记为可执行的内存区域内,所以这段代码完全可以作为gadgets。用来搜索ROP gadgets的是rp ++;要生成一个gadgets的文本文件,只要执行:

rp-win-x64 -f mod14.bin --raw=x64 --rop=1 --unique > mod14.txt

一般保护错误

操作系统一般将内存划分为不同的区域,有的区域只供操作系统使用,而有的系统是供应用程序使用的。当应用程序企图在分配给它的内存区域进行访问操作时,操作系统将中止这个程序的运行,用户得到的是一行错误码,告诉用户程序出现了一般保护错误。

例如,尝试映射到堆栈上的只能读写的执行代码:

setU8to(chain.data + 0, 0xeb);
setU8to(chain.data + 1, 0xfe);

chain.add(chain.data);

并尝试写入代码,将其映射为只读和执行:

setU8to(moduleBases[webkit], 0);

如果发生了段错误,系统将会提示“可用系统内存不足”,此时,网页加载也会失败。

本文标签: 索尼漏洞网页系列ROP