Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/post/hardware/zigbee/zstumbler.rb
19851 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Post
7
include Msf::Post::Hardware::Zigbee::Utils
8
9
def initialize(info = {})
10
super(
11
update_info(
12
info,
13
'Name' => 'Sends Beacons to Scan for Active ZigBee Networks',
14
'Description' => %q{
15
Send beacon signals to the broadcast address while channel hopping.
16
},
17
'License' => MSF_LICENSE,
18
'Author' => ['Craig Smith'],
19
'Platform' => ['hardware'],
20
'SessionTypes' => ['hwbridge'],
21
'Notes' => {
22
'Stability' => [CRASH_SAFE],
23
'SideEffects' => [],
24
'Reliability' => []
25
}
26
)
27
)
28
register_options([
29
OptInt.new('CHANNEL', [false, 'Disable channel hopping by forcing a channel (11-26)', nil]),
30
OptInt.new('LOOP', [false, 'How many times to loop over the channels (-1 will run in an endless loop)', 1]),
31
OptInt.new('DELAY', [false, 'Delay in seconds to listen on each channel', 2]),
32
OptString.new('DEVICE', [false, 'ZigBee device ID, defaults to target device', nil])
33
])
34
@seq = 0
35
@channel = 11
36
@stumbled = {}
37
@loop_count = 0
38
end
39
40
def display_details(routerdata)
41
stackprofile_map = {
42
0 => 'Network Specific',
43
1 => 'ZigBee Standard',
44
2 => 'ZigBee Enterprise'
45
}
46
stackver_map = {
47
0 => 'ZigBee Prototype',
48
1 => 'ZigBee 2004',
49
2 => 'ZigBee 2006/2007'
50
}
51
spanid, source, extpanid, stackprofilever, _channel = routerdata
52
stackprofilever = stackprofilever.unpack('H*')[0].hex
53
stackprofile = stackprofilever & 0x0f
54
stackver = (stackprofilever & 0xf0) >> 4
55
profile = 'Unknown'
56
profile = stackprofile_map[stackprofile] if stackprofile_map.key? stackprofile
57
ver = 'Unknown'
58
ver = stackver_map[stackver] if stackver_map.key? stackver
59
print_status("New Network: PANID: 0x#{spanid.upcase} SOURCE: 0x#{source.upcase}")
60
print_status(" Ext PANID: #{extpanid.upcase.scan(/../).join(':')} Stack Profile: #{profile}")
61
print_status(" Stack Version: #{ver}")
62
print_status(" Channel: #{@channel}")
63
end
64
65
def scan
66
@seq = 0 if @seq > 255
67
print_status("Scanning Channel #{@channel}")
68
set_channel(datastore['DEVICE'], @channel)
69
beacon = "\x03\x08#{@seq.chr}\xff\xff\xff\xff\x07"
70
inject(datastore['DEVICE'], beacon)
71
delay = Time.now + datastore['DELAY']
72
while delay > Time.now
73
pkt = recv(datastore['DEVICE'])
74
next unless pkt && !pkt.empty? && pkt['valid_crc']
75
76
pktdecode = dot154_packet_decode(pkt['data'])
77
next unless (pktdecode['FSF'] & DOT154_FCF_TYPE_MASK) == DOT154_FCF_TYPE_BEACON
78
79
key = "#{pktdecode['SPAN_ID']}#{pktdecode['SOURCE']}"
80
value = [pktdecode['SPAN_ID'], pktdecode['SOURCE'], pktdecode['EXT_PAN_ID'], pktdecode['STACK_PROFILE'], @channel]
81
if !@stumbled.key? key
82
@stumbled[key] = value
83
display_details(value)
84
end
85
end
86
sniffer_off(datastore['DEVICE']) # Needed to clear receive buffers
87
@seq += 1
88
@channel += 1 if !datastore['CHANNEL']
89
@loop_count += 1 if (@channel > 26) || datastore['CHANNEL']
90
@channel = 11 if @channel > 26
91
end
92
93
def run
94
if !get_target_device && !datastore['DEVICE']
95
print_error "No target device set. Either set one with the 'target' command or specify the DEVICE."
96
return
97
end
98
@channel = datastore['CHANNEL'] if datastore['CHANNEL']
99
@channel = 11 if @channel > 26
100
if datastore['LOOP'] == -1
101
loop { scan }
102
else
103
scan while (@loop_count < datastore['LOOP'])
104
end
105
end
106
end
107
108