《A Tale of Two Worlds (CCS‘19)》笔记

(22) 2024-04-15 14:01:01

简介

《A tale of two worlds: Assessing the vulnerability of enclave shielding runtimes》是CCS 2019的一篇论文,作者是Jo Van Bulck。

本文针对Enclave Interface Sanitization从ABI、API层面寻找漏洞。漏洞涉及Intel SGX-SDK(Edger8r)、Microsoft OpenEnclave(Deep Copy Marshalling)、Google Asylo和Rust Compiler等多个开源项目。

相关工作

相关工作如DarkROPGuard‘s Dilemma更关注在Enclave内利用传统内存安全漏洞(的技巧)。

A Tale of Two Worlds更关注各个SGX软件栈的漏洞态势及Enclave安全模型下的新型漏洞。在ABI层关注Enclave线程栈切换、寄存器状态清理;在API层关注pointersize参数。即Enclave进入及同步退出过程中的Sanitization和Defensive Check。

Boomerang关注TrustZone平台下Enclave内使用的指向Enclave外的指针的消毒缺陷。本文关注指向Enclave内的指针的消毒缺陷,与Boomerang正交。

Practical enclave malware with Intel SGX关注Enclave内恶意软件的危害( ⋆ \star 攻击者可依次攻陷远程服务Enclave → \rightarrow Enclave’s Host)

表1枚举了ABI/API层的漏洞类型/攻击向量。
《A Tale of Two Worlds (CCS‘19)》笔记 (https://mushiming.com/)  第1张

ABI层攻击向量

攻击向量1:Status Flag Registers

《A Tale of Two Worlds (CCS‘19)》笔记 (https://mushiming.com/)  第2张
SGX依靠Runtime清理大部分状态标识寄存器。Sancus只让Runtime处理Interrupt Flag。TrustZone硬件层将状态标识寄存器及安全世界栈寄存器都自动清理了。该攻击向量利用情况:

  1. Direction Flag
    ┌ \ulcorner Intel SGX-SDK(CVE-2019-14565)/OpenEnclave(CVE-2019-1370) ┘ \lrcorner
    进入Enclave时,tRTS未清除Direction Flag,rep指令操作方向被攻击者控制。
    如tRTS Bridge为output动态分配内存并清零,清零过程中,攻击者置位DF将output前Enclave堆帧(可能保存密钥)清零,而output内存未清零,残留数据泄漏。
  2. Alignment Check Flag
    ┌ \ulcorner Intel SGX-SDK ┘ \lrcorner
    进入Enclave时,tRTS未检查Alignment Check Flag。攻击者置位AC标识寄存器时,secret=0时访问AB不触发#AC异常,secret=1时访问BC触发#AC(AC清零则允许奇地址访问16Bit,AC置位时访问奇地址触发#AC异常,AEX返回后仍无法访问导致程序无法继续运行,对此可清零对齐掩码CR0.AM暂时禁用对齐检查)。此差异可反推secret。(页/段错误侧信道归因于Enclave内依赖OS页表机制)。

《A Tale of Two Worlds (CCS‘19)》笔记 (https://mushiming.com/)  第3张

攻击向量2:调用栈

《A Tale of Two Worlds (CCS‘19)》笔记 (https://mushiming.com/)  第4张

  1. Graphene 新建线程可通过OCALL Ret将线程栈恢复成其他线程OCALL时保存的上下文(其他线程可能已经OCALL Ret → \rightarrow ECALL Ret,但OCALL Ret并不会删除OCALL时备份的上下文)。
  2. SGX-LKL 新生线程可通过signal handler cmd进入Enclave,从未初始化内存中错误地恢复上下文。
  3. Sancus RTS 存在第一项所说的问题(恢复成OCALL备份的上下文)。此外,其利用jmp指令退出Enclave,跳转地址是程序指定的寄存器值,能够错误地跳转到Enclave内其它地方。

攻击向量3:Register State

《A Tale of Two Worlds (CCS‘19)》笔记 (https://mushiming.com/)  第5张
退出Enclave时需要保存并彻底清理寄存器状态。但EEXIT将清理的任务交给软件完成,AEX硬件流程中未对DF进行清理(按理说,微码设计中肯定是考虑了所有寄存器,毕竟寄存器数量是固定的,难道是认为DF不重要所以没清理?)。AEX中泄露的DF信息能被侧信道手段用于感知Enclave内字符串操作方向。

该攻击向量的利用情况:

  • SGX-LKL利用setjmp/longjmp函数在Enclave进出时简单地备份和恢复上下文。但setjmp没有清理所有CPU状态,使得攻击者在uRTS能够Dump XMM寄存器。(建议EEXIT前覆写敏感的寄存器)

API层攻击向量

主要关注Sanitization层指针、变长缓冲区的处理。

攻击向量4:指针

《A Tale of Two Worlds (CCS‘19)》笔记 (https://mushiming.com/)  第6张
跨越Enclave安全边界的指针应该恰当地指向预期的共享内存区域。

该攻击向量利用情况如下:

  1. OpenEnclave OEEDGER8R生成的桥函数(Listing 2)中,检查传参指针p_host_args报错后仍然使用之,当p_host_args指向Enclave时,会造成Enclave内存覆写。(Listing 2)(CVE-2019-0876)
    《A Tale of Two Worlds (CCS‘19)》笔记 (https://mushiming.com/)  第7张
    Built-in _handle_get_sgx_report() ECALL中缺乏对传参指针的检查,导致Enclave内存覆写。
  2. Google Asylo在Intel SGX SDK上增加了新的抽象层,该文找到14个有问题的[user_check]使用实例,发现Write 0原语等。Listing 8的ecall_dispatch_trusted_call中unmarshall [user_check] buffer之前未进行检查;并且在判断输入时错以为sgx_is_outside_enclave    ⟺    \iff not sgx_is_within_enclave《A Tale of Two Worlds (CCS‘19)》笔记 (https://mushiming.com/)  第8张
  3. Graphene在Enclave部署LibOS兼容Legacy Binary Application。但未对argvenvp指针进行检查。enclave_ecall_thread_start()没有检查传入的不可信函数指针,能够任意地址跳转,构成代码重用攻击。
  4. SGX-LKL也在Enclave部署LibOS(使用Linux Kernel Library)兼容Legacy Binary Application。但__sgx_init_enclave()未对argv参数消毒并直接传给Binary App,最终导致信息泄露。
    由于Enclave不支持rdtsc指令会触发SIGILL,SGX-LKL从不可信环境获取rdtsc结果,在Enclave内信号处理句柄传参siginfo补足(case SIGILL)。攻击者控制siginfo指向Enclave内任意地址(恰巧siginfo->signum==SIGILL),siginfo->arg被当作rdtsc值使用【将Enclave内存(即rdtsc值)回显到不可信环境,为了辅助攻击?可能需要复现代码来理解】。依据siginfo - > signum(实为攻击者指定的任意内存)差异,代码将执行不同case分支,分支的时延差异等能用于侧信道反推Enclave内存。(Listing 9)《A Tale of Two Worlds (CCS‘19)》笔记 (https://mushiming.com/)  第9张
  5. Sancus Listing 10的__sm_handle_input是自动生成的Bridge函数,用于解密传入Enclave的输入,但未检查payload。当payload指向Enclave内时,将对Enclave内容进行解密,造成信息泄露。
    《A Tale of Two Worlds (CCS‘19)》笔记 (https://mushiming.com/)  第10张此外,Sancus的Trusted Loader Enclave Code未对输入指针有效性进行检查。

攻击向量5:String

《A Tale of Two Worlds (CCS‘19)》笔记 (https://mushiming.com/)  第11张

  1. Intel SGX SDK CHECK_UNIQUE_POINTER检查操作前的strlen直接对未检查的_tmp_s进行长度测量。攻击者单步执行(利用sgx-step攻击)strlen函数,函数判断每一个字节时直到0终止符,会置位Page Access位,如果Access位未置位,推断此地址(减一)存储的值为0终止符。(CVE-2018-3626)
    《A Tale of Two Worlds (CCS‘19)》笔记 (https://mushiming.com/)  第12张
    图4说明了攻击的具体过程。1)线程A调用ecall_encrpytString,2)在最后一轮AEX时触发中断(通过Dummy Page页错误,或时钟中断),3)配置定时器用于周期性触发时钟中断,4)线程B调用ECALL中的strlen访问线程A的SSA中的XMM0,5)在每次定时器触发时钟中断时,6)检查并清除Page的Access位,以
    《A Tale of Two Worlds (CCS‘19)》笔记 (https://mushiming.com/)  第13张
    算法1揭示了从已知的Sbox(0)(0指侧信道反推出的0终止符)和Cyphertext[ShiftRows(Length)]推出Key[ShiftRows(Length)]密钥字节。
    《A Tale of Two Worlds (CCS‘19)》笔记 (https://mushiming.com/)  第14张
    下图给了一个更加形象的例子。
    《A Tale of Two Worlds (CCS‘19)》笔记 (https://mushiming.com/)  第15张
    Intel针对该攻击弃用了[sizefunc]EDL属性,并要求不可信环境提供字符串长度,以此长度在Enclave内设置字符串的0终止符。
  2. OpenEnclave 针对strlen侧信道也要求不可信环境提供字符串长度,但未对字符串添加0终止符,导致Enclave函数操作一个non-null-terminated字符串。(CVE-2019-0876)

攻击向量6:整数溢出

《A Tale of Two Worlds (CCS‘19)》笔记 (https://mushiming.com/)  第16张
攻击者如果能操控共享内存/Enclave内存布局(如传入一个刚好位于Enclave基地址前的指针),就能更有效的利用此漏洞。对此,运行时需要安全地使用不可信环境提供的size计算变长buffer的结束地址。

  1. Fortanix Rust-EDP 如Listing4所示,is_user_range()验证UserSafe Type(Rust Type System)时,变长Bufferend可能出现整数溢出绕过Line5的检查。
    《A Tale of Two Worlds (CCS‘19)》笔记 (https://mushiming.com/)  第17张
  2. Google Asylo 判断输入时错以为 s g x _ i s _ o u t s i d e _ e n c l a v e    ⟺    n o t   s g x _ i s _ w i t h i n _ e n c l a v e sgx\_is\_outside\_enclave \iff not\ sgx\_is\_within\_enclave sgx_is_outside_enclavenot sgx_is_within_enclave,未理解 o u t s i d e ≠ ¬ i n s i d e outside \ne \neg inside outside=¬inside。(如Listing 8所示,“攻击向量4指针”中提到过)
    《A Tale of Two Worlds (CCS‘19)》笔记 (https://mushiming.com/)  第18张
  3. Graphene-SGX 存在第1项、第2项(攻击向量7)提到的问题。Graphene通过OCALLOC在Enclave外开辟空间存放OCALL参数和返回值,它只在进入Enclave时检查Host栈指针严格落在Enclave外,OCALLOC可能让Host栈溢出进入ELRANGE(Enclave所占用的虚拟地址空间)但未对此检查,读写存放OCALL参数返回值的内存(可能在Enclave内)会导致信息泄漏或内存破坏。
  4. Keystone 如Listing 12所示,当epm_base=0x82800000epm_size=100000addr=0x1size=0xffffffffffffffff时,Line 4的检查会因为整数溢出而被绕过。
    《A Tale of Two Worlds (CCS‘19)》笔记 (https://mushiming.com/)  第19张
  5. Sancus tRTS提供的sancus_is_outside_sm()未能有效检查跨越Enclave地址空间或整数溢出环绕整个16位地址空间的不可信buffer

攻击向量8:Double Fetch

前面的攻击向量关注不可信指针解引用spatial层面。攻击向量8关注temporal层面。
《A Tale of Two Worlds (CCS‘19)》笔记 (https://mushiming.com/)  第20张

  • Graphene-SGX ms指针一直处uRTS(OCALLOC),未被拷贝进Enclave,在ms->ms_addr检查和使用期间,攻击者可以暂停线程并替换ms->ms_addr指向Enclave内,进而造成可信内存泄漏。(典型的Double Fetch/TOCTOU)
    《A Tale of Two Worlds (CCS‘19)》笔记 (https://mushiming.com/)  第21张

攻击向量9:Iago/OCALL返回值

《A Tale of Two Worlds (CCS‘19)》笔记 (https://mushiming.com/)  第22张
SGX SDK往往提供较少的内建OCALL,但SGX LibOS需要对大量使用的内建OCALL的返回值进行检查。

  1. Microsoft Open Enclave SDK oe_get_report_v2()中两次调用_oe_get_report_internal()(内含_get_quote() OCALL),第一次获取Quote所需内存大小用于分配Enclave内存,第二次将Quote写入Enclave堆。但第二次OCALL被攻击者返回过大的Size会导致读/写越界。
oe_result_t oe_get_report_v2(...) { 
   
    ...
    result = _oe_get_report_internal(
        flags,
        report_data,
        report_data_size,
        opt_params,
        opt_params_size,
        NULL, // Use NULL to only get Quote Size
        &tmp_buffer_size);// This func will call OCALL "_get_quote()"
    ...
    tmp_buffer = oe_calloc(1, tmp_buffer_size);
    ...
    result = _oe_get_report_internal(
        flags,
        report_data,
        report_data_size,
        opt_params,
        opt_params_size,
        tmp_buffer,
        &tmp_buffer_size);
    ...
    return OE_OK;
}
  1. LibOS-based runtimes
    → \rightarrow Grphene-SGXreaddir()等系统调用可以返回恶意的长度值,将Enclave外内容以任意长度写进Enclave内。
    → \rightarrow SGX-LKL中,未检查mmap()系统调用返回值完全落在Enclave外,未检查write()系统调用返回的不可信长度值。后者能导致Enclave内存被越界地拷贝到Enclave外。
    → \rightarrow Google Asylo存在未检查write syscall返回长度。
  2. Keystone,能利用write()系统调用构建Iago,类似于SGX-LKL POC。

攻击向量10:Uninitialized Padding

除了关注Pointer和Size参数,结构体中的(编译器自动添加的)未初始化填充部分也可能泄漏信息。
《A Tale of Two Worlds (CCS‘19)》笔记 (https://mushiming.com/)  第23张
对此可能的措施是使用memset安全初始化output,或声明结构体packed避免编译器引入Padding,但这两者需要先验知识。

  1. SDK-based runtimes Intel SGX-SDK/OE/Sancus/Keystone均存在Padding Leakage。
  2. LibOS-based runtimes Rust-EDP无此问题;Graphene-SGX使用#pragma packing指针,无此问题;SGX-LKL有此问题(sigaction和siginfo_t);Google Asylo较少(struct BridgeSignalHandler)存在此问题。

讨论

如何让对漏洞类型无感的Enclave开发者正确实施接口验证解决上述问题是一个挑战,我们需要更根本的解决方法来缓解这些漏洞。

Code Hardening
在代码层面进行加强。如利用Heap Obfuscation、Address Randomization,针对指针破坏更激进地销毁密码或检测指针的恶意企图。

Hardware-Assisted Solutions
利用处理器提供的细粒度内存保护(如Tagged Memory、Capability Architecture/Machine),还可以借鉴SMAP等纵深防御机制来保护Enclave。

Safe Programming Languages
Rust的Type System能有效地起作用,但不是“银弹”。运行时仍需构建预期的ABI调用规范、对不可信指针的正确消毒。此外,出现了EDGER8R的替代品,为Enclave自动生成安全封装。

结论

TEE运行时的保护责任尚未被清晰认识,安全问题频出。在8个TEE运行时找到35个接口消毒问题,归结为10类漏洞。需要更根本的接口消毒策略。后续可通过静态分析工具和Fuzzing探索攻击面。

涉及的CVE

current_description cve_id cvss2_score cwe paper project result reference
Insufficient initialization in Intel® SGX SDK Windows versions 2.4.100.51291 and earlier, and Linux versions 2.6.100.51363 and earlier, may allow an authenticated user to enable information disclosure, escalation of privilege or denial of service via local access. CVE-2019-14565 4.6 MEDIUM CWE-665 Improper Initialization A tale of two worlds: Assessing the vulnerability of enclave shielding runtimes SGX SDK 信息泄露、提权或DoS https://support.f5.com/csp/article/K57201259?utm_source=f5support&utm_medium=RSS ; https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00293.html (Vendor Advisory);
An information disclosure vulnerability exists when affected Open Enclave SDK versions improperly handle objects in memory, aka ‘Open Enclave SDK Information Disclosure Vulnerability’. CVE-2019-1370 2.1 LOW CWE-200 Exposure of Sensitive Information to an Unauthorized Actor A tale of two worlds: Assessing the vulnerability of enclave shielding runtimes OpenEnclave 信息泄露 https://github.com/openenclave/openenclave/commit/efe75044d215d43c2587ffd79a52074bf838368b (Patch); https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2019-1370 (Patch, Vendor Advisory);
An information disclosure vulnerability exists when affected Open Enclave SDK versions improperly handle objects in memory, aka ‘Open Enclave SDK Information Disclosure Vulnerability’. CVE-2019-1369 2.1 LOW CWE-200 Exposure of Sensitive Information to an Unauthorized Actor A tale of two worlds: Assessing the vulnerability of enclave shielding runtimes OpenEnclave 信息泄露 https://github.com/openenclave/openenclave/commit/a39476e5de854317a1a74ec3c08257a00c1625d5 (Patch); https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2019-1369 (Patch, Vendor Advisory);
An information disclosure vulnerability exists when affected Open Enclave SDK versions improperly handle objects in memory, aka ‘Open Enclave SDK Information Disclosure Vulnerability’. CVE-2019-0876 2.1 LOW NVD-CWE-noinfo Insufficient Information A tale of two worlds: Assessing the vulnerability of enclave shielding runtimes OpenEnclave 信息泄露 https://github.com/openenclave/openenclave/commit/d07769bcf73bb8a1b29374be1a50f93bae549f58 (Patch); https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2019-0876 (Patch, Vendor Advisory); http://www.securityfocus.com/bid/107743 (Third Party Advisory, VDB Entry);
Edger8r tool in the Intel SGX SDK before version 2.1.2 (Linux) and 1.9.6 (Windows) may generate code that is susceptible to a side channel potentially allowing a local user to access unauthorized information. CVE-2018-3626 1.9 LOW CWE-200 Exposure of Sensitive Information to an Unauthorized Actor A tale of two worlds: Assessing the vulnerability of enclave shielding runtimes SGX SDK EDGER8R 侧信道方式信息泄露 http://www.securityfocus.com/bid/103479 (Third Party Advisory, VDB Entry); https://security-center.intel.com/advisory.aspx?intelid=INTEL-SA-00117&languageid=en-fr (Vendor Advisory);
THE END

发表回复