COIN Attacks【源码分析】

论文笔记请见这里

COIN Attacks符号执行SGX_SQLite

从COIN Attack符号执行SGX_SQLite的过程入手分析COIN Attacks。从run.sh开始。

第一步 编译SGX_SQLite

SGX SIM Mode编译SGX_SQLite。(位于run.sh)

第二步 提取EDL信息

分析EDL文件并记录所有会将数据传入Enclave的E/OCALL函数及对应参数,具体包括OCALL返回值、[out]标记的OCALL参数、[in]标记的及其它所有的ECALL参数。这些参数称为不安全参数。信息放到unsafe_input_stat.tmpunsafe_ecall_stat.tmp文件。(位于edlParse.py

第三步 提取不安全参数的类型信息

结合第二步得出的信息,使用ModulePass读取(似乎会漏掉SDK的接口)每个不安全参数所包含内容的类型(如pointer所指Reference的类型,struct内的各个成员的类型)。基于LLVM Pass的RTTI能更简单地获取类型信息。信息放到unsafe_input_complete.tmp文件。(位于EnclaveSemantics.cpp

第四步 符号执行Enclave

加载Enclave.so

load_binary中,使用lief.parse解析enclave.so,并使用Triton的setConcreteMemoryAreaValue将Enclave加载起来。

加载不安全的输入信息

load_input_semantics函数将unsafe_input_complete.tmp里的不安全函数及其参数信息分别加载到数据结构interface_hook_fninput_semantics中。

加载ECALL信息

load_ECALLsunsafe_ecall_stat.tmp里的Ecall信息加载到数据结构primary_ECALLs中。permutations构建Ecall函数的各种排列。

为模拟器配置Hooks

config_hook_table中,利用lief.ELF.Binary丰富的信息,动态设置pltgot符号项Unsafe函数的地址。动态更新dlmallocdlfreememcpy函数的地址信息。动态更新__stack_chk_failtag的地址信息。

初始化triton上下文

单线程模拟执行(包括乱序执行)

定位urtssgx_ocallsgx_ocfree函数地址(也代表了Enclave退出)。Triton具体化所有符号内存引用,设置栈帧为每个Ecall分配0x10000大小的栈空间。选择需要乱序执行的Ecalls,对其参数设置内存值,用于模拟执行。关于设置参数内存值,初始用默认种子设置内存,每执行完一轮Ecall序列就随机化种子并改变内存值,最多执行MAX_SEED_ATTEMPT轮。

"""
run_single_thread_emul(perm_ECALLs_list) prepares and handles single thread mode of emulation
"""
def run_single_thread_emul(perm_ECALLs_list):
	...
    for order_ECALLs in list(perm_ECALLs_list):
    	...
        while seed_worklist:
			...
            Triton.concretizeAllMemory()
            ...
            for it_ECALL in order_ECALLs:
                ...
                stack_base_addr -= 0x10000
                ...
                if it_ECALL in input_semantics:
                    for param_ECALL in input_semantics[it_ECALL]:
                        config_memory_for_param(it_ECALL, param_ECALL, it_ECALL_addr, init_seed_flag, True)
                res = emulate(it_ECALL_addr, sgx_ocall, sgx_ofree, False)
			...
            if (len(seed_worklist) < MAX_SEED_ATTEMPT):
                new_seeds = query_new_seed()
			...

多线程模拟执行(包括并发执行)

总体类似于单线程模拟执行,但是对每个Ecall都起了单独的线程来执行,从而模拟并发。一个重要的细节是,在模拟执行中,每执行一条指令都会上锁,保证每个线程中每条指令都是原子性的完成的。

模拟执行

初始化模拟器。从每个Ecall函数第一条指令开始最多的模拟执行中,最多从入口指令开始往后执行MAX_INST_CNT条指令。检查当前指令是否符合策略。

检查当前指令是不是某个hook函数(针对dlmallocsgx_malloc_hook、针对dlfreesgx_free_hook、针对memcpysgx_memcpy)或tag(__stack_chk_fail),陷入到hook或者tag时也进行策略检查,若违反策略就构建报告。

策略检查是这项工作的关键所在

"""
emulate(pc, sgx_ocall, sgx_free, is_threaded) emulates instructions
"""
def emulate(pc, sgx_ocall, sgx_free, is_threaded):
	...
	ret = Triton.processing(instruction)
	...
	policies.inspection(instruction)
	...
    hook_process_inst(instruction)
	...
	print_report()
	...

检查策略(*)

(Enclave接口处的输入往往可以是任意值并被攻击者控制,因此用符号变量表示这些接口输入。)

条件1条件2条件3漏洞类型
Triton模拟完一条指令后会对指令检查拦截操作数为内存的指针解引用操作(指令为movmovsxlea)(位于oob_uaf_policy函数中)内存对象尾部跨出了堆分配时记录的Enclave堆对象的尾部OOB
(多线程下,当前线程Free内存后相较其它线程延迟10个指令确保Memory-reuse Delay)内存对象头部未指向堆分配时记录的Enclave堆对象内,并且与堆分配历史记录吻合UAF
第一步找到包含符号变量的cmp指令;第二步在紧跟的20条指令找到立即数高位为1(?)mov指令;第三步在紧跟的10条指令找到jmp指令(test_cmp_sides函数中)Ineffectual Condition
此外对存在对应Hook的指令进一步处理Enclave内调用memcpy函数时会被sgx_memcpy Hook函数拦截检测Enclave栈内存是否被memcpy复制到Enclave堆内存,后续人工检查堆内存是否通过Enclave接口被带出,从而造成栈信息泄漏(test_stack_leak函数中)栈信息泄漏
检查memcpy目标地址是否为Null(is_nd_or_heap_overflow函数中)Null Pointer Deference
检查目标堆对象有效大小(堆分配时会记录堆对象信息)是否小于memcpy参数指定的大小。(is_nd_or_heap_overflow函数中)堆溢出
Enclave内malloc内存时会被sgx_malloc_hook拦截
Enclave内free内存时会被sgx_free_hook拦截如果待释放内存未在堆分配情况记录表中记录,则说明该内存可能已经被释放或从未被分配,存在Double FreeDouble Free
当程序执行到__stack_chk_fail(编译器对程序代码插桩检查Stack Canary破坏触发__stack_chk_fail),报告存在栈溢出。(位于hook_process_inst栈溢出
ECALL被超过30个地址调用DDoS

(具体细节见这里

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值