本文主要是介绍RWCTF2022 Trust_or_not 复现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
RWCTF2022 Trust_or_not复现
RWCTF2022中有道逆向和TEE有关,准备复现一遍,顺便学习一下TEE。
TEE简介
TEE 全称叫做 Trust Executed Environment 可信执行系统,TEE 主要应用在手机以及 iot 设备上,比如用户的指纹识别以及支付相关的敏感操作都是在 TEE 中进行处理的,敏感的信息也是通过 TEE 加密之后存储在一个可信的位置。
TEE Feature
TEE有几个特别的名词,在此进行说明
REE:指非安全系统,手机上指的就是Android
bl1.bin
、bl2.bin
、bl31.bin
、bl32.bin
、bl33.bin
、前两个 bl* 主要和 boot 以及镜像加载有关,bl31 负责管理 SMC(Secure Monitor Control) 执行处理和中断,bl32 就是 TEE 系统镜像,bl33 为 REE 系统镜像也就是 Linux Kernel、uboot 之类的。调用流程如下图所示
TA 的全称是 Trusted Application 可信应用,既然有可信应用那么也就有不可信应用,不可信应用叫做 CA(Client Application) ,REE 通过调用 CA 来获取 TEE 提供的服务,每一个 CA 对应都有一个 TA ,TA 中调用 TEE 提供的 API 来满足 CA 发来的请求。每一个 TA 都被一个唯一的 UUID 标识。
TEE Secure Storage
接下来是很重要的TEE的安全存储。整体的流程如下
图中出现了很多密钥,HUK,SSK,TSK,FEK。
翻文档可以知道,这几个密钥分别的作用和存储位置
HUK
硬件唯一密钥,主要用于生成其他的密钥,文档里说明了这个永远不能被直接从软件中读到,secure side也不行,代表其重要性。
下方提及到,如果要在OP-TEE里寻找HUK,直接在tee_otp_get_hw_unique_key这个函数里面寻找,路径也标了出来。
SSK
SSK(安全存储密钥)的作用是生成TSK(可信程序存储密钥),是和设备相关的key。SSK是由HUK和静态字符串进行加密后得出的,且目前OP-TEE OS里我们只有一个SSK。
TSK
可信程序存储密钥由SSK和TA(可信程序)的UUID加密后得到,用处是用来保护FEK,也就是对FEK进行加密和解密
FEK
文件加密密钥。当TEE文件生成时,密钥管理器将用PRNG(伪随机数生成器)生成一个新的FEK,然后把加密后的FEK存储到元文件之中。FEK的作用是可以对存储在TEE的元文件的信息和块中的数据进行加密和解密。
元数据的加密流程
流程图如下
首先用TSK作为密钥,将FEK进行AES的MODE ECB 加密,得到的Encrypted FEK作为AAD(附加消息),FEK作为密钥,然后用Meta IV对Meta Data进行AES的MODE GCM加密,生成密文,tag(就是身份验证标签,MAC值,检测消息的完整性)和元IV,从而完成一套加密流程。
当需要更新元数据时,PRNG 将生成新的元 IV。meta IV 的大小在core/include/tee/fs_htree.h中定义
题目分析
对TEE稍作了解后,我们直接看题目。
HUK
首先我在Ubuntu 20.04上运行了一下这个TEE,发现这个题目是运行在qemu-system-aarch64中的,由HUK的定义我们可以知道它只和平台有关,而上方也说明了HUK永远都不应该被读到,
(以下是我的想法)
所以这里要找HUK应该是找不到的,如果可以做的话应该是初始值。
搜索源代码可知,初始值是全部memset为0
__weak TEE_Result tee_otp_get_hw_unique_key(struct tee_hw_unique_key *hwkey)
{memset(&hwkey->data[0], 0, sizeof(hwkey->data));return TEE_SUCCESS;
}
Static String
谷歌了半天,终于在文档里找着了
直接和pattern一起复制粘贴下来,这样我们就可以求SSK了
SSK
(本文的代码借鉴了https://www.anquanke.com/post/id/267183#h3-8 大佬的代码)
from hashlib import sha256
from hmac import HMACdef byte_to_string(s):return ''.join(["%02X " %i for i in s])
HUK = b'\x00'*0x10
chip_id = b'BEEF'*8
static_string = b'ONLY_FOR_tee_fs_ssk'
message = chip_id + static_string
SSK = HMAC(HUK, message, digestmod=sha256).digest()
print ("SSK: " + byte_to_string(SSK))
得出SSK
SSK: D0 23 CE 37 07 F6 CF 82 5E 2F 7C 1C 6A F8 2A 8B F1 E8 CF 9D E7 17 3D 74 31 2A A0 E2 77 6F 93 41
TSK
SSK我们已经知道,接下来是求ta文件的UUID。此处有三个做法
法一 直接通过偏移获得
搜索资料可知,ta的uuid存储在ta_head结构体之中,也存放在ta_head节中
然后010搜索ta_head节,这里的TA_STACK_SIZE搜索源码可知是4096,也就是0x1000
上方说了ta文件的代码用的是TA_STACK_SIZE,我就尝试了一下搜索0x1000的偏移,再加上ta文件头的偏移0x148后,就找到了uuid
不过感觉stack size不应该这么小(?
这里没有完全搞懂,希望有知道的师傅们指点一下
法二 拖进ida观察
查询资料可知,除类型为SEC4以外的ta文件删除了ta的文件头后是elf文件,证明我们可以直接拖进熟悉的ida来分析。于是我尝试了一下删除ta的文件头
然后拖进ida。在文件头中发现了uuid
法三 直接看文件名(草
笑死。
只能说一模一样
综上,我们可以得出uuid为
b'\xbb\x50\xe7\xf4\x37\x14\xbf\x4f\x87\x85\x8d\x35\x80\xc3\x49\x94'
然后计算TSK
from hashlib import sha256
from hmac import HMAC
def byte_to_string(s):return ''.join(['%02X ' % i for i in s])
HUK = b'\x00'*0x10
chip_id = b'BEEF'*8
static_string = b'ONLY_FOR_tee_fs_ssk'
message = chip_id + static_string
SSK = HMAC(HUK, message, digestmod=sha256).digest()
ta_uuid = b'\xbb\x50\xe7\xf4\x37\x14\xbf\x4f\x87\x85\x8d\x35\x80\xc3\x49\x94'
TSK = HMAC(SSK, ta_uuid, digestmod=sha256).digest()
print ("TSK: " + bytesToHexString(TSK))
TSK: 7E BE 82 6A A4 F4 57 AE FB EA EA 6E 34 BC D6 AA 14 A6 DD C7 EE 90 4C E4 9F 8F 20 71 3F 40 E6 CC
FEK
寻找encrypted FEK
参考https://cxybb.com/article/shuaifengyun/73655723
TEE保存敏感数据时,会将被secure storage保存的用户文件放在/data/tee,并以数字命名。还会生成一个dirf.db文件,保存整个安全存储保护的文件的所有节点和目录信息。
本题/data/tee目录下只有个数字命名的文件,也就是用户的加密后的数据。之前提到了加密后的文件会保存Encrypted FEK
struct tee_fs_htree_image {uint8_t iv[TEE_FS_HTREE_IV_SIZE];//加密iv+enc_fek时使用的iv值,每次保存head时会使用随机数更新uint8_t tag[TEE_FS_HTREE_TAG_SIZE];//加密iv+Enc_fek生成的数据的tag部分uint8_t enc_fek[TEE_FS_HTREE_FEK_SIZE];//使用TSK加密一个安全文件的fek生成的uint8_t imeta[sizeof(struct tee_fs_htree_imeta)];//加密iv+Enc_fek生成的数据的imeta部分uint32_t counter;//用于计算在保存tee_fs_htree_image的时候是存到ver0还是ver1
};
该结构体的enc_fek即保存着加密后的FEK,而根据下图的安全文件保存格式
我们知道文件头里就是我们想要找的enc_fek,搜索源码可知,TEE_FS_HTREE_IV_SIZE=16,TEE_FS_HTREE_TAG_SIZE=16,TEE_FS_HTREE_FEK_SIZE=16
于是在0x20的位置可以提取出enc_fek。
b"\xe4\x9a\x95\xf2\xb5\xf4\x9c\x04\xf6\x07\x9f\xfb\xf0\x2e\xd2\xef"
ver0和ver1的enc_fek都一样,找一个就够了。
然后可以计算出FEK了
计算结果
以下是我整个题最不解的地方。
网上搜索资料可知iv和tag存储在tee_fs_htree_node_image结构体里面
去看了源码的TEE_FS_HTREE_HASH_SIZE的大小,发现是32
在这里插入图片描述
TEE_FS_HTREE_HASH_SIZE是由TEE_SHA256_HASH_SIZE赋值的
然后综合这个图,我就去0x1000+0x20处找iv和tag,结果发现是错的
看了wp后发现,iv的偏移是0x1062。这个困扰了我很久,希望师傅们指点一下(哭
按答案的iv和tag,可以算出正确的flag
(因为不怎么会密码,直接复制粘贴
Resery师傅的脚本了)
此处解密的数据是上图的data block,也就是从0x2000开始的data
import os
import struct
from hashlib import sha256
from hmac import HMAC
from Crypto.Cipher import AES
import binasciidef bytesToHexString(bs):return ''.join(['%02X ' % b for b in bs])def AES_Decrypt_ECB(key, data):cipher = AES.new(key, AES.MODE_ECB)text_decrypted = cipher.decrypt(data)return text_decryptedfp = open("2","rb")
data = fp.read()
fp.close()HUK = b'\x00'*0x10
chip_id = b'BEEF'*8
static_string = b'ONLY_FOR_tee_fs_ssk'
message = chip_id + static_string + b'\x00'SSK = HMAC(HUK, message, digestmod=sha256).digest()
# print ("SSK: " + bytesToHexString(SSK))ta_uuid = b'\xbb\x50\xe7\xf4\x37\x14\xbf\x4f\x87\x85\x8d\x35\x80\xc3\x49\x94'
TSK = HMAC(SSK, ta_uuid, digestmod=sha256).digest()
# print ("TSK: " + bytesToHexString(TSK))Enc_FEK = b'\xe4\x9a\x95\xf2\xb5\xf4\x9c\x04\xf6\x07\x9f\xfb\xf0\x2e\xd2\xef'
FEK = AES_Decrypt_ECB(TSK, Enc_FEK)
# print ("FEK: " + bytesToHexString(FEK))# print ("........ decrypt block data ...........")
block_0 = data[0x2000:0x3000]Tee_fs_htree_node_image_1_iv = b'\xB4\xC9\x6A\x22\xE6\x36\x72\xCF\x6A\x44\x8F\x10\xA3\x11\x44\x68'
Tee_fs_htree_node_image_1_tag = b'\xCE\x65\xDE\x73\x08\xF9\x21\x09\xF2\xD2\x99\x9F\xA4\xB4\xE7\x51'cipher = AES.new(FEK, AES.MODE_GCM, nonce = Tee_fs_htree_node_image_1_iv)cipher.update(Enc_FEK)
cipher.update(Tee_fs_htree_node_image_1_iv)plaintext = cipher.decrypt_and_verify(block_0, Tee_fs_htree_node_image_1_tag)
print (plaintext)
得出flag为 rwctf{b5f3a0b72861b4de41f854de0ea3da10}
总结
回头看了一看,发现没我当时感觉的难,努力一下说不定也能做出来,而当时却打了退堂鼓。希望以后能自信一点。
还有RWCTF的题目真的很好,学到了很多东西,很开心。本题中没有搞懂的部分,之后会请教师傅们,争取能吃透。
参考
https://elixir.bootlin.com/op-tee/latest/source/core/kernel/
https://www.anquanke.com/post/id/267183#h2-12(参考的wp)
https://www.anquanke.com/post/id/236483#h2-5
https://cxybb.com/article/shuaifengyun/73655723
https://blog.csdn.net/shuaifengyun/article/details/74594861
https://github.com/OP-TEE/optee_os
这篇关于RWCTF2022 Trust_or_not 复现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!