Fun with USB Rocket Launchers and Python
I’ve had this USB Rocket Launcher gathering dust in my cupboard for some time but never really used it all that much, It’s primarily aimed at Windows users and has no software for other operating systems or documentation on how it works.
So last weekend I brought it into my workplace for some office warfare, and since our office is open plan this made it an ideal battleground, fueled by some Python.
UPDATE: Code has been posted to TCC’s GitLab, you can get it here: https://git.thecodecache.net/aleyshon/USB-Sentry
In order to make this work from within Python we needed to know what command were being sent to the device, so that we could replay them at our leisure.
To do this I used some software called USBPCap along with Wireshark to dump out the packets being sent.
The device I have uses the Vendor ID of 0x2123 and a Product ID of 0x1010. (DreamCheeky Thunder)
All commands sent to the device had a Request Type of 0x21 (Host to Device) and a Request of 0x09 (SET_CONFIGURATION). The device never returns any data. It is one way communication.
All payloads sent to the Rocket Launcher were always 8 bytes long and always started with 0x02 or 0x03, Followed by a single varying byte, Like this:
0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00 0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x00
Interesting! It seems the other six bytes were not used by any of the commands.
Eventually I had managed to capture all the commands being sent, one at a time and built up a little data sheet about it’s protocol, which was very simple:
Turret Down 0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00 Turret Up 0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x00 Turret Left 0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00 Turret Right 0x02,0x08,0x00,0x00,0x00,0x00,0x00,0x00 Turret Stop 0x02,0x20,0x00,0x00,0x00,0x00,0x00,0x00 Fire 0x02,0x10,0x00,0x00,0x00,0x00,0x00,0x00 LED On 0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00 LED Off 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00
With this data in hand, it was time for some Python! We opted to use the pyUSB library for interfacing with the device.
Here was the final code we came up with, it picks a random number between 1 and 6 and performs an action associated with that number, we will be uploading this to GitLab shortly.
import os import sys import time import usb.core import random class sentry: def __init__(self): # First try to find the USB device. self.dev = usb.core.find(idVendor=0x2123, idProduct=0x1010) if self.dev is None: raise ValueError('Launcher not found.') if self.dev.is_kernel_driver_active(0) is True: self.dev.detach_kernel_driver(0) self.dev.set_configuration() def mainloop(self): while(True): # Pick a random number between 1 and 6. action = random.randint(1,6) # Turn the turrentLED On. self.turrentLED(0x01) if(action == 1): print 'Moving Left' self.turretLeft() self.sleepRandom() elif(action == 2): print 'Moving Right' self.turretRight() self.sleepRandom() elif(action == 3): print 'Moving Up' self.turretUp() self.sleepRandomShort() elif(action == 4): print 'Moving Down' self.turretDown() self.sleepRandomShort() elif(action == 5): print 'Fire!!' self.turretFire() time.sleep(4) else: print 'Flash LED' for x in range(0, 2): self.turrentLED(0x01) time.sleep(0.5) self.turrentLED(0x00) time.sleep(0.5) # Turn the LED Off. self.turrentLED(0x00) # Stop the turret from moving. self.turretStop() # Wait a second until next action time.sleep(1) def turretUp(self): self.dev.ctrl_transfer(0x21,0x09,0,0,[0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x00]) def turretDown(self): self.dev.ctrl_transfer(0x21,0x09,0,0,[0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00]) def turretLeft(self): self.dev.ctrl_transfer(0x21,0x09,0,0,[0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00]) def turretRight(self): self.dev.ctrl_transfer(0x21,0x09,0,0,[0x02,0x08,0x00,0x00,0x00,0x00,0x00,0x00]) def turretStop(self): self.dev.ctrl_transfer(0x21,0x09,0,0,[0x02,0x20,0x00,0x00,0x00,0x00,0x00,0x00]) def turretFire(self): self.dev.ctrl_transfer(0x21,0x09,0,0,[0x02,0x10,0x00,0x00,0x00,0x00,0x00,0x00]) def turrentLED(self, cmd): self.dev.ctrl_transfer(0x21, 0x09, 0, 0, [0x03, cmd, 0x00,0x00,0x00,0x00,0x00,0x00]) def sleepRandom(self): r = random.randint(1,2) print 'Wating for {0} seconds'.format(r) time.sleep(r) def sleepRandomShort(self): r = random.random() print 'Waiting for {0} seconds'.format(r) time.sleep(r) if __name__ == '__main__': # We will need to be root to send custom crafted USB packets. if not os.geteuid() == 0: sys.exit("Script must be run as root.") sentry().mainloop()