Added module for zstumbler
parent
dcb42a3e69
commit
60cd04bc7b
|
@ -1,4 +1,5 @@
|
||||||
# -*- coding: binary -*-
|
# -*- coding: binary -*-
|
||||||
module Msf::Post::Hardware
|
module Msf::Post::Hardware
|
||||||
require 'msf/core/post/hardware/automotive/uds'
|
require 'msf/core/post/hardware/automotive/uds'
|
||||||
|
require 'msf/core/post/hardware/zigbee/utils'
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,259 @@
|
||||||
|
# -*- 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
|
||||||
|
|
||||||
|
# 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
|
||||||
|
if not client.zigbee
|
||||||
|
print_error("Not a Zigbee hwbridge session")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
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)
|
||||||
|
if not client.zigbee
|
||||||
|
print_error("Not a Zigbee hwbridge session")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
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)
|
||||||
|
if not client.zigbee
|
||||||
|
print_error("Not a Zigbee hwbridge session")
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
device = client.zigbee.target_device if not device
|
||||||
|
if not device
|
||||||
|
print_line("No target device set, use 'target' or specify bus via the options")
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
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)
|
||||||
|
if not client.zigbee
|
||||||
|
print_error("Not a Zigbee hwbridge session")
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
device = client.zigbee.target_device if not device
|
||||||
|
if not device
|
||||||
|
print_line("No target device set, use 'target' or specify bus via the options")
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
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)
|
||||||
|
if not client.zigbee
|
||||||
|
print_error("Not a Zigbee hwbridge session")
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
device = client.zigbee.target_device if not device
|
||||||
|
if not device
|
||||||
|
print_line("No target device set, use 'target' or specify bus via the options")
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
client.zigbee.recv(device)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Turn off Zigbee receiving
|
||||||
|
# @param device [String] Zigbee device ID
|
||||||
|
def sniffer_off(device)
|
||||||
|
if not client.zigbee
|
||||||
|
print_error("Not a Zigbee hwbridge session")
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
device = client.zigbee.target_device if not device
|
||||||
|
if not device
|
||||||
|
print_line("No target device set, use 'target' or specify bus via the options")
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
client.zigbee.sniffer_off(device)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Turn on Zigbee receiving
|
||||||
|
# @param device [String] Zigbee device ID
|
||||||
|
def sniffer_on(device)
|
||||||
|
if not client.zigbee
|
||||||
|
print_error("Not a Zigbee hwbridge session")
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
device = client.zigbee.target_device if not device
|
||||||
|
if not device
|
||||||
|
print_line("No target device set, use 'target' or specify bus via the options")
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
client.zigbee.sniffer_on(device)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Breaks up the packet into different sections. Also provides
|
||||||
|
# Some decoding information
|
||||||
|
# @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
|
|
@ -28,11 +28,54 @@ class Zigbee < Extension
|
||||||
])
|
])
|
||||||
end
|
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
|
# Gets supported Zigbee Devices
|
||||||
# @return [Array] Devices
|
# @return [Array] Devices
|
||||||
def supported_devices
|
def supported_devices
|
||||||
client.send_request("/zigbee/supported_devices")
|
client.send_request("/zigbee/supported_devices")
|
||||||
end
|
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
|
||||||
|
|
||||||
|
def inject(dev, data)
|
||||||
|
data = Base64.urlsafe_encode64(data)
|
||||||
|
client.send_request("/zigbee/#{dev}/inject?data=#{data}")
|
||||||
|
end
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
def sniffer_off(dev)
|
||||||
|
client.send_request("/zigbee/#{dev}/sniffer_off")
|
||||||
|
end
|
||||||
|
|
||||||
|
def sniffer_on(dev)
|
||||||
|
client.send_request("/zigbee/#{dev}/sniffer_on")
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_accessor :target_device
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,12 +18,21 @@ class Console::CommandDispatcher::Zigbee
|
||||||
#
|
#
|
||||||
def commands
|
def commands
|
||||||
all = {
|
all = {
|
||||||
'supported_devices' => 'Get supported zigbee devices'
|
'supported_devices' => 'Get supported zigbee devices',
|
||||||
|
'target' => 'Set the target device id',
|
||||||
|
'channel' => 'Set the channel'
|
||||||
}
|
}
|
||||||
|
|
||||||
all
|
all
|
||||||
end
|
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
|
# Lists all thesupported devices
|
||||||
#
|
#
|
||||||
|
@ -38,7 +47,7 @@ class Console::CommandDispatcher::Zigbee
|
||||||
print_line("none")
|
print_line("none")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
self.target_device = devices[0] if devices.size == 1
|
set_target_device(devices[0]) if devices.size == 1
|
||||||
str = "Supported Devices: "
|
str = "Supported Devices: "
|
||||||
str += devices.join(', ')
|
str += devices.join(', ')
|
||||||
str += "\nUse device name to set your desired device, default is: #{self.target_device}"
|
str += "\nUse device name to set your desired device, default is: #{self.target_device}"
|
||||||
|
@ -61,12 +70,43 @@ class Console::CommandDispatcher::Zigbee
|
||||||
print_line(device_opts.usage)
|
print_line(device_opts.usage)
|
||||||
return
|
return
|
||||||
when '-d'
|
when '-d'
|
||||||
self.target_device = val
|
set_target_device val
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
print_line("set target device to #{self.target_device}")
|
print_line("set target device to #{self.target_device}")
|
||||||
end
|
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 not 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
|
# Name for this dispatcher
|
||||||
#
|
#
|
||||||
|
@ -74,9 +114,7 @@ class Console::CommandDispatcher::Zigbee
|
||||||
'Zigbee'
|
'Zigbee'
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
attr_accessor :target_device
|
attr_accessor :target_device
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -67,6 +67,8 @@ class MetasploitModule < Msf::Auxiliary
|
||||||
if (res.code == 200)
|
if (res.code == 200)
|
||||||
print_status res.body if datastore["DEBUGJSON"] == true
|
print_status res.body if datastore["DEBUGJSON"] == true
|
||||||
return JSON.parse(res.body)
|
return JSON.parse(res.body)
|
||||||
|
elsif res.code == 401
|
||||||
|
print_error "Access Denied: #{res.body}"
|
||||||
end
|
end
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
##
|
||||||
|
# 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", nil]),
|
||||||
|
OptInt.new('LOOP', [false, "How many times to loop over the channels. -1 is forever", 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
|
||||||
|
@loop_count += 1 if @channel > 26 or datastore["CHANNEL"]
|
||||||
|
@channel = 11 if @channel > 26
|
||||||
|
@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"]
|
||||||
|
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"]
|
||||||
|
if datastore["LOOP"] == -1
|
||||||
|
while(1) do
|
||||||
|
scan
|
||||||
|
end
|
||||||
|
else
|
||||||
|
while(@loop_count < datastore["LOOP"])
|
||||||
|
scan
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -22,6 +22,7 @@ packets_sent = 0
|
||||||
last_sent = 0
|
last_sent = 0
|
||||||
username = None
|
username = None
|
||||||
password = None
|
password = None
|
||||||
|
kb = None
|
||||||
|
|
||||||
class MSFHandler(BaseHTTPRequestHandler):
|
class MSFHandler(BaseHTTPRequestHandler):
|
||||||
def status(self):
|
def status(self):
|
||||||
|
@ -53,6 +54,7 @@ class MSFHandler(BaseHTTPRequestHandler):
|
||||||
return status
|
return status
|
||||||
|
|
||||||
def statistics(self):
|
def statistics(self):
|
||||||
|
global packets_sent
|
||||||
stats = {}
|
stats = {}
|
||||||
stats["uptime"] = int(time.time()) - starttime
|
stats["uptime"] = int(time.time()) - starttime
|
||||||
stats["packet_stats"] = packets_sent
|
stats["packet_stats"] = packets_sent
|
||||||
|
@ -66,6 +68,39 @@ class MSFHandler(BaseHTTPRequestHandler):
|
||||||
def timezone(self):
|
def timezone(self):
|
||||||
return { "system_timezone": time.strftime("%Z") }
|
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):
|
def supported_devices(self):
|
||||||
devices = []
|
devices = []
|
||||||
for dev in kbutils.devlist():
|
for dev in kbutils.devlist():
|
||||||
|
@ -112,12 +147,20 @@ class MSFHandler(BaseHTTPRequestHandler):
|
||||||
elif self.path=="/zigbee/supported_devices":
|
elif self.path=="/zigbee/supported_devices":
|
||||||
self.send(self.supported_devices())
|
self.send(self.supported_devices())
|
||||||
elif self.path.startswith("/zigbee/"):
|
elif self.path.startswith("/zigbee/"):
|
||||||
re_idx = re.compile("/zigbee/(\w+)/")
|
re_dev = re.compile("/zigbee/([\d\w:]+)/")
|
||||||
m = re_idx.match(self.path)
|
m = re_dev.match(self.path)
|
||||||
if m:
|
if m:
|
||||||
idx = m.group(1)
|
dev = m.group(1)
|
||||||
if self.path.find("/set_freq?") > -1:
|
if self.path.find("/set_channel?") > -1:
|
||||||
self.send(self.set_freq(args))
|
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:
|
else:
|
||||||
self.send(self.not_supported(), 404)
|
self.send(self.not_supported(), 404)
|
||||||
else:
|
else:
|
||||||
|
@ -160,6 +203,7 @@ if __name__ == "__main__":
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
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('-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', '--password', default="rfcat_relaypass", help='HTTP Password', type=str)
|
||||||
parser.add_argument('-P', '--Port', default=8080, type=int)
|
parser.add_argument('-P', '--Port', default=8080, type=int)
|
||||||
|
@ -168,6 +212,12 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
ifo = parser.parse_args()
|
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
|
username = ifo.user
|
||||||
password = ifo.password
|
password = ifo.password
|
||||||
ip = "0.0.0.0"
|
ip = "0.0.0.0"
|
||||||
|
|
Loading…
Reference in New Issue