Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,10 @@ a serial sync with some hosts.
- Appears as: `zbid` lists the device as 'v2'
- Cause: expected behavior, as from the software side only v1 is different than v2-v4, and thus it doesn't see a difference
- Fix: N/A

#### Cannot identify hardware
- In case of problems identifying the hardware try to run the following command (present in [GoodFET](https://github.com/travisgoodspeed/goodfet/blob/master/firmware/apps/radios/ccspi.c)) before any killerbee command

- `~/goodfet/client$ sudo ./goodfet.monitor listapps full`


11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,13 @@ The install will detect and prompt you for what is needed.
On Ubuntu systems, you can install the needed dependencies with the following
commands:
```
# apt-get install python-gtk2 python-cairo python-usb python-crypto python-serial python-dev libgcrypt-dev
# python3 setup.py install
# apt-get install python-usb python-crypto python-serial python-dev libgcrypt-dev
```

On Mac OS, you can install the dependencies with the following commands
```
# brew install libusb libgcrypt
# pip3 install pyusb scapy
```

The python-dev and libgcrypt are required for the Scapy Extension Patch.
Expand All @@ -82,7 +87,7 @@ KillerBee uses the standard Python 'setup.py' installation file, once dependenci

Install KillerBee with the following command:
```
# python setup.py install
# python3 setup.py install
```

DIRECTORIES
Expand Down
11 changes: 8 additions & 3 deletions killerbee/GoodFET.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,12 @@ def bslResetZ1(self, invokeBSL=0):
By now only BSL mode is accessed.
@type invokeBSL: Integer
@param invokeBSL: 1 for a complete sequence, or 0 to only access RST/NMI pin
Applies BSL entry sequence on RST/NMI and TEST/VPP pins
Parameters:
invokeBSL = 1: complete sequence
invokeBSL = 0: only RST/NMI pin accessed

By now only BSL mode is accessed
'''
#if DEBUG > 1: sys.stderr.write("* bslReset(invokeBSL=%s)\n" % invokeBSL)
if invokeBSL:
Expand Down Expand Up @@ -372,7 +378,6 @@ def picROMfastclock(self, masterout):
return self.serialport.getCTS()

def telosBReset(self, invokeBSL=0):
'''Helper function for support of the TelosB platform.'''
# "BSL entry sequence at dedicated JTAG pins"
# rst !s0: 0 0 0 0 1 1
# tck !s1: 1 0 1 0 0 1
Expand Down Expand Up @@ -615,7 +620,7 @@ def setBaud(self,baud):
self.serialport.write(bytearray([0x00, 0x80, 1, baud]))

print("Changed host baud.")
self.serialport.baudrate = rates[baud];
self.serialport.setBaudrate(rates[baud]);
time.sleep(1);
self.serialport.flushInput()
self.serialport.flushOutput()
Expand All @@ -627,7 +632,7 @@ def readbyte(self):
def findbaud(self):
for r in self.baudrates:
print("\nTrying %i" % r);
self.serialport.baudrate = r;
self.serialport.setBaudrate(r);
#time.sleep(1);
self.serialport.flushInput()
self.serialport.flushOutput()
Expand Down
28 changes: 21 additions & 7 deletions killerbee/GoodFETCCSPI.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ def setup(self):

#Set up the radio for ZigBee
self.strobe(0x01); #SXOSCON
self.strobe(0x02); #SCAL
self.strobe(0x01); #SXOSCON ##YL: idk why but needed to enable ram poking
self.strobe(0x02); #SCAL
self.poke(0x11, 0x0AC2 & (~0x0800)); #MDMCTRL0, promiscuous
self.poke(0x12, 0x0500); #MDMCTRL1
self.poke(0x1C, 0x007F); #IOCFG0
Expand Down Expand Up @@ -77,12 +78,11 @@ def peek(self,reg,bytes=2):
bytes=2;

self.writecmd(self.CCSPIAPP,0x02,len(data),data);
try:
toret = (self.data[2] + (self.data[1] << 8))
except Exception as e:
print("issue in peeking for a register")
print(e)
toret = self.data[1] << 8

toret=(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These ord's are causing errors

======================================================================                                
ERROR: test_init (test_apimote_driver.TestApimoteDriver)                                              
----------------------------------------------------------------------                                
Traceback (most recent call last):                 
  File "/Users/taylor/workspace/killerbee/tests/test_apimote_driver.py", line 11, in test_init        
    driver=APIMOTE(os.environ['APIMOTE_DEVSTRING'])                                                   
  File "/Users/taylor/.pyenv/versions/killerbee/lib/python3.9/site-packages/killerbee-3.0.0b1-py3.9-macosx-10.15-x86_64.egg/killerbee/dev_apimote.py", line 53, in __init__
    self.handle.setup()                            
  File "/Users/taylor/.pyenv/versions/killerbee/lib/python3.9/site-packages/killerbee-3.0.0b1-py3.9-macosx-10.15-x86_64.egg/killerbee/GoodFETCCSPI.py", line 25, in setup
    self.poke(0x11, 0x0AC2 & (~0x0800)); #MDMCTRL0, promiscuous                                       
  File "/Users/taylor/.pyenv/versions/killerbee/lib/python3.9/site-packages/killerbee-3.0.0b1-py3.9-macosx-10.15-x86_64.egg/killerbee/GoodFETCCSPI.py", line 92, in poke
    if self.peek(reg,bytes)!=val and reg!=0x18:    
  File "/Users/taylor/.pyenv/versions/killerbee/lib/python3.9/site-packages/killerbee-3.0.0b1-py3.9-macosx-10.15-x86_64.egg/killerbee/GoodFETCCSPI.py", line 83, in peek
    ord(self.data[2])+                             
TypeError: ord() expected string of length 1, but int found     

self.data[2]+(self.data[1]<<8)
);

return toret;
def poke(self,reg,val,bytes=2):
"""Write a CCSPI Register."""
Expand Down Expand Up @@ -199,6 +199,20 @@ def pokeram(self,adr,data):
return;

lastpacket=list(range(0,0xff));

def RF_txrxpacket(self,packet,timeout=1):
data="\0";
self.data=data;
packet = [timeout&0xff, timeout>>8] + packet

self.writecmd(self.CCSPIAPP,0x86,len(packet),packet);
buffer=self.data;
self.lastpacket=buffer;
if(len(buffer)==0):
return None;

return buffer;

def RF_rxpacket(self):
"""Get a packet from the radio. Returns None if none is
waiting."""
Expand Down
2 changes: 1 addition & 1 deletion killerbee/GoodFETatmel128.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def pyserInit(self, port, timeout, attemptlimit):
break
if self.verbose:
print("Connected after %02i attempts." % attempts);
self.serialport.timeout = 12;
self.serialport.setTimeout(12);

def serClose(self):
self.connected = 0
Expand Down
22 changes: 3 additions & 19 deletions killerbee/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,6 @@
from .config import * #to get DEV_ENABLE_* variables

# Utility Functions
def getKillerBee(channel: int, page: int=0) -> KillerBee:
'''
Returns an instance of a KillerBee device, setup on the given channel/page.
Error handling for KillerBee creation and setting of the channel is wrapped
and will raise an Exception().
@return: A KillerBee instance initialized to the given channel/page.
'''
kb: KillerBee = KillerBee()
if kb is None:
raise Exception("Failed to create a KillerBee instance.")
try:
kb.set_channel(channel, page)
except Exception as e:
raise Exception('Error: Failed to set channel to %d/%d' % (channel, page), e)
return kb

def show_dev(vendor: str=None, product: str=None, gps: str=None, include: str=None) -> None:
'''
A basic function to output the device listing.
Expand Down Expand Up @@ -158,10 +142,10 @@ def __init__(self, device: str=None, datasource: str=None, gps: str=None) -> Non
self.driver = TELOSB(self.dev)
elif gfccspi and subtype == 1:
from .dev_apimote import APIMOTE
self.driver = APIMOTE(self.dev, revision=1)
self.driver = APIMOTE(self.dev)
elif gfccspi and subtype == 2:
from .dev_apimote import APIMOTE
self.driver = APIMOTE(self.dev, revision=2)
self.driver = APIMOTE(self.dev)
else:
raise KBInterfaceError("KillerBee doesn't know how to interact with serial device at '%s'." % self.dev)
# Otherwise unrecognized device string type was provided:
Expand Down Expand Up @@ -412,7 +396,7 @@ def inject(self, packet: str, channel: Optional[int]=None, count: int=1, delay:

return self.driver.inject(packet, channel, count, delay, page)

def pnext(self, timeout: int=100) -> Optional[Dict[str, Union[int, bool, str]]]:
def pnext(self, timeout: int=100) -> Optional[Dict[Union[int, str], Any]]:
'''
Returns packet data as a string, else None.
@type timeout: Integer
Expand Down
4 changes: 2 additions & 2 deletions killerbee/daintree.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ def pnext(self) -> Optional[list[Any]]:

try:
while(1):
record: List[bytes] = self._fh.readline().split(' ')
if record[0][0] == "#":
record: list[bytes] = self._fh.readline().split(b' ')
if record[0] == b"#":
continue
else:
break
Expand Down
75 changes: 49 additions & 26 deletions killerbee/dev_apimote.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,34 +22,29 @@
from .kbutils import KBCapabilities, makeFCS
from .GoodFETCCSPI import GoodFETCCSPI

# Default revision of the ApiMote. This is liable to change at any time
# as new ApiMote versions are released. Automatic recognition would be nice.
DEFAULT_REVISION: int = 2

CC2420_REG_SYNC: int = 0x14

class APIMOTE:
def __init__(self, dev: str, revision: int=DEFAULT_REVISION) -> None:

def __init__(self, dev: str) -> None:
'''
Instantiates the KillerBee class for the ApiMote platform running GoodFET firmware.
@type dev: String
@param dev: Serial device identifier (ex /dev/ttyUSB0)
@type revision: Integer
@param revision: The revision number for the ApiMote, which is used by
the called GoodFET libraries to properly communicate with
and configure the hardware.
@return: None
@rtype: None
'''
self.packet_queue: Optional[bytes] = None
self.packet_queue_rssi: Optional[int] = None

self._channel: Optional[int] = None
self._page: int = 0
self.handle: Optional[Any] = None
self.dev: str = dev

self.__revision_num: int = revision
# Set enviroment variables for GoodFET code to use
os.environ["platform"] = "apimote{}".format(self.__revision_num)
os.environ["board"] = "apimote{}".format(self.__revision_num)
os.environ["platform"] = "apimote2"
os.environ["board"] = "apimote2"
self.handle = GoodFETCCSPI()
self.handle.serInit(port=self.dev)
self.handle.setup()
Expand Down Expand Up @@ -94,7 +89,7 @@ def get_dev_info(self) -> list[Union[str, Any]]:
@rtype: List
@return: List of 3 strings identifying device.
'''
return [self.dev, "GoodFET Apimote v{}".format(self.__revision_num), ""]
return [self.dev, "GoodFET Apimote v2", ""]

# KillerBee expects the driver to implement this function
def sniffer_on(self, channel: Optional[int]=None, page: int=0) -> None:
Expand Down Expand Up @@ -205,26 +200,54 @@ def pnext(self, timeout: int=100) -> Any:

if self.__stream_open == False:
self.sniffer_on()

if self.packet_queue is None:
packet: Optional[Any] = None
start = datetime.utcnow()

while (packet is None and
(start + timedelta(microseconds=timeout) > datetime.utcnow())):
packet = self.handle.RF_rxpacket()
rssi = self.handle.RF_getrssi() #TODO calibrate

if packet is None:
return None

if ord(packet[0])+1 < len(packet):
self.packet_queue = packet[ord(packet[0])+1+1:]
self.packet_queue_rssi = rssi

frame = packet[1:ord(packet[0])+1]
else:
packet = self.packet_queue
self.packet_queue = None
frame = packet

if self.packet_queue_rssi is None:
rssi = None
else:
rssi = self.packet_queue_rssi

packet: Optional[bytes] = None
start: datetime = datetime.utcnow()

while (packet is None and (start + timedelta(microseconds=timeout) > datetime.utcnow())):
packet = self.handle.RF_rxpacket()
rssi: int = self.handle.RF_getrssi() #TODO calibrate

if packet is None:
return None

frame: bytes = packet[1:]
validcrc: bool = False
if frame[-2:] == makeFCS(frame[:-2]):
validcrc = True
#Return in a nicer dictionary format, so we don't have to reference by number indicies.
#Note that 0,1,2 indicies inserted twice for backwards compatibility.
result: Dict[Union[int, str], Any] = {0:frame, 1:validcrc, 2:rssi, 'bytes':frame, 'validcrc':validcrc, 'rssi':rssi, 'location':None}
result['dbm'] = rssi - 45 #TODO tune specifically to the Apimote platform (does ext antenna need to different?)
result: Dict[Union[int, str], Any] = {
0: frame,
1: validcrc,
2: rssi,
'bytes': frame,
'validcrc': validcrc,
'rssi': rssi,
'location': None
}

result['datetime'] = datetime.utcnow()
if rssi is None:
result['dbm'] = None
else:
result['dbm'] = rssi - 45 #TODO tune specifically to the Apimote platform (does ext antenna need to different?)
return result

def ping(self, da: Any, panid: Any, sa: Any, channel: Optional[int]=None, page: int=0) -> None:
Expand Down
2 changes: 1 addition & 1 deletion killerbee/kbutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ def isgoodfetccspi(serialdev: str) -> Tuple[bool, Optional[int]]:
os.environ["board"] = "apimote2" #set enviroment variable for GoodFET code to use
gf = GoodFETCCSPI()
try:
gf.serInit(port=serialdev, attemptlimit=2)
gf.serInit(port=serialdev, attemptlimit=30)
#gf.setup()
except serial.serialutil.SerialException as e:
raise KBInterfaceError("Serial issue in kbutils.isgoodfetccspi: %s." % e)
Expand Down
5 changes: 2 additions & 3 deletions killerbee/scapy_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,17 @@
setattr(conf, 'killerbee_page', DEFAULT_KB_PAGE)
setattr(conf, 'killerbee_device', DEFAULT_KB_DEVICE)
setattr(conf, 'killerbee_nkey', None)
from scapy import plist
from scapy.base_classes import SetGen # type: ignore
from scapy.packet import Gen, Raw # type: ignore
from scapy.all import Dot15d4 # type: ignore
from scapy.all import Dot15d4FCS # type: ignore
from scapy.all import plist # type: ignore
from scapy.all import PcapWriter # type: ignore
from scapy.all import ZigbeeSecurityHeader # type: ignore
from scapy.all import ZigbeeNWK # type: ignore
from scapy.all import ZigbeeAppDataPayload # type: ignore
from scapy.all import ZigbeeNWKCommandPayload # type: ignore
from scapy.all import Packet # type: ignore
from scapy.all import Layer # type: ignore

# This line will allow KillerBee's pcap reader to overwrite scapy's reader that is imported on the
# above line, per suggestion from cutaway at https://code.google.com/p/killerbee/issues/detail?id=28:
Expand Down Expand Up @@ -593,7 +592,7 @@ def kbgetmiclen(seclevel: int) -> int:
return lengths[seclevel]

@conf.commands.register
def kbgetpanid(packet: Gen) -> Tuple[Optional[bytes], Optional[Layer]]:
def kbgetpanid(packet: Gen) -> Tuple[Optional[bytes], Optional[Any]]:
"""Returns the pan id and which layer it was found in or None, None"""
for layer in packet.layers():
for field in packet[layer].fields:
Expand Down
File renamed without changes.
17 changes: 2 additions & 15 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,6 @@
apt_get_pkgs = []
pip_pkgs = []

# We have made gtk, cairo, scapy-com into optional libraries
try:
import gtk
except ImportError:
warn.append("gtk")
apt_get_pkgs.append("python-gtk2")

try:
import cairo
except ImportError:
warn.append("cairo")
apt_get_pkgs.append("python-cairo")

# Ensure we have either pyUSB 0.x or pyUSB 1.x, but we now
# prefer pyUSB 1.x moving forward. Support for 0.x may be deprecated.
try:
Expand Down Expand Up @@ -80,15 +67,15 @@
)

setup(name = 'killerbee',
version = '3.0.0-beta.0',
version = '3.0.0-beta.1',
description = 'ZigBee and IEEE 802.15.4 Attack Framework and Tools',
author = 'Joshua Wright, Ryan Speers',
author_email = 'jwright@willhackforsushi.com, ryan@riverloopsecurity.com',
license = 'LICENSE.txt',
packages = ['killerbee'],
scripts = ['tools/zbdump', 'tools/zbgoodfind', 'tools/zbid', 'tools/zbreplay',
'tools/zbconvert', 'tools/zbdsniff', 'tools/zbstumbler', 'tools/zbassocflood',
'tools/zbfind', 'tools/zbscapy', 'tools/zbwireshark', 'tools/zbkey',
'tools/zbscapy', 'tools/zbwireshark', 'tools/zbkey',
'tools/zbwardrive', 'tools/zbopenear', 'tools/zbfakebeacon',
'tools/zborphannotify', 'tools/zbpanidconflictflood', 'tools/zbrealign', 'tools/zbcat',
'tools/zbjammer', 'tools/kbbootloader'],
Expand Down
2 changes: 0 additions & 2 deletions tests/fixtures/test_dt_dump.dcf

This file was deleted.

2 changes: 1 addition & 1 deletion tests/test_apimote_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def test_sniffer_on_off(self):
driver.close()
self.assertTrue(True)

def test_set_channe(self):
def test_set_channel(self):
driver=APIMOTE(os.environ['APIMOTE_DEVSTRING'])

self.assertRaises(Exception, driver.set_channel, 1)
Expand Down
Loading