Official description
The only prototype of our brand new IoT device was stolen with the laptop containing the application source code… ;(
And of course we had no backup ;( ;(
For some reasons, the device is still online here, can you help us recover the secret value ?
All we can provide is this logic analyzer capture.
We are given a capture.dsl
file and a URL https://espmyadmin.insomnihack.ch/
.
Exploration
Web service
We open https://espmyadmin.insomnihack.ch/
and we are greeted with a secret
value prompt and a link to https://espmyadmin.insomnihack.ch/config
.
We open https://espmyadmin.insomnihack.ch/config
and we get some information:
- the chip is an ESP32-S3,
- encryption is set to
Enabled (DEVELOPMENT) - AES-256
,FLASH_CRYPT_CONFIG=0xf
, - Wi-Fi MAC is
7C:DF:A1:E0:71:F1
, - then we get eFuses values, including
XTS_AES_256_KEY_1
andXTS_AES_256_KEY_2
.
The ESP32-S3 is a newer variant of the ESP32. These chips use Tensilica processors with Xtensa instruction set.
Encryption is activated, it’s a good time to open the manufacturer documentation: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/security/flash-encryption.html. We learn that:
- two 256-bit key blocks are used for
XTS_AES_256
mode, - the partition table should look like:
I (62) boot: ## Label Usage Type ST Offset Length I (69) boot: 0 nvs WiFi data 01 02 0000a000 00006000 I (76) boot: 1 storage Unknown data 01 ff 00010000 00001000 I (84) boot: 2 factory factory app 00 00 00020000 00100000 I (91) boot: 3 nvs_key NVS keys 01 04 00120000 00001000
- a tool
espsecure.py
(in esptool) is able to encrypt and decrypt flash data using the--aes_xts
flag (AES-XTS mode).
capture.dsl
After a quick search online, we learn that .dsl
files are
DSView traces.
We open it using DSView, and we get 4 logic signals: CS
, MISO
, MOSI
and
CLK
. This is an SPI interface. The chip select CS
is pulled down when there
is activity on MISO
and MOSI
, so it is active-low.
Let’s make the hypothesis this is a SPI flash.
We click Decode
, then select SPI flash
as a protocol and run the decoder.
After one minute of decoding, we confirm our hypothesis as there is no decoder
error, it is indeed an SPI flash!
As hinted by the challenge prompt, the goal seems to be to recover a secret from the encrypted flash using one SPI capture.
Proposed solution
We build an encrypted flash dump from the SPI capture.
Then, we use espsecure.py
, XTS_AES_256_KEY_1
and XTS_AES_256_KEY_2
to
decrypt the flash partitions.
Finally, we open the factory app partition in Ghidra and reverse the secret
value.
Building encrypted flash dump from logic analyser capture
We extract the SPI flash commands from DSView using a CSV export. Then we use the following Python script to reassemble a flash image:
|
|
We plot the entropy of the resulting image using binwalk -E spi_flash.bin
:
We observe a large block starting at 0x20000. According to the default partition table, this is the factory app partition. As the entropy is almost 1, we confirm that the partition is encrypted. Let’s extract this encrypted partition:
dd if=spi_flash.bin of=app.enc bs=131072 skip=1
We now have the encrypted factory app partition.
Decrypting factory app partition
As we were not sure of the key order or endianness, we made a Python script to quickly try a set of key and plot the entropy. If the output entropy is low, then the key is the right one.
|
|
Then decrypt and plot entropy using:
espsecure.py decrypt_flash_data --aes_xts -a 0x20000 -k key.bin -o app.dec app.enc
binwalk -E app.bin
We now have the decrypted factory app partition.
Reversing the secret value
Running strings
on the app partition reveals some useful strings such as
Wrong secret
, Correct secret !
, secret=([A-Za-z0-9]{32})
and
Your flag is :
.
As of January 2023, Ghidra does not officially support Xtensa instruction set, nor loading directly a ESP32 flash partition, but there are community contributions for these! We follow this guide to set up Ghidra: https://olof-astrand.medium.com/analyzing-an-esp32-flash-dump-with-ghidra-e70e7f89a57f.
Note that you should use ESP32-S3 SVD and esp32s3_rev0_rom.elf
ROM available at https://github.com/espressif/svd/ and https://github.com/espressif/esp-rom-elfs/releases.
After running the automatic analysis in Ghidra, we look for cross-references to
the previous found strings. After some reversing, we find the problematic
memcmp
:
|
|
We wrote the following script to retrieve the secret, then the flag:
|
|
We get the flag: INS{e$P_Fl4sh_3ncrypt1on_5uck$!}