Hacking the SABRENT low cost AirPlay/AirTunes dongle for speakers

What device ?

SABRENT WIFI Audio Receiver (WF-RADU) is a small, low cost (< 20$) WIFI AirPlay / AirTunes receiver used to transform any audio system with a 3.5″ line-in in a AirPlay compatible device.

Under which conditions ?

No hardware modification to the device.

What to expect ?

More control on the (chinese) device. Login in a remote shell, and be able to change parameters to the device, use it as a very limited but always-on server.

What were the pitfalls ?

The CPU used is very low end (MIPS 24K V4.12, with 240 Bogomips ;-). Very low onboard DDR (32MB).

Solution

Analysis the device

Firstly, I’m using a browser with a french language setup. With that browser, I’m not getting any interface from the device, because it does not detect my language, and as such does not send the right “translation script”. Without this, it’s impossible to set up the device on my wireless network.

But because I’m reluctant to throw any failing device without a first inspection, running the javascript debugger to stop on any exception, I was able to load the “langage_en.js” file required to at least configure the device (and yes, I’ve setup my browser to use English, yet it does not work, the main page still insist to load an inexistant “language_0.js” file).

Once updated with the latest firmware, and configured to run on my network, I was able to scan for open ports.

The device, by default, has a telnet server running.

The issue is that I did not know which password and user was available to log in (and the web interface is so limited it does not give any clue).

Finding the credentials for login into the device

Ok. Now we have a firmware file and a device that’s closed to us.

First a “file” gave me this:

$ file 141105_SABRENT_WFAudio_V207.bin
141105_SABRENT_WFAudio_V207.bin: u-boot legacy uImage, Linux Kernel Image, Linux/MIPS, OS Kernel Image (lzma), 5437776 bytes, Wed Nov  5 18:07:13 2014, Load Address: 0x80000000, Entry Point: 0x80483000, Header CRC: 0xA210031E, Data CRC: 0x66CC54A8

Looks like a simple uImage file?

Well, not really. It has a uImage header, but it does not fill the complete binary (doing a dd to extract the content resulted in an invalid LZMA archive, end is garbled).

Ok, so second try with binwalk. If you don’t have binwalk, you should download the sources and compile it yourself, as most distribution comes with a huge amount of useless dependencies.

$ binwalk ~/141105_SABRENT_WFAudio_V207.bin
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 uImage header, header size: 64 bytes, header CRC: 0xA210031E, created: Wed Nov 5 18:07:13 2014, image size: 5437776 bytes, Data Address: 0x80000000, Entry Point: 0x80483000, data CRC: 0x66CC54A8, OS: Linux, CPU: MIPS, image type: OS Kernel Image, compression type: lzma, image name: "Linux Kernel Image"
64 0x40 LZMA compressed data, properties: 0x5D, dictionary size: 33554432 bytes, uncompressed size: 4849468 bytes
1522064 0x173990 Squashfs filesystem, little endian, non-standard signature, version 3.0, size: 3913667 bytes, 585 inodes, blocksize: 65536 bytes, created: Wed Nov 5 18:07:12 2014

This is much better. The main root filesystem is at position 1522064, so a dd extracted it.

Then, inspecting the area, this starts by the magic word “shsq” which is the mark for a squashfs filesystem with LZMA (only in very recent version).

In order to extract this filesystem, let’s use Firmware mod kit

After building (go into the src folder and run configure before attempting the main folder’s scripts), run this command:

$ mkdir out ; ./unsquashfs_all.sh path/to/sabre.squashfs.from.dd.extract out

Then go to the out folder, you’ve a local version of the filesystem the device is using.

And then… no /etc/passwd. It seems this is generated by the init script, so let’s dig into them.

Bingo:

genSysFiles()
{
# login=`nvram_get 2860 Login`
# pass=`nvram_get 2860 Password`
 login=szrnd
 pass=rndSZ
 if [ "$login" != "" -a "$pass" != "" ]; then
 echo "$login::0:0:Adminstrator:/:/bin/sh" > /etc/passwd
 echo "$login:x:0:$login" > /etc/group
 chpasswd.sh $login $pass
 fi
 if [ "$CONFIG_PPPOL2TP" == "y" ]; then
 echo "l2tp 1701/tcp l2f" > /etc/services
 echo "l2tp 1701/udp l2f" >> /etc/services
 fi
}

Tested on the real device: it works

Enhancing the experience

Now that we can connect on the device, we can do multiple things to enhance the device behavior.

First, it seems the device runs with a bunch of (useless) tools for its main purpose that we can reuse.

If you plug a usb stick on the device, it mount it automatically. It even has ntfs-3g fuse driver to read from the NTFS formatted USB mass storage drives.

It also has a mplayer builtin, so you can play any mp3 file directly from the plugged drive. For a 20$ device, it’s more capable than those AVR’s audio player.

It’s using slaap for the airtune protocol server, and an unknown UPNP renderer.

It also have a serial port you can address via a socket (I think, I’ve not tried).

For a more complete picture of the inside, look below:

This is the inside of the SABRENT WFAudio device

This is the inside of the SABRENT WFAudio device

Advertisements

19 thoughts on “Hacking the SABRENT low cost AirPlay/AirTunes dongle for speakers

  1. Paul says:

    First let me compliment you on you work.

    Second, if you don’t mind I have a couple of questions.

    Do you have any plans to continue or do you the think there is any reason to continue hacking this device?

    I am not familiar with the slaap AirPlay server. Do you know if it is an Airplay2 server with sync capability?

    Thanks

    P

    • It’s possible, with the right cross compiler, to add a binary to the system and to modify files in the firmware. We don’t have the source code for the kernel so we can’t change the “low-level” behavior. However, there is not much features you could add that are not already available. At first, I thought I could use a GPIO to trigger a relay to switch on / off the speaker depending on stream presence (that is, save energy when not used). But I realized that the USB is not protected whatsoever and the power lines are directly connected to the USB host port itself. So, I’ve plugged my USB speaker on it, and it works as a “feature enhancement”, making a “AirPlay speaker” for 20 more dollars.

      So, unless we start modifying the schematic and solder small wires on the CPU’s pin, there is nothing we can do to enhance the device.

      Concerning slaap, I don’t have the source for it, but I’m sure it’s a DAAP compatible server with TCP AND UDP/RTP mode (so it somehow “qualifies” as a AirPlay v2). I wonder if the source code comes from this project: https://github.com/jasonmc/forked-daapd since the config file format look similar (not the same unfortunately).

      I’ve another AirPlay speaker at home, and when I capture the network traffic with Wireshark between the Mac and the speaker, I see that the other speaker “speaks” a different protocol than those (it’s immediately encrypted), while it’s in clear with this device, so I can’t conclude concerning the version of the protocol.

      In all cases, it works perfectly with the Mac, and with Pulseaudio with RAOP sink on the NAS, so that fits my need.

  2. Paul says:

    A couple more questions if you don’t mind

    First, I tried the login information via a telnet connection to my device and it did not work. Did you have to change them in the system first or did the stock logo. Information work?

    I was using:

    login=szrnd
    pass=rndSZ

    As far as features, I like your idea of adding a switching capability to the device. This would be helpful when using the device with a audio receiver. But, the real feature I am interested in is setting up the device as a bridged Wifi AP on my network.

    P

    • Actually, that’s what I’ve found in the last firmware I’ve downloaded from Sabrent website and it worked when installed. If you have a different firmware, you’ll need to apply the same steps as I did to figure out what is the login/PW to use. I’m not sure I understand your expectation. To have a bridge, you need 2 interfaces, but this device only has one.
      Can you be more specific ?

  3. tweakedxvi says:

    I know this is a few months old now but throwing it out there.

    I’ve browsed through the file system but couldn’t figure out if what i’m looking for is possible, I wish this thing had a “Car Mode” where it could use DHCP to assign IP address and Subnet for use in the car but omit the Gateway and DNS entries to preserve your phones connectivity to wireless data.

    Any idea if this can be done with this device the way it’s configured? Only thing i could find is the /etc/udhcpd.conf file but that doesn’t seem to do the trick and is overwritten each time the device is rebooted.

    As a side note, i had the same FW version installed as you and the UN/PW didn’t work. Reflashed and did a factory reset (hold the button down for 60 seconds) and it still wouldn’t work. Reflashed one more time and tried telnet without a factory reset and was able to log in fine.

    • I don’t really understand your need. If you want the system to be an access point, and you’ll connect your car/phone to it, you can do it with the official feature set (no hacking required).
      If you want the system to connect to your car’s WIFI access point, you can do it also directly.
      If you want to prevent the system from “phoning home” when connected to your car’s WIFI, then yes, you’ll need to hack it (but in that case, you’ll need to extract the firmware’s filesystem, modify the boot scripts to add “route del default gw” or equivalent, repack the firmware and flash it again with your mod. Since when you plug a USB stick, it’s mounted automatically, I think, without modification to the firmware, that a resident is looking for a specific file (to update the firmware via USB). Maybe you can put your script on a usb key and have the system execute your command whenever you plug the USB key to it (once connected of course).

      • I’m trying to figure this out as well as it really is the only bad part about this device. The issue here is that when you use the DHCP server on the SABRENT it gives out a default gateway so that your phone thinks it should use the SABRENT for all internet access effectively making your phone useless. The only workaround is to give your phone a static IP address on the SABRENT network *without* a default gateway. That way your phone connects to LTE and uses SABRENT wifi for streaming. It’s not an issue after you do it the first time – but having other non-technical people follow it is rather difficult to explain.

      • That’s the issue with AirPlay in general, it’s using IP network to do it stuff, and as such they are so many possible configuration for an IP network that one configuration could not fit all. The other option would be to remove the gw from the DHCP server’s configuration, but unfortunately, it’s not possible without repacking a firmware. Typically, I’m using this device at home, and I let it connect to my home’s WIFI (and so are the other device on the network), so it’s not a real issue for me.

  4. Mrwilliematt says:

    I know I ‘m late to the conversation but I wondered if you noticed which DAC chip is used in this device we you had it open?

    • No, unfortunately, I have not checked. I don’t think its top notch (don’t expect a super high end DAC on a 20$ device), but it’s enough to get decent sound on my USB powered speaker.

      • Fel says:

        I’m not sure if I’m misunderstanding, do you mean you got the unit to output audio through the usb port? If so, what changes did you make to enable the usb audio out? What does the usb port used for by deafult?

      • The USB port on the device is directly connected to the USB cable. So when you power the device via USB, the power is also “routed” to the USB host port (except for data lines). I’ve a USB powered speaker (5W, out-of-spec chinese product). Instead of plugging the chinese speaker via a USB power socket, I’m plugging the device on the USB power socket, and plugging the speaker on the device host port. The audio in 3.5mm from the speaker is plugged into the audio out plug of the device. Very standard in fact.

        However, you can plug a USB key on the USB host port and it’s recognized and mounted (but there is no action done afterward). Since you’ve telnet running, you can have one of your server starting mplayer with the files on your USB key.

        If you intend to plug a USB DAC on the host, I think it can be done, but you’ll have to modify the firmware to include the USB’s DAC driver. You can also store this driver on a USB key, plug a USB hub with both the USB key and the USB DAC, launch a command remotely to insmod the driver, and swap the /dev/pcmXXX devices so the built-in Airplay’s server is using this instead of built-in’s low cost DAC.

      • Fel says:

        Thanks for the clarification. That’s a cool and compact idea. Yes, I was looking toward using this in a car with a USB DAC, so I think I’ll have to do some digging into it once I receive my unit.

  5. torresweb says:

    Just to avoid a lot of work, could you consider to share the modified firmware?
    If not public, send me by e-mail. Tks in advanced!

    • I’ve not modified the firmware in a way that’s packable. I’ve opened the official firmware to find out the login & pw for the root user, then I’m using the telnet server / port to launch the commands I’m interest with. Repacking a firmware is another step that’s much more harder to make it right, and I’ve not seen the need for yet. In the end for such a device you need another device on the network and it happens that the same device is also able to send telnet commands as well.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s