Sandbox沙箱在计算机领域中是一种程序隔离的机制,其目的则是限制不可信进程的权限。沙箱技术则常用于执行未经测试的或不可信的客户程序,(比如沙箱杀毒一类的),为了避免不可信程序可能破坏其他的程序运行,沙箱技术可以为不可信的程序提供虚拟化的磁盘,内存以及网络资源,而这又是对客户是透明的。
常规的安全机制则主要以降权来解决问题,但降权并不能带来真正的安全,sandbox也不能带来全方位的安全,沙箱机制结合多种系统安全技术来实现安全,从设计的理念上,打破传统的单一防御到纵深防御。
常规的纵深防御有六种常见的手法:
1 安全的编码(Secure Code),减少编写的错误。
2 应用技漏洞缓解技术(Application-level exploitation)(SSP,relro)
3 系统级漏洞缓解技术(System-level exploit mitigation)(ASLR,NX),
4 降权处理(Privilege Dropping)(Sandboxing)
5 强制访问控制(Mandatory access control)(MAC,SELinux)
6 更新策略(Update strategy)
进程和权限
1 每个进程拥有独自的地址空间
2 MMU硬件强制分离地址空间
3 内核在系统中有强制性的接口层(kernel的安全策略)
4 每个进程拥有进程权限边界
5 root用户拥有至高的权限
6 其他用户拥有自主访问控制DAC访问权限
一般情况下的权限控制为:
进程A拥有的权能比进程B拥有的多,则A可以获得B进程可以访问的资源
1 root用户运行任何程序都是特权用户
2 2个进程如果拥有相同的uid,和gid。则可以拥有相同的权限
3 一般不能比较不同uids用户的进程权限
进程和权限的分离
1 线程
将内部特权进行分离(一般情况下)如NaCI,SECCOMP Sandbox
2 Debugging
如果A进程可以Ptrace()B,那么A的权限要大于B的权限
Linux标准的权限资源有
1 Users,和 groups
1 uid,euid,suid,fsuid
2 gid,egid,sgid,fsgid,超级组
2 POSIX.1e 权能
3 Quota control
4 Linux Container
5 LSM(Linux Security Module)
Linux的权能划分了不同的权限单位
如:CAP_NET_RAW: 允许使用RAW和PACKET Socket
CAP_SYS_ADMIN: 管理员操作权能(mount,sethostname等)
CAP_NET_BIND_SERVICE:bind绑定端口权限<1024
权能的限制
1 常见的误区:
1 忘记切换uid 为0的超级用户。很多功能需要root用户的权能
2 root 操作
1 只有用到root权能的时候,才将权限提升为root权限
2 很多操作只需普通用户的权能。
使用切换root
1 需要对文件系统进行权限控制的时候,需要root用户
2 只有root可以操作的活动
3 需要一些陷入或escape的权限时,需要流行的chroot技术。
4 模块注入 非chroot进程的ptrace()
新的命名空间(Namespaces:CLONE_NEW*)
CLONE_NEWPID: New pid namespace(2.6.24)
CLONE_NEWNET:New network namsespace(2.6.26)
CLONE_NEWIPC,CLONE_NEWUTS,CLONE_NEWNS(2.6.19)
资源限制
为了安全的资源限制机制
1 RLIMIT_NOFILE:不能获得新的句柄,但可以rename或者unlink
2 RLIMIT_NPROC: 不能创建新的进程
如果为了安全,RLIMIT_NPRC需要设置为(0,0),因为一些攻击者可以替代已经存在的句柄去创建新的socket或者文件句柄。
Dumpable(Debuggable)进程
Linux支持对每个进程进行dumpable标志。
通过PR_SET_DUMPABLE标记设置prctl,跟踪执行你没有权限的程序,或者切换uid。
一个进程没有CAP_SYS_PTRACE权能,是不能ptrace非dumpable的进程
需要一个进程权限提升或者可以降低其他进程的权限来满足dumpable。
MAC强制的访问控制
在内核机制中,基于LSM钩子的有,SELInux,SMACK,TOMOYO
内核机制之外的有:GRSecuirty, RSBAC, AppArmor
Sandbox 采取权限限制的策略
Sandbox与MAC的区别
MAC需要管理员去分发布商。每个程序需要一套单独的规则库,不需要对代码的控制权
Sandbox则是面向开发者,每个程序可以运行在多个设备上,不要要设备管理员的权限
常见的sandbox的设计:
1 ptrace() sandbox (vsftpd)
2 setuid sandbox(chromium)
3 SECCOMP sandbox(chromium)
1 ptrace 架构:
setuid sandbox
setuid sandbox基于Linux Kernel 所提供的安全机制如DAC实现,利用了uid/gid + chroot()+capability的组合来达到目标,实现起来相对较为简单。
传统的root 很难避免以下问题:1 需要对文件系统删除的访问2 RLIMIT_NOFILE 不够时的处理3 防止其他进程ptrace 4阻止信号发送给其他进程。
(一) Setuid :
利用uid的切换工作:
1我们需要获取uid/gid的定义池,但不需要资源/etc/passwd
2调用时,搜索到未用的uid/gid.然后切换到这个uid/gid
3执行sandbox。
Linux uid/gid 机制主要是用于进程的权限隔离,当你要执行不可信的程序时,那么在启动该程序的时,为其分配一个random uid。然后设置setuid。工作流程如下
Fork() ->setuid()->{设置相关的进程资源限制,如RLMIT_NPROC(0,)}->execve();
Setuid() 需要root的权限(或者具有CAP_SETUID 权能)才能调用成功。
(二) Chroot:
chroot 是 linux kernel 的另一个安全功能,他主要用于修改进程的根目录,比如执行chroot(“/tmp/sandbox/1”)则可以将当前进程的根目录切换为”/tmp/sandbox/1”。那么该进程的文件操作权限则被限制在当前目录下。
Chroot需要root权限(或者具有CAP_SYS_CHROOT权能)才能调用成功。
如果按照前面执行的顺序,具有root权限的进程A去执行chroot,然后再调用setuid,->..->execve(),这样是不可以的,因为execve所执行的路径已经发生改变,可执行文件已经不存在了。
Chris Evans的文章给了一个解决方法:
a) A创建一个子进程B,注意使用clone()和CLONE_FS,这样可以让A和B共享根目录,当前目录,等等 b) A 降权去执行execve(“Worker”),B等待A进程发来的特殊消息. c) 当A想执行chroot时,发送消息告知B。 d) B执行chroot(),新的根目录会对A和Worker同时生效 e) B退出。
对A程序来说,由于它是以Root身份运行,那么就可能作为攻击点,比如confuesed deputy问题。下面针对这个问题加以说明。
(三) Linux Capability
主要解决confused deputy问题,这个问题典型的代表是跨站点请求伪造(CSRF)。
Linux支持Capability的主要目的则是细化root特权,避免confused deputy问题。比如ping这个命令,需要raw_sockets,所以需要root的权限才可以运行,如果有了Capablity机制,该程序只要一个CAP_NET_RAW的权能,便可以运行,根据最小权限原则,该程序可以去掉所有不必要的权能。
当前kernel支持的权能多大30多种。在kernel2.6.24以后,普通用户也具有了capability.
CAP_CHOWN 0 //允许改变文件的所有权 CAP_DAC_OVERRIDE 1 //忽略对文件的所有DAC访问限制 CAP_DAC_READ_SEARCH 2 //忽略所有对读,搜索操作的限制 CAP_FOWNER 3 //如果文件属于进程的UID,就取消对文件读限制 CAP_FSETID 4 //允许设置setuid位 CAP_KILL 5 //允许对不属于自己的进程发送信号 CAP_SETGID 6 //允许改变组ID CAP_SETUID 7 //允许改变用户ID CAP_SETPCAP 8 //允许向其他进程转移能力以及删除其他进程读任意能力 CAP_LINUX_IMMUTABLE 9 //允许修改文件的不可修改(IMMUTABLE)和只添加(APPEND-ONLY)属性 CAP_NET_BIND_SERVICE 10 //允许绑定到小于1024读端口 CAP_NET_BROADCAST 11 //允许网络广播和多播访问 CAP_NET_ADMIN 12 //允许执行网络管理任务:接口/防火墙和路由等 CAP_NET_RAW 13 //允许使用原始(raw)套接字 CAP_IPC_LOCK 14 //允许锁定共享内存片段 CAP_IPC_OWNER 15 //忽略IPC所有权检查 CAP_SYS_MODULE 16 //插入和删除内核模块 CAP_SYS_RAWIO 17 //允许对ioperm/iopl CAP_SYS_CHROOT 18 //允许使用chroot()系统调用 CAP_SYS_PTRACE 19 //允许跟踪任何进程 CAP_SYS_PACCT 20 //允许配置进程记账(process accounting) CAP_SYS_ADMIN 21 //允许执行系统管理任务:加载/卸载文件系统,设置磁盘配额,开/关交换设备和文件等 CAP_SYS_BOOT 22 //允许重启系统 CAP_SYS_NICE 23 //允许提升优先级,设置其他进程的优先级 CAP_SYS_RESOURCE 24 //忽略资源限制 CAP_SYS_TIME 25 //允许改变系统时钟 CAP_SYS_TTY_CONFIG 26 //允许配置TTY设备 CAP_MKNOD 27 //允许使用mknod()系统调用 CAP_LEASE 28 //允许取消文件上的租借期 CAP_AUDIT_WRITE 29 // CAP_AUDIT_CONTROL 30 //允许用户登录系统等 CAP_SETFCAP 31 // CAP_MAC_OVERRIDE 32 // CAP_MAC_ADMIN 33 // CAP_TRUST_ADMIN 34 // CAP_ALL ** //All Capability 0 ** //no Capability
Setuid sandbox简单易行,在google chromuim 早期的沙箱机制中使用了它,但现在已经默认为seccomp机制了。利用ipc机制创建socket pair
Seccomp
Seccomp 是 Andrea Arcangeli在2005年设计的,其目的则是解决 grid computer中的安全问题,比如你打算租借cpu资源,但又担心不可信的代码会破坏你的系统,那么seccomp
则为你提供了一个“安全(SAFE,not SECURE)”的环境。
内核从2.6.10开始引入seccomp机制,该机制限制系统调用为read(),write(),exit(),sigreturn(). 只有4个系统调用被允许,相对较为简单,其限制了不能分配内存,不能共享内存, 不能创建新的文件描述符。成为了一个纯计算型的代码。
运行在seccomp机制下的线程成为可信线程,当不可信的线程请求可信线程进行系统调用时,可信线程验证后方可进行调用。可信线程也只能使用只读的存储器,不能读取可变的区域。
有人提出了对seccomp机制的改进,利用bitmap增加一个新的mode,来限制使用那些权能。
通过截获系统调用来实现sandbox是一贯的做法,在现在的操作系统中,用户空间和内核空间是隔离的,一个进程只能通过系统调用才能从用户空间进入内核空间,如果一个进程不执行系统调用,那么被攻击的风险便会降低。当然,不调用系统调用是不切合实际的。
针对chromium使用的sandbox机制,我们将接下来进行分析。