CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/tools/hardware/killerbee_msfrelay.py
Views: 1904
1
#!/usr/bin/env python2
2
# Note: This module explicitly requires Python2 as KillerBee does not yet support Python3:
3
# https://github.com/riverloopsec/killerbee/tree/cb04e169a635ad4bc0772b631e1b332320f7a8da#killerbee
4
5
# KillerBee Metasploit relay server
6
7
import re
8
import os
9
import sys
10
import cmd
11
import time
12
import json
13
import base64
14
import socket
15
import threading
16
import pkg_resources # Used to get killerbee version
17
18
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
19
from urlparse import parse_qs, urlparse
20
from killerbee import *
21
22
last_errors = 0
23
starttime = 0
24
packets_sent = 0
25
last_sent = 0
26
username = None
27
password = None
28
kb = None
29
30
class MSFHandler(BaseHTTPRequestHandler):
31
def status(self):
32
status = {}
33
hw_versions = []
34
fw_version = pkg_resources.get_distribution("killerbee").version
35
device_names = []
36
for dev in kbutils.devlist():
37
hw_versions.append(dev[2])
38
device_names.append(dev[1])
39
if len(hw_versions) > 0:
40
status["operational"] = 1
41
else:
42
status["operational"] = 0
43
status["hw_specialty"] = { "zigbee": True }
44
# TODO: We should check firmware before reporting transmit capabilities
45
status["hw_capabilities"] = { "transmit": True}
46
status["last_10_errors"] = last_errors
47
status["api_version"] = "0.0.3"
48
status["fw_version"] = fw_version
49
if len(hw_versions) == 1:
50
status["hw_version"] = hw_versions[0]
51
status["device_name"] = device_names[0]
52
elif len(hw_versions) > 1:
53
status["hw_version"] = ', '.join(hw_versions)
54
status["device_name"] = ', '.join(device_names)
55
else:
56
status["hw_version"] = "Not Supported"
57
return status
58
59
def statistics(self):
60
global packets_sent
61
stats = {}
62
stats["uptime"] = int(time.time()) - starttime
63
stats["packet_stats"] = packets_sent
64
stats["last_request"] = last_sent
65
stats["voltage"] = "0.0v"
66
return stats
67
68
def datetime(self):
69
return { "sytem_datetime": int(time.time()) }
70
71
def timezone(self):
72
return { "system_timezone": time.strftime("%Z") }
73
74
def set_channel(self, args):
75
if not "chan" in args:
76
return self.not_supported()
77
chan = int(args["chan"][0])
78
kb.set_channel(chan)
79
return { "success": True }
80
81
def inject(self, args):
82
global packets_sent
83
if not "data" in args:
84
return self.not_supported()
85
try:
86
kb.inject(base64.urlsafe_b64decode(args["data"][0]))
87
packets_sent+=1
88
except Exception as e:
89
print("ERROR: Unable to inject packet: {0}".format(e))
90
return { "success": False }
91
return { "success": True }
92
93
def recv(self):
94
pkt = kb.pnext()
95
if pkt != None and pkt[1]:
96
return {"data": base64.urlsafe_b64encode(pkt[0]), "valid_crc": pkt[1], "rssi": pkt[2] }
97
return {}
98
99
def sniffer_off(self):
100
kb.sniffer_off()
101
return {"success": True }
102
103
def sniffer_on(self):
104
kb.sniffer_on()
105
return {"success": True }
106
107
def supported_devices(self):
108
devices = []
109
for dev in kbutils.devlist():
110
devices.append(dev[0])
111
return { "devices": devices }
112
113
def not_supported(self):
114
return { "status": "not supported" }
115
116
def send(self, data, resp=200):
117
self.send_response(resp)
118
self.send_header('Content-type', 'application/json')
119
self.end_headers()
120
self.wfile.write(json.dumps(data))
121
return
122
123
def do_AUTHHEAD(self):
124
self.send_response(401)
125
self.send_header('WWW-Authenticate', 'Basic realm=\"Killerbee MSF Relay\"')
126
self.send_header('Content-type', 'text/html')
127
self.end_headers()
128
self.wfile.write("Please Authenticate")
129
130
def do_GET(self):
131
if not password == None:
132
if self.headers.getheader('Authorization') == None:
133
print("Did not authenticate")
134
self.do_AUTHHEAD()
135
return
136
if not self.headers.getheader('Authorization') == 'Basic '+base64.b64encode(username + ":" + password):
137
print("Bad Authentication")
138
self.do_AUTHHEAD()
139
return
140
url = urlparse(self.path)
141
args = parse_qs(url.query)
142
if self.path=="/status":
143
self.send(self.status())
144
elif self.path=="/statistics":
145
self.send(self.statistics())
146
elif self.path=="/settings/datetime":
147
self.send(self.datetime())
148
elif self.path=="/settings/timezone":
149
self.send(self.timezone())
150
elif self.path=="/zigbee/supported_devices":
151
self.send(self.supported_devices())
152
elif self.path.startswith("/zigbee/"):
153
re_dev = re.compile("/zigbee/([\d\w:]+)/")
154
m = re_dev.match(self.path)
155
if m:
156
dev = m.group(1)
157
if self.path.find("/set_channel?") > -1:
158
self.send(self.set_channel(args))
159
elif self.path.find("/inject?") > -1:
160
self.send(self.inject(args))
161
elif self.path.find("/recv") > -1:
162
self.send(self.recv())
163
elif self.path.find("/sniffer_off") > -1:
164
self.send(self.sniffer_off())
165
elif self.path.find("/sniffer_on") > -1:
166
self.send(self.sniffer_on())
167
else:
168
self.send(self.not_supported(), 404)
169
else:
170
self.send(self.not_supported(), 404)
171
else:
172
self.send(self.not_supported(), 404)
173
return
174
175
class Killerbee_MSFRelay(cmd.Cmd):
176
intro = """
177
KillerBee Metasploit Relay
178
"""
179
180
def __init__(self, ip='0.0.0.0', port=8080):
181
cmd.Cmd.__init__(self)
182
183
self._ip = ip
184
self._port = port
185
self._sock = None
186
self._pause = False
187
188
self.start()
189
190
def start(self):
191
self._go = True
192
while self._go:
193
# serve the NIC port
194
try:
195
self._sock = HTTPServer((self._ip, self._port), MSFHandler)
196
starttime = int(time.time())
197
print("KillerBee MSFRelay running.")
198
self._sock.serve_forever()
199
except KeyboardInterrupt:
200
self._sock.socket.close()
201
self._go = False
202
except:
203
sys.excepthook(*sys.exc_info())
204
205
if __name__ == "__main__":
206
import argparse
207
208
parser = argparse.ArgumentParser()
209
parser.add_argument('-i', '--iface', '--dev', action='store', dest='devstring')
210
parser.add_argument('-u', '--user', default="msf_relay", help='HTTP Username', type=str)
211
parser.add_argument('-p', '--password', default="rfcat_relaypass", help='HTTP Password', type=str)
212
parser.add_argument('-P', '--Port', default=8080, type=int)
213
parser.add_argument('--noauth', default=False, action="store_true", help='Do not require authentication')
214
parser.add_argument('--localonly', default=False, action="store_true", help='Listen on localhost only')
215
216
ifo = parser.parse_args()
217
218
try:
219
kb = KillerBee(device=ifo.devstring)
220
except KBInterfaceError as e:
221
print("Interface Error: {0}".format(e))
222
sys.exit(-1)
223
224
username = ifo.user
225
password = ifo.password
226
ip = "0.0.0.0"
227
port = ifo.Port
228
if ifo.noauth:
229
username = None
230
password = None
231
if ifo.localonly:
232
host = "127.0.0.1"
233
234
wait_msg = False
235
dev_found = False
236
while not dev_found:
237
try:
238
devs = kbutils.devlist()
239
if len(devs) > 0:
240
dev_found = True
241
elif not wait_msg:
242
print("Insert KillerBee compatible ZigBee device. (You may need to add permissions)")
243
wait_msg = True
244
except KeyboardInterrupt:
245
sys.exit()
246
except:
247
if not wait_msg:
248
print("Insert KillerBee compatible ZigBee device. (You may need to add permissions)")
249
wait_msg = True
250
251
beerelay = Killerbee_MSFRelay(ip, port)
252
253
import atexit
254
atexit.register(cleanupInteractiveAtExit)
255
256