Fueled by the rise of the Internet of Things, do it yourself alarm systems have become a multi-billion dollar industry that is increasingly disrupting traditional alarm companies share of the home security market. One area of concern with IoT is the security of these ubiquitous devices. So I thought it would be a fun project to examine the security of these systems. After a bit of searching, one brand in particular stood out, firstly due to its price point, and secondly its accessibility and popularity in North America: iSmartAlarm (ISM) https://www.ismartalarm.com
In the course of research on this system I Identified six important issues that can be used to bypass or disable different aspects of the alarm system. Five of them by attacking the radio network the alarm system uses, and one via the traditional IP based network.
Radio frequency based attacks:
Network based attacks:
In this post I describe ways to attack the ISM radio network. The majority of these attacks aren't specific to ISM and are directly attacking their implementation of the Texas Instruments (TI) SimpliciTI low-power radio network protocol/firmware.
To start things off, I tore down each device that comes with the kit to take a look at the PCB's and see what I could find.
Looking at the main-board for the alarm system I can quickly identify some components and ports including:
Remote device internals:
Looking at the back of the main-board I can see the PCB legend conveniently labels which pins correspond to what for the UART serial port. Using this knowledge, I hook up a Saleae logic analyzer to some soldered headers to determine the baud rate of the port:
Saleae returned a result of 58173 baud for the UART port, which is very close to the common rate of 57600 baud which I will use when hooking up a UART to USB converter.
After starting a screen session and resetting the alarm system I am greeted with this clobbered dmesg from the UART:
There some security concerns using older version of the kernel and busybox:
Linux version 2.6.21:
I will cover some of this in more detail later.
What looks more important currently is these strings that get printed at the very end of the dmesg. Specifically the 0007XXXX sections:
ISSA0C2C020300 [0007AF1D] 222D203D09395FD740395FD7740AAF ISSA0C2C020300 [00075E60] 225203D0D88E0860B395FD7340A8C ISSA0C2C020300  1C26203D032B6082EA2B6081FF0A95
These hex values match the addresses seen in the mobile application when adding devices to the RF network (only devices with these addresses are allowed to communicate with the alarm system):
Curious to see the inner workings of these devices; I hooked up a GoodFET from River Loop security to the JTAG pads and started to dump the CODE region from the 8051 MCU inside of the TI CC1110 chip on each of them.
Once dumped, I searched for one of the addresses that I had seen in both the application and the dmesg output. This resulted one of them being located at the very last page (1024 byte flash memory section) of the CODE region and the XDATA region (7FFF and FFF0):
I then took the `.diffs` on two separate devices firmware dumps. This resulted in the only difference actually being this address value, with no changes to anything else within the flash firmware:
Moving on to IDA’s hex view to take a closer look, the first thing I immediately notice is the ASCII string, "SimpliciTI's Key" within the firmware dump:
After googling the string, it turns out that TI has developed a low-power RF communications network stack built for these chips called SimpliciTI. Source code was available for the protocol on their web page and I downloaded it along with a few application notes I sourced elsewhere that give great detail of the entire protocol and its usages:
Reading through the source code, I find a file called nwk_security.c which is compiled into a network application that controls encryption and decryption of RF packets using a software based encryption scheme utilizing the XTEA block cipher and a modified CTR mode operating on a 4 byte incrementing counter.
This file also contains areas for setting the encryption key, IV, and a 1 byte MAC (message authentication code). Oddly they aren't using the MAC in its traditional sense for message integrity, why, I have no idea and it seems quite useless as we'll see in later parts.
As you can see and might've guessed, ISmartAlarm is using the default key from the SimpliciTI protocol. I then checked the firmware again to confirm my suspicions, indeed they are also using the default IV and MAC (It looks off because of endianness when converted into the long data type four times):
After thoroughly reading code and application notes a few things became clear:
Within the general outline for developers application note, it is described how a device would join a network upon boot up. This means that when a remote or sensor is flashed with an address value known by the alarm system, that device will automatically initiate a link session with it to join the network and initiate an end-to-end encrypted session. Why is SimpliciTI configured to do this by default?
The reason is from what I could gather is the protocol doesn't know the power state of a device on the network at any given time. Unless the vendor specifically creates circuitry and code to keep enough capacitance in the system to send one last packet saying "I'm dying" if it's shutting down, or requires each device to broadcast back every few seconds to adjust for this lack of feature. So by flashing a address to a device, I would be removing its power and status on the network. This device is now told to attempt connecting using this new address of a device known valid to the alarm system. Therefore I should be able to automatically go through this procedure with one of the devices, because it is programmed by default to automatically do the following on boot up as was observed with radio tools created in later sections:
To test out if what I was reading was true, I attempted to use the address value from another remote device with the remote device I had already hooked up to the GoodFET using some simple python code that calculates the Intel hex checksum for an arbitrary device address, then appends it and a end record to a new line within a '.ihex' file that I could tell the GoodFET to flash at the page where the address value is stored at as seen earlier. If you are unfamiliar with the Intel Hex format, I recommend you review the Wikipedia article as it explains the specification well.
Once flashed to the remote device, I pressed the panic button on it after it had booted up and to my surprise it made the alarm system sound its siren.
The ability to completely bypass the authentication checks by knowing a single plain text address severely undermines the security of the protocol.
To put this into more simple terms:
If device A (alarm system) has a certain set of encryption keys, and device B (client) has those encryption keys, which it needs out of box to communicate with device A. All an attacker needs is the address of device C (another client authorized on the network), and they can add themselves to the network without actually going through the process of telling device A to enroll and add device B, because you can pretend to be device C; which is already on the network. Because it is impossible for the SimpliciTI protocol to work in encrypted mode with two different sets of keys, only one can be used, unless the vendor directly changes core SimpliciTI code. Adding to that, keys cannot be exchanged over the RF link unless the vendor writes custom code on top of the protocol firmware to do so, which is risky and the keys would be sent over plain text or a already known encryption scheme.
Now that I can remotely clone and impersonate other authenticated devices on the network using a previously unauthorized device I wrote a new python script and some quick C that would brute-force all device source addresses from the range of '00070000' to '0007FFFF'. As the brute-force was happening a serial byte is sent to an Arduino that was hooked up to a transistor circuit which would pull the panic button pad on the device to ground for every subsequent address that was flashed. This way I didn't have to physically press the button each time.
With a bit of solder and electrical tape, I bundled it together into a portable iSmartAlarm attacking device using the guts of one of the devices:
Button automation schematic:
70000 to 7FFFF seems to be the maximum range of addresses that all the included devices are programmed at, allowing for 65536 possible addresses.
This video shows the brute-force attack in action:
This was fantastic, I was a able to impersonate every authenticated device on the network, but there were still some things I had to overcome.
Firstly, this process of flashing, rebooting the device, and pressing the button, took over 3 seconds per address. Meaning it would take a little over 3 days to exhaust the entire address space with a single remote device. Multiple devices could be purchased separately to accelerate this attack to under 15 minutes using a non-linear search algorithm.
Secondly, there is no way for an attacker to know either than audibly that a command was successfully issued using a correct source address, as in there is no feedback whatsoever in this scenario. One would need to try every possibility regardless to ensure the alarm system was really unlocked.
To overcome these issues I decided I needed to find a way to intercept and decode the packets sent out by these devices which would allow me to discover the source addresses that are included in the frame structure as seen here:
I turned to the Ettus Research USRP B210 which would allow me to intercept the packets sent by the devices on the network, and GNURadio to determine what they held based off the SimpliciTI application notes explaining the packet frame structure for plain text and cipher-text communications.
Looking up the FCC ID on the back of the remotes gives us a test plot that shows the device operates at a frequency of 908 MHz and is potentially 2-FSK modulated, because of the distinct two peaks that resemble MARK and SPACE frequencies.
The datasheet also references modulation types supported by the CC1110 chip, such as 2-FSK, GFSK, MSK, ASK and OOK.
Using the GQRX spectrum analyzer to validate further, I set it to 908 MHz with peak hold envelope set to on. Indeed looks like 908 MHz and does resemble a 2-FSK modulated signal:
In order to get a clearer view of the signal to investigate, samples were recorded using the Ettus uhd_rx_cfile tool and then subsequently opened in baudline. After tweaking the settings for awhile I eventually get very clear view of the 2-FSK keying and can see certain segments of the packet including the preamble and sync word:
I now can build a simple GNURadio flowgraph to demodulate this signal using the USRP as a source, and a FFT Sink. In order to avoid the DC spike in the middle of the signal that is produced by the USRP, I tuned the frequency to 520 KHz below the center target frequency, then shifted it back using the "Frequency Xlating FIR Filter" block. A WX GUI slider is used also used here to control the center frequency offset as it deviates at times between different devices.
I can see from this FFT plot now the signal just like I saw in GQRX with the peak hold evelope set to on:
Now the signal can be filtered of any noise around it. To do this I use a lowpass filter against the signal using a cutoff value of around 11KHz. This is derived from calculating the deviation between the MARK and SPACE frequencies of the 2-FSK signal. A transition width of 6 KHz for the lowpass is used for aggressiveness between the passband and stopband.
Transition width (This is the area between where the waveform "turns the corner" and where it "hits the bottom"):
Now a "Quadrature Demod", "Binary Slicer", "Char to Float" and “WAV file sink” block is added to the flow-graph. The flowgraph now becomes:
This will demodulate, slice the signal into binary and send the data to a WAV file for further analysis with Audacity.
From this newly created binary sequence from GNURadio, I can clearly see the preamble and sync word:
I don't know for sure if this packet was sent without any corruption or interference, causing the bit values to be incorrect. Unless I manually calculate the CRC checksum of the packet and compare it to the last two bytes in it, this is more work than I'd like to do.
What I do instead is use the GoodFET to dump all the radio modem register values of the CC1110 chip and read the configured sync word from the SYNC1 and SYNC0 registers. Additionally I can use this register dump to help gain useful information about the radio configuration by inputting other register values into the SimpliciTI development software which will retrieve information such as the symbol rate, channel spacing, deviation, sync word mode and data whitening mode.
Sync word register values:
SimpliciTI software register calculations:
The dump shows that the sync word is indeed 0xD391 (1101001110010001), and the SimpliciTI development software shows a symbol rate of 38.385 kBaud, a channel spacing of 50 KHz, deviation of approximately 47 KHz, and disabled data whitening mode (thank god because PN9 sequencing math is tough stuff).
The samples per symbol which we need to calculate by hand for our next block is derived by dividing the sample rate by the symbol rate, resulting in 31.2364 kBaud. Using this value I can configure a clock recovery block with the omega set to our new found symbol rate. I can also remove the WAV sink as it isn't needed anymore:
Next is to input the sync words like we saw in Audacity (11010011100100011 101001110010001) into a correlate access code block from a binary slicer and connect it to a custom block I created called the "iSmartAlarm packet decoder". This custom block interprets the binary data from the packets that first matches this sync word and next attempts to calculate the CRC checksum of the packet to validate integrity before being sent out to a queue for further processing.
The final flow-graph looks like so:
Now I can build a new python script that will manage its execution in a thread and pull messages from the queue, dissect the frames from within and print them out in an array of colors depicting different sections of the packet. I recommend you check out the application notes and source code to see what they mean. Here is a brief visual (red is encrypted payload section):
Now that I can decode SimpliciTI packets, I should be able to intercept the source address of a registered remote device on the network because that section is sent over plaintext; then flash a separate blank remote device using that source address by leveraging some of our previous code to unlock the system.
Let's test it:
[14:09:25.357656] Frequency tuned to: 908001.80 KHz [14:09:28.162292] Frequency tuned to: 908001.56 KHz [14:09:28.562866] Frequency tuned to: 908001.32 KHz [14:09:28.663153] Frequency tuned to: 908001.08 KHz [14:09:28.763470] Frequency tuned to: 908000.90 KHz [14:09:28.864392] Frequency tuned to: 908000.66 KHz [14:09:28.964674] Frequency tuned to: 908000.42 KHz [14:09:29.165145] Frequency tuned to: 908000.18 KHz [14:09:29.365579] Frequency tuned to: 907999.70 KHz [14:09:29.465807] Frequency tuned to: 907999.52 KHz [14:09:29.566111] Frequency tuned to: 907999.04 KHz [14:09:29.866679] Frequency tuned to: 907998.80 KHz [14:09:35.577611] 13 88888888 00075E60 60 83 05 34 DE A9 8F B1 8A 8F 4E C1 [+] Chip ID is 0xffff, implying a wiring problem. attempting soft reboot. [+] Source address captured from iSmartAlarm remote, attempting unlock… IHEX: :107FF000FFFFFFFFFFFFFF0000000000075E60FFC4 :00000001FF Flashing <cStringIO.StringI object at 0x7fcd4baf81c8> Flashing buffer to 0x007c00 Flashed final page at 007c00 [+] Writing Serial Done [+] Acknowledgement received from destination. Most likely unlocked :D
It worked! I can unlock alarm systems within seconds now by impersonating these authenticated devices.
A few comments about the packet output, briefly:
13 88888888 00075E60 60 83 05 34 DE A9 8F B1 8A 8F 4E C1
To recap on what an attacker scenario would currently look like:
Alternatively running the code in attack mode one or zero will attempt an unlock 30 seconds after a source address is intercepted, or to plain brute-force 65536 possibilities.
Disclaimer: In this section I will only be explaining how this can be accomplished, code available to do this will be purposely broken or incomplete to prevent war-driving abuse or attacks on systems alike resulting in possible sensitive data exposure. Don't forget, I'm not attacking a iSmartAlarm specific radio network. I'm attacking a established radio network protocol developed by TI that is used in hundreds, if not thousands of other products that could have also made the same fatal implementation mistakes. It would also require an attacker to write a transmit stage as well as much more complicated python code to craft and encode packets while watching out for new ones to increment by.
The first method is to decrypt a link session packet, which is a connectionless network application. Within this encrypted packet contains the legitimate counter value that will be used during an encrypted session. To elaborate on that, here is an excerpt from the TI Security application note (pg.5):
"Network applications and the Unconnected User Datagram Link ID (UUD) are not connection based. It is not possible to maintain a coherent 4 byte counter. Instead the frames sent to a network application and the UUD populate the counter hint with a random value. This value is used by the recipient to decrypt the payload. The hint is used as the lsbyte of a counter whose remaining 3 bytes are 0. The validity of the frame and defense against rogue frames comes from the protection of the values of the IV and the key. In addition there is the protection afforded by the MAC. This is how there can be some security around the exchange of counter starting values when the Link session is engaged. The Link session takes place on the Link Network application port."
This means that the device will read the counter hint from a link session packet and append it to 3 bytes of zero value and use it to decrypt the payload to discover the actual counter value with the key and IV.
Counter hint = A5, therefore the entire 4 byte counter would be 000000A5.
Since I have the ability to remotely clone devices at will and reboot them causing a new link session to be established, I can obtain this random counter value relatively easily, allowing me to decrypt the link session payload and obtain the counter value to be used in the encrypted session thanks to already knowing the key and IV. Once decrypted, I can craft packets to be sent to the network acting as an authorized device.
Counter hint frame section details:
The FCS means frame check sequence, and it is a cumulative sum of all bytes in the packet that is concatenated with the fixed value MAC. But because the plain text contents of each encrypted section are the same for each specific remote command this value is meaningless and will remain the same throughout.
For those interested in a code representation of this decryption oracle:
from xtea import * from binascii import hexlify <deframing code here> def ctr_hint(ctr): return ctr ctr = hexlify(frame[12:13]) payload = hexlify(frame[15:]) xtea_key = “SimpliciTI’s Key” xtea_iv = 0x87654321 i = new(xtea_key, mode=MODE_CTR, IV=xtea_iv, counter=ctr_hint(ctr)) cipher_block = i.encrypt(payload) plain_text = xor_strings(cipher_block, payload)
The second method is to mount a chosen-ciphertext-attack (CCA) on the encrypted section if I know what the plain text of an alarm system command looks like by just decrypting it once by leveraging the link session vulnerability. This will allow me to encrypt the known plain text using 16777216 possible counter values with the key and IV fairly quickly until a cipher-text (payload) match is found. This short counter space is possible thanks to knowing the last byte of a 4 byte counter from the hint.
Say I intercept a 64 bit block of cipher-text with the value of
DE A9 8F B1 8A 8F 4E C1and have a known plain text of a remote command:
00 02 00 FF FF FF 00 85. I can then encrypt the plain text with the XTEA block cipher as defined in the SimpliciTI code with the known key, IV and a incrementing counter used from 0 to 16777216. Once I’m presented with cipher-text result matching the intercepted cipher-text, the used counter value will be known for that cipher-text and I can increment that recovered counter value by how many packets have been sent by the target device since the attack began. This is entirely possible due to the protocol using completely predictable counter values that are only incremented by one.
I'd like to point out a bit of a TI failure was noticed here too. Since they are using a CTR mode and actually placing this so-called “MAC” within the encrypted section, they are allowing the scheme to be entirely malleable with the CTR mode. What should have been done is encrypt-then-MAC. This would encrypt the plain text, MAC the cipher-text + IV then append it to the cipher-text, thwarting any type of malleability.
Here is a quick example to explain this current situation of malleability without proper message authentication:
Say we want to encrypt the message m=01010101. The CTR mode will use the stored counter and the chosen encryption function to generate a keystream, for example, s=10010110, and compute the cipher-text:
c = m ⊕ s=01010101 ⊕ 10010110 = 11000011
I could now, for example, flip the second bit in the plain text message m by changing c to c′:
c′= c ⊕ 01000000 = 10000011
The decryption function would then use the CTR mode to derive the same key stream s as before, but use it to decrypt c′, which would result in:
m′= c′ ⊕ s=10000011 ⊕ 10010110 = 00010101
As you can see, the second bit (which used to be 1) in the original message was changed to 0 by this change, while leaving the remaining parts of the data unchanged. This ability to manipulate and observe the changes in the oracle is an example of malleability. Now with a proper scheme of encrypt-then-MAC all of this extrapolated information would be useless because the message would first need to be authenticated with the MAC. This would protect all users of the protocol that choose to encrypt the same plain text over and over again but of course using a different counter value for each transaction through the cipher.
The link session will always have some known plain text values too. Namely the port number that the remote device should connect to after the link session has been completed and the link token. This port number can be easily seen in plain text within a packet right after a secure link has been established. The link token is set in firmware to a static value of "0xDEADBEEF" which is in the packet, this would also aid in extrapolating encryption oracle information when no other encryption constants are known.
Jamming is a fairly simple way to cause most RF communications to become useless. I say most because there are ways to protect against some types of jamming such as spread spectrum, frequency hopping, and DSSS. But unfortunately iSmartAlarm employs none of these protections that are actually possible with the CC1110 features, here's a quick example:
Device packets undisturbed by noise:
Jammer in operation creating noise:
The alarm system is now completely useless. Operating or importing a frequency jammer is illegal. This test was done inside of a cage at very low power.
This attack is fairly simple and requires a 900 MHz directional jammer and a device to replay packets such as a SDR or a RFCat enabled device. I will use a YardStick with RFCat in this scenario. With the directional jammer pointed at the target house I can receive packets using the YardStick and they will not be able to reach the alarm system. Since the alarm system cannot receive any packets it's local counter will remain the same for the device that is currently being intercepted, the attacker can now disable the directional jammer at will and replay the packet as long as during the jamming process the victim didn't send more than 255 commands to the alarm system in a furious rage to open it. If they did it would cause the counters to become out of sync and the victim would actually have a dud remote unless they took the batteries back out and put them back in. This piece of code shows that an error will occur if the received counter value is off by more than 255:
Though this is impractical due to it only working if you are able to send the command before the target does. That is highly unlikely by this point, and the target will probably just use their smart phone to unlock the alarm system.
BusyBox udhcpc vulnerability (CVE-2011-2716)
This attack is possible due to the massively outdated software present on the alarm system, specifically BusyBox.
I was able to compromise a “mock” DHCP server the alarm system is connected to. From there command injection is be possible if it parses the DHCP option HOST_NAME, DOMAIN_NAME, NIS_DOMAIN or TFTP_SERVER_NAME. In the case of dhcpd, all I had to do is configure it like so and wait until the system parses these variables:
It is unknown why at times the system parses these variables. Maybe to report back as a status check? I’m not sure, but when it does, it improperly sanitizes the shell metacharacters and executes the injection.
Even though some serious pre-conditions need to be satisfied in-order to successfully exploit this vulnerability, it isn’t all too surprising that someone might have their most likely backdoored or poorly secured chinese router open to the internet.
What does this mean for iSmartAlarm? Not much probably. People will continue to purchase "Smart" devices as long as it is popular and trendy. As long as something is popular and trendy, many manufacturers will make devices to sell, all with varying degrees of security. iSmartAlarm took precautions to make things difficult, but not nearly difficult enough in my opinion.
There is, as with most scenarios, a trade off between cost and high-security. Perhaps iSmartAlarm did some research and concluded that "less security" was okay to keep it under a certain price point.
Seekintoo contacted iSmartAlarm several times without any response or comment from the firm. While we strive for ethical and responsible disclosure, we also realize the drive for research advancement, and shared information in the community.
In this case, we can only assume the manufacturer does not believe that thier customers will care or understand the implications. In this case we feel it is necessary to make sure that any customers who may be concerned are able to read about and understand this research.
While the iSmartAlarm might have some "smart" features, it's not exactly smart when it comes to security, which is the entire premise of their market and product.
The GNURadio GRC files, blocks and python scripts can be downloaded from our github.
Comments, concerns, and corrections are welcome and not triaged by any marketing machine we are aware of: dpidhirney (at) seekintoo (dot) com