DEF CON 30 CTF Quals | Teedium Wallet 复盘插图

ARM TEE中Trusted Application的Pwnable题目

这是一道关于ARM TEE(可信执行环境)中Trusted Application的 Pwnable 题目。在该题目中,使用的TEE OS是OP-TEE OS。下面是整体架构图:

image.png-155.1kB

源码和漏洞分析

题目的源码可以在以下链接找到:https://github.com/Nautilus-Institute/quals-2022/tree/main/teedium-wallet

serialize_tx函数中调用serialize_sighash时,没有对原始缓冲区进行重新分配(realloc)的操作,这可能导致堆溢出。但是,只能溢出4个固定值为1的字节。

图片.png-549.7kB

作者已经提供了Exploit,因此主要记录一下调试过程。调试的难点主要在于OP-TEE OS和TA都开启了ASLR(地址空间布局随机化)。根据这个步骤,我们可以通过在tee_thread_enter_user_mode函数下断点来确定OP-TEE kernel加载基址在0xE100000处。然后,我们需要 patch 掉内核加载时的ASLR种子以便进行调试。

此外,Normal World和Secure World都有日志输出。在Secure World的日志中,可以获得TA的加载地址。为了获取日志,还需要修改QEMU的启动参数。

图片.png-633kB

Exploit和调试过程

在启动QEMU之前,请先启动监听日志的命令 nc -z 127.0.0.1 54320 || python3 soc_term.py 54320nc -z 127.0.0.1 54321 || python3 soc_term.py 54321。然后,在启动QEMU后,可以使用GDB在地址0xE101CD8处设置断点。

执行Exploit后,每次切换到TEE的用户模式时,都会在0xE101CD8处停止。第一次是ldelf,第二次是题目的TA。

从日志中获得TA的基地址后,就可以对TA进行调试了。

Exploit分析和堆管理器

TA中使用的堆管理器是bget allocator。Exploit中的利用方式是在释放堆块时伪造一个已释放的堆块,然后在合并(unlink)时将栈上的返回地址(fp)修改为输入的缓冲区,并进行ROP迁移。

当释放溢出的堆块时,由于prevfree为1,当前堆块的前一个堆块会被认为处于空闲状态。此外,由于bget使用负数表示分配的堆块大小,正数表示释放的堆块大小,因此合并完前一个堆块后,它的大小变成了一个非常大的数。

之后,在计算下一个堆块时,相当于加上了一个负数,指向了伪造的堆块。由于伪造的堆块的bsize大于0,因此会被认为后一个堆块也处于空闲状态,然后继续进行合并。

在unlink操作时,将栈上的返回地址(fp)修改为输入缓冲区,最后进行ROP迁移。

ROP调用syscall获取flag,并将其复制到输出缓冲区。

图片.png-629.4kB

TA的ASLR和内存布局

在TA开启ASLR的情况下,通过观察发现只有TA本身的加载基址会变化。变化的范围由get_pad_begin确定,默认配置是(0x0-0x80)*0x1000

E/LD:  region  0: va 0x00102000 pa 0x0e300000 size 0x002000 flags rw-s (ldelf)
E/LD:  region  1: va 0x00104000 pa 0x0e302000 size 0x00b000 flags r-xs (ldelf)
E/LD:  region  2: va 0x0010f000 pa 0x0e30d000 size 0x001000 flags rw-s (ldelf)
E/LD:  region  3: va 0x00110000 pa 0x0e30e000 size 0x004000 flags rw-s (ldelf)
E/LD:  region  4: va 0x00114000 pa 0x0e312000 size 0x001000 flags r--s
E/LD:  region  5: va 0x00115000 pa 0x0e34b000 size 0x001000 flags rw-s (stack)
E/LD:  region  6: va 0x00182000 pa 0x00001000 size 0x02a000 flags r-xs [0] # TA Code
E/LD:  region  7: va 0x001ac000 pa 0x0002b000 size 0x00e000 flags rw-s [0] # TA Data
E/LD:  region  8: va 0x00200000 pa 0x40b90c78 size 0x002000 flags rw-- (param) # 输出buffer
E/LD:  region  9: va 0x00202000 pa 0x40bbc060 size 0x006000 flags rw-- (param) # 输入buffer