Back in college, my roommate got me one of those USB missile launchers that allows you to pan and tilt and fire foam darts. Specifically, it was a Dream Cheeky “Rocket Baby” model (they have since been discontinued). Although it was a fun desk toy, the novelty wore off relatively quickly, and it spent several years sitting in my closet.
Last year, that same former-roommate was designing some CTF challenges for a local infosec conference, Security B-Sides Rochester, and convinced me to develop a fun challenge that utilized the missile launcher. Essentially, my job was to create a small web application where anyone visiting the page could control the pan and tilt movement of the missile launcher, but with the firing ability locked out (there was also a webcam strapped to the turret which streamed video to the page). The goal for participants in this particular CTF challenge, then, was to find and leverage a vulnerability in order to make it actually fire. The details of the CTF challenge itself aren’t important for this post, but I just figured I’d provide a little bit of background about why I decided to do this.
Reverse Engineering the Protocol
Of course, in order to create this challenge, I first had to be able to interface with the missile launcher. As this is a pretty trivial USB device, there already existed plenty of projects/libraries which interface with these toys. To me, though, for small personal projects like this, it’s rewarding to figure that stuff out for myself and write my own code to interface with it. I avoided the temptation of looking at existing implementations and busted out my Beagle USB 480 Protocol Analyzer (which I had originally purchased back when I did my USB independent study).
The missile launcher came with software for Windows, so I booted into Windows, installed the Dream Cheeky software, plugged in the USB analyzer, and started capturing bus activity. Upon plugging in the missile launcher, the enumeration information immediately revealed that this was a USB HID (Human Interface Device). Being a pretty simple device, I was able to take a very straightforward approach to reversing the protocol:
- Use the Dream Cheeky software to “reset” the missile launcher to a nominal position
- While idle, annotate the live capture to indicate that I’ll be tilting the missile launcher up
- Use the Dream Cheeky software to tilt the launcher all the way up until it stops
- Repeat 2-3 for tilting down, panning left, panning right, and firing
Movement Observations
Each time that I instructed the missile launcher to move or fire, I was unexpectedly greeted with a huge spewing of data on the bus (I had initially anticipated seeing perhaps a single packet for each requested operation). This traffic consisted of a continuous stream of alternating Output Report and Input Report HID transfers, each containing only a single byte of payload information. In particular, this is what I observed:
During Tilt Up
While tilting up, I observed the following sequence of HID reports:
- Output Report: 64
- Input Report: 0
- Output Report: 64
- Input Report: 0
- Output Report: 2
- Input Report: 0
- A lengthy repeating stream of pairs:
- Output Report: 64
- Input Report: 0
- Once the launcher was fully tilted up, the stream of traffic terminated, with the last two HID transfers being:
- Input Report: 2
- Output Report: 32
During Tilt Down
While tilting down, I observed a similar pattern with different values:
- Output Report: 64
- Input Report: 2
- Output Report: 64
- Input Report: 2
- Output Report: 1
- Input Report: 2
- A dozen or so pairs of:
- Output Report: 64
- Input Report: 2
- A lengthy repeating stream of pairs:
- Output Report: 64
- Input Report: 0
- Once the launcher was fully tilted down, the stream of traffic terminated, with the last two HID transfers being:
- Input Report: 1
- Output Report: 32
During Pan Left
- Output Report: 64
- Input Report: 1
- Output Report: 64
- Input Report: 1
- Output Report: 4
- Input Report: 1
- A lengthy repeating stream of pairs of:
- Output Report: 64
- Input Report: 1
- Once the launcher was fully panned left, the stream of traffic terminated, with the last two HID transfers being:
- Input Report: 5
- Output Report: 32
During Pan Right
- Output Report: 64
- Input Report: 5
- Output Report: 64
- Input Report: 5
- Output Report: 8
- Input Report: 5
- A handful or so of pairs of:
- Output Report: 64
- Input Report: 5
- A lengthy repeating stream of pairs of:
- Output Report: 64
- Input Report: 1
- Once the launcher was fully tilted down, the stream of traffic terminated, with the last two HID transfers being:
- Input Report: 9
- Output Report: 32
Movement Analysis
Before proceeding to try to figure out what happens when firing, I first tried to understand the commonalities between each of the movements. It seemed like there were a few general patterns that could be extracted:
- The output reports for each movement always started with two 64s, then some other number (which was always a power of two), then more 64s throughout the movement, excepting the very last one
- Input reports for “tilt up” and “pan left” had a constant value throughout the movement, excepting the very last one
- Input reports for “tilt down” and “pan right” transitioned values towards the beginning of movement, but otherwise followed the other patterns observed here
- All movements ended with the input report value changing, followed immediately by the sending of an output report with a value of 32
Having organized my thoughts, I was able to guess at the following:
- The role of the non-64 output report value at the beginning of movement indicated the action to take:
- 1 = down
- 2 = up
- 4 = left
- 8 = right
- The role of the set output report value of 32 was to stop movement
With some additional ad-hoc fiddling around moving the turret around, I verified that these conclusions seemed to hold true.
Unfortunately, the near-continuous stream of output report values of 64 and the role of the input report values were both still a bit mysterious to me. The input reports values were particularly confusing because, as I continued to play around with various movements, I saw different values than the ones I observed during the original capture.
Finally, after much experimentation with moving the turret all around in different directions, I noticed a crucial point: the input value only changed at the end of a movement if I moved the turret all the way to one of its extremes. This made me recognize that the input report values actually contained indications that the turret was at boundaries of its movement. This explains why in my initial observations I saw the value change towards the beginning of the movement as I panned the turret down from its top-most value, and as I panned the turret right from its left-most value. Having come to this epiphany, and playing around with some additional movements to verify my guesses, I arrived at the following mappings for input report values:
- 1 = turret is tilted all the way down
- 2 = turret is tilted all the way up
- 4 = turret is panned all the way left
- 8 = turret is panned all the way right
Furthermore, these values can be ORed together as flags to indicate multiple conditions. This is why I observed an input report value of 5 when I had panned far left after tilting the turret all the way down, for example.
Now there was still the mystery of the set output report values of 64. This one was a little less obvious. Although I’m still not entirely certain of it, this appears to be a mechanism to force the device to send an input report so that it can determine when to send the “stop” command (output report value 32).
Firing Observations and Analysis
Having figured out the aspects above, figuring out the firing operation was actually pretty easy. In fact, when firing, I observed the exact same type of pattern as with the movements, except that the output report value for firing was 16, and the input report value would contain a flag value of 16 to indicate that the missile had fired (due to the mechanisms used to launch the darts, it takes a while in the “firing” state before the spring is fully compressed and then released).
Writing the Controlling Software
With this information figured out, I wanted to create a small command-line client to be able to control the functionality of the missile launcher. You can find the resulting utility on my GitHub account. The software concisely details all of the conclusions that I have drawn out above using C code.
Although I had written software to interface with USB devices prior to this, all such instances were communicating with vendor-defined devices, and either used low-level kernel drivers or the libusb library to communicate. Since this device utilizes an existing USB class (i.e., the HID class), I figured I could use a higher-level library that specifically targets HID devices. With a quick Google search I found that the HIDAPI library does just that. Armed with this library, it became very easy to send output reports and read input reports from the device. Within no time, I was controlling the missile launcher with my own software.
Although not related to the missile launcher, there was something else that was new to me in this project that I figured would be worth mentioning. Since I was developing a command-line application, I wanted to use an existing argument parsing framework to make my life easier. Normally, I would spring for getopt since it’s pretty much the defacto standard for POSIX command-line argument parsing. However, for whatever reason, I decided to see what other options are out there, and I came across argp. After reading a bit about it, I decided to use that over getopt because it provides more boilerplate functionality (for example, automatically handling the GNU-standard –help and –version arguments), and, while not POSIX compliant, was nevertheless available on the platform that I was targeting (Linux).