沙箱逃逸----切换进程工作模式绕过
这两天打 CSAW 又学到了一种新的沙箱逃逸的方法–切换进程的工作模式,使用32位的系统调用号执行系统调用,来绕过原本沙箱禁用掉的系统调用。理解起来倒也不难,但是有几个点需要注意一下,这里详细的记录下利用过程。
利用过程&&调试
先看下程序逻辑(如下),就是输入数据,然后将其执行。在执行前开启了沙箱保护。
我们看一下本题沙箱禁用的系统调用(如下图),我们发现没法执行execve,同时禁用了openat和open这两个系统调用,这就意味着orw和execve两种拿到flag的方式都无法使用了。
这里我们利用一种新的思路来进行沙箱逃逸,观察上图的禁用规则,我们发现并没有检查架构。如果正常检查架构的沙箱规则应该如下:
控制cs寄存器
而retf这个指令是相当于pop ip;pop cs
而在x64系统下,进程有两种工作模式(32位工作模式和64位工作模式)。决定了是哪种工作模式的是cs寄存器**(cs=0x23 则为32位工作模式,cs=0x33 则为64位工作模式),如上所说,我们可以用retf指令来控制cs寄存器。而这里要注意,因为我们切换的是32位工作模式,因此这里的ip寄存器应该是eip寄存器,而cs寄存器本身也是四字节,所以我们想要往eip和cs寄存器填充的两个值一共应该是八字节数据,共占用一个64位程序下的内存单元才对**。
映射小于等于四字节地址
但是有一点如果切换到32位工作模式后,那寄存器用的则是32位寄存器,原本64位寄存器里装的6字节地址就无法正常使用了,因此在这之前我们需要调用mmap映射一段小于等于四字节的可读可写可执行的内存地址空间,然后我们将执行流迁移到这片区域上,因为地址小于等于四字节放到32位寄存器中也是ok的。
上图是执行mmap映射了一段可读可写可执行的区域,下图是执行系统调用read将数据写到刚刚映射出来的这段区域
切换进程的工作模式
切换进程的工作模式其实就是用retf指令来控制cs寄存器,不过需要注意的是我们将执行流迁移到新映射的内存区后,将栈也迁移过来(因为原本的栈地址是6字节的,我们切换到32位工作模式后无法再访问原本的栈)。迁移栈的地方要和映射的起始区域错开,不能将栈进行新的迁移后,执行push时干扰到我们原本布置的指令。
首先是先布置一下eip和cs的数据,先push到栈里(这里一定要注意是二者共用一个内存单元,一个值仅仅占四字节),举个例子,比如我映射了一段0x100000的内存区域,然后要切换到32位的工作模式上,那么我压入的数据应该是0x2300100000(因为要迁移执行流,所以给eip寄存器的是0x100000)(如下图)
下图是已经执行了retf,切换到了32位工作模式。(我们观察下面的栈也可以看出来,执行后的栈已经无法使用了,对比上面正常的栈,发现只保留了4字节,这就说明已经切换了32位工作模式)
最后就是记得把栈给迁移过来(如下)
orw获取flag
然后打一个常规的32位orw即可。(如下)
执行32位下的execve的报错
最终正常执行我们的32位程序中的系统调用即可,这里要注意一下,我们还是无法执行execve获取shell,因为execve(“/bin/sh”,0,0)其实是去运行了/bin/sh这个程序,而这个程序的位数是跟系统一样的。如果是64位系统,那么/bin/sh这个程序就是64位的(依旧绕不过沙箱),这样就导致了我们虽然是工作模式切换过来了,但是后续执行/bin/sh的时候报错了。
执行32位中的execve情况如下:
这里要解释一下图中看的明明是执行的munmap,这是因为工作模式虽然切换到32位了,但是这个gdb调试到这里,它依然认为这个系统调用号是64位的,所以就显示了munmap,不过现在确实执行的是32位中的execve系统调用。
可以看见红框里的报错提示,首先第一行我们确实是成功执行了execve(“/bin/sh”,0,0),创建了新的进程/usr/bin/dash
但是第二行就报了一个错误,说是Bad system call。这就说明执行了64位的系统调用,然后被沙箱给禁用了。这也就验证了上面所说的/bin/sh这个程序就是64位的(依旧绕不过沙箱)。
因此我们依旧只能用orw读出flag。
EXP:
from tools import * |
参考文章:
特殊情况下sandbox的bypass - vi0let - 博客园 (cnblogs.com)
题目附件:
链接:https://pan.baidu.com/s/1NXZ8zk2CsqUwwkua5QvoFA?pwd=7gt0
提取码:7gt0