( original text by @boredpentester )
At this point we’re actually reversing ESP8266 firmware to understand the functionality, specifically, we’d like to understand what the loop function does, which is the main entry point once booted.
Reversing the loop function
I’ve analysed and commented the assembly below to detail guessed ports, functions and hostnames:
From the above, we’ve determined that:
Is loading a pointer to the hostname variable into the a12 register. This is followed by loading of what looks like a port number into various other registers, again followed by a call0 instruction. This behaviour led me to guess this is likely our connect() function.
From this analysis, we’ve determined our port knocking sequence to be as follows:
With the application connecting predictably, to services.ioteeth.com on port 445.
With that, we’ve effectively solved the challenge! All that’s left is to get the secrets!
Getting the secrets!
In order to obtain the secrets, we need to knock on the now known ports in the correct order. We can do this in various ways, using nmap or even netcat, but I prefer to use the knock binary, as it’s purpose built (and is part of the knockd package).
Accessing the service, we receive the following:
In this post, we set out to understand how a particular firmware image communicated with external services to apparently obtain secrets. We knew nothing about the firmware initially and wanted to describe a methodology for analysing unknown formats.
Ultimately we’ve taken the following steps:
- Analysed the file using common Linux utilities file, binwalk, strings and hexdump
- Made note that our firmware image is based on the ESP8266 and is likely performing a form of port knocking, prior to accessing secrets, based on the strings within.
- Performed research, as well as reversed open source tools, to understand the hardware on which the firmware image runs, its processor, boot process and the memory layout, as well the firmware image format itself.
- Equipped our tools with the appropriate additions to understand the Xtensa processor.
- Written a loader for IDA that’s capable of loading future firmware images of this format.
- Came to understand the format of compiled code prior to being exported as a firmware image.
- Written and compiled our own code for the ESP8266 to obtain debugging symbols.
- Patched and made use of FireEye’s IDB2PAT IDA plugin, to generate FLIRT signatures from our debug build.
- Applied our FLIRT signatures across our target firmware image, to recognise library functions.
- Observed the use of vtable’s to call library functions and used this to classify other unknown library functions.
- Used references to functions of known and likely libraries to locate the firmware image’s main processing loop.
- Reverse engineered the main loop function to understand our port knocking sequence.
- Made use of the knock client to perform our port knocking and reap all of the secrets!
I’d like to think that this methodology can be applied more generally when analysing unknown binaries or firmware images. In this case, we were fortunate in that most of the internals had been documented already and as documented here, our job was to put the pieces together. I’d encourage the reader to look at other firmware images, such as router firmware for example.
Special thanks to the author’s of the following for their insight:
- https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/examples/WiFiClient/WiFiClient.ino – ESP8266 Wifi Connect Example
- https://richard.burtons.org/2015/05/17/decompiling-the-esp8266-boot-loader-v1-3b3/ – Decompiling the boot loader
- https://github.com/nodemcu/nodemcu-firmware/tree/c8037568571edb5c568c2f8231e4f8ce0683b883 – NodeMCU tools
- https://github.com/espressif/esptool – used to understand the firmware format
- http://developers-club.com/posts/255135/ – describes memory layout and format
- http://developers-club.com/posts/255153/ – describes memory layout and format
- https://github.com/fireeye/flare-ida – FireEye’s IDB2PAT plugin!
- https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map – segment memory map!
- https://en.wikipedia.org/wiki/ESP8266 – Description of the device
- http://wiki.linux-xtensa.org/index.php/ABI_Interface – Xtensa calling convention
- http://cholla.mmto.org/esp8266/xtensa.html – Xtensa instruction set
- https://en.wikipedia.org/wiki/ESP8266 – ESP8266 Wiki page
- IDA 6.8.
- IDA FLAIR Utils 6.8.
- Xtensa IDA processor plugin.
- Linux utils: file, strings and hexdump.
- FireEye’s IDB2PAT.
- Knock of the Knockd package.
I’m always keen to hear feedback, be it corrections or comments more generally. Drop me a tweet and feel free to share this post, as well as your own experiences reverse engineering firmware.
In future posts, I’ll be taking apart common, cheap ‘smart’ products such as doorbells and other things I’d like to use at home.