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/ and we are greeted with a secret
value prompt and a link to
https://espmyadmin.insomnihack.ch/config and we get some information:
- the chip is an ESP32-S3,
- encryption is set to
Enabled (DEVELOPMENT) - AES-256,
- Wi-Fi MAC is
- then we get eFuses values, including
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
- 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_xtsflag (AES-XTS mode).
After a quick search online, we learn that
.dsl files are
We open it using DSView, and we get 4 logic signals:
CLK. This is an SPI interface. The chip select
CS is pulled down when there
is activity on
MOSI, so it is active-low.
Let’s make the hypothesis this is a SPI flash.
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.
We build an encrypted flash dump from the SPI capture.
Then, we use
decrypt the flash partitions.
Finally, we open the factory app partition in Ghidra and reverse the secret
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
strings on the app partition reveals some useful strings such as
Correct secret !,
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
We wrote the following script to retrieve the secret, then the flag:
We get the flag: