Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Linksys EA4500 Device Firmware Decryption

Linksys EA4500 Firmware Decryption

I recently pulled a Linksys EA4500 out of storage for evaluation. The first thing I wanted to do was to update the firmware for the device. https://www.linksys.com/us/support-article?articleNum=148385 offers the latest version of the firmware, which is 3.1.7 as of this writing.

However, we can see with the filename that its probably encrypted: FW_EA4500V3_3.1.7.181919_prod.gpg.img

When I run binwalk I don't get any meaningful results, confirming my suspcicions:

$ binwalk FW_EA4500V3_3.1.7.181919_prod.gpg.img

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
3168198       0x3057C6        Cisco IOS experimental microcode, for "k"

Note that the Cisco IOS experimental microcode result is almost always a false positive, even though this is a Cisco branded device.

So we need to find the key. We know that it is a GPG key. The Linksys product support page says this:

However, if you prefer to do manual updates and your router is on version 3.1.6.166173 or older, YOU MUST download & update your router using firmware version 3.1.6 (Build 172023) first before loading the latest firmware

This leads me to believe the firmware was once not encrypted and then a subsequent version was encrypted. That means the gpg key is probably somewhere in an earlier firmware version. So next we download the version 3.1.6. The filename is thus: FW_EA4500V3_3.1.6.172023_prod.img

Note that there is no gpg substring in the file name. This leads me to believe that this firmware version is not encrypted. We run binwalk to confirm:

$ binwalk FW_EA4500V3_3.1.6.172023_prod.img

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             uImage header, header size: 64 bytes, header CRC: 0x522CD43A, created: 2016-04-21 20:36:47, image size: 1536238 bytes, Data Address: 0x80060000, Entry Point: 0x80060000, data CRC: 0xF4B0BD80, OS: Linux, CPU: MIPS, image type: OS Kernel Image, compression type: lzma, image name: "Linksys Impala Router"
64            0x40            LZMA compressed data, properties: 0x6D, dictionary size: 8388608 bytes, uncompressed size: 4555944 bytes
3145728       0x300000        Squashfs filesystem, little endian, version 4.0, compression:xz, size: 14179096 bytes, 3201 inodes, blocksize: 262144 bytes, created: 2016-04-21 21:30:41

Score! So we can use binwalk's Matryoshka extraction mode to extract the squashs filesystem:

$ binwalk -eM FW_EA4500V3_3.1.6.172023_prod.img

Now that we have the filesystem extracted for version 3.1.6, we need to go looking for something that looks like a public key.

I did a find for *.asc*, *.pem, and *.gpg to no avail, so I decided to just grep for what I was looking for:

$ grep -r 'PUBLIC KEY' .
./etc/certs/server.pem:-----BEGIN PUBLIC KEY-----
./etc/certs/server.pem:-----END PUBLIC KEY-----
./etc/keydata:-----BEGIN PGP PUBLIC KEY BLOCK-----
./etc/keydata:-----END PGP PUBLIC KEY BLOCK-----
Binary file ./lib/libcrypto.so.0.9.8 matches
Binary file ./usr/bin/gpg matches

From experience I can guess that ./etc/certs/server.pem is most likely the web management interface's TLS cert for HTTPS communications. But ./etc/keydata looking interesting:

$ file ./etc/keydata 
./etc/keydata: PGP public key block Public-Key (old)

So let's try it out and see if it can decrypt the 3.1.7 firmware version:

$ gpg --import ./etc/keydata
$ gpg --decrypt FW_EA4500V3_3.1.7.181919_prod.gpg.img > FW_EA4500V3_3.1.7.181919_prod.img

And it works! Now we have a plaintext version of the firmware:

$ file FW_EA4500V3_3.1.7.181919_prod.img
FW_EA4500V3_3.1.7.181919_prod.img: u-boot legacy uImage, Linksys Impala Router, Linux/MIPS, OS Kernel Image (lzma), 1536489 bytes, Fri Jun 16 00:41:05 2017, Load Address: 0x80060000, Entry Point: 0x80060000, Header CRC: 0x9DACD513, Data CRC: 0xA097E0E3
$ binwalk FW_EA4500V3_3.1.7.181919_prod.img

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             uImage header, header size: 64 bytes, header CRC: 0x9DACD513, created: 2017-06-16 00:41:05, image size: 1536489 bytes, Data Address: 0x80060000, Entry Point: 0x80060000, data CRC: 0xA097E0E3, OS: Linux, CPU: MIPS, image type: OS Kernel Image, compression type: lzma, image name: "Linksys Impala Router"
64            0x40            LZMA compressed data, properties: 0x6D, dictionary size: 8388608 bytes, uncompressed size: 4556000 bytes
3145728       0x300000        Squashfs filesystem, little endian, version 4.0, compression:xz, size: 15154172 bytes, 3294 inodes, blocksize: 262144 bytes, created: 2017-06-16 01:34:18

Now I can start the reverse engineering process.

It's also worth noting that although we can decrypt the firmware for reverse engineering, we cannot encrypt our own firmware to upload to the device. That integrity checking is mostly what the firmware decryption is in place for - to prevent malicious actors from uploading a modified firmware version. Because the private key is kept private, it is not possible to encrypt custom firmware. Also, my bet is that the 3.1.7 firmware has checks in place to prevent unencrypted firmware from being flashed onto the device, meaning it is probably not possible to downgrade from 3.1.7.

@kenballus
Copy link

kenballus commented Jan 21, 2021

Confirmed working on the EA6100 as well.

@m-1-k-3
Copy link

m-1-k-3 commented Jan 1, 2022

also working on FW_EA2750_1.1.8.184154_prod.gpg.img

@BrandonReynolds
Copy link

BrandonReynolds commented Jun 14, 2022

EA2500 v4 utilizes this same encryption mechanism. V1-3 do not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment