Peplink FusionHub - Looking under the hood

by Tom Richards

Tuesday, Aug 3, 2021

I decided to take a look at the FusionHub virtual routing appliance from Peplink. Here’s how to open it up and get inside.

FusionHub is a software package designed for Peplink-brand networking equipment. It provides a bandwidth bonding and VPN solution for users of these devices. FusionHub is essentially the host-it-yourself version of Peplink’s cloud offering, SpeedFusion Cloud.

0. Download FusionHub

Fetch the appliance image from the official Peplink site.

$ wget https://download.peplink.com/firmware/fusionhub/fusionhub-8.0.1-build1644.zip
$ unzip -d peplink fusionhub-8.0.1-build1644.zip
$ cd peplink

1. Inspect zip file

After downloading the zip file, we observe that it contains some disk images in various virtualization formats, as well as some documentation.

$ unzip -l fusionhub-8.0.1-build1644.zip
Archive:  fusionhub-8.0.1-build1644.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  2019-11-04 16:23   FusionHub/
      239  2019-11-04 16:23   FusionHub/Google Compute Engine download link.txt
        0  2019-10-29 10:12   FusionHub/OVF/
119389696  2019-10-29 10:07   FusionHub/OVF/FusionHub.ova
      130  2019-10-30 14:44   FusionHub/RAW image download link.txt
        0  2019-10-29 10:01   FusionHub/VHD/
419430912  2019-10-29 09:45   FusionHub/VHD/fusionhub.vhd
        0  2019-10-29 10:01   FusionHub/VMDK/
123928576  2019-10-29 09:45   FusionHub/VMDK/fusionhub.vmdk
      169  2019-10-30 14:48   How to upgrade.txt
       77  2015-01-27 14:35   Installation Guide.txt
   117352  2019-10-30 14:33   Release Notes.pdf
        0  2019-10-29 09:51   Upgrade/
 67420386  2019-10-29 09:48   Upgrade/fw-fusionhub-8.0.1-build1644.bin
---------                     -------
730287537                     14 files

The release notes identify this image as “Firmware 8.0.1” with a release date of Oct 31, 2019.

In addition to the included disk images, there are a few text files which contain URLs for other (assumedly less common) image formats.

2. Inspect disk image

I downloaded the .raw image using the link provided in the RAW image download link.txt file for easier inspection.

$ file fusionhub-8.0.1-build1644.raw
fusionhub-8.0.1-build1644.raw: DOS/MBR boot sector, extended partition table

Because it has an MBR partition table, we can use fdisk to see some basic information about the partitions:

$ fdisk -l fusionhub-8.0.1-build1644.raw
Disk fusionhub-8.0.1-build1644.raw: 400 MiB, 419430400 bytes, 819200 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x00000000

Device                         Boot  Start    End Sectors  Size Id Type
fusionhub-8.0.1-build1644.raw1        2048  22527   20480   10M 83 Linux
fusionhub-8.0.1-build1644.raw2       22528 819199  796672  389M  5 Extended
fusionhub-8.0.1-build1644.raw5       24576 270335  245760  120M 83 Linux
fusionhub-8.0.1-build1644.raw6      272384 518143  245760  120M 83 Linux
fusionhub-8.0.1-build1644.raw7      520192 724991  204800  100M 83 Linux
fusionhub-8.0.1-build1644.raw8      727040 819199   92160   45M 83 Linux

Looks like it has some Linux filesystems on it. I wonder what they contain?

3. Inspect partitions

First, we add some device maps for the partitions.

$ sudo kpartx -av fusionhub-8.0.1-build1644.raw
add map loop0p1 (254:1): 0 20480 linear 7:0 2048
add map loop0p2 (254:2): 0 2 linear 7:0 22528
add map loop0p5 (254:3): 0 245760 linear 7:0 24576
add map loop0p6 (254:4): 0 245760 linear 7:0 272384
add map loop0p7 (254:5): 0 204800 linear 7:0 520192
add map loop0p8 (254:6): 0 92160 linear 7:0 727040

Then, we inspect the partitions further.

$ sudo blkid /dev/loop0 /dev/mapper/loop0p*
/dev/loop0: PTTYPE="dos"
/dev/mapper/loop0p1: UUID="c2f2f35b-82b9-45cf-a64d-0c611bcebc9b" SEC_TYPE="ext2" BLOCK_SIZE="1024" TYPE="ext3"
/dev/mapper/loop0p2: PTTYPE="dos"
/dev/mapper/loop0p5: UUID="a36c1423-0ef5-4e89-be54-ad7a80aeaf9b" TYPE="crypto_LUKS"
/dev/mapper/loop0p6: UUID="6915da70-88fd-4a4f-9de8-90ef02349e84" TYPE="crypto_LUKS"
/dev/mapper/loop0p7: UUID="1c53188f-829c-402a-b239-6903b034e1d9" TYPE="crypto_LUKS"
/dev/mapper/loop0p8: UUID="9f421f40-e148-438b-a83a-5a6e7db0fb82" TYPE="crypto_LUKS"

Drat. They’re encrypted. Well, the appliance boots itself without asking for any keys or passwords, so the keys must be in there somewhere.

4. Inspect boot partition

What about that unencrypted boot partition?

$ sudo mount /dev/mapper/loop0p1 /mnt/fusionboot/
$ cd /mnt/fusionboot/
$ find .
.
./lost+found
./boot
./boot/grub
./boot/grub/locale

<snip>

./boot/grub/grubenv
./boot/grub/grub.cfg

Ah yes, the GRUB config will have useful information in it! It must contain a passphrase or something.

$ cat boot/grub/grub.cfg
set default=0
set timeout=5
set menu_color_normal=white/black
set menu_color_highlight=black/light-gray
clear
set linux_gfx_mode=text
export linux_gfx_mode
set root='(crypto0)'

menuentry 'Peplink FusionHub v8.0.1 build 1644' {
	cryptomount hd0,5
	linux	/bootdata1.bin root=/dev/ram0 fw=1 crashkernel=32M-1G:32M,1G-:32M
	initrd	/bootdata2.bin
}

menuentry 'Peplink FusionHub v8.0.1 build 1644' {
	cryptomount hd0,6
	linux	/bootdata1.bin root=/dev/ram0 fw=2 crashkernel=32M-1G:32M,1G-:32M
	initrd	/bootdata2.bin
}

Guess not. Clearly they have done some clever boot-time key hiding thing that I can’t be bothered to figure out. If you know of a quick and easy way to extract the keys at this stage, please let me know!

As a quick aside, it is interesting to see two virtually identical boot options here. Seems like this could be a nice way to boot a known good firmware if an update goes bad.

With that, we’re off to obtain the keys a different way.

5. Boot the virtual appliance

Import the .ova file into VirtualBox and boot it up.

$ VBoxManage import ./FusionHub/OVF/FusionHub.ova
$ VBoxManage startvm FusionHub

6. Dump the memory

As we saw in a previous step, the partitions are encrypted with LUKS. Since they automatically unlock themselves, the keys must be in memory.

After the appliance is fully booted, dump the VM’s memory to a file.

$ VBoxManage debugvm FusionHub dumpvmcore --filename=fusionmem.raw

Poweroff the VM (and delete it if you like). We won’t be needing it anymore.

$ VBoxManage controlvm FusionHub poweroff
$ VBoxManage unregistervm FusionHub --delete

7. Install / build FindAES

We need to search the dumped memory for the encryption keys which will unlock the partitions. Fortunately for us, FindAES is a great tool for the job.

Yes, yes. I know. The project is on SourceForge which is yucky. But the actual code for FindAES itself is truly a work of art. The whole thing is 391 lines of C with no dependencies. Trust me on this one, FindAES is the right tool for the job.

If you’re on Arch Linux, you can install FindAES from the AUR. Otherwise, you can fetch the source and build it yourself:

$ wget https://downloads.sourceforge.net/findaes/findaes-1.2.zip
$ unzip findaes-1.2.zip
$ cd findaes-1.2
$ make

8. Identify possible encryption keys

Use FindAES to identify AES keys from the memory dump.

$ findaes fusionmem.raw
Searching fusionmem.raw
Found AES-256 key schedule at offset 0x1df4f30:
6c a4 5c 93 20 6f 07 91 c1 e7 fd bc c6 76 48 ce a5 8c 08 cb da 50 44 02 9f 13 c1 38 c4 f1 65 24
Found AES-256 key schedule at offset 0x1dfb250:
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
Found AES-256 key schedule at offset 0x1fcadb0:
58 ee 24 c8 c5 dd 98 c3 13 c8 23 cf 10 9b 05 dc df 58 98 0d c1 60 f2 ec 75 61 30 df f3 85 53 4f
Found AES-256 key schedule at offset 0x7f09830:
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
Found AES-256 key schedule at offset 0x358c08c0:
59 80 17 5b d2 5f 72 26 98 f8 bf 0d 3b 6c ce ea fb da 30 0f 2a 59 70 ad f8 98 5f e6 ab 7c 4f 1a
Found AES-256 key schedule at offset 0x358c10c0:
66 ea aa 4e 95 c4 4e ed 6c 20 f0 a7 d7 b2 e4 b6 6a 2a 38 de c3 9e 29 0e 8f cf 0b e0 e2 3c 57 c7
Found AES-256 key schedule at offset 0x358c18c0:
08 f3 76 8c 03 c7 22 11 da 81 ba 79 25 eb 07 eb 8c 63 a4 46 77 1d 32 14 61 19 24 ef 0f 4e cb cf
Found AES-256 key schedule at offset 0x358c20c0:
e7 73 d2 79 1a 5a 7a 13 e0 18 f1 08 9d 41 3a ed bb b2 e7 d7 26 54 8e 2e 02 63 11 50 da 66 20 df
Found AES-256 key schedule at offset 0x3590c8c0:
6a 69 8d d3 be fe ba 7d 24 bd 23 6c 6b c6 a6 0a 1f 31 0d e8 b8 98 74 3b e5 3c e9 22 5c 7a 31 04
Found AES-256 key schedule at offset 0x3590d0c0:
be db 98 6d 64 2a 60 a2 19 68 cd 54 54 dc a3 d0 77 de cd a2 03 15 9a fc 9d 27 39 15 50 a7 6a 7d
Found AES-256 key schedule at offset 0x3f6184c0:
61 de e8 0a e8 f3 a9 6d 49 7b 27 68 a3 6a 97 9f 8a cb 39 bd 84 b8 cc d0 4f 10 af ef a4 73 98 3f
Found AES-256 key schedule at offset 0x3f6188a0:
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
Found AES-256 key schedule at offset 0x3f6189f0:
5e f1 25 68 3f 5f 12 f9 2d f5 24 44 3f 79 bc f9 04 ff 26 04 63 95 9b 31 64 87 7d 92 81 da 80 29
Found AES-256 key schedule at offset 0x3f75b950:
95 11 c4 31 2c 97 13 97 c6 0b 07 86 5f 7d 2c 9a 66 4f 69 36 b7 d4 24 18 86 38 76 9c f2 5f 92 2a
Found AES-256 key schedule at offset 0x3fbdacc0:
d5 e6 c8 97 89 fe f0 ab 6c 92 75 6c 5d 5a 1a 60 35 fc 61 04 bd df 9b 53 de 02 a9 ec f2 fe 7f 77
Found AES-256 key schedule at offset 0x3fbdbcc0:
27 e8 c9 8f 96 99 66 3b 63 a6 b3 4a ba 2f 16 3d c2 b1 df 14 4e 97 eb 9f d6 dc ed af b1 50 7e 9c
Found AES-256 key schedule at offset 0x3fc8d0d0:
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f

9. Try to use the discovered keys

I did a little bit of preprocessing on the keys to make scripting easier. It basically amounts to this:

$ findaes fusionmem.raw | grep -Ev 'Searching|Found' | tr -d ' ' | sort -u
000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
08f3768c03c72211da81ba7925eb07eb8c63a446771d3214611924ef0f4ecbcf
27e8c98f9699663b63a6b34aba2f163dc2b1df144e97eb9fd6dcedafb1507e9c
58ee24c8c5dd98c313c823cf109b05dcdf58980dc160f2ec756130dff385534f
5980175bd25f722698f8bf0d3b6cceeafbda300f2a5970adf8985fe6ab7c4f1a
5ef125683f5f12f92df524443f79bcf904ff260463959b3164877d9281da8029
61dee80ae8f3a96d497b2768a36a979f8acb39bd84b8ccd04f10afefa473983f
66eaaa4e95c44eed6c20f0a7d7b2e4b66a2a38dec39e290e8fcf0be0e23c57c7
6a698dd3befeba7d24bd236c6bc6a60a1f310de8b898743be53ce9225c7a3104
6ca45c93206f0791c1e7fdbcc67648cea58c08cbda5044029f13c138c4f16524
9511c4312c971397c60b07865f7d2c9a664f6936b7d424188638769cf25f922a
bedb986d642a60a21968cd5454dca3d077decda203159afc9d27391550a76a7d
d5e6c89789fef0ab6c92756c5d5a1a6035fc6104bddf9b53de02a9ecf2fe7f77
e773d2791a5a7a13e018f1089d413aedbbb2e7d726548e2e02631150da6620df

Place your nicely formatted keys in the following script:

#!/usr/bin/env bash
#
# File: fusion-unlock.sh
#

keys=(
000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
057b6fbd9b0970b574227e8a0d9b7ab60340f1f950afb7226ee820aab9a2e910
08f3768c03c72211da81ba7925eb07eb8c63a446771d3214611924ef0f4ecbcf
27e8c98f9699663b63a6b34aba2f163dc2b1df144e97eb9fd6dcedafb1507e9c
5980175bd25f722698f8bf0d3b6cceeafbda300f2a5970adf8985fe6ab7c4f1a
66eaaa4e95c44eed6c20f0a7d7b2e4b66a2a38dec39e290e8fcf0be0e23c57c7
6a698dd3befeba7d24bd236c6bc6a60a1f310de8b898743be53ce9225c7a3104
96f93a36c9cfb7e24c76b043878e9d38ca28b5ded013e622e48fde97d840ab2d
99be9f34762326ba9a1954747777d43897900410607f41dad5fd3d3ad18599be
bedb986d642a60a21968cd5454dca3d077decda203159afc9d27391550a76a7d
ca9e80f1a3340fd9f8349c5d7d2b2c18d4656a78996fa43eea3ed3cb27013035
d5e6c89789fef0ab6c92756c5d5a1a6035fc6104bddf9b53de02a9ecf2fe7f77
dd0df83663c11e76e7f7730cc8c71fe95cacc6d55fc1908441699f6e6c14ee83
e773d2791a5a7a13e018f1089d413aedbbb2e7d726548e2e02631150da6620df
)

for key in "${keys[@]}"
do
  echo "Trying $key"
  echo $key | xxd -r -ps > fusionhub.key
  if sudo cryptsetup open /dev/mapper/loop0p5 fusionvol --master-key-file fusionhub.key;
  then
    echo "Success! $key"
    exit
  fi
done

Run the script and it will hopefully unlock the partition using one of the keys we found in memory.

$ ./fusion-unlock.sh
Trying 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
Volume key does not match the volume.
Trying 057b6fbd9b0970b574227e8a0d9b7ab60340f1f950afb7226ee820aab9a2e910
Volume key does not match the volume.
Trying 08f3768c03c72211da81ba7925eb07eb8c63a446771d3214611924ef0f4ecbcf
Volume key does not match the volume.
Trying 27e8c98f9699663b63a6b34aba2f163dc2b1df144e97eb9fd6dcedafb1507e9c
Success! 27e8c98f9699663b63a6b34aba2f163dc2b1df144e97eb9fd6dcedafb1507e9c

10. Here are the keys

Repeating the above setup once per partition, we discover which keys belong to their respective partitions. It is worth mentioning, however, that the contents of partition 5 and 6 are identical, and partitions 7 and 8 do not actually have any files on them.

loop0p5: 27e8c98f9699663b63a6b34aba2f163dc2b1df144e97eb9fd6dcedafb1507e9c
loop0p6: 5980175bd25f722698f8bf0d3b6cceeafbda300f2a5970adf8985fe6ab7c4f1a
loop0p7: 08f3768c03c72211da81ba7925eb07eb8c63a446771d3214611924ef0f4ecbcf
loop0p8: 6a698dd3befeba7d24bd236c6bc6a60a1f310de8b898743be53ce9225c7a3104

From this point forward, we will only inspect the contents of partition 5.

11. Inspect the unlocked partition

Now that we have opened the encrypted LUKS volume, we can mount it and inspect it further.

$ sudo mount /dev/mapper/fusionvol /mnt/fusionvol
$ cd /mnt/fusionvol

$ ls -ahl
total 40M
drwxr-xr-x 3 root root 1.0K Oct 28  2019 .
drwxr-xr-x 7 root root 4.0K Aug  3 01:51 ..
-rw-r--r-- 1 root root 3.3M Oct 28  2019 bootdata1.bin
-rw-r--r-- 1 root root  37M Oct 28  2019 bootdata2.bin
drwx------ 2 root root  12K Oct 28  2019 lost+found
-rw-r--r-- 1 root root   17 Oct 28  2019 software-release

Neat! There are those bootdata1.bin and bootdata2.bin files we saw earlier in the GRUB config. So the first one is the Linux boot image, and the second one is the actual root filesystem. Apparently the whole thing runs from memory.

$ file *.bin
bootdata1.bin: Linux kernel x86 boot executable bzImage, version 4.9.188-pismolabs+ (buildbot@build) #1 SMP Thu Oct 17 23:29:32 HKT 2019, RO-rootFS, swap_dev 0x3, Normal VGA
bootdata2.bin: gzip compressed data, was "rdisk.e2fs", last modified: Thu Oct 17 16:22:47 2019, max compression, from Unix, original size modulo 2^32 100663296

12. Inspect ramdisk

First, we uncompress the image. There isn’t enough space on the original partition to do this, so we make a copy elsewhere first.

$ cp bootdata2.bin /tmp/rdisk.e2fs.gz
$ cd tmp
$ gunzip rdisk.e2fs.gz

$ file rdisk.e2fs
rdisk.e2fs: Linux rev 0.0 ext2 filesystem data, UUID=00000000-0000-0000-0000-000000000000

Now that we have a regular root filesystem image, let’s take a look around.

13. Inspect the real root filesystem

$ sudo mount /tmp/rdisk.e2fs /mnt/fusionroot
$ cd /mnt/fusionroot

$ ls -ahl
total 34K
drwxr-xr-x 13 root root 1.0K Oct 17  2019 .
drwxr-xr-x  8 root root 4.0K Aug  3 02:12 ..
drwxr-xr-x  2 root root 2.0K Oct 17  2019 bin
lrwxrwxrwx  1 root root    9 Oct  8  2015 dev -> ./tmp/dev
lrwxrwxrwx  1 root root    9 Oct  8  2015 etc -> ./tmp/etc
drwxr-xr-x  2 root root 1.0K Jul 14  2005 fwupmnt
drwxr-xr-x  5 root root 2.0K Oct 17  2019 lib
lrwxrwxrwx  1 root root    3 Oct 17  2019 lib64 -> lib
lrwxrwxrwx  1 root root   11 Oct 17  2019 linuxrc -> bin/busybox
drwx------  2 root root  16K Jul  6  2005 lost+found
lrwxrwxrwx  1 root root    7 Oct 17  2019 mnt -> tmp/mnt
drwxr-xr-x  2 root root 1.0K Jul  6  2005 proc
drwx------  3 root root 1.0K Oct 17  2019 root
lrwxrwxrwx  1 root root    7 Oct 17  2019 run -> var/run
drwxr-xr-x  2 root root 1.0K Oct 17  2019 sbin
drwxr-xr-x  2 root root 1.0K Jul 20  2009 sys
drwxr-xr-x  9 root root 1.0K Oct 17  2019 tmp
drwxr-xr-x  9 root root 1.0K Oct 17  2019 usr
lrwxrwxrwx  1 root root    7 Oct  8  2015 var -> tmp/var
drwxr-xr-x  9 root root 1.0K Oct 17  2019 web

We’re finally in! This is basically a choose-your-own-adventure at this point. There are so many things to look at. Here are a few bits which I considered to be interesting:

14. Notes

I was not able to detect any telltale signs of a specific Linux distribution. It appears to be a custom Busybox-based Linux build using classic SYSV init scripts. /sbin/init points to busybox, which uses /etc/inittab to start the system’s services.

$ cat etc/inittab
null::sysinit:/etc/rc.sysinit
null::sysinit:/usr/local/ilink/bin/sysinit_prepare
null::syslog:/usr/bin/metalog -C /var/run/ilink/metalog.conf
null::wait:/usr/local/ilink/bin/sysinit
null::respawn:/usr/bin/runsvdir /var/service
null::once:/usr/local/ilink/bin/start_activate
null::respawn:/usr/local/ilink/bin/timesyncd
null::respawn:/usr/sbin/crond -f
null::respawn:/usr/local/ilink/bin/wtpmon
null::respawn:/usr/local/ilink/bin/wan_link_usage_hourly
tty1::respawn:/usr/local/ilink/bin/fh_console

The bulk of the web interface resides in the /web directory. A handful of small CGI binaries are present there. Their file size leads me to believe that they are probably written in C. I hope these web-facing binaries written in memory unsafe languages have been sufficiently fuzzed! 😈️

$ cd web/cgi-bin/MANGA
$ find . -mindepth 1 -maxdepth 1 -type f -exec file {} \;
./cgibox.cgi: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 4.9.141, stripped
./wwan_status_daemon: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 4.9.141, stripped
./chkupgrade.cgi: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 4.9.141, stripped
./firmware.cgi: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 4.9.141, stripped
./index.cgi: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 4.9.141, stripped
./extap_fwb.cgi: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 4.9.141, stripped

These files are dynamically linked and refer to some custom libraries which are present in the /lib directory. My research environment is unaware of this library path, so they appear as “not found” here.

$ ldd cgibox.cgi
	linux-vdso.so.1 (0x00007ffcb3700000)
	libcgi.so => not found
	libstatus.so => not found
	libpepinfo.so => not found
	libpepmodule.so => not found
	libstrutils.so => not found
	libssl.so.1.1 => /usr/lib/libssl.so.1.1 (0x00007f477ea91000)
	libcrypto.so.1.1 => /usr/lib/libcrypto.so.1.1 (0x00007f477e7b1000)
	libroutedb.so => not found
	libvpnstatus.so => not found
	libpepos.so => not found
	librt.so.1 => /usr/lib/librt.so.1 (0x00007f477e7a6000)
	libsqlite3.so => /usr/lib/libsqlite3.so (0x00007f477e661000)
	libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007f477e63e000)
	libjansson.so.4 => /usr/lib/libjansson.so.4 (0x00007f477e62e000)
	libc.so.6 => /usr/lib/libc.so.6 (0x00007f477e462000)
	libdl.so.2 => /usr/lib/libdl.so.2 (0x00007f477e45b000)
	libm.so.6 => /usr/lib/libm.so.6 (0x00007f477e317000)
	/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007f477eb5d000)

The web server on the appliance is Nginx, version 1.12.2. Somehow, this particular version has avoided having any critical security issues. …yet.

$ ./nginx -v
nginx version: nginx/1.12.2

15. Cleanup

Unmount and unmap the raw image partitions, if you feel inclined to do so. If not, a reboot will clear this right up for you.

$ sudo kpartx -v -d fusionhub-8.0.1-build1644.raw

Conclusion

In this post, we jumped through the necessary hoops to deobfuscate the software (somewhat), and we learned a lot about the contents of the FusionHub virtual appliance.

Future

I briefly attempted to run binary-only fuzzers on these CGI executables, but I clearly have a lot to learn before I surface any meaningful results from doing so. Hopfeully I will find some more time for this and we can discover some really interesting things then!

🙂️