Merge remote-tracking branch 'origin/dev' into dev

# Conflicts:
#	Makefile
#	pwnagotchi/plugins/default/hashie.py
This commit is contained in:
jayofelony
2024-03-07 21:37:27 +01:00
132 changed files with 3297 additions and 1080 deletions

View File

@ -199,6 +199,9 @@ def list_plugins(args, config, pattern='*'):
available_not_installed = set(available.keys()) - set(installed.keys())
max_len_list = available_and_installed if args.installed else available_not_installed
if not max_len_list:
print('Maybe try: sudo pwnagotchi plugins update')
return 1
max_len = max(map(len, max_len_list))
header = line.format(name='Plugin', width=max_len, version='Version', enabled='Active', status='Status')
line_length = max(max_len, len('Plugin')) + len(header) - len('Plugin') - 12 # lol
@ -239,7 +242,7 @@ def list_plugins(args, config, pattern='*'):
print('-' * line_length)
if not found:
logging.info('Maybe try: pwnagotchi plugins update')
print('Maybe try: sudo pwnagotchi plugins update')
return 1
return 0

View File

@ -1,73 +0,0 @@
import pwnagotchi.plugins as plugins
import logging
import subprocess
import string
import os
'''
Aircrack-ng needed, to install:
> apt-get install aircrack-ng
'''
class AircrackOnly(plugins.Plugin):
__author__ = 'pwnagotchi [at] rossmarks [dot] uk'
__version__ = '1.0.1'
__license__ = 'GPL3'
__description__ = 'confirm pcap contains handshake/PMKID or delete it'
def __init__(self):
self.text_to_set = ""
self.options = dict()
def on_ready(self):
return
def on_loaded(self):
logging.info("aircrackonly plugin loaded")
if 'face' not in self.options:
self.options['face'] = '(>.<)'
check = subprocess.run(
'/usr/bin/dpkg -l aircrack-ng | grep aircrack-ng | awk \'{print $2, $3}\'', shell=True,
stdout=subprocess.PIPE)
check = check.stdout.decode('utf-8').strip()
if check != "aircrack-ng <none>":
logging.info("aircrackonly: Found " + check)
else:
logging.warning("aircrack-ng is not installed!")
def on_handshake(self, agent, filename, access_point, client_station):
display = agent.view()
to_delete = 0
handshake_found = 0
result = subprocess.run(('/usr/bin/aircrack-ng ' + filename + ' | grep "1 handshake" | awk \'{print $2}\''),
shell=True, stdout=subprocess.PIPE)
result = result.stdout.decode('utf-8').translate({ord(c): None for c in string.whitespace})
if result:
handshake_found = 1
logging.info("[AircrackOnly] contains handshake")
if handshake_found == 0:
result = subprocess.run(('/usr/bin/aircrack-ng ' + filename + ' | grep "PMKID" | awk \'{print $2}\''),
shell=True, stdout=subprocess.PIPE)
result = result.stdout.decode('utf-8').translate({ord(c): None for c in string.whitespace})
if result:
logging.info("[AircrackOnly] contains PMKID")
else:
to_delete = 1
if to_delete == 1:
os.remove(filename)
self.text_to_set = "Removed an uncrackable pcap"
logging.warning("Removed uncrackable pcap " + filename)
display.update(force=True)
def on_ui_update(self, ui):
if self.text_to_set:
ui.set('face', self.options['face'])
ui.set('status', self.text_to_set)
self.text_to_set = ""

View File

@ -28,7 +28,8 @@ def check(version, repo, native=True):
resp = requests.get("https://api.github.com/repos/%s/releases/latest" % repo)
latest = resp.json()
info['available'] = latest_ver = latest['tag_name'].replace('v', '')
is_arm64 = info['arch'].startswith('aarch')
is_armhf = info['arch'].startswith('arm')
is_aarch = info['arch'].startswith('aarch')
local = version_to_tuple(info['current'])
remote = version_to_tuple(latest_ver)
@ -36,12 +37,20 @@ def check(version, repo, native=True):
if not native:
info['url'] = "https://github.com/%s/archive/%s.zip" % (repo, latest['tag_name'])
else:
if is_arm64:
# check if this release is compatible with aarch64
if is_armhf:
# check if this release is compatible with armhf
for asset in latest['assets']:
download_url = asset['browser_download_url']
if (download_url.endswith('.zip') and
(info['arch'] in download_url or (is_arm64 and 'aarch64' in download_url))):
(info['arch'] in download_url or (is_armhf and 'armhf' in download_url))):
info['url'] = download_url
break
elif is_aarch:
# check if this release is compatible with arm64/aarch64
for asset in latest['assets']:
download_url = asset['browser_download_url']
if (download_url.endswith('.zip') and
(info['arch'] in download_url or (is_aarch and 'aarch' in download_url))):
info['url'] = download_url
break
@ -189,7 +198,7 @@ class AutoUpdate(plugins.Plugin):
to_check = [
('jayofelony/bettercap', parse_version('bettercap -version'), True, 'bettercap'),
('jayofelony/pwngrid', parse_version('pwngrid -version'), True, 'pwngrid-peer'),
('jayofelony/pwnagotchi-bookworm', pwnagotchi.__version__, False, 'pwnagotchi')
('jayofelony/pwnagotchi', pwnagotchi.__version__, False, 'pwnagotchi')
]
for repo, local_version, is_native, svc_name in to_check:

View File

@ -11,6 +11,10 @@ from pwnagotchi import plugins
import pwnagotchi.ui.faces as faces
from pwnagotchi.bettercap import Client
from pwnagotchi.ui.components import Text
from pwnagotchi.ui.view import BLACK
import pwnagotchi.ui.fonts as fonts
class FixServices(plugins.Plugin):
__author__ = 'jayofelony'
@ -21,19 +25,16 @@ class FixServices(plugins.Plugin):
__help__ = """
Reload brcmfmac module when blindbug is detected, instead of rebooting. Adapted from WATCHDOG.
"""
__defaults__ = {
'enabled': True,
}
def __init__(self):
self.options = dict()
self.pattern1 = re.compile(r'wifi error while hopping to channel')
self.pattern2 = re.compile(r'Firmware has halted or crashed')
self.pattern3 = re.compile(r'error 400: could not find interface wlan0mon')
self.pattern = re.compile(r'brcmf_cfg80211_nexmon_set_channel.*?Set Channel failed')
self.pattern2 = re.compile(r'wifi error while hopping to channel')
self.pattern3 = re.compile(r'Firmware has halted or crashed')
self.pattern4 = re.compile(r'error 400: could not find interface wlan0mon')
self.isReloadingMon = False
self.connection = None
self.LASTTRY = 0
self._count = 0
def on_loaded(self):
"""
@ -42,14 +43,27 @@ class FixServices(plugins.Plugin):
logging.info("[Fix_Services] plugin loaded.")
def on_ready(self, agent):
last_lines = self.get_last_lines('journalctl', ['-n10', '-k'], 10)
last_lines = ''.join(list(TextIOWrapper(subprocess.Popen(['journalctl', '-n10', '-k'],
stdout=subprocess.PIPE).stdout))[-10:])
try:
cmd_output = subprocess.check_output("ip link show wlan0mon", shell=True)
logging.debug("[Fix_Services ip link show wlan0mon]: %s" % repr(cmd_output))
if ",UP," in str(cmd_output):
logging.info("wlan0mon is up.")
logging.debug("wlan0mon is up.")
logging.info("[Fix_Services] Logs look good!")
if len(self.pattern.findall(last_lines)) >= 3:
if hasattr(agent, 'view'):
display = agent.view()
display.set('status', 'Blind-Bug detected. Restarting.')
display.update(force=True)
logging.debug('[Fix_Services] Blind-Bug detected. Restarting.')
try:
self._tryTurningItOffAndOnAgain(agent)
except Exception as err:
logging.warning("[Fix_Services turnOffAndOn] %s" % repr(err))
else:
logging.debug("[Fix_Services] Logs look good!")
except Exception as err:
logging.error("[Fix_Services ip link show wlan0mon]: %s" % repr(err))
@ -63,12 +77,12 @@ class FixServices(plugins.Plugin):
# apparently this only gets messages from bettercap going to syslog, not from syslog
def on_bcap_sys_log(self, agent, event):
if re.search('wifi error while hopping to channel', event['data']['Message']):
logging.info("[Fix_Services]SYSLOG MATCH: %s" % event['data']['Message'])
logging.info("[Fix_Services]**** restarting wifi.recon")
logging.debug("[Fix_Services]SYSLOG MATCH: %s" % event['data']['Message'])
logging.debug("[Fix_Services]**** restarting wifi.recon")
try:
result = agent.run("wifi.recon off; wifi.recon on")
if result["success"]:
logging.info("[Fix_Services] wifi.recon flip: success!")
logging.debug("[Fix_Services] wifi.recon flip: success!")
if hasattr(agent, 'view'):
display = agent.view()
if display:
@ -82,23 +96,14 @@ class FixServices(plugins.Plugin):
logging.error("[Fix_Services]SYSLOG wifi.recon flip fail: %s" % err)
self._tryTurningItOffAndOnAgain(agent)
def get_last_lines(self, command, args, n):
try:
process = subprocess.Popen([command] + args, stdout=subprocess.PIPE)
output = TextIOWrapper(process.stdout)
lines = output.readlines()
last_n_lines = ''.join(lines[-n:])
return last_n_lines
except Exception as e:
print(f"Error occurred: {e}")
return None
def on_epoch(self, agent, epoch, epoch_data):
last_lines = self.get_last_lines('journalctl', ['-n10', '-k'], 10)
other_last_lines = self.get_last_lines('journalctl', ['-n10'], 10)
other_other_last_lines = self.get_last_lines('tail', ['-n10', '/home/pi/logs/pwnagotchi.log'], 10)
last_lines = ''.join(list(TextIOWrapper(subprocess.Popen(['journalctl', '-n10', '-k'],
stdout=subprocess.PIPE).stdout))[-10:])
other_last_lines = ''.join(list(TextIOWrapper(subprocess.Popen(['journalctl', '-n10'],
stdout=subprocess.PIPE).stdout))[-10:])
other_other_last_lines = ''.join(
list(TextIOWrapper(subprocess.Popen(['tail', '-n10', '/var/log/pwnagotchi.log'],
stdout=subprocess.PIPE).stdout))[-10:])
# don't check if we ran a reset recently
logging.debug("[Fix_Services]**** epoch")
if time.time() - self.LASTTRY > 180:
@ -108,18 +113,31 @@ class FixServices(plugins.Plugin):
logging.debug("[Fix_Services]**** checking")
# Look for pattern 1
if len(self.pattern1.findall(other_last_lines)) >= 5:
if len(self.pattern.findall(last_lines)) >= 3:
logging.debug("[Fix_Services]**** Should trigger a reload of the wlan0mon device:\n%s" % last_lines)
if hasattr(agent, 'view'):
display = agent.view()
display.set('status', 'Blind-Bug detected. Restarting.')
display.update(force=True)
logging.debug('[Fix_Services] Blind-Bug detected. Restarting.')
try:
self._tryTurningItOffAndOnAgain(agent)
except Exception as err:
logging.warning("[Fix_Services] TTOAOA: %s" % repr(err))
# Look for pattern 2
elif len(self.pattern2.findall(other_last_lines)) >= 5:
logging.debug("[Fix_Services]**** Should trigger a reload of the wlan0mon device:\n%s" % last_lines)
if hasattr(agent, 'view'):
display = agent.view()
display.set('status', 'Wifi channel stuck. Restarting recon.')
display.update(force=True)
logging.info('[Fix_Services] Wifi channel stuck. Restarting recon.')
logging.debug('[Fix_Services] Wifi channel stuck. Restarting recon.')
try:
result = agent.run("wifi.recon off; wifi.recon on")
if result["success"]:
logging.info("[Fix_Services] wifi.recon flip: success!")
logging.debug("[Fix_Services] wifi.recon flip: success!")
if display:
display.update(force=True, new_data={"status": "Wifi recon flipped!",
"face": faces.COOL})
@ -131,9 +149,9 @@ class FixServices(plugins.Plugin):
except Exception as err:
logging.error("[Fix_Services wifi.recon flip] %s" % repr(err))
# Look for pattern 2
elif len(self.pattern2.findall(other_last_lines)) >= 1:
logging.info("[Fix_Services] Firmware has halted or crashed. Restarting wlan0mon.")
# Look for pattern 3
elif len(self.pattern3.findall(other_last_lines)) >= 1:
logging.debug("[Fix_Services] Firmware has halted or crashed. Restarting wlan0mon.")
if hasattr(agent, 'view'):
display = agent.view()
display.set('status', 'Firmware has halted or crashed. Restarting wlan0mon.')
@ -145,9 +163,9 @@ class FixServices(plugins.Plugin):
except Exception as err:
logging.error("[Fix_Services monstart]: %s" % repr(err))
# Look for pattern 3
elif len(self.pattern3.findall(other_other_last_lines)) >= 3:
logging.info("[Fix_Services] wlan0 is down!")
# Look for pattern 4
elif len(self.pattern4.findall(other_other_last_lines)) >= 3:
logging.debug("[Fix_Services] wlan0 is down!")
if hasattr(agent, 'view'):
display = agent.view()
display.set('status', 'Restarting wlan0 now!')
@ -171,7 +189,7 @@ class FixServices(plugins.Plugin):
elif level == "debug":
logging.debug(message)
else:
logging.info(message)
logging.debug(message)
if ui:
ui.update(force=force, new_data=displayData)
@ -186,7 +204,7 @@ class FixServices(plugins.Plugin):
# avoid overlapping restarts, but allow it if it's been a while
# (in case the last attempt failed before resetting "isReloadingMon")
if self.isReloadingMon and (time.time() - self.LASTTRY) < 180:
logging.info("[Fix_Services] Duplicate attempt ignored")
logging.debug("[Fix_Services] Duplicate attempt ignored")
else:
self.isReloadingMon = True
self.LASTTRY = time.time()
@ -213,7 +231,7 @@ class FixServices(plugins.Plugin):
cmd_output = subprocess.check_output("ip link show wlan0mon", shell=True)
logging.debug("[Fix_Services ip link show wlan0mon]: %s" % repr(cmd_output))
if ",UP," in str(cmd_output):
logging.info("wlan0mon is up. Skip reset?")
logging.debug("wlan0mon is up. Skip reset?")
# not reliable, so don't skip just yet
# print("wlan0mon is up. Skipping reset.")
# self.isReloadingMon = False
@ -234,7 +252,7 @@ class FixServices(plugins.Plugin):
except Exception as err:
logging.error("[Fix_Services wifi.recon off] error %s" % (repr(err)))
logging.info("[Fix_Services] recon paused. Now trying wlan0mon reload")
logging.debug("[Fix_Services] recon paused. Now trying wlan0mon reload")
try:
cmd_output = subprocess.check_output("monstop", shell=True)
@ -250,14 +268,13 @@ class FixServices(plugins.Plugin):
#
# Future: while "not fixed yet": blah blah blah. if "max_attemts", then reboot like the old days
#
tries = 0
tries = 1
while tries < 3:
try:
# unload the module
cmd_output = subprocess.check_output("sudo modprobe -r brcmfmac", shell=True)
self.logPrintView("info", "[Fix_Services] unloaded brcmfmac", display,
{"status": "Turning it off #%s" % tries, "face": faces.SMART})
time.sleep(1 + tries)
# reload the module
try:
@ -265,27 +282,25 @@ class FixServices(plugins.Plugin):
cmd_output = subprocess.check_output("sudo modprobe brcmfmac", shell=True)
self.logPrintView("info", "[Fix_Services] reloaded brcmfmac")
time.sleep(10 + 4 * tries) # give it some time for wlan device to stabilize, or whatever
# success! now make the mon0
try:
cmd_output = subprocess.check_output("monstart", shell=True)
self.logPrintView("info", "[Fix_Services interface add wlan0mon] worked #%s: %s"
self.logPrintView("info", "[Fix_Services interface add wlan0mon worked #%s: %s"
% (tries, cmd_output))
time.sleep(tries + 5)
try:
# try accessing mon0 in bettercap
result = connection.run("set wifi.interface wlan0mon")
if "success" in result:
logging.info("[Fix_Services set wifi.interface wlan0mon] worked!")
self._count = self._count + 1
time.sleep(1)
logging.debug("[Fix_Services set wifi.interface wlan0mon worked!")
# stop looping and get back to recon
break
else:
logging.debug("[Fix_Services set wifi.interfaceface wlan0mon] failed? %s" % repr(result))
logging.debug(
"[Fix_Services set wifi.interfaceface wlan0mon] failed? %s" % repr(result))
except Exception as err:
logging.debug("[Fix_Services set wifi.interface wlan0mon] except: %s" % repr(err))
logging.debug(
"[Fix_Services set wifi.interface wlan0mon] except: %s" % repr(err))
except Exception as cerr: #
if not display:
print("failed loading wlan0mon attempt #%s: %s" % (tries, repr(cerr)))
@ -303,11 +318,11 @@ class FixServices(plugins.Plugin):
tries = tries + 1
if tries < 3:
logging.info("[Fix_Services] wlan0mon didn't make it. trying again")
logging.debug("[Fix_Services] wlan0mon didn't make it. trying again")
if not display:
print(" wlan0mon didn't make it. trying again")
else:
logging.info("[Fix_Services] wlan0mon loading failed, no choice but to reboot ..")
logging.debug("[Fix_Services] wlan0mon loading failed, no choice but to reboot ..")
pwnagotchi.reboot()
# exited the loop, so hopefully it loaded
@ -317,14 +332,14 @@ class FixServices(plugins.Plugin):
"face": faces.INTENSE})
else:
print("And back on again...")
logging.info("[Fix_Services] wlan0mon back up")
logging.debug("[Fix_Services] wlan0mon back up")
else:
self.LASTTRY = time.time()
time.sleep(8 + tries * 2) # give it a bit before restarting recon in bettercap
self.isReloadingMon = False
logging.info("[Fix_Services] re-enable recon")
logging.debug("[Fix_Services] re-enable recon")
try:
result = connection.run("wifi.clear; wifi.recon on")
@ -345,13 +360,24 @@ class FixServices(plugins.Plugin):
logging.error("[Fix_Services wifi.recon on] %s" % repr(err))
pwnagotchi.reboot()
def on_unload(self, ui):
# called to setup the ui elements
def on_ui_setup(self, ui):
with ui._lock:
try:
logging.info("[Fix_Services] unloaded")
except Exception as err:
logging.error("[Fix_Services] unload err %s " % repr(err))
pass
# add custom UI elements
if "position" in self.options:
pos = self.options['position'].split(',')
pos = [int(x.strip()) for x in pos]
else:
pos = (ui.width() / 2 + 35, ui.height() - 11)
logging.debug("Got here")
# called when the ui is updated
def on_ui_update(self, ui):
return
def on_unload(self, ui):
return
# run from command line to brute force a reload

View File

@ -98,7 +98,7 @@ class GPS(plugins.Plugin):
lat_pos = (127, 74)
lon_pos = (122, 84)
alt_pos = (127, 94)
elif ui.is_waveshare27inch():
elif ui.is_waveshare2in7():
lat_pos = (6, 120)
lon_pos = (1, 135)
alt_pos = (6, 150)

View File

@ -1,179 +0,0 @@
import logging
import subprocess
import os
import json
import pwnagotchi.plugins as plugins
from threading import Lock
'''
hcxpcapngtool needed, to install:
> git clone https://github.com/ZerBea/hcxtools.git
> cd hcxtools
> apt-get install libcurl4-openssl-dev libssl-dev zlib1g-dev
> make
> sudo make install
'''
class Hashie(plugins.Plugin):
__author__ = 'Jayofelony'
__version__ = '1.0.4'
__license__ = 'GPL3'
__description__ = '''
Attempt to automatically convert pcaps to a crackable format.
If successful, the files containing the hashes will be saved
in the same folder as the handshakes.
The files are saved in their respective Hashcat format:
- EAPOL hashes are saved as *.22000
- PMKID hashes are saved as *.16800
All PCAP files without enough information to create a hash are
stored in a file that can be read by the webgpsmap plugin.
Why use it?:
- Automatically convert handshakes to crackable formats!
We dont all upload our hashes online ;)
- Repair PMKID handshakes that hcxpcapngtool misses
- If running at time of handshake capture, on_handshake can
be used to improve the chance of the repair succeeding
- Be a completionist! Not enough packets captured to crack a network?
This generates an output file for the webgpsmap plugin, use the
location data to revisit networks you need more packets for!
Additional information:
- Currently requires hcxpcapngtool compiled and installed
- Attempts to repair PMKID hashes when hcxpcapngtool cant find the SSID
- hcxpcapngtool sometimes has trouble extracting the SSID, so we
use the raw 16800 output and attempt to retrieve the SSID via tcpdump
- When access_point data is available (on_handshake), we leverage
the reported AP name and MAC to complete the hash
- The repair is very basic and could certainly be improved!
Todo:
Make it so users dont need hcxpcapngtool (unless it gets added to the base image)
Phase 1: Extract/construct 22000/16800 hashes through tcpdump commands
Phase 2: Extract/construct 22000/16800 hashes entirely in python
Improve the code, a lot
'''
def __init__(self):
self.lock = Lock()
self.options = dict()
def on_loaded(self):
logging.info("[Hashie] Plugin loaded")
def on_unloaded(self):
logging.info("[Hashie] Plugin unloaded")
# called when everything is ready and the main loop is about to start
def on_ready(self, agent):
config = agent.config()
handshake_dir = config['bettercap']['handshakes']
logging.info('[Hashie] Starting batch conversion of pcap files')
with self.lock:
self._process_stale_pcaps(handshake_dir)
def on_handshake(self, agent, filename, access_point, client_station):
with self.lock:
handshake_status = []
fullpathNoExt = filename.split('.')[0]
name = filename.split('/')[-1:][0].split('.')[0]
if os.path.isfile(fullpathNoExt + '.22000'):
handshake_status.append('Already have {}.22000 (EAPOL)'.format(name))
elif self._writeEAPOL(filename):
handshake_status.append('Created {}.22000 (EAPOL) from pcapng'.format(name))
if os.path.isfile(fullpathNoExt + '.16800'):
handshake_status.append('Already have {}.16800 (PMKID)'.format(name))
elif self._writePMKID(filename):
handshake_status.append('Created {}.16800 (PMKID) from pcapng'.format(name))
if handshake_status:
logging.info('[Hashie] Good news:\n\t' + '\n\t'.join(handshake_status))
def _writeEAPOL(self, fullpath):
fullpathNoExt = fullpath.split('.')[0]
filename = fullpath.split('/')[-1:][0].split('.')[0]
subprocess.getoutput('hcxpcapngtool -o {}.22000 {} >/dev/null 2>&1'.format(fullpathNoExt, fullpath))
if os.path.isfile(fullpathNoExt + '.22000'):
logging.debug('[Hashie] [+] EAPOL Success: {}.22000 created'.format(filename))
return True
return False
def _writePMKID(self, fullpath):
fullpathNoExt = fullpath.split('.')[0]
filename = fullpath.split('/')[-1:][0].split('.')[0]
subprocess.getoutput('hcxpcapngtool -o {}.16800 {} >/dev/null 2>&1'.format(fullpathNoExt, fullpath))
if os.path.isfile(fullpathNoExt + '.16800'):
logging.debug('[Hashie] [+] PMKID Success: {}.16800 created'.format(filename))
return True
return False
def _process_stale_pcaps(self, handshake_dir):
handshakes_list = [os.path.join(handshake_dir, filename) for filename in os.listdir(handshake_dir) if filename.endswith('.pcapng')]
failed_jobs = []
successful_jobs = []
lonely_pcaps = []
for num, handshake in enumerate(handshakes_list):
fullpathNoExt = handshake.split('.')[0]
pcapFileName = handshake.split('/')[-1:][0]
if not os.path.isfile(fullpathNoExt + '.22000'): # if no 22000, try
if self._writeEAPOL(handshake):
successful_jobs.append('22000: ' + pcapFileName)
else:
failed_jobs.append('22000: ' + pcapFileName)
if not os.path.isfile(fullpathNoExt + '.16800'): # if no 16800, try
if self._writePMKID(handshake):
successful_jobs.append('16800: ' + pcapFileName)
else:
failed_jobs.append('16800: ' + pcapFileName)
if not os.path.isfile(fullpathNoExt + '.22000'): # if no 16800 AND no 22000
lonely_pcaps.append(handshake)
logging.debug('[hashie] Batch job: added {} to lonely list'.format(pcapFileName))
if ((num + 1) % 50 == 0) or (num + 1 == len(handshakes_list)): # report progress every 50, or when done
logging.info('[Hashie] Batch job: {}/{} done ({} fails)'.format(num + 1, len(handshakes_list), len(lonely_pcaps)))
if successful_jobs:
logging.info('[Hashie] Batch job: {} new handshake files created'.format(len(successful_jobs)))
if lonely_pcaps:
logging.info('[Hashie] Batch job: {} networks without enough packets to create a hash'.format(len(lonely_pcaps)))
self._getLocations(lonely_pcaps)
def _getLocations(self, lonely_pcaps):
# export a file for webgpsmap to load
with open('/root/.incompletePcaps', 'w') as isIncomplete:
count = 0
for pcapFile in lonely_pcaps:
filename = pcapFile.split('/')[-1:][0] # keep extension
fullpathNoExt = pcapFile.split('.')[0]
isIncomplete.write(filename + '\n')
if os.path.isfile(fullpathNoExt + '.gps.json') or os.path.isfile(fullpathNoExt + '.geo.json'):
count += 1
if count != 0:
logging.info('[Hashie] Used {} GPS/GEO files to find lonely networks, '
'go check webgpsmap! ;)'.format(str(count)))
else:
logging.info('[Hashie] Could not find any GPS/GEO files '
'for the lonely networks'.format(str(count)))
def _getLocationsCSV(self, lonely_pcaps):
# in case we need this later, export locations manually to CSV file, needs try/catch format/etc.
locations = []
for pcapFile in lonely_pcaps:
filename = pcapFile.split('/')[-1:][0].split('.')[0]
fullpathNoExt = pcapFile.split('.')[0]
if os.path.isfile(fullpathNoExt + '.gps.json'):
with open(fullpathNoExt + '.gps.json', 'r') as tempFileA:
data = json.load(tempFileA)
locations.append(filename + ',' + str(data['Latitude']) + ',' + str(data['Longitude']) + ',50')
elif os.path.isfile(fullpathNoExt + '.geo.json'):
with open(fullpathNoExt + '.geo.json', 'r') as tempFileB:
data = json.load(tempFileB)
locations.append(
filename + ',' + str(data['location']['lat']) + ',' + str(data['location']['lng']) + ',' + str(data['accuracy']))
if locations:
with open('/root/locations.csv', 'w') as tempFileD:
for loc in locations:
tempFileD.write(loc + '\n')
logging.info('[Hashie] Used {} GPS/GEO files to find lonely networks, '
'load /root/locations.csv into a mapping app and go say hi!'.format(len(locations)))

View File

@ -144,6 +144,9 @@ class MemTemp(plugins.Plugin):
elif ui.is_waveshare2in7():
h_pos = (192, 138)
v_pos = (211, 122)
elif ui.is_waveshare1in54V2():
h_pos = (53, 77)
v_pos = (154, 65)
else:
h_pos = (155, 76)
v_pos = (175, 61)