Tuesday 12 March 2013

You can ring my bell! Adventures in sub-GHz RF land...

Dammit! Now that song is stuck in my head and will be going around and around for the next three days... Thanks, Anita Ward! (and apologies if it's now stuck in yours too! :)

But she's right: you can ring my bell. And I can ring yours. And hers.  What the hell - let's just all ring each-other's bells shall we? And dim your lights. And open your garage door. And let's do it from the comfort and safety of my car, whilst driving around...

Speaking of hell, what the hell am I talking about???

A little while ago I got involved in a project that needed some hardware security testing. It was a complex system that used just about every protocol under the sun, including RF. 

Now RF, like other 'invisible' transport mechanisms, always gets me interested because, in my experience, once data becomes invisible, something magical happens: they forget about security. Nobody can see what's going on, so we don't need to worry about it, right? Wrong. Time and time again I've seen this... MagStripes, InfraRed, RFID, Bluetooth, Magic Moon Beams. You name it, they'll send data over it insecurely.

In this case the RF was mostly standard stuff like WiFi and Zigbee, but there was also something going on in the 400MHz band, so how to take a look at what was there?

The obvious answer is to use an SDR (Software Defined Radio), and from previous projects I have a USRP which fits the bill. However, as I travel a lot, I prefer something a little more portable, so I'm always on the lookout for smaller alternatives. As it happens, a friend gave me a nice Christmas gift (thanks CJ!) of a FunCube dongle:

This very cool device can receive on any frequency from 64MHz to 1.7GHz and fits in my laptop bag so is absolutely ideal. It also presents itself to the PC as a pseudo sound card, so is very easy to interface to. This was a fantastic bonus for me as I'm already comfortable with the idea of converting audio into data and have used the soundcard in my laptop for that purpose on many previous projects (e.g. magstripes).

Radio is, almost by definition, very mysterious. You can't see it and you can't hear it, so using a soundcard is actually a very good shortcut to helping understand this completely unknown source of data. It's not intuitively obvious that it should be that way, but the human brain is very good at recognising patterns, and the soundcard not only provides us with auditory data that our ears will immediately be able to latch onto, but also visual data in the form of an editable wave file. The bottom line is that I don't understand how radio works, and I don't particularly want to - all I want is to be able to capture whatever's being sent over it and convert into something I can deal with - i.e. bits and bytes. So how to do that?

The first task is to determine exactly what frequency our signal is on. There are several ways of doing this, and the simplest is to make a rough guess and just take a listen. If you're anywhere close you'll hear something when you activate the device, and you can then tune up or down until you've found the centre frequency and you're getting nice crisp clean signals. This is particularly important when trying to convert mysterious airy-fairy analogue signals back into nice reliable 0s and 1s, as any deviation can end up corrupting your data beyond all recognition.

Another way is to use a spectrum analyser. This is essentially another type of RF receiver, that listens on a very wide band and shows you any spikes or other discrepancies, one of which will be the signal you're looking for. This can be in the form of software using the FunCube itself, such as HDSDR (Windows) or QUISK (Linux), or a standalone hardware device like the RF Explorer. I actually use both. The RF Explorer to quickly find the signal, and then QUISK or HDSDR to fine tune.

So getting back to our examination, I can't talk about the actual device in question, but since I have a wireless doorbell, let's take a look at that instead...

Like most such devices, it helpfully tells you what frequency it's using on its R&TTE approval label. In this case, 433.92 MHz.

Putting that into HDSDR and hitting the button produces a nice 'hot' line right on the centre (the white and orange blob in the top window), so it looks like we're in the money... We can also hear what is obviously data.

OK, so now what? How do we get it from the sound card into nice friendly binary data?

Although we've decided against using the USRP, it's companion software, GNU Radio, is the obvious choice. It has a great helper tool called GNU Radio Companion which makes this kind of task an absolute doddle. There is a plugin for the FunCube which is now bundled with the main GNU Radio distribution, so no extra work is required to get it up and running.

Firing it up, we can build a simple setup that connects our funcube to our speakers:

and again, if we run it, we get some nice 'data' sounding output... So we can hear it, and it sounds like data, but we still can't do anything useful with it. Saving it to a wavefile is just as easy:

and now this is where the fun begins. We can edit that file with any audio editor. I used Audacity but pretty much anything will do.

We can clearly see our data bursts, and if we zoom in:

we can see some proper structure to it. This not only sounds like data but it looks like it too. What we appear to have is long pulses and short pulses, so we can imagine they may represent 0s and 1s just as they are - maybe a short pulse is a 0 and a long a 1...

Now I know I said I wasn't interested in understanding radio, but there is one little thing that will help to convert our data from it's current analogue form into proper digital, and that's modulation. There are many modulation schemes out there, but the two you're most likely to encounter at this level are FM (Frequency Modulation) and AM (Amplitude Modulation). FM is normally used for things that need reasonably high fidelity, like speech or music, but AM, although it can also be used for speech and music, is perfectly suited to binary data as all it needs to be is either 'ON' or 'OFF'. This is also known as OOK, or On-Off Keying, and as we can see from our sample, this is clearly what we are dealing with here. We have a flat line when we're 'OFF', which then becomes wavy when we're 'ON'.

Now we know we're dealing with AM, we can get GNU Radio to do one more job for us: demodulate the AM signal.

And our signal now looks like this:

Now, instead of bursts of wavy stuff, it's pretty much a straight line that goes high or low which is very clearly binary data. We have long pulses and short pulses, and the whole sample is simply this short pattern repeating. If we assume the short pulse represents a 0 and the long a 1, this decodes as:


Add some leading zeros to bring it up to a multiple of eight bits and we get 00001000 00011110, which is 08 1E in hex. Of course it may actually be interpreted differently - the 0 and 1 may be the other way around, and the bit order may be reversed, but for our purposes, at this stage, it really doesn't matter as long as it makes some kind of sense.

Great, so now what? I know my doorbell push-button is spitting out '081E', so therefore the bell itself must be listening for '081E' and ringing when it hears it. My neighbour's bell-push won't set it off as it's presumably sending out a different number. But how to test this?

Ideally, I'd like to transmit my own signal, from something other than the bell-push, and if the bell rings I know I've got it right. Unfortunately, as cool as it is, the Fun Cube is just a receiver, so we need something that can transmit as well... The easy option would be to go back to the USRP, but I've already discounted that as it won't fit in my laptop bag and I'd like to be able to do this on the move...

As I mentioned, the original device we were looking at was also using WiFi and Zigbee, so we were using an Ubertooth 2.4GHz dongle to poke around with that. I knew there were chips in the same device range that did sub-GHz frequencies, so I asked Mike Ossman, the Ubertooth's designer, if he knew of any projects utilising these. I was in luck: he did. Not only had he got some fun and interesting research of his own, but he pointed me at RFCat, a new project (at the time) designed to do exactly this kind of thing. Perfect! Not only would I be able to receive the signals from the bell-push, but I should be able to emulate them as well.

RFCat is based around a Texas Instruments SoC (System on Chip) called the CC1111. These are really very cool devices, which provide microprocessor and built-in RF transceiver all in one package. This one even has an AES capable crypto co-processor and built-in USB, so it is the ideal platform for this kind of tomfoolery...

Development kits in 433, 868 and 915 MHz bands are available off the shelf, and come in two forms: either as a standalone USB dongle (868/915 only):

or these nifty wristwatches:

RFCat is a replacement firmware package for the USB dongle part of the kit, and allows low level access to the radio functions via a simple USB command interface. Oh, and it's in python. Joy! :)

So one impatient wait for an overnight delivery later I'm in business and I've got my RFCat dongle up and running. It has a nice object oriented interface, so all you need to do is create an instance and start doing stuff with it (my commands are in bold)...

$ rfcat -r
'RfCat, the greatest thing since Frequency Hopping!'

Research Mode: enjoy the raw power of rflib

currently your environment has an object called "d" for dongle.  this is how you interact with the rfcat dongle:
    >>> d.ping()
    >>> d.setFreq(433000000)
    >>> d.setMdmModulation(MOD_ASK_OOK)
    >>> d.makePktFLEN(250)
    >>> d.RFxmit("HALLO")
    >>> d.RFrecv()
    >>> print d.reprRadioConfig()

Python 2.7.2+ (default, Jul 20 2012, 22:15:08)
Type "copyright", "credits" or "license" for more information.

IPython 0.10.2 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object'. ?object also works, ?? prints more.

In [1]: d.ping()
PING: 26 bytes transmitted, received: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' (0.002653 seconds)
PING: 26 bytes transmitted, received: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' (0.002528 seconds)
PING: 26 bytes transmitted, received: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' (0.004721 seconds)
PING: 26 bytes transmitted, received: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' (0.004821 seconds)
PING: 26 bytes transmitted, received: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' (0.004573 seconds)
PING: 26 bytes transmitted, received: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' (0.002605 seconds)
PING: 26 bytes transmitted, received: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' (0.002430 seconds)
PING: 26 bytes transmitted, received: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' (0.002678 seconds)
PING: 26 bytes transmitted, received: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' (0.002519 seconds)
PING: 26 bytes transmitted, received: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' (0.002820 seconds)
Out[1]: (10, 0, 0.0331571102142334)

In [2]: d.setFreq(433920000)

In [3]: d.RFxmit('\x08\x1E')
In [4]:

At this point, not surprisingly, my doorbell didn't ring. This is because our interpretation of the data, giving us HEX 081E, is a little bit simplistic. The RFCat dongle doesn't understand that we want to represent a 0 as a short pulse and a 1 as a long, so we have to do a bit more work to get it into a format that RFCat can deal with...

A traditional microprocessor controlled radio circuit would typically have a separate circuit or daughterboard for the radio portion, and the microprocessor would signal the data it wanted to send by toggling a pin HIGH/LOW. The microprocessor would be entirely responsible for making sure that the timing was correct - i.e. that it held the pin HIGH for as long as it wanted the RF to be 'ON', and LOW for the duration of the 'OFF' period. However, in these SoC devices, the radio part is all done for you and you simply need to tell it what modulation scheme you want, speed of transmission etc., feed it some data and it will do the rest.

As we already know the modulation scheme (AM/OOK), that bit's easy, so now we just have to think of our original signal in terms of OOK, and what our data would need to look like to produce the same signal.

Looking at the original trace, it's pretty 'readable', but If we want to really tidy it up we can turn it into a square wave and this will make visual checking of bit lengths much easier and more accurate. Since a .wav file is just a header with a bunch of values for each sample, it's really easy to manipulate. In this case we want to take any value that is below 0 and set it to absolute minimum, and anything above 0 we set to maximum, which is effectively what the original source was doing before the signal got converted and sent over RF - a 0 was a pin going LOW and a 1 was a pin going HIGH...

Accordingly, I wrote a little command line tool for tweaking wav files:

 $ wav-cli.py /tmp/test1.wav square 0 out /tmp/ts.wav

  Converting to square wave

  Writing /tmp/ts.wav

and this is the result:

Now we can accurately convert the signal into true OOK binary. We take the smallest element as our single binary digit, and then represent the data with a 1 when we want the line to go high, and 0 when we want it to go low, taking into account the size of our pulse compared to the single binary digit. In this case we only have two different size pulses - short and long, so we can represent them with a single or double digit:

Again, we need to add some leading or trailing 0s to give ourselves an 8-bit multiple, so the final number we end up with is 00101100 10010010 01001001 01101101 10110010, or 2C 92 49 6D B2 in HEX. Since it's always the same, we don't really need to understand what this message 'means', only to be able to reproduce it.

So in theory, if I set up RFCat to work in OOK mode with the correct speed and modulation, I should be able to transmit  2C92496DB2 and my doorbell should ring (the speed I get by measuring a short pulse width in seconds) ...

In [1]: d.setFreq(433920000)

In [2]: d.setMdmDRate(int(1.0/0.000302))

In [3]: d.setMdmModulation(MOD_ASK_OOK)

In [4]: d.RFxmit('\x2C\x92\x49\x6D\xB2')

Hmm.... Nothing. However, my bell-push didn't just transmit the message once, it sent it dozens of times, so maybe I need to do the same:

In [5]: d.RFxmit('\x2C\x92\x49\x6D\xB2' * 60)

Nope, still nothing. Going back to my original trace I could see there was a gap between each data pulse, which we can easily simulate by adding some extra '0' bits, so:

In [6]: d.RFxmit('\x2C\x92\x49\x6D\xB2\x00\x00\x00' * 60)

Bingo! The doorbell rings and my dogs go crazy telling me there's someone at the door! Nice!!!

Well, this is very cool and all, but it's not very, erm... Bond, is it? I mean, Daniel Craig isn't going to get the girl, save the world and keep Dame Judi happy by saying... "Hang on Bad Guys, I've just got to get my laptop out...  plug in this USB dongle... nearly got it... just a tick... Ouch, that hurt!"

No. Not really.

What we need is something much cooler, sexier, and, well.... shiny! Something Gucci that's always right there, ready to go at a moment's notice... .

But wait! What's that in the box of bits that came with my dev kit? A wristwatch? With a frikkin' transmitter built into it???? OK.... now that's what I'm talkin' 'bout!

Come to Papa...

And so, I give you the latest thing from my local toy store... It's called "radio":

Chronos Integrated Commander

Or ChronIC for short...

It's basically a cut-down RFCat-like firmware package that allows you to use the watch to transmit arbitrary signals. You can set it up either from the watch itself, or via the original Chronos dongle with a python helper, and then the up/down buttons on the right of the watch do the transmitting.

The python helper looks like this:

 $ chronic-cli.py

Usage: /usr/local/bin/chronic-cli.py <COMMAND> [ARG(s)] ... [<COMMAND> [ARG(s)] ... ]


    BAUD <RATE>                                                 Set RF modem baudrate
    BYRON                                                       Configure for Byron doorbell emulation
    DELAY <0-255>                                               Delay in MS between each DATA transmission
    DOWN <HEX> <HEX> <HEX>                                      Set DATA for DOWN button - 3 * 63 bytes
    EXIT                                                        Force sync mode EXIT on Chronos
    FREQ <FREQUENCY>                                            Set Frequency (e.g. 433920000)

    FRIEDLAND                                                   Configure for Friedland doorbell emulation
    MAN <'ON'|'OFF'>                                            Set Manchester Encoding
    MOD <FSK|GFSK|OOK|MSK>                                      Modulation:
                                                                   FSK -  Frequency Shift Keying
                                                                   GFSK - Gaussian Frequency Shift Keying
                                                                   OOK -  On-Off Keying (in ASK mode)
                                                                   MSK - Multiple Frequency Shift Keying
    REPEAT <0-255>                                              Number of times to repeat DATA when button pressed
    RUKU                                                        Configure for Ruku garage door emulation
    SERIAL <BAUD>                                               Set access point comms baudrate (default 115200)
    PULSE <WIDTH>                                               Set pulsewidth (baud rate = 1.0/pulsewidth)
    TIME                                                        Synchronise time/date
    UP <HEX> <HEX> <HEX>                                        Set DATA for UP button - 3 * 63 bytes

  Commands will be executed sequentially and must be combined as appropriate.
  It is recommended to finish with an EXIT to help conserve battery.

Full instructions are in the README in the github repo, but here is an example of setting it up to ring my doorbell. Put the watch in 'SYNC' mode, and then:

$ chronic-cli.py freq 433920000 man off delay 0 repeat 60 pulse 0.000320 up 2C92496DB2000000 '' '' down 2C92496DB2000000 '' '' exit

  Setting Frequency: 433920000 (OK)

  Setting Manchester Encoding: OFF (OK)

  Setting delay: 0 (OK)

  Setting repeat: 60 (OK)

  Setting pulsewidth: 0.00032 (3124.237061 Hz) (OK)

  Setting UP Button: (OK)

  Setting DOWN Button: (OK)

  Sending EXIT command

Or you can take the shortcut:

$ chronic-cli.py byron

  Setting up for Byron Doorbell

    Setting Frequency: 433920000
    Setting Manchester Encoding: OFF
    Setting Delay: 0
    Setting Repeat: 60
    Setting PulseWidth: 0.000320 (3124.237061 Hz)
    Setting UP button: 2C92496DB2000000
    Setting DOWN button: 2C92496DB2000000

Or use the built-in menu option:

And there are plenty of other targets...

Discussions on the gnuradio mailing list back in 2006 show that the obvious one of a car key was being looked at. Matt Ettus says:

"After the Wired article today, I've received a couple of email from people who are concerned that the USRP could be used to clone their keyfob transmitters for car alarms and garage doors. I'm not concerned, since there are already many ways to do this (just check the back of pupular science magazine). However, I am curious about it. I know that we can capture and play back any rf signal. The question is whether that replayed signal would result in the door being unlocked. I was under the impression that most of those systems allow an unlock code to only be used once, but does anyone out there know for sure?"

Well, here's your answer: 

Unlocking and re-locking my son's Beemer:

And the wife's Disco (note the pause and the second set of 'clunks' - this is because the first command only opens the driver's door, but because we have the option to send multiple sequences we can send another open command which then opens the rest of the doors):

Of course, opening car doors is a nice party trick, but because modern vehicles are secured by rolling codes, that's all it is - a party trick. You'll be able to do this once and once only with each 'hacked' sequence...

What's of more concern to me are devices like the 'Owl Plug':

These handy little devices allow you to control mains voltage appliances via RF. Clearly, this could have serious consequences if care is not taken when switching things on and off. What if it's an electric heater and it got shoved into a corner to vacuum the room? It gets switched back on and bingo, the curtains are on fire! Let's hope they've made the protocol nice and secure then!

Oh, dear. No rolling code. Same bit sequence every time:

And the only difference between the five buttons on the remote is a few bits. I suspect, therefore, that the only difference between my remote and my neighbour’s will also only be a few bits, so it's probably not much of an exercise to figure out which ones I need to brute force to be able to go around switching things on and off at random (I've ordered another one and will check, so watch this space...).

As usual, the code is available on the Aperture Labs tools page, but please bear in mind that while playing with your own RF devices is perfectly OK in any reasonable society, playing with other people's (without their permission) is most definitely not (and probably illegal)! Behave! :)