Tuesday, December 3, 2013

Binwally: Directory tree diff tool using Fuzzy Hashing

For this post, I'll discuss about the concept of directory tree and binary diffing and how it could be used to find potential vulnerabilities and security issues that were (silently) patched on firmware images.

Silent patching is a big deal as we don't have many security researchers like Spender around. This is a common practice among companies that create software and firmwares for embedded devices. Changelogs from new firmwares often contains few information about security issues, outlining the changes as "bugfixes" or "enhancements": we get no CVE's and we don't know how critical the flaws are.

In addition to that, you may occasionally find some reference for the string 'Ac1db1tch3z' on your code (which means that you got a free vulnerability assessment) or your employee Joel might forget to remove a backdoor from the firmware. Diffing the content from previous firmwares may be useful to find out when these backdoors were first installed, modified and/or removed.

I introduce you to Binwally: a simple script to perform directory tree diffing using the concept of Fuzzy Hashing (ssdeep) to define a matching score between binaries.

Binwally says "no" to Silent Patching

Fuzzy Hashing

Fuzzy Hashing, also know as context triggered piecewise hashes (CTPH), can match inputs that have homologies. Such inputs have sequences of identical bytes in the same order, although bytes in between these sequences may be different in both content and length. The concept was introduced by Andrew Tridgell and the most well-known tool is ssdeep, created by Jesse Kornblum.

The usage example outlined on ssdeep's homepage summarizes it well:
$ ls -l foo.txt
-rw-r--r--   1 jessekor  jessekor  240 Oct 25 08:01 foo.txt
$ cp foo.txt bar.txt
$ echo 1 >> bar.txt

A cryptographic hashing algorithm like MD5 can't be used to match these files; they have wildly different hashes.
$ md5deep foo.txt bar.txt
7b3e9e08ecc391f2da684dd784c5af7c  /Users/jessekornblum/foo.txt
32436c952f0f4c53bea1dc955a081de4  /Users/jessekornblum/bar.txt

But fuzzy hashing can! We compute the fuzzy hash of one file and use the matching mode to match the other one.
$ ssdeep -b foo.txt > hashes.txt
$ ssdeep -bm hashes.txt bar.txt
bar.txt matches foo.txt (64)

The number at the end of the line is a match score, or a weighted measure of how similar these files are. The higher the number, the more similar the files.

Binwally

Binwally is a simple Python script that uses this concept to diff directory trees in order to find different, unique and matching files, displaying an overall score of the results. It was based on diffall.py from the book Programming Python (4th Edition) and it requires python-ssdeep, a wrapper for ssdeep (which is coded in C). You can download the script from my Github, following the link below:


The code is pretty straightforward, it takes two dirs/files as arguments and displays which files are unique, the ones that matches and the ones that differs and their match score. It still needs some improvement (the matching score is based on the number of files and don't consider the filesizes for example) but it works fine for what it purposes to accomplish.


Comparing two directory trees from a firmware unsquased using Binwalk and firmware-mod-kit:


You can already achieve this using Winmerge, but the tool does not display a matching score, it's not command line based and not scriptable. You can check my previous post describing how to use it to differ firmware images.

Binwally is best used with Binwalk, that's why I'll talk to devttys0 to merge it with his tool (maybe a new command line switch under the Binary Diffing options). Binwalk already supports binary diffing (-H switch), but it will just compare files and firmware images. The problem is that firmware images are usually packed, encrypted and/or compressed. When you unpack and compare the extracted files and their directory tree, you have much more valuable information. If you disassemble the code and compare the results again, you get even better data - this is what bindiff from Zynamics/Google does pretty well. The Insinuator blog has a nice example on how to use bindiff for RE.

Binwally Usage: Dissecting DLink Backdoor Patch

So you may have heard recently that some DLink routers had a backdoor and that a security update was issued to address the vulnerability.

According to Bruce Schneier, we should "Trust but verify": that's what we are going to do here. First let's download the backdoored version (v1.13) and the patched version (1.14) from DLink's FTP. Next step is to extract the firmware images (binwalk -e DIR100A1_FW114WWB02.bix DIR100_v5.0.0EUb3_patch02.bix) and compare the directory trees using Binwally:

$ python binwally.py _DIR100_v5.0.0EUb3_patch02.bix.extracted/ _DIR100A1_FW114WWB02.bix.extracted/


I removed the matching files and symlinks for better reading, but the analysis is now narrowed to a small set of files. According to the release notes, a minor PPoE dial up issue was also fixed, that may be the reason why "/bin/pppd" had differences.

Some files like the "/www/Home/bsc_lan.htm" have a matching score of 100 even though they have different content and MD5, for example. This is due to the nature of Fuzzy Hashing, as the small modification was not enough to change the fuzzy hash value. It's important to note that files with a "match" result do actually have the same content and also have a matching score of 100.


There's a new Shell script on the patched 1.14 firmware, located at "/etc/wdhttp.sh". It seems that Joel "do not know how to write sash loop command ugly code":


Busybox was another binary that had a different pattern. Running them using QEMU shows that they still have the same version (v1.0.0-pre2) and different compile dates (2011.09.15 and 2013.10.31).



According to the analysis from devttys0, the binary "/bin/webs" had the backdoor function (if you did not read his analysis yet, read it here). Binwally returned a match score of 0 because it was unable to find similar patterns. The binaries have different sizes and were probably compiled using different toolchains, containing different offsets, as displayed on the diff from Winmerge:


Binwalk from v1.3.0 beta on now displays 3D binary data visualization, so let's have a look on how they differ in a 3D plane:


This is time to use an approach other than byte comparison and fuzzy hashing. Bindiff uses graph-theoretical approach to compare executables by identifying identical and similar functions. We first need to analyze both files using IDA to create the needed IDB files. After inputting both files on bindiff, we notice a high level of similarity on the Call Graphs:


Let's focus on the previously backdoored function "alpha_auth_check":


We can easily spot the difference displaying the flow graph:


Zooming in (courtesy of NSA):



It seems that Joel's "xmlset_roodkcableoj28840ybtide" is gone, say hello to "iNteLalsEtvaLuewitHoutnAme". And yes, it seems that Joel (and the binaries that can re-configure the device's settings) can only access the device from 127.0.0.1 now  =)


Conclusion

Binary and directory tree diffing is a powerful tool for reverse engineering and to find potential compromise of a system as long as you have a "known template". In the context of Embedded Systems, it reveals modified files, settings and directories, narrowing the analysis to a small set of data when analyzing different firmware images.

To all the vendors out there it's important to be transparent on what's being fixed, alerting the end-users about how critical the issues are. And please, leave the backdooring job to the guys who "read the constitution" and are paid for that, OK?

Monday, November 11, 2013

Unpacking Firmware Images from Cable Modems

Hacking Cable modems used to be very popular during the early 2000’s. People like DerEngel and Isabella from TCNiSO carried lots of research on the topic and talks from bitemytaco (R.I.P) and BlakeSelf during DEFCON 16 and DEFCON 18 covered lots of information on the subject.

Securing cable modems is more difficult than other embedded devices because, on most cases, you can’t choose your own device/firmware and software updates are almost entirely controlled by your ISP. Most cable modems offer a limited administrative interface and management commands are sent using SNMP.

Cable Modem Firmware

There are basically three types of firmware images for cable modems:

- Signed and compresed (PKCS#7 & binary)
- Compressed binary images
- RAM dump images (uncompressed & raw)

You can dump your own firmware image using JTAG or sniffing the connection during upgrades, for example. I’m a big fan of binwalk and I always wondered why it doesn't unpack firmwares from popular Broadcom based cable modems so I decided to research on this.

Unpacking the Firmware

For this analysis I’ll use Cisco DPC3925, which is a very common DOCSIS 3.0 modem here in Brazil. Cisco DPC3925 has a BCM3380 chipset, 16MB Flash x 64MB DRAM memory configuration.


The compressed firmware image has around 4MB. Using strings against the file didn't help much and binwalk v1.2.1 (without any additional parameters) did not recognize it.


We can gather lots of useful information from the vendor’s page: user guides, datasheets, licensing information and open source disclaimer for the product. There are no sources available on Cisco's home, but the Copyright Notices section states that the product uses LZMA SDK 4.21.


So we know that the firmware is probably packed using LZMA but we still need to figure out how to unpack it. Binwalk -i displays results marked as invalid during the scan and we might get some clue:


The LZMA header is not well documented. There are some good resources on lzma-purejs Github and you can also check binwalk's magic file signatures (devttys0 already did all the hard work for us).

  Offset Size  Description
    0     1    lc, lp and pb in encoded form
    1     4    dictSize (little endian)
    5     8    uncompressed size (little endian)

The Bootloader in the beggining of the flash contains the necessary information to boot the firmware image. On the top of the firmware there's always an extractor which decompress the firmware into DRAM.

Offset 0x677 is a good candidate because it's located in the beginning of the file and it seems to have a valid header. 5D 00 00 00 01 indicates a LZMA compression level of -8 and the next 64 bits should be the data's uncompressed size (in little endian).


The 64 bits following the header (00 20 20 0E 3A 28 AB EF) is clearly not a valid uncompressed size (2898643604054482944 bytes). It represents the actual compressed data, making binwalk and 7zr unable to extract it.

What we need to do here is append a few extra bytes to the header so our regular 7zr binary can recognize and extract the data. We don't know the uncompressed size for the firmware yet: the good news is that we can append and specify a big value here, allowing 7zr utility to unpack it (although complaining that the EOF was reached too early). Let's specify 268435456 bytes (256MB), convert it to little endian (00 00 00 10 00 00 00 00) and append it to the original LZMA header. The new header should be something like ... 5D 00 00 00 01 00 00 00 10 00 00 00 00 00 20 20 ...

I took the opportunity to have a look on binwalk's API and wrote a simple lzma-unpacker.py:

This code will be obsolete in a couple of days because I'm pretty sure Binwalk incorporate this (a plugin maybe?)


The data was extracted successfully and contains 21982740 bytes. If we replace the uncompressed size on the LZMA header with the correct value in Little Endian (14 6E 4F 01 00 00 00 00), the 7zr tool would not complain about the file integrity.


Most Broadcom cable modems are packed this way, including the ones manufactured by different vendors. The script was fully tested and works fine for the following models:

  - Cisco DPC3925, DPC2434
  - Motorola SB5100, SB5101, SVG6582, SVG1202
  - Thomson ACG905, DCM425, DHG534, DHG544, DWG850, DWG874
  - Webstar DPC2203

Firmware Analysis

Now that you successfully unpacked the firmware, here's a couple of cool things you should do:

- Find default passwords


- Find backdoors



- Pentest the Web Application




- Fingerprint your device and submit to NMAP

- Find similar devices using scans.io dataset

- Mail HD Moore a copy of the firmware and wait for the CVE Spam

Sunday, September 1, 2013

Analyzing and Running binaries from Firmware Images - Part 1

During the first part of SIMET Box Firmware analysis, we downloaded the firmware Image, extracted its contents, compared/analyzed its base and found a couple of interesting files (SSH keys, binary files, init scripts, firewall rules and so on).

For this part we'll focus on identifying binaries, comparing and executing them to find interesting data. Whenever you're analyzing binaries from different architectures, there are a couple of nice tools that aid debugging, reversing and emulating their behavior, like objdump, readelf and QEMU.

Embedded Debian Project provides pre-built binary toolchains for mips, mipsel, arm, armel, powerpc, and a couple of other architectures. In order to download and install it on Debian based Linux distros, you have to apt-get its archive signing key:
sudo apt-get install emdebian-archive-keyring

Now you you need to include their repository on your /etc/apt/sources.list:
deb http://www.emdebian.org/debian/ squeeze main

After the apt-get update you can install binutils for you target archs:
sudo apt-get install binutils-mips-linux-gnu binutils-mipsel-linux-gnu  binutils-arm-linux-gnueabi

For this little exercise I'll analyze three busybox binaries, from three different firmwares: busybox-simet (from SIMET Box), busybox-asuswrt (from AsusWRT-Merlin firmware) and busybox-sb6120 (from Motorolla's SB6120 Surfboard Cable Modem).

Architecture, Big-Endian or Little Endian?

When analyzing SIMET Box we already knew that the device was based on ar71xx platform, which is MIPS based and big endian as stated on OpenWRT's official page. If you want to find it by your own you can use the file utility:


Emdebian binutils also provide useful tools to identify further info from unknown binaries. A nice hack that I commonly use is to display information from object files using different toolchains in order to find out which one understands the file structure properly. For example, objdump -f displays contents of the overall file header.

  • SIMET Box tl-wr740n-v4 (architecture: mips:isa32r2, file format elf32-tradbigmips)

  • AsusWRT-Merlin v3.0.0.4.374.32 (architecture: mips:isa32 file format elf32-tradlittlemips)

  • SB6120 v1.0.2.4-SCM01 (architecture: arm, file format elf32-bigarm)

We now know each file's format/architecture and can proceed using QEMU to emulate the binaries on a virtual environment.

QEMU

QEMU is a generic and open source machine emulator and virtualizer that supports architectures like MIPS, ARM and PowerPC. In order to setup and run single binaries with QEMU on Debian based Linux distributions, you need to install the qemu-user-static package. RogueAsian and devtty0 detail these steps here and here.
sudo apt-get install qemu-user-static

It's important to run qemu on a chrooted environment to avoid mixing your target's libraries with those on your host system.

AsusWRT-Merlin v3.0.0.4.374.32

Let's try this on AsusWRT's busybox first. We'll have to use qemu-mipsel-static because it's MIPS32 based and Little Endian.


Hmmm, not so lucky this time, ld-uClibc.so is missing. Let's check the dynamic section and copy the necessary libraries from the original firmware:
mips-linux-gnu-objdump -x bin/busybox-asuswrt | grep lib


We can also cross compile these libraries on our own or install the target C libraries with dpkg-cross, but using the firmware original libraries is always preferred. After copying the necessary files, we can finally execute it using QEMU:
cp `whereis qemu-mipsel-static | cut -d" " -f2` .
sudo chroot . ./qemu-mipsel-static bin/busybox-asuswrt


SB6120 v1.0.2.4-SCM01

Let's try to run busybox from Motorolla's cable modem Surfboard SV6120 (ARM/Big Endian):

cp `whereis qemu-armeb-static | cut -d" " -f2` .
sudo chroot . ./qemu-armeb-static bin/busybox-sb6120


BusyBox v1.4.2, might be vulnerable to CVE-2011-2716 =)

SIMET Box tl-wr740n-v4

Running the busybox binary extracted from SIMET Box (MIPS/Big Endian):

cp `whereis qemu-mips-static | cut -d" " -f2` .
sudo chroot . ./qemu-mips-static bin/busybox-simet
mips-linux-gnu-readelf -h bin/busybox-simet


Unfortunately, qemu-mips-static did not recognize the ELF image properly and was unable to run SIMET Box's binaries on the fly. For the next post I'll detail on how to overcome this issue with SIMET Box's busybox by running a full OpenWRT MIPS environment on QEMU. This is useful because we can compile and run our own (compatible) kernel, set up a network device, analyze the network activity and its system-wide interactions.

Conclusion
These techniques help identifying unknown binaries from unknown architectures and running them on a virtual environment. They might be useful to analyze malware for embedded systems (Internet Census 2012 anyone?), during forensic analysis and to hack/find vulnerabilities on firmware images.


Sunday, August 25, 2013

SIMET Box Firmware Analysis: Embedded Device Hacking & Forensics

For my first blog post I decided to have a quick look on the firmware from SIMET Box. SIMET is organized by the Brazilian NIC.br in order to test and monitor the Internet speed across the country. For more info (in portuguese) visit their site here. All the data collected is available to the community on reports and heat maps like this.

The organization is now handing out free Wi-Fi routers to Brazilians in order to measure the Internet quality on different regions. The SIMET Box equipment is a custom TL-WR740N pre-installed with OpenWRT. You can also download and install the standalone firmware on other TPLink's SOHO routers.



The project is quite interesting but in times of PRISM and NSA I don't like the idea of using a "black box" at home, so I decided to check its design.

Firmware

As I don't have the actual box, I'll analyze SIMET Box's firmware image. The firmware can be downloaded from http://simet.nic.br/firmware. For this initial analysis I'll be using simetbox-tl-wr740n-v4.bin (MD5 d08798093e1591bece897671e96b5983).


Let's start by using Craig Heffner's binwalk and firmware-mod-kit to unsquash the filesystem:

binwalk -Me simetbox-tl-wr740n-v4.bin


After extracting the files we can browse through the squashfs-root dir and grep files to identify OpenWrt's version base:


We now know that SIMET Box is based on Attitude Adjustment branch (v12.09) for Atheros AR71xx, downloadable on OpenWRT's official site: openwrt-ar71xx-generic-tl-wr740n-v4-squashfs-factory.bin.

After extracting the base firmware (using binwalk) we now have two directory trees to diff. We can use WinMerge or Kdiff3 to compare files.


 

There are some new init.d scripts like atualiza_arqs, autossh, miniupnpd and zabbix_agentd:


Lots of binaries (/bin/busibox for example) are quite similar: they may have a small version difference or were compiled using particular command line arguments:


List of files created by SIMET Box (not present on the OpenWrt's base firmware):
while read -r i ; do file $i ; done < list.txt
/etc/config/autossh: ASCII text
/etc/config/upnpd: ASCII text
/etc/dropbear/authorized_keys: OpenSSH DSA public key
/etc/dropbear/id_rsa: data
/etc/hotplug.d/button/00-button: ASCII text
/etc/hotplug.d/iface/20-autossh: POSIX shell script, ASCII text executable
/etc/hotplug.d/iface/50-miniupnpd: POSIX shell script, ASCII text executable
/etc/init.d/atualiza_arqs_simet: POSIX shell script, ASCII text executable
/etc/init.d/autossh: POSIX shell script, ASCII text executable
/etc/init.d/miniupnpd: POSIX shell script, ASCII text executable
/etc/init.d/zabbix_agentd: POSIX shell script, ASCII text executable
/etc/rc.d/S11sysctl: symbolic link to `../init.d/sysctl'
/etc/rc.d/S19firewall: symbolic link to `../init.d/firewall'
/etc/rc.d/S45atualiza_arqs_simet: symbolic link to `../init.d/atualiza_arqs_simet'
/etc/rc.d/S60zabbix_agentd: symbolic link to `../init.d/zabbix_agentd'
/etc/rc.d/S80autossh: symbolic link to `../init.d/autossh'
/etc/rc.d/S95miniupnpd: symbolic link to `../init.d/miniupnpd'
/etc/uci-defaults/50-reset: POSIX shell script, ASCII text executable
/etc/uci-defaults/50-reset-wps: POSIX shell script, ASCII text executable
/etc/uci-defaults/50-wifi: POSIX shell script, ASCII text executable
/etc/uci-defaults/99-miniupnpd: POSIX shell script, ASCII text executable
/etc/uci-defaults/luci-i18n-portuguese_brazilian: POSIX shell script, UTF-8 Unicode text executable
/etc/uci-defaults/luci-theme-bootstrap: POSIX shell script, ASCII text executable
/etc/uci-defaults/luci-upnp: POSIX shell script, ASCII text executable
/etc/zabbix_agentd.conf: ASCII text
/lib/libpthread-0.9.33.2.so: ELF 32-bit MSB shared object, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked (uses shared libs), corrupted section header size
/lib/libpthread.so.0: symbolic link to `libpthread-0.9.33.2.so'
/root/.ssh/known_hosts: ASCII text, with very long lines
/sbin/fw3: ELF 32-bit MSB executable, MIPS, MIPS32 rel2 version 1, dynamically linked (uses shared libs), corrupted section header size
/usr/bin/auto_upgrade: symbolic link to `simet_tools'
/usr/bin/checa_udhcpc.sh: POSIX shell script, ASCII text executable
/usr/bin/get_mac_address.sh: POSIX shell script, ASCII text executable
/usr/bin/simet_client: ELF 32-bit MSB executable, MIPS, MIPS32 rel2 version 1, dynamically linked (uses shared libs), corrupted section header size
/usr/bin/simet_dns: symbolic link to `simet_tools'
/usr/bin/simet_porta25: symbolic link to `simet_tools'
/usr/bin/simet_tools: ELF 32-bit MSB executable, MIPS, MIPS32 rel2 version 1, dynamically linked (uses shared libs), corrupted section header size
/usr/bin/sshreversetunnel: POSIX shell script, ASCII text executable
/usr/bin/teste_spoofing.sh: POSIX shell script, ASCII text executable
/usr/bin/wifionoff: POSIX shell script, ASCII text executable
/usr/lib/lua/luci/controller/simet.lua: ASCII text
/usr/lib/lua/luci/controller/upnp.lua: ASCII text
/usr/lib/lua/luci/i18n/base.pt-br.lmo: data
/usr/lib/lua/luci/i18n/upnp.ca.lmo: data
/usr/lib/lua/luci/i18n/upnp.cs.lmo: data
/usr/lib/lua/luci/i18n/upnp.de.lmo: data
/usr/lib/lua/luci/i18n/upnp.es.lmo: data
/usr/lib/lua/luci/i18n/upnp.fr.lmo: data
/usr/lib/lua/luci/i18n/upnp.hu.lmo: data
/usr/lib/lua/luci/i18n/upnp.it.lmo: data
/usr/lib/lua/luci/i18n/upnp.ja.lmo: data
/usr/lib/lua/luci/i18n/upnp.no.lmo: data
/usr/lib/lua/luci/i18n/upnp.pl.lmo: data
/usr/lib/lua/luci/i18n/upnp.pt-br.lmo: data
/usr/lib/lua/luci/i18n/upnp.pt.lmo: data
/usr/lib/lua/luci/i18n/upnp.ro.lmo: data
/usr/lib/lua/luci/i18n/upnp.ru.lmo: data
/usr/lib/lua/luci/i18n/upnp.vi.lmo: data
/usr/lib/lua/luci/i18n/upnp.zh-cn.lmo: data
/usr/lib/lua/luci/model/cbi/upnp/upnp.lua: ASCII text
/usr/lib/lua/luci/sgi/uhttpd.lua: ASCII text
/usr/lib/lua/luci/view/admin_status/index/upnp.htm: ASCII text
/usr/lib/lua/luci/view/simet/simet.htm: HTML document, UTF-8 Unicode text
/usr/lib/lua/luci/view/themes/bootstrap/footer.htm: HTML document, ASCII text
/usr/lib/lua/luci/view/themes/bootstrap/header.htm: HTML document, ASCII text
/usr/lib/lua/luci/view/upnp_status.htm: HTML document, ASCII text
/usr/lib/opkg/info/autossh.conffiles: ASCII text
/usr/lib/opkg/info/autossh.control: ASCII text
/usr/lib/opkg/info/autossh.list: ASCII text
/usr/lib/opkg/info/hping3.control: ASCII text
/usr/lib/opkg/info/hping3.list: ASCII text
/usr/lib/opkg/info/libip6tc.control: ASCII text
/usr/lib/opkg/info/libip6tc.list: ASCII text
/usr/lib/opkg/info/libnfnetlink.control: ASCII text
/usr/lib/opkg/info/libnfnetlink.list: ASCII text
/usr/lib/opkg/info/libopenssl.control: ASCII text
/usr/lib/opkg/info/libopenssl.list: ASCII text
/usr/lib/opkg/info/libpcap.control: ASCII text
/usr/lib/opkg/info/libpcap.list: ASCII text
/usr/lib/opkg/info/libpthread.control: ASCII text
/usr/lib/opkg/info/libpthread.list: ASCII text
/usr/lib/opkg/info/luci-app-simet.control: ASCII text
/usr/lib/opkg/info/luci-app-simet.list: ASCII text
/usr/lib/opkg/info/luci-app-upnp.control: ASCII text
/usr/lib/opkg/info/luci-app-upnp.list: ASCII text
/usr/lib/opkg/info/luci-i18n-portuguese-brazilian.control: ASCII text
/usr/lib/opkg/info/luci-i18n-portuguese-brazilian.list: ASCII text
/usr/lib/opkg/info/luci-sgi-uhttpd.control: ASCII text
/usr/lib/opkg/info/luci-sgi-uhttpd.list: ASCII text
/usr/lib/opkg/info/luci-theme-bootstrap.control: ASCII text
/usr/lib/opkg/info/luci-theme-bootstrap.list: ASCII text
/usr/lib/opkg/info/miniupnpd.conffiles: ASCII text
/usr/lib/opkg/info/miniupnpd.control: ASCII text
/usr/lib/opkg/info/miniupnpd.list: ASCII text
/usr/lib/opkg/info/simet-base-files.control: ASCII text
/usr/lib/opkg/info/simet-base-files.list: ASCII text
/usr/lib/opkg/info/simet-client.control: ASCII text
/usr/lib/opkg/info/simet-client.list: ASCII text
/usr/lib/opkg/info/simet-tools.control: ASCII text
/usr/lib/opkg/info/simet-tools.list: ASCII text
/usr/lib/opkg/info/uhttpd-mod-lua.control: ASCII text
/usr/lib/opkg/info/uhttpd-mod-lua.list: ASCII text
/usr/lib/opkg/info/zabbix-agentd.control: ASCII text
/usr/lib/opkg/info/zabbix-agentd.list: ASCII text
/usr/lib/opkg/info/zlib.control: ASCII text
/usr/lib/opkg/info/zlib.list: ASCII text
/usr/lib/libcrypto.so.1.0.0: ELF 32-bit MSB shared object, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, corrupted section header size
/usr/lib/libip6tc.so: symbolic link to `libip6tc.so.0.0.0'
/usr/lib/libip6tc.so.0: symbolic link to `libip6tc.so.0.0.0'
/usr/lib/libip6tc.so.0.0.0: ELF 32-bit MSB shared object, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, corrupted section header size
/usr/lib/libjson-c.so.2: symbolic link to `libjson-c.so.2.0.1'
/usr/lib/libjson-c.so.2.0.1: ELF 32-bit MSB shared object, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, corrupted section header size
/usr/lib/libnfnetlink.so.0: symbolic link to `libnfnetlink.so.0.2.0'
/usr/lib/libnfnetlink.so.0.2.0: ELF 32-bit MSB shared object, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, corrupted section header size
/usr/lib/libpcap.so: symbolic link to `libpcap.so.1.1'
/usr/lib/libpcap.so.1.1: symbolic link to `libpcap.so.1.1.1'
/usr/lib/libpcap.so.1.1.1: ELF 32-bit MSB shared object, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, corrupted section header size
/usr/lib/libssl.so.1.0.0: ELF 32-bit MSB shared object, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, corrupted section header size
/usr/lib/libz.so: symbolic link to `libz.so.1.2.7'
/usr/lib/libz.so.1: symbolic link to `libz.so.1.2.7'
/usr/lib/libz.so.1.2.7: ELF 32-bit MSB shared object, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, corrupted section header size
/usr/lib/uhttpd_lua.so: ELF 32-bit MSB shared object, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, corrupted section header size
/usr/sbin/autossh: ELF 32-bit MSB executable, MIPS, MIPS32 rel2 version 1, dynamically linked (uses shared libs), corrupted section header size
/usr/sbin/hping3: ELF 32-bit MSB executable, MIPS, MIPS32 rel2 version 1, dynamically linked (uses shared libs), corrupted section header size
/usr/sbin/miniupnpd: ELF 32-bit MSB executable, MIPS, MIPS32 rel2 version 1, dynamically linked (uses shared libs), corrupted section header size
/usr/sbin/zabbix_agentd: ELF 32-bit MSB executable, MIPS, MIPS32 rel2 version 1, dynamically linked (uses shared libs), corrupted section header size
/usr/share/libiwinfo/hardware.txt: ASCII text
/usr/share/miniupnpd/firewall.include: POSIX shell script, ASCII text executable
/www/luci-static/bootstrap/cascade.css: assembler source, ASCII text
/www/luci-static/bootstrap/favicon.ico: MS Windows icon resource - 1 icon
/www/luci-static/bootstrap/html5.js: HTML document, ASCII text, with very long lines
/www/simet/ceptro.png: PNG image data, 78 x 30, 8-bit colormap, non-interlaced
/www/simet/cgi.png: PNG image data, 46 x 30, 8-bit colormap, non-interlaced
/www/simet/nic.png: PNG image data, 47 x 25, 8-bit colormap, non-interlaced
/www/simet/nonet.htm: UTF-8 Unicode text
/www/simet/offline.jpg: JPEG image data, EXIF standard
/www/simet/simetbox_minilogo.png: PNG image data, 111 x 23, 8-bit colormap, non-interlaced
/www/simet/view_tab.css: assembler source, ASCII text
/www/simet/view_tab.js: UTF-8 Unicode text, with very long lines

This simple technique is quite useful for forensic analysis of embedded devices, as you have a white-list of known binaries and config files. It's important to review both created and modified files, but I'll focus on the ones listed above. Each binary and config file can be reviewed separately so we can find interesting entries like:

  • SSH reverse tunnel settings and authorized_keys:
  • Password changing scripts and Iptables rules:

  • The device management starting page has an external iframe and users are identified by their MAC Address via HTTP GET requests:

  • Cronjobs to test external access to port 25 and if the ISP allows IP spoofing:
  • Script using hping3 to test if the user's ISP allows packet spoofing:

  • Zabbix agent settings:

As a quick advice to SIMET engineers, it would be nice to have HTTPS for those external queries, a bit more of transparency on what the equipment does internally, who's able to access it (whose authorized_keys are those?), what external IP addresses it communicates with and what information is being collected. Securing SOHO modems is very important, specially here in Brazil where lots of recent attacks were targeting these devices (Fabio Assolini's talk "The tale of one thousand and one DSL modems" detailed this a year ago).

On the next post I'll detail how to run those MIPS32 binaries on a virtual environment using QEMU and analyze some of the files with IDA Pro.