Dumping Firmware
Up to this point in previous posts I've talked about identifying chips, analyzing PINs, using tools like the BusPirate and JTAGulater, etc. Today I'm going to demonstrate a very important aspect of hardware analysis: Dumping Firmware.
I'm using a Mikrotik mAP2nd router for demonstration purposes.
First thing is to disassemble the device and gain access to the electronics.
Next is taking photographs and examining / identifying the chips:
The bottom face of the board:
Next we have to identify chips likely to contain the firmware. In this case its a:
Winbond 25Q128JVSM 3V 128M-BIT SERIAL FLASH MEMORY
Then we download and review the Datasheet: https://datasheetspdf.com/pdf-file/1462146/Winbond/25Q128JVSM/1
In the datasheet we find the PIN out map of the chip:
I started out trying to make this work with my BusPirate 4.0 but after some troubleshooting and self tests I discovered the power pins are broken so I switched to my BusPirate v3.6.
On the Winbond chip the GND, CS, CLK, and 3.3 PINs are clearly marked. The additional PINs are:
- DO: This is the Data Out pin, which corresponds to MISO (Master In Slave Out) on the BusPirate.
- DI: This is the Data In pin, which corresponds to MOSI (Master Out Slave In) on the BusPirate.
Now we attach some SALEAE probes to the PINs on the chip. NOTE: There is a dot on the chip that indicates the first PIN which is the CS PIN:
I attached my Saleae logic analyzer to the probes and attempted to identify the PIN signals but this turned out to be too noisy to be of much use:
I ended up wiring it up as follows, with the colored wires I had on hand:
WIRE COLOR CHIP PINS BPIRATE PINS
- Yellow - CS - CS
- Green - DO - MISO
- Purple - GND - GND
- Black - VCC - +3.3
- Red - CLK - CLK
- Orange - DI - MOSI
It ended up looking something like this:
The BusPirate will energize the chip so no need to plug in the router. I then ran the flashrom command to dump the firmware:
flashrom -p buspirate_spi:dev=/dev/ttyUSB0,spispeed=500k -r firmware_dump.bin -VVV
It ran for several minutes, outputing lots of bytes to the screen and eventually I saw something like this:
0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff done. programmer_unmap_flash_region: unmapped 0x0000000000000000 buspirate_sendrecv: write 1, read 0 Sending 0x00 buspirate_sendrecv: write 0, read 4 , receiving 0x42 0x42 0x49 0x4f buspirate_sendrecv: write 0, read 1 , receiving 0x31 Raw bitbang mode version 1 buspirate_sendrecv: write 1, read 0 Sending 0x0f Bus Pirate shutdown completed.
-rw-r--r-- 1 root root 16777216 Sep 9 17:47 firmware_dump.bin
Looks like it was successful! Lets check the dump file:
root@therion:~# file firmware_dump.bin firmware_dump.bin: data root@therion:~# du -sh firmware_dump.bin 16M firmware_dump.bin
Next we employ the use of binwalk to attempt to extract the firmware and get some files to analyze:
binwalk -B firmware_dump.bin
DECIMAL HEXADECIMAL DESCRIPTION
----------------------------------------------------------------
1936 0x790 CRC32 polynomial table, little endian
950480 0xE80D0 xz compressed data
<---- SNIP -------->
6369136 0x612F70 gzip compressed data, has original file name: "roteros.dll", from Unix, last modified: 2021-05-31
<---- SNIP -------->
9013347 0x898863 gzip compressed data, has original file name: "secure.dll", from Unix, last modified: 2021-05-31
9052581 0x8A21A5 gzip compressed data, has
9130578 0x8B5252 gzip compressed data, has original file name: "iframe.html", from Unix, last modified: 2021-05-31
9130689 0x8B52C1 gzip compressed data, has original file name: "uploader.html", from Unix, last modified: 2021-05-31
9131091 0x8B5453 PNG image, 7 x 7, 8-bit/color RGBA, non-interlaced
9288447 0x8DBAFF gzip compressed data, has original file name: "dhcp.dll", from Unix, last modified: 2021-05-31 07:33:47
9328697 0x8E5839 gzip compressed data, has original file name: "hotspot.dll", from Unix, last modified: 2021-05-31 07:36:35
9612831 0x92AE1F gzip compressed data, has original file name: "master-min.js", from Unix, last modified: 2021-05-31 07:12:40
9698952 0x93FE88 gzip compressed data, has original file name: "curve255-min.js", from Unix, last modified: 2021-05-31 07:12:39
9701272 0x940798 gzip compressed data, has original file name: "master.css", from Unix, last modified: 2021-05-31 06:53:12
9705404 0x9417BC gzip compressed data, has original file name: "roteros.jg", from Unix, last modified: 2021-05-31 07:27:57
9775464 0x952968 gzip compressed data, has original file name: "advtool.jg", from Unix, last modified: 2021-05-31 07:33:25
9776830 0x952EBE gzip compressed data, has original file name: "dhcp.jg", from Unix, last modified: 2021-05-31 07:33:48
9780471 0x953CF7 gzip compressed data, has original file name: "hotspot.jg", from Unix, last modified: 2021-05-31 07:36:36
<---- SNIP -------->
11046166 0xA88D16 Unix path: /sys/devices/system/cpu
11049606 0xA89A86 ELF, 32-bit MSB MIPS64 executable, MIPS, version 1 (SYSV)
<---- SNIP -------->
11144298 0xAA0C6A ELF, 32-bit MSB MIPS64 executable, MIPS, version 1 (SYSV)
<---- SNIP -------->
13527045 0xCE6805 Neighborly text, "neighbor discovery-settings set discover-interface-list=!dynamicc"
13527889 0xCE6B51 Neighborly text, "neighbor discovery-settings set discover-interface-list=LAN /tool mac-server set allowed-interface-list=LAN"
13675196 0xD0AABC xz compressed data
<---- SNIP -------->
Then we can take a look at some of the extracted files and look for interesting strings, web application source, etc.:
user@ubuntu18:~/data/_firmware_dump.bin.extracted$ cat iframe.html<html><body onload="parent.generateContent(parent.location.hash.substr(1));"></body></html><html> <head> <link rel="stylesheet" type="text/css" href="master.css"></link> </head> <style> form { display: inline; width: 100%; } input { width: 100%; height: 26px; background: #fff; border: 1px solid #888; margin: 0; padding: 1px; font-family: verdana, arial, helvetica, sans-serif; font-size: 12px; box-shadow: none; -mox-box-shadow: none; } </style> <body style="margin:0; white-space: nowrap"> <form id="form" action="/jsproxy/upload" method="post" enctype="multipart/form-data"> <input id="file" type="file" name="file"> </form> </body></html>
Here is one of the extracted binaries:
user@ubuntu18:~/data/_firmware_dump.bin.extracted$ strings A89A86.elf |more
routeros-mipsbe long-term mips RouterOS for mipsbe RouterBOARDs, includes all supported features ipv6 system mips Main package with basic services and drivers 6872ae85d171de472dcb356b395c9f03d85f55e1
bridgeports.dat bridgeports.idx switch-config.idx switch-config.dat wlccfgrule.dat wlccfgrule.idx wlcacl.dat wlcacl.idx ether1 00:00.0 switch0 10 dc:2c:6e:44:3b:e1 dc:2c:6e:44:3b:e1 ,nD; ,nD; ether2 00:00.0 switch0 20 dc:2c:6e:44:3b:e2 dc:2c:6e:44:3b:e2 gpio ,nD; ,nD; ! pwr-line1 00:00.0 switch0 50 dc:2c:6e:44:3b:e3 dc:2c:6e:44:3b:e3 ,nD; ,nD; wlan10 dc:2c:6e:44:3b:e4 dc:2c:6e:44:3b:e4 cmanifacecfg.dat cmanifacecfg.idx chain0 chain1 chain0 chain1 !6mac:0x500/0x60, phy:0x2201, a5:0x0, a2:0x0, eeprom:0x0 DC2C6E443BE MikroTik
#| Welcome to RouterOS! #| 1) Set a strong router password in the System > Users menu #| 2) Upgrade the software in the System > Packages menu #| 3) Enable firewall on untrusted networks #| 4) Set your country name to observe wireless regulations #| ----------------------------------------------------------------------------- #| RouterMode: #| * WAN port is protected by firewall and enabled DHCP client #| * Wireless and Ethernet interfaces (except WAN port/s) #| are part of LAN bridge #| LAN Configuration: #| IP address 192.168.88.1/24 is set on bridge (LAN port) #| DHCP Server: enabled; #| DNS: enabled; #| wlan1 Configuration: #| mode: ap-bridge; #| band: 2ghz-b/g/n; #| tx-chains: 0;1; #| rx-chains: 0;1; #| installation: indoor; #| wpa2: no; #| ht-extension: 20/40mhz-XX; #| WAN (gateway) Configuration: #| gateway: ether1 ; #| ip4 firewall: enabled; | NAT: enabled; #| DHCP Client: enabled; :global ssid; :global defconfMode; :log info "Starting defconf script"; #------------------------------------------------------------------------------- # Apply configuration. # these commands are executed after installation or configuration reset #------------------------------------------------------------------------------- :if ($action = "apply") do={ # wait for interfaces :local count 0; :while ([/interface ethernet find] = "") do={ :if ($count = 30) do={ :log warning "DefConf: Unable to find ethernet interfaces"; /quit; } :delay 1s; :set count ($count +1); }; :local count 0; :while ([/interface wireless print count-only] < 1) do={ :set count ($count +1); :if ($count = 40) do={ :log warning "DefConf: Unable to find wireless interface(s)"; /ip address add address=192.168.88.1/24 interface=ether1 comment="defconf"; /quit
From there we can disassemble files with IDA or Ghidra, hunt for hardcoded secrets or passwords, look for vulnerabilities, etc.
Thanks for reading!
A.