How we remotely identify Cisco's RV34X versions
A quick research into remotely identifying Cisco’s RV43Xs
Trigger
We decided to identify those VPN routers on the Internet when we noticed signs that a critical vulnerability could be exploited.
Methodology
Find a target set
With no software name or version available we finally prepared a search query including a JARM filter :
+http.status:301 +jarm:"29d29d00029d29d21c29d29d29d29d881e59db99b9f67f908be168829ecef9" +"Location: ./login.html" +"Content-Length: 178"
This LeakIX service query allowed us to find all the RV34x we currently have in index.
Analyse the targets
With multiple panel at our disposal, we started searching for version numbers anywhere in the code.
Nothing caught our eye in those scripts. They are reused across multiple versions.
We then noticed the static files were returning Last-Modified
headers :
Checking facts
We decided to start correlating those headers to actual release dates.
To our surprise on the targets, the dates weren’t matching any version whatsoever and where pretty random.
Extracting the firmware
One thing that caught my attention is the software nginx mentioned in the Server
header.
Surely that can’t be an IOS firmware, so we downloaded the files from Cisco’s
website (RV34X-v1.0.03.24-2021-10-22-09-51-15-AM.img
) to investigate with it binwalk:
$ binwalk ~/Downloads/RV34X-v1.0.03.24-2021-10-22-09-51-15-AM.img
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 uImage header, header size: 64 bytes, header CRC: 0x3856B86F, created: 2021-10-22 04:21:20, image size: 74890751 bytes, Data Address: 0x0, Entry Point: 0x0, data CRC: 0x90B59708, OS: Linux, CPU: ARM, image type: Firmware Image, compression type: gzip, image name: "RV340 Firmware Package"
64 0x40 gzip compressed data, from Unix, last modified: 2021-10-22 04:21:18
12888796 0xC4AADC MySQL MISAM index file Version 7
30375202 0x1CF7D22 lrzip compressed data
67511151 0x406236F PGP RSA encrypted session key - keyid: EE5BA5A 5CC79EFE RSA Encrypt-Only 3072b
The first line tells us the firmware is a package and binwalk recognizes it.
We extract that package, and repeat the process for every sub-package :
$ binwalk ~/Downloads/RV34X-v1.0.03.24-2021-10-22-09-51-15-AM.img -e .
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 uImage header, header size: 64 bytes, header CRC: 0x3856B86F, created: 2021-10-22 04:21:20, image size: 74890751 bytes, Data Address: 0x0, Entry Point: 0x0, data CRC: 0x90B59708, OS: Linux, CPU: ARM, image type: Firmware Image, compression type: gzip, image name: "RV340 Firmware Package"
$ find
.
./_RV34X-v1.0.03.24-2021-10-22-09-51-15-AM.img.extracted
./_RV34X-v1.0.03.24-2021-10-22-09-51-15-AM.img.extracted/40.gz
./_RV34X-v1.0.03.24-2021-10-22-09-51-15-AM.img.extracted/40
$ file ./_RV34X-v1.0.03.24-2021-10-22-09-51-15-AM.img.extracted/40
40: POSIX tar archive (GNU)
$ tar -xvf ./_RV34X-v1.0.03.24-2021-10-22-09-51-15-AM.img.extracted/40
md5sum_fw-rv340
fw.gz
preupgrade.gz
preupgrade_md5sum
$ tar -xzvf fw.gz
barebox-c2krv340.bin
firmware_time
firmware_version
img_version
md5sums_fw
openwrt-comcerto2000-hgw-rootfs-ubi_nand.img
openwrt-comcerto2000-hgw-uImage.img
preupgrade.gz
preupgrade_md5sum
$ binwalk openwrt-comcerto2000-hgw-rootfs-ubi_nand.img
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 UBI erase count header, version: 1, EC: 0x0, VID header offset: 0x800, data offset: 0x1000
$ binwalk -e openwrt-comcerto2000-hgw-rootfs-ubi_nand.img
$ find _openwrt-comcerto2000-hgw-rootfs-ubi_nand.img.extracted/|head -20
_openwrt-comcerto2000-hgw-rootfs-ubi_nand.img.extracted/
_openwrt-comcerto2000-hgw-rootfs-ubi_nand.img.extracted/ubifs-root
_openwrt-comcerto2000-hgw-rootfs-ubi_nand.img.extracted/ubifs-root/1225039038
_openwrt-comcerto2000-hgw-rootfs-ubi_nand.img.extracted/ubifs-root/1225039038/rootfs
_openwrt-comcerto2000-hgw-rootfs-ubi_nand.img.extracted/ubifs-root/1225039038/rootfs/sbin
_openwrt-comcerto2000-hgw-rootfs-ubi_nand.img.extracted/ubifs-root/1225039038/rootfs/sbin/mke2fs
_openwrt-comcerto2000-hgw-rootfs-ubi_nand.img.extracted/ubifs-root/1225039038/rootfs/sbin/jffs2mark
_openwrt-comcerto2000-hgw-rootfs-ubi_nand.img.extracted/ubifs-root/1225039038/rootfs/sbin/power_up.sh
_openwrt-comcerto2000-hgw-rootfs-ubi_nand.img.extracted/ubifs-root/1225039038/rootfs/sbin/udhcpc
_openwrt-comcerto2000-hgw-rootfs-ubi_nand.img.extracted/ubifs-root/1225039038/rootfs/sbin/power_down.sh
_openwrt-comcerto2000-hgw-rootfs-ubi_nand.img.extracted/ubifs-root/1225039038/rootfs/sbin/hotplug2
_openwrt-comcerto2000-hgw-rootfs-ubi_nand.img.extracted/ubifs-root/1225039038/rootfs/sbin/snapshot
_openwrt-comcerto2000-hgw-rootfs-ubi_nand.img.extracted/ubifs-root/1225039038/rootfs/sbin/firstboot
_openwrt-comcerto2000-hgw-rootfs-ubi_nand.img.extracted/ubifs-root/1225039038/rootfs/sbin/cyclesoak
_openwrt-comcerto2000-hgw-rootfs-ubi_nand.img.extracted/ubifs-root/1225039038/rootfs/sbin/fdisk
_openwrt-comcerto2000-hgw-rootfs-ubi_nand.img.extracted/ubifs-root/1225039038/rootfs/sbin/wan-port-workaround
_openwrt-comcerto2000-hgw-rootfs-ubi_nand.img.extracted/ubifs-root/1225039038/rootfs/sbin/mdev
_openwrt-comcerto2000-hgw-rootfs-ubi_nand.img.extracted/ubifs-root/1225039038/rootfs/sbin/validate_data
_openwrt-comcerto2000-hgw-rootfs-ubi_nand.img.extracted/ubifs-root/1225039038/rootfs/sbin/mkfs.ext2
_openwrt-comcerto2000-hgw-rootfs-ubi_nand.img.extracted/ubifs-root/1225039038/rootfs/sbin/hwclock
And that’s it, we have the content of the rootfs available for reading.
It’s a fair assumption Cisco’s using openwrt for those routers :)
Find and ID the web files
After some digging we find the web directory :
$ find ubifs-root/1225039038/rootfs/www/
ubifs-root/1225039038/rootfs/www/config/config.json
ubifs-root/1225039038/rootfs/www/model
ubifs-root/1225039038/rootfs/www/login.html
ubifs-root/1225039038/rootfs/www/index.html.default
ubifs-root/1225039038/rootfs/www/i18n
ubifs-root/1225039038/rootfs/www/i18n/lang.json
ubifs-root/1225039038/rootfs/www/i18n/login_tw.js
ubifs-root/1225039038/rootfs/www/i18n/login_en.js
ubifs-root/1225039038/rootfs/www/i18n/lang_tw.js
ubifs-root/1225039038/rootfs/www/i18n/lang_en.js
ubifs-root/1225039038/rootfs/www/portal
ubifs-root/1225039038/rootfs/www/portal/logo.png
ubifs-root/1225039038/rootfs/www/portal/bg.jpg
and after more investigation we notice that only 3 files have a modification date matching the build file every time :
Rechecking facts
Using our target set, we try accessing multiple /cgi-bin/blockpage.cgi
on multiple devices.
Everytime their Last-Modified
header matches an image build available for download.
The boring part
One can now build a bot that HEADs /cgi-bin/blockpage.cgi
, and compare the Last-Modified
header against the firmware list to get the final version :
var ciscoVersionMap = map[string][]string{
"2022-Jan-6": {"1.0.03.26"},
"2021-Oct-22": {"1.0.03.24"},
"2021-Jun-12": {"1.0.03.22"},
}
End word
The results are now available at https://leakix.net/search?scope=leak&q=plugin%3ACiscoRV
Sharing is caring!