Insomni’Hack 2017 write-up : Internet Of Fail – 400

Challenge :

The « This » link give you a file named: iof-07439bc6dfe424ad52e70c05684e3b1b87badf69.elf (392Kb)

(you can download the binary HERE) display this:

Have a look to the ELF file, what kind of hardware did Balda choose ? …

What -the fuck- is this target ? First guess helped with Google was a ESP8266 board.

Playing with « strings » command give us a little more :

The folder with the name esp32 give us the target : ESP32, the little brother of the ESP8266.

2 others strings are the 2 web pages : it clearly give the game, you need to submit the good password, then the flag is a sha1() of the founded password.

The pain to get THE tools

Search for « reversing esp32 code » and you get *0* reply. Easy. About reversing the ESP8266, you are more lucky but nothing will do the job straight away.

The first idea is to send the file to It looks like it failed, but we’ll find later it was a not so bad disassembling. Only the entry point was bad, and we’ve think it didn’t manage to disassemble all the op-codes, we were wrong.

Digging again with « strings » give us that the ELF was generated with crosstool-NG. We download the official development dev-kit : . Objdump is always your friend and objdump was inside.

Opening the file give us something clean and neat. But a 175000+ lines in a single flat file opened with vi doesn’t help you that much to understand something.

Looking for a modern disassembling tool is needed. IDA-PRO doesn’t help, the target is unknown. Even adding a Xtensa plug-in doesn’t work at all.

Google point us Radare2 ! But the Debian packaged version was not able to handle the Xtensa assembler. It is mandatory to build Radare2 from the source code.

Intermediate point

  • We can’t run and debug live the device, we don’t have the good board.
  • We’ve not found any simulator that can run the firmware.
  • We can at least hope for a static analysis but …
  • We don’t know the Xtensa op-code
  • We’ve never used Radare2

OK, everything is under control.

Find an entry point

Even if IDA doesn’t display Xtensa op-code it handle nice the ELF file regarding the sections, offset, strings etc. Interesting strings and their memory locations :

The string containing the winning page is at address 0x3f406834. If if we locate a reference to this string, we should not be too far from the password checking code.

Let’s introduce you Radare2 !

It’s never too late to do the good things, but we need to learn Radare2 in a few minutes. This page from Thanat0s help us a lot (the whole blog is full of nice stuff) !

Here is what a 5 minutes tutorial gives on the binary firmware :

With Radare2 we’ve found an address using the pointer to the winning string. Address 0x400d0ad4. But, all the op-code in this sector doesn’t seems to look some good. When you look binary, you see a table of pointer. Unfortunately no more reference to 0x400d0ad4 in the code …

Let’s go back to the xtensa-esp32-elf-objdump output. We where more lucky with this one (remember we never used Radare2 before …).

The upper op-codes looks like nice, register, pointers etc. The new interesting address become 0x401040ab.

After doing our homework on Radare2, here is the interesting zone :

All the decision rely on the beqz.n a10, 0x401040bd . This means that our new interesting address is the function 0x40103fe8 :

According to the two last screenshots we know the path in the code to display. More interesting, we know where the result of the password checking is stored : 0x400d0a98. This result must be equal to 0xffff at the end of those 22 functions or it’ll never reach the display of the winning page.

Xtensa op-code, or how to learn a new target in 5 minutes

Now, we must start the hard job : reverting the 22 functions and compute the password to submit for displaying the winning page. A major problem is the Xtensa op-codes : a sort of RISC unaligned CPU, with 2 ou 3 (!!!) bytes instructions set. Little endian. Damn !

You can download the 662 pages reference guide HERE (xtensa Instruction Set Architecture (ISA) Reference Manual.pdf) .

Some funny instructions, wont give the sense, just guess :

  • slli a8, a6, 4
  • extui a9, a7, 4, 4
  • entry a1, 48
  • memw
  • quou a2, a10, a8

Now the big deal, looking inside the 22 functions

21 on 22 functions have the same pattern, exemple :

21 functions do this pseudo-code (1 function is a simple xor) :

The difficulty is that NOT ALL the 21 functions must be called …

This is a good thing, because not all the sub-function have sense : some are impossible compute, some are non-printable chars etc.

To be more accurate in witch function we need to reverse, we’ve extracted all the xored values at the end of each function. Then we’ve tried to find a path to obtain 0xffff as result. Here is the table « function / xored values » :

Then, the possible paths to obtain 0xffff (each bit to 1) as result are :

Witch give this simple path :

But, that’s the theory … It never works as is because we for sure made a mistake somewhere :). Anyway, it has help a little to select the function to reverse.

Recover the 0x400d0aa0 empty buffer …

As we where quiet sure of our kung fu, we’ve got another problem :

During the reverse of the 21 functions, some use the content of address 0x400d0aa0. This address is in the RAM zone, and in static analysis, you’re stuck.

While seeking on the whole assembly we found this peace of code :

This function looks like a regular sprintf to construct the HTTP reply from the device. The code look like this :

The interesting thing is that now we can guess what is the value, a MAC address and Balda was kind enough to insert it in the HTTP reply. Let’s dump a request to the server :

The empty 6 bytes buffer is now known : *0x400d0aa0 = 18fe346a95fc

Finish him !!

Now we have everything to compute all 21 functions, here is a summary of the whole reverse process :

We can deduct the password is G0t_yoU_xt3ns4!

The flag is INS{0c89d3e733a40a02a3dffbe0a0a902b78590d225}.

What we’ve done the wrong way

When you are in CTF context only one thing matter : the FLAG. Quick and dirt, no rules. But here is a list of things we should have tried and for sure have a better (faster) success :

  • The firmware use FreeRTOS. Trying to reverse regarding the library included should give some good results and probably a good mapping of each part of the firmware.
  • Try to compile with the same crosscompil tools and compare your own « Hello world ! » served the same way. It should provide us valuable information under GDB with the symbols. As we used objdump from the official crosscompil tools, the dev-env was ready.
  • The ESP32 have a rom. On github we found this file: esp32.rom.ld . We didn’t exploit this but we bet that’s a way to understand better all the code.

Hey men, it’s time to go now

The CTF last a WE. We start looking this task Saturday AM 10h and we flag it Sunday PM 9h40, 20 minutes before the end of the game. OK, it was not a 36H run, but it takes a lot of time to get ride of all the Balda’s traps. This write-up only give the path to get the solution, but forget a lot of invalids try ;). q3k from Dragon Sector solved it in 9H.

Those kind of hardware reverse engineering are very interesting : you learn a lot of trix using tools various, some new CPU / instructions sets and you overhaul various skills.

For the tenth anniversary of Insomni’Hack CTF, well done Baldanos, a nice challenge ! And a big thanks to SCRT team for the CTF & Insomni’Hack since the beginning.



Challenge solved by Azox (azox @8008135_) & Phil (@CaptainRicard)

Write-up by Phil

Challenge by Balda ( @Baldanos or )

Pièces jointes

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Post Navigation