Security Embedded is 12+ years of experience in building secure systems. Learn more about how we can help you by exploring Phil's blog or contacting us.

Attacking Firmware Loads

Firmware is the heart and soul of an embedded device. It's also the softest place to attack. Attacking firmware requires at least some static analysis or debugging a live device. So the bar isn't low for these attacks, but it isn't rocket science, either.

Let's pick up where we left off with our 88MC200-based IoT device. This microcontroller has a SPI flash package on-board. We could decap the chip, build a jig for the SPI flash die and read it out that way. That involves some pretty unpleasant chemicals though, and is pretty destructive. Let's call that plan 'Z'... there has to be lower hanging fruit.

Before we can find an easy attack vector, we should gather all the information we can on how the device we're attacking works. For this device, an Android or iOS app is its interface and controller. Android applications are a bit easier to muck around with, so let's grab the APK for the application.

If you're looking at Android apps, you'll want to grab apktool. While APK files are JAR archives, Android uses custom encoding for its resources. apktool takes the effort out of this, and generates human readable outputs. As a bonus, it also disassembles Dalvik bytecode (still used by the Android Runtime in modern Android) as Smali, a human-readable version of the code.

As a quick aside, the Dalvik bytecode machine model is for a register machine. So following variables and values is pretty simple. Basic familiarity with Java is helpful. All those handy automatic coercions in the language are explicit in the disassembly.

Let's find a trail of breadcrumbs we can follow in our disassembled APK:

> grep -ri "http://" | wc -l
13353

That's a non-starter. But on closer inspection:

assets/m1_source.txt:14027:Local FM 105.7 =http://stream.nxs.nl/asx/local/Stream

Let's remove this file from the running. As well, there are some XML files that contain schema URLs so let's make sure they're not considered:

> grep -rin "http://" | grep -v "schemas.android.com" | grep -v m1_source.txt | wc -l
347

Getting better. Glancing at what grep found, this file stands out:

smali_classes2/com/XXXCompany/XXXProduct/net/data/ApiUrls.smali

This looks promising. Let's look in this file for "firmware":

.field public static final FIRMWARE_UPDATA_LIST:Ljava/lang/String; = "http://fwversions.XXXCompany.com/getfwversion?devicetype=%1$s"

BINGO! This is almost too easy. So when we visit the URL as-is:

< HTTP/1.1 409 Conflict
* Server nginx/1.4.6 (Ubuntu) is not blacklisted
< Server: nginx/1.4.6 (Ubuntu)
< Date: Sun, 10 Jul 2016 14:11:52 GMT
< Content-Type: text/plain; charset=utf-8
< Content-Length: 24
< Connection: keep-alive
<
parameters not complete

This is starting to look promising. Those who are familiar with java.string.String will note the "%1$s" field in the URL. We should be passing this string through java.string.Formatter. A quick glance at the documents tells us that the '$s' format specification tells us to expect a java.lang.Short. OK, let's put a random short in there, say, 0:

< HTTP/1.1 404 Not Found
* Server nginx/1.4.6 (Ubuntu) is not blacklisted
< Server: nginx/1.4.6 (Ubuntu)
< Date: Sun, 10 Jul 2016 14:14:50 GMT
< Content-Type: text/plain; charset=utf-8
< Content-Length: 19
< Connection: keep-alive
<
404 page not found

So 0 is not a valid device. We could write a script to brute-force identify all valid devices. This seems rude, and like something that will earn us unwanted attention. Let's go back to the Smali disassembly and see who uses this string:

> grep -r FIRMWARE_UPDATA_LIST *
smali_classes2/com/XXXCompany/XXXProduct/net/data/ApiUrls.smali:.field public static final FIRMWARE_UPDATA_LIST:Ljava/lang/String; = "http://fwversions.XXXCompany.com/getfwversion?devicetype=%1$s"

Uh oh. Can we at least find the URL used elsewhere?

> grep -r fwversions *
smali/com/XXXCompany/XXXProduct/activity/FirmwareUpdateActivity$a.smali: const-string v2, "http://fwversions.XXXCompany.com/getfwversion?devicetype=%1$s"
smali_classes2/com/XXXCompany/XXXProduct/net/data/ApiUrls.smali.field public static final FIRMWARE_UPDATA_LIST:Ljava/lang/String; = "http://fwversions.XXXCompany.com/getfwversion?devicetype=%1$s"

OK, so the constant is either duplicated in code, or the Dalvik compiler was being clever. The FirmwareUpdateActivity generates a URL using a field called deviceType. A few quick greps through the code leads us to this file:

./com/XXXCompany/XXXProduct/data/DeviceType.smali

which contains all our device type codes as a list of constants. Like stealing candy from a baby.

Our device in question has the code 10117 according to this file. So what happens when we visit the above URL with that device code?

< HTTP/1.1 200 OK
* Server nginx/1.4.6 (Ubuntu) is not blacklisted
< Server: nginx/1.4.6 (Ubuntu)
< Date: Sun, 10 Jul 2016 14:36:29 GMT
< Content-Type: application/json
< Content-Length: 217
< Connection: keep-alive
< Accept-Ranges: bytes
< Last-Modified: Sat, 02 Jul 2016 04:29:55 GMT
<
{"2":{"versions":[{"version":"20026","url":"http://jp-fwversions.XXXCompany.com/firmware/download/10117/20026.bin","date":"2016-07-02","changelog":{"cn":"修复bug:\n 1、修复bug","en":"fix time task bug"}}]}}

Bingo! Let's grab that firmware image, and fire up our hex editor...

An attack is already brewing at this point. There's no authentication of update notification. Creating an authentication server that simulates this one should be a piece of cake. Before we can do that, we need to be able to craft our own firmware image. Stay tuned, we'll dive into that next time.

What's in a Firmware Load?

What Are You Leaving on the FR4* Table?