一大堆东西里有bl1.bin,bl2.bin,bl31.bin,bl32.bin,bl32_extra1.bin -bios bl1.bin <– Specify the custom bios.;bl1, bl2 are just vendor firmware shit from arm, safe to ignore it lol;bl32_extra1 is optee kernel that run in tRuStzone. 所以我门真正要分析的就是bl32_extra.bin(optee的内核)
/** * struct shdr - signed header * @magic: magic number must match SHDR_MAGIC * @img_type: image type, values defined by enum shdr_img_type * @img_size: image size inbytes * @algo: algorithm, defined by public key algorithms TEE_ALG_* * from TEE Internal API specification * @hash_size: size of the signed hash * @sig_size: size of the signature * @hash: hash of an image * @sig: signature of @hash */ struct shdr { uint32_t magic; uint32_t img_type; uint32_t img_size; uint32_t algo; uint16_t hash_size; uint16_t sig_size; /* * Commented out element used to visualize the layout dynamic part * of the struct. * * hashis accessed through the macro SHDR_GET_HASH and * signature is accessed through the macro SHDR_GET_SIG * * uint8_t hash[hash_size]; * uint8_t sig[sig_size]; */ };
/** * struct shdr_bootstrap_ta - bootstrap TA subheader * @uuid: UUID of the TA * @ta_version: Version of the TA */ struct shdr_bootstrap_ta { uint8_t uuid[sizeof(TEE_UUID)]; uint32_t ta_version; };
2文件到底是什么文件? More importantly, the only file with newer modified timestamp (very important CTF cheesing strategy) is data/tee/2. that’s where optee store encrypted blobs for its “secure object” storage api. it’s some hash tree shit. The way the hash tree is setup is there’s a bunch of encrypted blobs in data/tee and a encrypted directory node dirf.db as well. But we’re only give the blob 2, but with no directory node dirf.db.
The flag is stored in this encrypted blob. The problem is how do we decrypt it, or get optee to read it out. 文件格式如下:
/* * File layout * [demo withinput: * BLOCK_SIZE = 4096, * node_size = 66, * block_nodes = 4096/(66*2) = 31 ] * * phys block 0: * tee_fs_htree_image vers 0 @ offs = 0 * tee_fs_htree_image vers 1 @ offs = sizeof(tee_fs_htree_image) * * phys block 1: * tee_fs_htree_node_image 0 vers 0 @ offs = 0 * tee_fs_htree_node_image 0 vers 1 @ offs = node_size * tee_fs_htree_node_image 1 vers 0 @ offs = node_size * 2 * tee_fs_htree_node_image 1 vers 1 @ offs = node_size * 3 * ... * tee_fs_htree_node_image 30 vers 0 @ offs = node_size * 60 * tee_fs_htree_node_image 30 vers 1 @ offs = node_size * 61 * * phys block 2: * data block 0 vers 0 * * phys block 3: * data block 0 vers 1 */ /* * htree_image is the header of the file, there's two instances of it. One * which is committed and the other is used when updating the file. Which * is committed is indicated by the "counter" field, the one with the * largest value is selected. * * htree_node_image is a node in the hash tree, each node has two instances * which is committed is decided by the parent node .flag bit * HTREE_NODE_COMMITTED_CHILD. Which version is the committed version of * node 1 is determined by the by the lowest bit of the counter field in * the header. * * Note that nodes start counting at 1 while blocks at 0, this means that * block 0 is represented by node 1. */
if (IS_ENABLED(CFG_CORE_HUK_SUBKEY_COMPAT_USE_OTP_DIE_ID)) return tee_otp_get_die_id(buffer, len);
for (i = 0; i < len; i++) buffer[i] = pattern[i % 4];
return TEE_SUCCESS; }
/* * This does special treatment for RPMB and SSK key derivations to give * the same result as when huk_subkey_derive() wasn't used. */ static TEE_Result huk_compat(void *ctx, enum huk_subkey_usage usage) { TEE_Result res = TEE_SUCCESS; uint8_t chip_id[TEE_FS_KM_CHIP_ID_LENGTH] = { 0 }; static uint8_t ssk_str[] = "ONLY_FOR_tee_fs_ssk"; switch (usage) { case HUK_SUBKEY_RPMB: return TEE_SUCCESS; case HUK_SUBKEY_SSK: res = get_otp_die_id(chip_id, sizeof(chip_id)); if (res) return res; res = crypto_mac_update(ctx, chip_id, sizeof(chip_id)); if (res) return res; return crypto_mac_update(ctx, ssk_str, sizeof(ssk_str)); default: return mac_usage(ctx, usage); } }
import os import struct from hashlib import sha256 # from Crypto.Hash import HMAC, SHA256 from hmac import HMAC from Crypto.Cipher import AES import binascii
defAES_Encrypt_CBC(key, iv, data): # vi = '0102030405060708' pad = lambda s: s + (16 - len(s) % 16) * chr(16 - len(s) % 16) data = pad(data) cipher = AES.new(key.encode('utf8'), AES.MODE_CBC, iv.encode('utf8'))