Chromium

Chromium 主要包含两大核心组成部分:渲染引擎和浏览器内核。

Chromium 目前使用 Blink 作为渲染引擎,它是基于 webkit 定制而来的,核心逻辑位于项目仓库的third_party/blink/目录下。渲染引擎做的事情主要有:

  • 解析并构建 DOM 树。Blink 引擎会把 DOM 树转化成 C++ 表示的结构,以供 V8 操作
  • 调用 V8 引擎处理 JavaScript 和 Web Assembly 代码,并对 HTML 文档做特定操作
  • 处理 HTML 文档定义的 CSS 样式
  • 调用 Chrome Compositor,将 HTML 对应的元素绘制出来。这个阶段会调用 OpenGL,未来还会支持 Vulkan。在 Windows 平台上,该阶段还会调用 DirectX 库处理;在处理过程中,OpenGL还会调用到 Skia,DirectX 还会调用到 ANGLE

Blink组件间的调用先后关系,几乎所有发生在浏览器页签中的工作,都有Blink参与处理。可用下图概括:

image-20210722105345920

浏览器内核扮演连接渲染引擎及系统的“中间人”角色,具有一定“特权”,负责处理的事务包括但不限于:

  • 管理收藏夹、cookies以及保存的密码等重要用户信息
  • 负责处理网络通讯相关的事务
  • 在渲染引擎和系统间起中间人的角色。渲染引擎通过Mojo与浏览器内核交互,包含组件:download、payments等等。

Chromium渲染引擎涉及大量C++编写的组件,出现漏洞的概率不小。因此,基于纵深防御理念浏览器引入了沙箱机制。渲染引擎等组件不直接与系统交互,而是通过一个被称为 MOJO 的 IPC 组件与浏览器引擎通讯(也被称为 broker),再与系统交互。进而可以实现:即便沙箱中的进程被攻破,但无法随意调用系统API产生更大的危害。

image-20210722112145132

Sandbox

  • 沙箱是一个 C++ library,沙箱进程便是通过该C++ library所创建,为了确保安全性,沙箱进程所处的执行环境是非常受限的。

  • 沙盒进程可以自由使用的唯一资源是 CPU 周期和内存。例如,沙箱进程不能向磁盘写数据或显示它们自己的窗口。

  • Chromium renderers 便是一个沙盒进程。沙箱的目标是提供关于一段代码最终能做什么或不能做什么的硬保证。

  • 沙箱限制了在沙箱内运行代码的 bug 的影响性,例如:这种bug不能在用户帐户中安装持久性恶意软件(因为沙箱禁止写入文件系统)也不能从计算机本地当中读取任何文件。但是沙箱不能够对系统组件提供保护(如运行它的内核)

  • 沙箱无法针对系统组件(例如运行它的内核)中的错误提供任何保护。

  • 沙箱在运行初始时并不是完全状态,只有当进程调用LowerToken()方法后,沙箱才会完全生效。这样的设置,使得沙箱进程在启动这段时间内,可以自由的获取关键资源,加载 library,读取配置文件。所以,当进程开始和不受信任的文件交互之前,应尽快调用 LowerToken()

    Note:如果进程被感染,在调用LowerToken()后,打开的操作系统句柄都可能会被恶意软件滥用。

    浏览器渲染引擎、GPU、PPAPI插件以及语音识别服务等进程是运行在沙箱中的。此外不同系统平台下的部分服务也会受沙箱保护,例如Windows下打印时调用的PDF转换服务、icon浏览服务;MacOS下NaCl loader、需要访问IOSurface的镜像服务等。

Windows Sandbox 架构

  • Windows sandbox 是仅限于 user-mode的沙箱,也没有特殊的内核模式驱动程序,因此用户不需要成为管理员,以确保 Sandbox 的正常运行。
  • Sandbox 有 32 位和 64 位两种,在所有的 Win7 和 Win10 均已经被测试
  • Sandbox 在进程级粒度进行运作,任何需要沙箱化的目标,都需要其是独立进程。最简单的沙箱配置需要两个进程:一个是被称为 broker 的 privileged controller,以及被称为 target 的一个或多个沙箱化进程。
  • Sandbox 作为静态库提供,必须链接到 broker 和目标可执行文件。

The broker process

在 chromium 中,broker就是浏览器的主进程。宽泛的说,borker 是权限控制器 / sandbox进程活动的管理员。其职责是:

  • 指定每个目标进程中的策略
  • 生成目标进程
  • 维护沙箱策略引擎服务
  • 维护沙箱拦截管理器
  • 维护沙箱IPC服务(与target进程的通信)

broker 的存活时间总是比他生成的目标进程要长,Sandbox IPC是一种用于将某些 Windows API 调用从 target 转发到 broker 的低级机制(不同于Chromium的IPC),这些 API 根据策略而定。策略允许的 API 则由 borker 进行调用,结果会通过同样的IPC返回给目标进程。 Interceptions manager 的工作给应该通过 IPC 转发给 broker 的Windows API调用提供补丁。

The target process

在 chromium 中,target process 就是 renderers,除非执行了 --no-sandbox命令。target 进程维护所有将在沙箱中运行的代码,以及沙箱 client 方面的基础架构:

  • 对所有代码进行沙箱化
  • 沙箱化 IPC client
  • 沙箱策略引擎客户端
  • 沙箱拦截

2、3、4 是 sandbox library 的一部分,需要和被沙箱化的代码一同链接

Interceptions(hooks)是 Windows API 调用通过沙箱 IPC 转发到 broker 的方式。The interceptions (also known as hooks) are how Windows API calls are forwarded via the sandbox IPC to the broker.

Sandbox restrictions

沙盒依赖于 Windows 提供的四种保护机制:

  • A restricted token

  • The Windows job object

  • The Windows desktop object

  • Integrity levels

这些机制在保护操作系统,操作系统的限制,用户提供的数据上相当的高效,前提是:

  • 所有可以安全化的资源都有一个比null更好的安全描述符。换言之,没有关键资源会有错误的安全配置。
  • 电脑还没有被恶意软件破坏。
  • 第三方软件不会降低系统的安全性。

The token

对于 Chromium Sandbox 最严格的 token 采用以下形式:

1
2
3
4
5
6
7
8
9
Regular Groups
Logon SID : mandatory
All other SIDs : deny only, mandatory
Restricted Groups
S-1-0-0 : mandatory
Privileges
None
Integrity
Untrusted integrity level label (S-1-16-0x0)

Chromium 的渲染器以某个 token 运行,意味着渲染器进程使用的几乎所有资源都已被浏览器获取,它们的句柄也将被复制到渲染器的进程中。

NOTE:token 不是派生于anonymous or guest 的 token,它继承于 user’s token 与用户的登录相关联。因此,系统或域中已有的任何审计仍然可以使用。

根据设计,沙箱 token 不能保护下面这些不安全资源:

  • 挂载的FAT或FAT32卷: 它们的安全描述符是 NULL。在 target 中运行的恶意软件可以读写这些磁盘空间。
  • TCP/IP: Windows 200和Windows XP(但在Vista中不会)中的TCP/IP socket的安全性实际上是无效的。target 中的恶意代码可能会向任何主机发送和接收网络数据包。
  • 一些未标记的 objects,例如匿名共享内存 (e.g. bug 338538)

The Job object

target 进程也运行于 object 之下,使用这个 Windows 机制,一些没有传统对象或安全描述符的的全局限制被强制执行:

  • 禁止用SystemParametersInfo()做用户共享的系统范围的修改,这可以用于切换鼠标按钮或者设置屏幕保护程序超时
  • 禁止创建或修改桌面对象
  • 禁止修改用户共享的显示设置,比如分辨率和主显示器
  • 禁止读写剪贴板
  • 禁止设置全局Windows hook(使用SetWindowsHookEx())
  • 禁止访问全局原子表
  • 禁止访问在作业对象外创建的USER句柄
  • 单活跃的进程限制(不允许创建子进程)

Chromium 渲染器通常在这些限制全部都开启后运行。每个渲染器运行在其自己的 Job object 里。

The alternate desktop

token 和 job object 规定了一个安全边界。

  • 只要进程的 token 相同且处于同一 job object 下,那么他们同处于同一个安全的上下文环境中。
  • 在同一桌面下具有有窗口的应用程序也处于同一个安全的上下文环境中。因为发送和接收窗口消息不受任何安全检查的约束。

在标准Windows安装中,至少有两个桌面和交互式窗口站相关联:常规(默认)桌面和登录桌面。Sandbox创建了与所有目标进程关联的第三个桌面。此桌面不可见也不能交互,并且有效地隔离沙箱化进程,使其不能窥探用户的交互,不能在更多特权的环境下发送消息到Windows。

唯一的缺点是会使用4MB 的 RAM,Vista下可能会更多。

The integrity levels

  • Integrity 级别是由一组特殊的 SID 和 ACL 条目实现的,它们代表五个不断增加的特权级别:untrusted, low, medium, high, system

  • 如果一个对象处于比请求者更高级的信用等级,访问该对象就会受限。

  • Integrity 级别还实现了用户界面权限隔离,Integrity 性级别的规则应用于在同一桌面下的不同进程之间交换窗口消息

  • token 可以向更高 level 的 object 读数据,但是不能写数据。

  • 大多数桌面应用程序以 medium integrity (MI)信任等级运行,信任度较低的程序(保护模式下的 IE 和 GPU 的 Sandbox)以 low integrity (LI) 信任等级运行,而 renderer 则以最低的信任等级运行。

一个低 level 的 token 只能访问以下资源:

  • 从大部分的文件里读取数据
  • 可以向 %USER PROFILE%\AppData\LocalLow 写数据
  • 读注册表的大部分内容
  • 可以向 HKEY_CURRENT_USER\Software\AppDataLow写数据
  • 剪贴板(为某些格式做复制粘贴)
  • 远程过程调用(RPC)
  • TCP/IP Socket
  • 通过ChangeWindowMessageFilter暴露窗口消息
  • 通过LI标签共享内存
  • 拥有LI启动激活的权限,访问COM接口
  • 通过LI标签暴露的命名管道

Process mitigation policies

沙箱通过 SetProcessMitigationPolicy 方法来给 target 进程设置保护措施,以强化安全特性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
Data Execution Prevention:
数据执行保护,是一组在存储器上运行额外检查的硬件和软件技术,有助于防止恶意程序码在系统上运行。和 LINUX 下的 NX 保护比较类似,堆栈只有读写权限,没有执行权限,主要用途是限制以写 shellcode 为主的攻击手段。

Relocate Images:
>= Win8
在进程中对所有图片做随机地址加载(ASLR)(必须被所有图片支持)

Heap Terminate:
>= Win8
结束Windows堆占用进程

Bottom-up ASLR:
>= Win8
地址随机化

High-entropy ASLR:
>= Win8
为自底向上ASLR增加随机等级到1TB

Strict Handle Checks:
>= Win8
对于恶意句柄引用立即抛出异常

Win32k.sys lockdown:
>= Win8
ProcessSystemCallDisablePolicy 允许从目标过程中选择性禁用系统调用
渲染器进程现在将此设置为DisallowWin32kSystemCalls,这意味着不再允许来自win32k.sys服务的用户模式的调用。这大大减少了渲染器提供的内核攻击面。

App Container (low box token):
>= Win8
在Windows里,这由内核层的一个Low Box Token实现,它是有着限制优先权(通常只有SeChangeNotifyPrivilege和 SeIncreaseWorkingSetPrivilege)的一个剥离版本,运行在低信用等级,这个容器还由一组“能力”实现,它们可以映射到进程允许/拒绝做的事情(查看MSDN获取更详细的描述)。从沙箱角度看,最有趣的能力是否决是对网络的访问,如果令牌是Low Box Token,INTERNET_CLIENT能力没有出现的话,就会执行网络检查。
因此沙箱对已有的限制令牌,添加了Low Box相关的属性,并且不授予任何能力,以获得没有来自沙箱化进程的网络访问这样的额外的网络保护。

Disable Extension Points (legacy hooking):
>= Win8
ProcessExtensionPointDisablePolicy
以下注入向量被阻断:
AppInit DLLs Winsock Layered Service Providers (LSPs)
Global Window Hooks (not thread-targeted hooks)
Legacy Input Method Editors (IMEs)

Control Flow Guard (CFG):
>= Win8.1 Update 3 (KB3000850)
CFG通过在编译和链接期间,记录下所有的间接调用信息,并把他们记录在最终的可执行文件中,并且在所有的间接调用之前插入额外的校验,当间接调用的地址被篡改时,会触发一个异常,操作系统介入处理。

CET Shadow Stack:
Available in Windows 10 2004 December Update.
未在渲染器中启用.

Disable Font Loading:
>= Win10
ProcessFontDisablePolicy

Disable Loading of Unsigned Code (CIG):
>= Win10 TH2
ProcessSignaturePolicy
防止将未签名代码加载到进程中。这意味着攻击者不能在获得执行权限后加载一个DLL库(其他沙盒缓解措施会起到作用),更重要的是,可以防止第三方DLL注入到我们的进程中,这会影响稳定性和我们启用其他安全缓解措施的能力
为所有沙盒子进程启用.
为沙盒渲染器进程启用(预启动)。这消除了一个进程启动时间间隔,在该时间间隔内,可能会将不正确签名的dll本地注入到呈现程序进程中。

Disable Image Load from Remote Devices:
>= Win10 TH2
ProcessImageLoadPolicy
E.g. UNC path to network resource.

Disable Image Load of “mandatory low” (low integrity level):
>= Win10 TH2
ProcessImageLoadPolicy
E.g. temporary internet files.

Extra Disable Child Process Creation:
>= Win10 TH2
If the Job level <= JOB_LIMITED_USER, set PROC_THREAD_ATTRIBUTE_CHILD_PROCESS_POLICY to PROCESS_CREATION_CHILD_PROCESS_RESTRICTED via UpdateProcThreadAttribute().
额外的防御层。提供 job level 可以屏蔽该防御

Sandbox policy

target 进程的实际限制由 Sandbox policy 进行配置。Sandbox policy 只是一个编程接口,borker 调用它来定义限制和允许。四个功能控制限制,大致对应四个Windows机制:

  • TargetPolicy::SetTokenLevel()
  • TargetPolicy::SetJobLevel()
  • TargetPolicy::SetIntegrityLevel()
  • TargetPolicy::SetDesktop()

前三个调用使用一个整数级别的参数,该参数从非常strict 到 非常 loose。例如,token 有 7 个 level、job 有 5 个 level,Chromium渲染器通常以四种机制中最严格的级别运行。最后一个(桌面)策略是二进制的,只能用于检测目标是否在备用桌面上运行。

Target bootstrapping

target 不伴随着限定策略一同执行,它们从一个和常规用户进程 token 非常相似的token开始执行。因为在进程引导过程中,操作系统加载程序需要访问大量资源,其中大部分是未认证且随时会变化的。另外,大部分应用程序使用标准开发工具提供的标准CRT,在进程得到引导后,CRT也需要初始化,这时CRT初始化的内部再次变成未认证状态了。

在引导阶段,进程实际上使用了两种令牌(token):

  • 锁定令牌(lockdown token),即进程令牌

  • 初始令牌(initial token),即设置为初始线程的模拟令牌

事实上,真正的SetTokenLevel定义是:

1
SetTokenLevel(TokenLevel initial, TokenLevel lockdown)

在所有的初始化操作完成后,main()或WinMain()会继续执行,还有两个令牌会存活,但只有初始线程可以使用更强大的那个初始令牌。target的责任是在准备完成后销毁初始令牌。通过调用下面函数实现:

1
LowerToken()

调用完LowerToken()后,target 唯一可用的 token 便是 lockdown token,并且在此之后完整的沙箱限制开始生效。该调用不可撤销。注意,初始令牌是模拟令牌仅对主线程有效,target 进程中创建的其他线程仅使用锁定令牌,因此不会尝试获取符合安全检查的任何系统资源。

target 始于特权令牌,这简化了explicit policy,因为任何需要在进程启动时执行一次的特权操作都可以在LowerToken()调用之前完成,并且不需要在策略中包含规则。

NOTE

确保在调用 LowerToken() 之前关闭使用初始令牌获得的任何敏感操作系统句柄。任何泄露的句柄都可能被恶意软件滥用以逃离沙箱。

参考

https://chromium.googlesource.com/chromium/src/+/HEAD/docs/design/sandbox_faq.md

https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/design/sandbox.md

https://blog.csdn.net/u011453773/article/details/51162334?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-1&spm=1001.2101.3001.4242