1
mirror of https://github.com/rapid7/metasploit-framework synced 2024-11-05 14:57:30 +01:00

Land #8065, Zigbee Hardware Bridge Extension

This commit is contained in:
Pearce Barry 2017-03-20 10:44:15 -05:00
commit 06ebb22a8f
No known key found for this signature in database
GPG Key ID: 0916F4DEA5C5DE0A
10 changed files with 884 additions and 1 deletions

View File

@ -0,0 +1,38 @@
Actively scans the Zigbee channels by sending a beacon broadcast packet and listening for responses.
## Options
**DEVICE**
ZigBee Device ID. Defaults to the target device that is specified via the target command or if
one device is presented when running 'supported_devices' it will use that device.
**CHANNEL**
The channel to scan. Setting this options will prevent the stumbler from changing channels. Range is 11-26, inclusive. Default: not set
n
**LOOP**
How many times to loop over the channels. Specifying a -1 will loop forever. Default: 1
**DELAY**
The delay in seconds to listen to each channel. Default: 2
## Scenarios
Scanning channel 11 for other ZigBee devices in the area.
```
hwbridge > run post/hardware/zigbee/zstumbler channel=11
[*] Scanning Channel 11
[*] New Network: PANID: 0x4724 SOURCE: 0x25D5
[*] Ext PANID: 6E:03:C7:74:31:E2:74:AA Stack Profile: ZigBee Enterprise
[*] Stack Version: ZigBee 2006/2007
[*] Channel: 11
[*] New Network: PANID: 0x4724 SOURCE: 0x7DD1
[*] Ext PANID: 6E:03:C7:74:31:E2:74:AA Stack Profile: ZigBee Enterprise
[*] Stack Version: ZigBee 2006/2007
[*] Channel: 11
```

View File

@ -157,6 +157,16 @@ class HWBridge < Rex::Post::HWBridge::Client
console.disable_output = original
end
#
# Loads the zigbee extension
#
def load_zigbee
original = console.disable_output
console.disable_output = true
console.run_single('load zigbee')
console.disable_output = original
end
#
# Load custom methods provided by the hardware
#

View File

@ -1,4 +1,5 @@
# -*- coding: binary -*-
module Msf::Post::Hardware
require 'msf/core/post/hardware/automotive/uds'
require 'msf/core/post/hardware/zigbee/utils'
end

View File

@ -0,0 +1,255 @@
# -*- coding: binary -*-
module Msf
class Post
module Hardware
module Zigbee
module Utils
## Constants for packet decoding fields
# Frame Control Field
DOT154_FCF_TYPE_MASK = 0x0007 #: Frame type mask
DOT154_FCF_SEC_EN = 0x0008 #: Set for encrypted payload
DOT154_FCF_FRAME_PND = 0x0010 #: Frame pending
DOT154_FCF_ACK_REQ = 0x0020 #: ACK request
DOT154_FCF_INTRA_PAN = 0x0040 #: Intra-PAN activity
DOT154_FCF_DADDR_MASK = 0x0C00 #: Destination addressing mode mask
DOT154_FCF_VERSION_MASK = 0x3000 #: Frame version
DOT154_FCF_SADDR_MASK = 0xC000 #: Source addressing mask mode
# Frame Control Field Bit Shifts
DOT154_FCF_TYPE_MASK_SHIFT = 0 #: Frame type mask mode shift
DOT154_FCF_DADDR_MASK_SHIFT = 10 #: Destination addressing mode mask
DOT154_FCF_VERSION_MASK_SHIFT = 12 #: Frame versions mask mode shift
DOT154_FCF_SADDR_MASK_SHIFT = 14 #: Source addressing mask mode shift
# Address Mode Definitions
DOT154_FCF_ADDR_NONE = 0x0000 #: Not sure when this is used
DOT154_FCF_ADDR_SHORT = 0x0002 #: 4-byte addressing
DOT154_FCF_ADDR_EXT = 0x0003 #: 8-byte addressing
DOT154_FCF_TYPE_BEACON = 0 #: Beacon frame
DOT154_FCF_TYPE_DATA = 1 #: Data frame
DOT154_FCF_TYPE_ACK = 2 #: Acknowledgement frame
DOT154_FCF_TYPE_MACCMD = 3 #: MAC Command frame
DOT154_CRYPT_NONE = 0x00 #: No encryption, no MIC
DOT154_CRYPT_MIC32 = 0x01 #: No encryption, 32-bit MIC
DOT154_CRYPT_MIC64 = 0x02 #: No encryption, 64-bit MIC
DOT154_CRYPT_MIC128 = 0x03 #: No encryption, 128-bit MIC
DOT154_CRYPT_ENC = 0x04 #: Encryption, no MIC
DOT154_CRYPT_ENC_MIC32 = 0x05 #: Encryption, 32-bit MIC
DOT154_CRYPT_ENC_MIC64 = 0x06 #: Encryption, 64-bit MIC
DOT154_CRYPT_ENC_MIC128 = 0x07 #: Encryption, 128-bit MIC
# Infer if the current session is for a ZigBee device.
# @return [Boolean] true if session is for a ZigBee device, false otherwise
def is_zigbee_hwbridge_session?
return true if client.zigbee
print_error("Not a ZigBee hwbridge session")
false
end
# Verify if a device has been specified.
# @return [Boolean] true if device is specified, false otherwise
def verify_device(device)
return true if device
print_line("No target device set, use 'target' or specify bus via the options.")
false
end
# Retrieves the target Zigbee device. This is typically set by the user via the
# interactive HWBridge command line
# @return [String] Zigbee device ID
def get_target_device
return unless is_zigbee_hwbridge_session?
return client.zigbee.get_target_device
end
# Sets the target default Zigbee Device. This command typically isn't called via a script
# Instead the user is expected to set this via the interactive HWBridge commandline
# @param device [String] Zigbee device ID
def set_target_device(device)
return unless is_zigbee_hwbridge_session?
client.zigbee.set_target_device device
end
# Sets the Zigbee Channel
# @param device [String] Zigbee device ID
# @param channel [Integer] Channel number, typically 11-25
def set_channel(device, channel)
return {} unless is_zigbee_hwbridge_session?
device = client.zigbee.target_device unless device
return {} unless verify_device(device)
client.zigbee.set_channel(device, channel)
end
# Inject raw packets. Need firmware on the zigbee device that supports transmission.
# @param device [String] Zigbee device ID
# @param data [String] Raw binary data sent as a string
def inject(device, data)
return {} unless is_zigbee_hwbridge_session?
device = client.zigbee.target_device unless device
return {} unless verify_device(device)
client.zigbee.inject(device, data)
end
# Recieves data from the Zigbee device
# @param device [String] Zigbee device ID
# @return [String] Binary blob of returned data
def recv(device)
return {} unless is_zigbee_hwbridge_session?
device = client.zigbee.target_device unless device
return {} unless verify_device(device)
client.zigbee.recv(device)
end
# Turn off Zigbee receiving
# @param device [String] Zigbee device ID
def sniffer_off(device)
return {} unless is_zigbee_hwbridge_session?
device = client.zigbee.target_device unless device
return {} unless verify_device(device)
client.zigbee.sniffer_off(device)
end
# Turn on Zigbee receiving
# @param device [String] Zigbee device ID
def sniffer_on(device)
return {} unless is_zigbee_hwbridge_session?
device = client.zigbee.target_device unless device
return {} unless verify_device(device)
client.zigbee.sniffer_on(device)
end
# Breaks up the packet into different sections. Also provides
# Some decoding information. This method relates to Killerbee's Pktchop method and
# Returns a similar array structure PktChop. If it's a beacon data you will also have
# A BEACONDATA array of raw beacon related packets. You can pull other decoded portions from
# the returned hash such as
# FSF
# SEQ
# SPAN_ID
# SOURCE
# SUPERFRAME
# GTS
# PENDING_ADDRESS_COUNT
# PROTOCOL_ID
# STACK_PROFILE
# CAPABILITY
# EXT_PAN_ID
# TX_OFFSET
# UPDATE_ID
# @param packet [String] Raw data from recv
# @return [Hash] { PktChop => [Array of data], ..
def dot154_packet_decode(packet)
result = {}
offset = 0
pktchop = ['', '', '', '', '', '', [], '']
pktchop[0] = packet[0,2]
# Sequence number
pktchop[1] = packet[2]
# Byte swap
fcf = pktchop[0].reverse.unpack("H*")[0].hex
result["FSF"] = fcf
result["SEQ"] = pktchop[1]
# Check if we are dealing with a beacon frame
if (fcf & DOT154_FCF_TYPE_MASK) == DOT154_FCF_TYPE_BEACON
beacondata = ["", "", "", "", "", "", "", "", "", ""]
# 802.15.4 fields, SPAN and SA
pktchop[4] = packet[3,2]
pktchop[5] = packet[5,2]
result["SPAN_ID"] = pktchop[4].reverse.unpack("H*")[0]
result["SOURCE"] = pktchop[5].reverse.unpack("H*")[0]
offset = 7
# Superframe specification
beacondata[0] = packet[offset,2]
result["SUPERFRAME"] = beacondata[0]
offset+=2
# GTS data
beacondata[1] = packet[offset]
result["GTS"] = beacondata[1]
offset+=1
# Pending address count
beacondata[2] = packet[offset]
result["PENDING_ADDRESS_COUNT"] = beacondata[2]
offset+=1
# Protocol ID
beacondata[3] = packet[offset]
result["PROTOCOL_ID"] = beacondata[3]
offset+=1
# Stack Profile version
beacondata[4] = packet[offset]
result["STACK_PROFILE"] = beacondata[4]
offset+=1
# Capability information
beacondata[5] = packet[offset]
result["CAPABILITY"] = beacondata[5]
offset+=1
# Extended PAN ID
beacondata[6] = packet[offset,8]
result["EXT_PAN_ID"] = beacondata[6].reverse.unpack("H*")[0]
offset+=8
# TX Offset
beacondata[7] = packet[offset,3]
result["TX_OFFSET"] = beacondata[7]
offset+=3
# Update ID
beacondata[8] = packet[offset]
result["UPDATE_ID"] = beacondata[8]
offset+=1
pktchop[6] = beacondata
result["BEACONDATA"] = beacondata
else
# Not a beacon frame
# DPAN
pktchop[2] = packet[3,2]
offset = 5
# Examine the destination addressing mode
daddr_mask = (fcf & DOT154_FCF_DADDR_MASK) >> 10
if daddr_mask == DOT154_FCF_ADDR_EXT
pktchop[3] = packet[offset,8]
offset+=8
elsif daddr_mask == DOT154_FCF_ADDR_SHORT
pktchop[3] = packet[offset,2]
offset+=2
end
# Examine the Intra-PAN flag
if (fcf & DOT154_FCF_INTRA_PAN) == 0
pktchop[4] = packet[offset,2]
offset+=2
end
# Examine the source addressing mode
saddr_mask = (fcf & DOT154_FCF_SADDR_MASK) >> 14
if daddr_mask == DOT154_FCF_ADDR_EXT
pktchop[5] = packet[offset,8]
offset+=8
elsif daddr_mask == DOT154_FCF_ADDR_SHORT
pktchop[5] = packet[offset,2]
offset+=2
end
end
# Append remaining payload
pktchop[7] = packet[offset,packet.size] if offset < packet.size
result["PktChop"] = pktchop
return result
end
end
end
end
end
end

View File

@ -0,0 +1,95 @@
#
# -*- coding: binary -*-
require 'rex/post/hwbridge/client'
module Rex
module Post
module HWBridge
module Extensions
module Zigbee
###
# Zigbee extension - set of commands to be executed on zigbee compatible hw bridges
###
class Zigbee < Extension
def initialize(client)
super(client, 'zigbee')
# Alias the following things on the client object so that they
# can be directly referenced
client.register_extension_aliases(
[
{
'name' => 'zigbee',
'ext' => self
}
])
end
# Sets the default target device
# @param device [String] Target Zigbee device ID
def set_target_device(device)
self.target_device = device
end
# Retrieves the default zigbee device ID
# @return [String] Zigbee device ID
def get_target_device
self.target_device
end
# Gets supported Zigbee Devices
# @return [Array] Devices
def supported_devices
client.send_request("/zigbee/supported_devices")
end
# Sets the channel
# @param dev [String] Device to affect
# @param channel [Integer] Channel number
def set_channel(dev, channel)
client.send_request("/zigbee/#{dev}/set_channel?chan=#{channel}")
end
# Injects a raw packet
# @param dev [String] Zigbee Device ID
# @param data [String] Raw hex data that will be Base64 encoded
def inject(dev, data)
data = Base64.urlsafe_encode64(data)
client.send_request("/zigbee/#{dev}/inject?data=#{data}")
end
# Receives data from transceiver
# @param dev [String] Zigbee Device ID
# @return [Hash] { data: HexString, valid_crc: X, rssi: X }
def recv(dev)
data = client.send_request("/zigbee/#{dev}/recv")
if data.size > 0
data["data"] = Base64.urlsafe_decode64(data["data"]) if data.has_key? "data"
end
data
end
# Disables sniffer and puts the device in a state that can be changed (like adujsting channel)
# @param dev [String] Zigbee Device ID
def sniffer_off(dev)
client.send_request("/zigbee/#{dev}/sniffer_off")
end
# Enables sniffer receive mode. Not necessary to call before calling recv
# @param dev [String] Zigbee Device ID
def sniffer_on(dev)
client.send_request("/zigbee/#{dev}/sniffer_on")
end
attr_accessor :target_device
end
end
end
end
end
end

View File

@ -63,7 +63,7 @@ class Console::CommandDispatcher::Automotive
def cmd_busconfig(*args)
bus = ''
bus_config_opts = Rex::Parser::Arguments.new(
'-h' => [ false, 'Help Banner' ],
'-h' => [ false, 'Help banner' ],
'-b' => [ true, 'Target bus']
)
bus_config_opts.parse(args) do |opt, _idx, val|

View File

@ -0,0 +1,125 @@
# -*- coding: binary -*-
require 'rex/post/hwbridge'
require 'msf/core/auxiliary/report'
module Rex
module Post
module HWBridge
module Ui
###
# Zigbee extension - set of commands to be executed on Zigbee compatible devices
###
class Console::CommandDispatcher::Zigbee
include Console::CommandDispatcher
include Msf::Auxiliary::Report
#
# List of supported commands.
#
def commands
all = {
'supported_devices' => 'Get supported ZigBee devices',
'target' => 'Set the target device id',
'channel' => 'Set the channel'
}
all
end
# Sets the target device both in the UI class and in the base API
# @param device [String] Device ID
def set_target_device(device)
self.target_device = device
client.zigbee.set_target_device device
end
#
# Lists all thesupported devices
#
def cmd_supported_devices
devices = client.zigbee.supported_devices
if !devices or !devices.has_key? "devices"
print_line("error retrieving list of devices")
return
end
devices = devices["devices"]
unless devices.size > 0
print_line("none")
return
end
set_target_device(devices[0]) if devices.size == 1
str = "Supported Devices: "
str << devices.join(', ')
str << "\nUse device name to set your desired device, default is: #{self.target_device}"
print_line(str)
end
#
# Sets the default target device
#
def cmd_target(*args)
self.target_device = ""
device_opts = Rex::Parser::Arguments.new(
'-h' => [ false, 'Help banner' ],
'-d' => [ true, 'Device ID' ]
)
device_opts.parse(args) do |opt, _idx, val|
case opt
when '-h'
print_line("Usage: target -d <device id>\n")
print_line(device_opts.usage)
return
when '-d'
set_target_device val
end
end
print_line("set target device to #{self.target_device}")
end
#
# Sets the channel
#
def cmd_channel(*args)
chan = 11
dev = self.target_device if self.target_device
xopts = Rex::Parser::Arguments.new(
'-h' => [ false, 'Help banner' ],
'-d' => [ true, 'ZigBee device' ],
'-c' => [ true, 'Channel number' ]
)
xopts.parse(args) do |opt, _idx, val|
case opt
when '-h'
print_line("Usage: channel -c <channel number>\n")
print_line(xopts.usage)
return
when '-d'
dev = val
when '-c'
chan = val.to_i
end
end
if !dev
print_line("You must specify or set a target device")
return
end
client.zigbee.set_channel(dev, chan)
print_line("Device #{dev} channel set to #{chan}")
end
#
# Name for this dispatcher
#
def name
'Zigbee'
end
attr_accessor :target_device
end
end
end
end
end

View File

@ -67,6 +67,8 @@ class MetasploitModule < Msf::Auxiliary
if (res.code == 200)
print_status res.body if datastore["DEBUGJSON"] == true
return JSON.parse(res.body)
elsif res.code == 401
print_error "Access Denied: #{res.body}"
end
return nil
@ -98,6 +100,9 @@ class MetasploitModule < Msf::Auxiliary
if self.hw_specialty.has_key? "automotive"
sess.load_automotive if self.hw_specialty["automotive"] == true
end
if self.hw_specialty.has_key? "zigbee"
sess.load_zigbee if self.hw_specialty["zigbee"] == true
end
end
#

View File

@ -0,0 +1,103 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'rex'
require 'msf/core/post/hardware/zigbee/utils'
class MetasploitModule < Msf::Post
include Msf::Post::Hardware::Zigbee::Utils
def initialize(info={})
super( update_info( info,
'Name' => 'Sends Beacons to Scan for Active ZigBee Networks',
'Description' => %q{ Post Module to send beacon signals to the broadcast address while
channel hopping},
'License' => MSF_LICENSE,
'Author' => ['Craig Smith'],
'Platform' => ['hardware'],
'SessionTypes' => ['hwbridge']
))
register_options([
OptInt.new('CHANNEL', [false, "Disable channel hopping by forcing a channel (11-26)", nil]),
OptInt.new('LOOP', [false, "How many times to loop over the channels (-1 will run in an endless loop)", 1]),
OptInt.new('DELAY', [false, "Delay in seconds to listen on each channel", 2]),
OptString.new('DEVICE', [false, "ZigBee device ID, defaults to target device", nil])
], self.class)
@seq = 0
@channel = 11
@stumbled = {}
@loop_count = 0
end
def display_details(routerdata)
stackprofile_map = {0 => "Network Specific",
1 => "ZigBee Standard",
2 => "ZigBee Enterprise"}
stackver_map = {0 => "ZigBee Prototype",
1 => "ZigBee 2004",
2 => "ZigBee 2006/2007"}
spanid, source, extpanid, stackprofilever, channel = routerdata
stackprofilever = stackprofilever.unpack("H*")[0].hex
stackprofile = stackprofilever & 0x0f
stackver = (stackprofilever & 0xf0) >> 4
profile = "Unknown"
profile = stackprofile_map[stackprofile] if stackprofile_map.has_key? stackprofile
ver = "Unknown"
ver = stackver_map[stackver] if stackver_map.has_key? stackver
print_status("New Network: PANID: 0x#{spanid.upcase} SOURCE: 0x#{source.upcase}")
print_status(" Ext PANID: #{extpanid.upcase.scan(/../).join(':')} Stack Profile: #{profile}")
print_status(" Stack Version: #{ver}")
print_status(" Channel: #{@channel}")
end
def scan
@seq = 0 if @seq > 255
print_status("Scanning Channel #{@channel}")
set_channel(datastore["DEVICE"], @channel)
beacon = "\x03\x08#{@seq.chr}\xff\xff\xff\xff\x07"
inject(datastore["DEVICE"], beacon)
delay = Time.now + datastore["DELAY"]
while delay > Time.now()
pkt = recv(datastore["DEVICE"])
if pkt and pkt.size > 0 and pkt["valid_crc"]
pktdecode = dot154_packet_decode(pkt["data"])
if (pktdecode["FSF"] & DOT154_FCF_TYPE_MASK) == DOT154_FCF_TYPE_BEACON
key = "#{pktdecode["SPAN_ID"]}#{pktdecode["SOURCE"]}"
value = [pktdecode["SPAN_ID"], pktdecode["SOURCE"], pktdecode["EXT_PAN_ID"], pktdecode["STACK_PROFILE"], @channel]
if not @stumbled.has_key? key
@stumbled[key] = value
display_details(value)
end
end
end
end
sniffer_off(datastore["DEVICE"]) # Needed to clear receive buffers
@seq += 1
@channel += 1 if not datastore["CHANNEL"]
@loop_count += 1 if @channel > 26 or datastore["CHANNEL"]
@channel = 11 if @channel > 26
end
def run
if not get_target_device and not datastore["DEVICE"]
print_error "No target device set. Either set one with the 'target' command or specify the DEVICE."
return
end
@channel = datastore["CHANNEL"] if datastore["CHANNEL"]
@channel = 11 if @channel > 26
if datastore["LOOP"] == -1
while(1) do
scan
end
else
while(@loop_count < datastore["LOOP"])
scan
end
end
end
end

251
tools/hardware/killerbee_msfrelay Executable file
View File

@ -0,0 +1,251 @@
#!/usr/bin/env python
# KillerBee Metasploit relay server
import re
import os
import sys
import cmd
import time
import json
import base64
import socket
import threading
import pkg_resources # Used to get killerbee version
from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer
from urlparse import parse_qs,urlparse
from killerbee import *
last_errors = 0
starttime = 0
packets_sent = 0
last_sent = 0
username = None
password = None
kb = None
class MSFHandler(BaseHTTPRequestHandler):
def status(self):
status = {}
hw_versions = []
fw_version = pkg_resources.get_distribution("killerbee").version
device_names = []
for dev in kbutils.devlist():
hw_versions.append(dev[2])
device_names.append(dev[1])
if len(hw_versions) > 0:
status["operational"] = 1
else:
status["operational"] = 0
status["hw_specialty"] = { "zigbee": True }
# TODO: We should check firmware before reporting transmit capabilities
status["hw_capabilities"] = { "transmit": True}
status["last_10_errors"] = last_errors
status["api_version"] = "0.0.3"
status["fw_version"] = fw_version
if len(hw_versions) == 1:
status["hw_version"] = hw_versions[0]
status["device_name"] = device_names[0]
elif len(hw_versions) > 1:
status["hw_version"] = ', '.join(hw_versions)
status["device_name"] = ', '.join(device_names)
else:
status["hw_version"] = "Not Supported"
return status
def statistics(self):
global packets_sent
stats = {}
stats["uptime"] = int(time.time()) - starttime
stats["packet_stats"] = packets_sent
stats["last_request"] = last_sent
stats["voltage"] = "0.0v"
return stats
def datetime(self):
return { "sytem_datetime": int(time.time()) }
def timezone(self):
return { "system_timezone": time.strftime("%Z") }
def set_channel(self, args):
if not "chan" in args:
return self.not_supported()
chan = int(args["chan"][0])
kb.set_channel(chan)
return { "success": True }
def inject(self, args):
global packets_sent
if not "data" in args:
return self.not_supported()
try:
kb.inject(base64.urlsafe_b64decode(args["data"][0]))
packets_sent+=1
except Exception, e:
print("ERROR: Unable to inject packet: {0}".format(e))
return { "success": False }
return { "success": True }
def recv(self):
pkt = kb.pnext()
if pkt != None and pkt[1]:
return {"data": base64.urlsafe_b64encode(pkt[0]), "valid_crc": pkt[1], "rssi": pkt[2] }
return {}
def sniffer_off(self):
kb.sniffer_off()
return {"success": True }
def sniffer_on(self):
kb.sniffer_on()
return {"success": True }
def supported_devices(self):
devices = []
for dev in kbutils.devlist():
devices.append(dev[0])
return { "devices": devices }
def not_supported(self):
return { "status": "not supported" }
def send(self, data, resp=200):
self.send_response(resp)
self.send_header('Content-type','application/json')
self.end_headers()
self.wfile.write(json.dumps(data))
return
def do_AUTHHEAD(self):
self.send_response(401)
self.send_header('WWW-Authenticate', 'Basic realm=\"Killerbee MSF Relay\"')
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write("Please Authenticate")
def do_GET(self):
if not password == None:
if self.headers.getheader('Authorization') == None:
print("Did not authenticate")
self.do_AUTHHEAD()
return
if not self.headers.getheader('Authorization') == 'Basic '+base64.b64encode(username + ":" + password):
print("Bad Authentication")
self.do_AUTHHEAD()
return
url = urlparse(self.path)
args = parse_qs(url.query)
if self.path=="/status":
self.send(self.status())
elif self.path=="/statistics":
self.send(self.statistics())
elif self.path=="/settings/datetime":
self.send(self.datetime())
elif self.path=="/settings/timezone":
self.send(self.timezone())
elif self.path=="/zigbee/supported_devices":
self.send(self.supported_devices())
elif self.path.startswith("/zigbee/"):
re_dev = re.compile("/zigbee/([\d\w:]+)/")
m = re_dev.match(self.path)
if m:
dev = m.group(1)
if self.path.find("/set_channel?") > -1:
self.send(self.set_channel(args))
elif self.path.find("/inject?") > -1:
self.send(self.inject(args))
elif self.path.find("/recv") > -1:
self.send(self.recv())
elif self.path.find("/sniffer_off") > -1:
self.send(self.sniffer_off())
elif self.path.find("/sniffer_on") > -1:
self.send(self.sniffer_on())
else:
self.send(self.not_supported(), 404)
else:
self.send(self.not_supported(), 404)
else:
self.send(self.not_supported(), 404)
return
class Killerbee_MSFRelay(cmd.Cmd):
intro = """
KillerBee Metasploit Relay
"""
def __init__(self, ip='0.0.0.0', port=8080):
cmd.Cmd.__init__(self)
self._ip = ip
self._port = port
self._sock = None
self._pause = False
self.start()
def start(self):
self._go = True
while self._go:
# serve the NIC port
try:
self._sock = HTTPServer((self._ip, self._port), MSFHandler)
starttime = int(time.time())
print("KillerBee MSFRelay running.")
self._sock.serve_forever()
except KeyboardInterrupt:
self._sock.socket.close()
self._go = False
except:
sys.excepthook(*sys.exc_info())
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-i', '--iface', '--dev', action='store', dest='devstring')
parser.add_argument('-u', '--user', default="msf_relay", help='HTTP Username', type=str)
parser.add_argument('-p', '--password', default="rfcat_relaypass", help='HTTP Password', type=str)
parser.add_argument('-P', '--Port', default=8080, type=int)
parser.add_argument('--noauth', default=False, action="store_true", help='Do not require authentication')
parser.add_argument('--localonly', default=False, action="store_true", help='Listen on localhost only')
ifo = parser.parse_args()
try:
kb = KillerBee(device=ifo.devstring)
except KBInterfaceError as e:
print("Interface Error: {0}".format(e))
sys.exit(-1)
username = ifo.user
password = ifo.password
ip = "0.0.0.0"
port = ifo.Port
if ifo.noauth:
username = None
password = None
if ifo.localonly:
host = "127.0.0.1"
wait_msg = False
dev_found = False
while not dev_found:
try:
devs = kbutils.devlist()
if len(devs) > 0:
dev_found = True
elif not wait_msg:
print("Insert KillerBee compatible ZigBee device. (You may need to add permissions)")
wait_msg = True
except KeyboardInterrupt:
sys.exit()
except:
if not wait_msg:
print("Insert KillerBee compatible ZigBee device. (You may need to add permissions)")
wait_msg = True
beerelay = Killerbee_MSFRelay(ip, port)
import atexit
atexit.register(cleanupInteractiveAtExit)