Revert "Revert "Testing pcapng fileformat""

This reverts commit d142840307.
This commit is contained in:
Jeroen Oudshoorn
2024-02-05 17:16:13 +01:00
parent 5a6ec7b4b8
commit dffcbbf447
9 changed files with 44 additions and 53 deletions

View File

@ -48,7 +48,7 @@ class GPS(plugins.Plugin):
if self.running: if self.running:
info = agent.session() info = agent.session()
self.coordinates = info["gps"] self.coordinates = info["gps"]
gps_filename = filename.replace(".pcap", ".gps.json") gps_filename = filename.replace(".pcapng", ".gps.json")
if self.coordinates and all([ if self.coordinates and all([
# avoid 0.000... measurements # avoid 0.000... measurements

View File

@ -5,22 +5,21 @@ import glob
import re import re
import pwnagotchi.grid as grid import pwnagotchi.grid as grid
import pwnagotchi.plugins
import pwnagotchi.plugins as plugins import pwnagotchi.plugins as plugins
from pwnagotchi.utils import StatusFile, WifiInfo, extract_from_pcap from pwnagotchi.utils import StatusFile, WifiInfo, extract_from_pcapng
from threading import Lock from threading import Lock
def parse_pcap(filename): def parse_pcap(filename):
logging.info("grid: parsing %s ..." % filename) logging.info("grid: parsing %s ..." % filename)
net_id = os.path.basename(filename).replace('.pcap', '') net_id = os.path.basename(filename).replace('.pcapng', '')
if '_' in net_id: if '_' in net_id:
# /root/handshakes/ESSID_BSSID.pcap # /root/handshakes/ESSID_BSSID.pcapng
essid, bssid = net_id.split('_') essid, bssid = net_id.split('_')
else: else:
# /root/handshakes/BSSID.pcap # /root/handshakes/BSSID.pcapng
essid, bssid = '', net_id essid, bssid = '', net_id
mac_re = re.compile('[0-9a-fA-F]{12}') mac_re = re.compile('[0-9a-fA-F]{12}')
@ -36,7 +35,7 @@ def parse_pcap(filename):
} }
try: try:
info = extract_from_pcap(filename, [WifiInfo.BSSID, WifiInfo.ESSID]) info = extract_from_pcapng(filename, [WifiInfo.BSSID, WifiInfo.ESSID])
except Exception as e: except Exception as e:
logging.error("grid: %s" % e) logging.error("grid: %s" % e)
@ -87,10 +86,10 @@ class Grid(plugins.Plugin):
agent.view().on_unread_messages(self.unread_messages, self.total_messages) agent.view().on_unread_messages(self.unread_messages, self.total_messages)
def check_handshakes(self, agent): def check_handshakes(self, agent):
logging.debug("checking pcaps") logging.debug("checking pcapng's")
config = agent.config() config = agent.config()
pcap_files = glob.glob(os.path.join(agent.config()['bettercap']['handshakes'], "*.pcap")) pcap_files = glob.glob(os.path.join(agent.config()['bettercap']['handshakes'], "*.pcapng"))
num_networks = len(pcap_files) num_networks = len(pcap_files)
reported = self.report.data_field_or('reported', default=[]) reported = self.report.data_field_or('reported', default=[])
num_reported = len(reported) num_reported = len(reported)
@ -103,7 +102,7 @@ class Grid(plugins.Plugin):
logging.debug(" exclude: %s" % config['main']['whitelist']) logging.debug(" exclude: %s" % config['main']['whitelist'])
for pcap_file in pcap_files: for pcap_file in pcap_files:
net_id = os.path.basename(pcap_file).replace('.pcap', '') net_id = os.path.basename(pcap_file).replace('.pcapng', '')
if net_id not in reported: if net_id not in reported:
if self.is_excluded(net_id, agent): if self.is_excluded(net_id, agent):
logging.debug("skipping %s due to exclusion filter" % pcap_file) logging.debug("skipping %s due to exclusion filter" % pcap_file)

View File

@ -82,12 +82,12 @@ class Hashie(plugins.Plugin):
if os.path.isfile(fullpathNoExt + '.22000'): if os.path.isfile(fullpathNoExt + '.22000'):
handshake_status.append('Already have {}.22000 (EAPOL)'.format(name)) handshake_status.append('Already have {}.22000 (EAPOL)'.format(name))
elif self._writeEAPOL(filename): elif self._writeEAPOL(filename):
handshake_status.append('Created {}.22000 (EAPOL) from pcap'.format(name)) handshake_status.append('Created {}.22000 (EAPOL) from pcapng'.format(name))
if os.path.isfile(fullpathNoExt + '.16800'): if os.path.isfile(fullpathNoExt + '.16800'):
handshake_status.append('Already have {}.16800 (PMKID)'.format(name)) handshake_status.append('Already have {}.16800 (PMKID)'.format(name))
elif self._writePMKID(filename): elif self._writePMKID(filename):
handshake_status.append('Created {}.16800 (PMKID) from pcap'.format(name)) handshake_status.append('Created {}.16800 (PMKID) from pcapng'.format(name))
if handshake_status: if handshake_status:
logging.info('[Hashie] Good news:\n\t' + '\n\t'.join(handshake_status)) logging.info('[Hashie] Good news:\n\t' + '\n\t'.join(handshake_status))
@ -111,7 +111,7 @@ class Hashie(plugins.Plugin):
return False return False
def _process_stale_pcaps(self, handshake_dir): 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('.pcap')] handshakes_list = [os.path.join(handshake_dir, filename) for filename in os.listdir(handshake_dir) if filename.endswith('.pcapng')]
failed_jobs = [] failed_jobs = []
successful_jobs = [] successful_jobs = []
lonely_pcaps = [] lonely_pcaps = []

View File

@ -108,7 +108,7 @@ class NetPos(plugins.Plugin):
return return
netpos["ts"] = int("%.0f" % time.time()) netpos["ts"] = int("%.0f" % time.time())
netpos_filename = filename.replace('.pcap', '.net-pos.json') netpos_filename = filename.replace('.pcapng', '.net-pos.json')
logging.debug("NET-POS: Saving net-location to %s", netpos_filename) logging.debug("NET-POS: Saving net-location to %s", netpos_filename)
try: try:

View File

@ -142,6 +142,6 @@ class OnlineHashCrack(plugins.Plugin):
for row in csv.DictReader(cracked_list): for row in csv.DictReader(cracked_list):
if row['password']: if row['password']:
filename = re.sub(r'[^a-zA-Z0-9]', '', row['ESSID']) + '_' + row['BSSID'].replace(':','') filename = re.sub(r'[^a-zA-Z0-9]', '', row['ESSID']) + '_' + row['BSSID'].replace(':','')
if os.path.exists( os.path.join(handshake_dir, filename+'.pcap') ): if os.path.exists( os.path.join(handshake_dir, filename+'.pcapng')):
with open(os.path.join(handshake_dir, filename+'.pcap.cracked'), 'w') as f: with open(os.path.join(handshake_dir, filename+'.pcapng.cracked'), 'w') as f:
f.write(row['password']) f.write(row['password'])

View File

@ -13,8 +13,8 @@ from dateutil.parser import parse
webgpsmap shows existing position data stored in your /handshakes/ directory webgpsmap shows existing position data stored in your /handshakes/ directory
the plugin does the following: the plugin does the following:
- search for *.pcap files in your /handshakes/ dir - search for *.pcapng files in your /handshakes/ dir
- for every found .pcap file it looks for a .geo.json or .gps.json or .paw-gps.json file with - for every found .pcapng file it looks for a .geo.json or .gps.json or file with
latitude+longitude data inside and shows this position on the map latitude+longitude data inside and shows this position on the map
- if also an .cracked file with a plaintext password inside exist, it reads the content and shows the - if also an .cracked file with a plaintext password inside exist, it reads the content and shows the
position as green instead of red and the password inside the infopox of the position position as green instead of red and the password inside the infopox of the position
@ -87,7 +87,8 @@ class Webgpsmap(plugins.Plugin):
# returns all positions # returns all positions
try: try:
self.ALREADY_SENT = list() self.ALREADY_SENT = list()
response_data = bytes(json.dumps(self.load_gps_from_dir(self.config['bettercap']['handshakes'])), "utf-8") response_data = bytes(
json.dumps(self.load_gps_from_dir(self.config['bettercap']['handshakes'])), "utf-8")
response_status = 200 response_status = 200
response_mimetype = "application/json" response_mimetype = "application/json"
response_header_contenttype = 'application/json' response_header_contenttype = 'application/json'
@ -100,7 +101,8 @@ class Webgpsmap(plugins.Plugin):
self.ALREADY_SENT = list() self.ALREADY_SENT = list()
json_data = json.dumps(self.load_gps_from_dir(self.config['bettercap']['handshakes'])) json_data = json.dumps(self.load_gps_from_dir(self.config['bettercap']['handshakes']))
html_data = self.get_html() html_data = self.get_html()
html_data = html_data.replace('var positions = [];', 'var positions = ' + json_data + ';positionsLoaded=true;drawPositions();') html_data = html_data.replace('var positions = [];',
'var positions = ' + json_data + ';positionsLoaded=true;drawPositions();')
response_data = bytes(html_data, "utf-8") response_data = bytes(html_data, "utf-8")
response_status = 200 response_status = 200
response_mimetype = "application/xhtml+xml" response_mimetype = "application/xhtml+xml"
@ -163,7 +165,8 @@ class Webgpsmap(plugins.Plugin):
all_files = os.listdir(handshake_dir) all_files = os.listdir(handshake_dir)
# print(all_files) # print(all_files)
all_pcap_files = [os.path.join(handshake_dir, filename) for filename in all_files if filename.endswith('.pcap')] all_pcap_files = [os.path.join(handshake_dir, filename) for filename in all_files if
filename.endswith('.pcapng')]
all_geo_or_gps_files = [] all_geo_or_gps_files = []
for filename_pcap in all_pcap_files: for filename_pcap in all_pcap_files:
filename_base = filename_pcap[:-5] # remove ".pcap" filename_base = filename_pcap[:-5] # remove ".pcap"
@ -180,22 +183,18 @@ class Webgpsmap(plugins.Plugin):
if check_for in all_files: if check_for in all_files:
filename_position = str(os.path.join(handshake_dir, check_for)) filename_position = str(os.path.join(handshake_dir, check_for))
logging.debug("[webgpsmap] search for .paw-gps.json")
check_for = os.path.basename(filename_base) + ".paw-gps.json"
if check_for in all_files:
filename_position = str(os.path.join(handshake_dir, check_for))
logging.debug(f"[webgpsmap] end search for position data files and use {filename_position}") logging.debug(f"[webgpsmap] end search for position data files and use {filename_position}")
if filename_position is not None: if filename_position is not None:
all_geo_or_gps_files.append(filename_position) all_geo_or_gps_files.append(filename_position)
# all_geo_or_gps_files = set(all_geo_or_gps_files) - set(SKIP) # remove skipped networks? No! # all_geo_or_gps_files = set(all_geo_or_gps_files) - set(SKIP) # remove skipped networks? No!
if newest_only: if newest_only:
all_geo_or_gps_files = set(all_geo_or_gps_files) - set(self.ALREADY_SENT) all_geo_or_gps_files = set(all_geo_or_gps_files) - set(self.ALREADY_SENT)
logging.info(f"[webgpsmap] Found {len(all_geo_or_gps_files)} position-data files from {len(all_pcap_files)} handshakes. Fetching positions ...") logging.info(
f"[webgpsmap] Found {len(all_geo_or_gps_files)} position-data files from {len(all_pcap_files)} handshakes. Fetching positions ...")
for pos_file in all_geo_or_gps_files: for pos_file in all_geo_or_gps_files:
try: try:
@ -213,9 +212,7 @@ class Webgpsmap(plugins.Plugin):
pos_type = 'gps' pos_type = 'gps'
elif pos.type() == PositionFile.GEO: elif pos.type() == PositionFile.GEO:
pos_type = 'geo' pos_type = 'geo'
elif pos.type() == PositionFile.PAWGPS: gps_data[ssid + "_" + mac] = {
pos_type = 'paw'
gps_data[ssid+"_"+mac] = {
'ssid': ssid, 'ssid': ssid,
'mac': mac, 'mac': mac,
'type': pos_type, 'type': pos_type,
@ -224,10 +221,10 @@ class Webgpsmap(plugins.Plugin):
'acc': pos.accuracy(), 'acc': pos.accuracy(),
'ts_first': pos.timestamp_first(), 'ts_first': pos.timestamp_first(),
'ts_last': pos.timestamp_last(), 'ts_last': pos.timestamp_last(),
} }
# get ap password if exist # get ap password if exist
check_for = os.path.basename(pos_file).split(".")[0] + ".pcap.cracked" check_for = os.path.basename(pos_file).split(".")[0] + ".pcapng.cracked"
if check_for in all_files: if check_for in all_files:
gps_data[ssid + "_" + mac]["pass"] = pos.password() gps_data[ssid + "_" + mac]["pass"] = pos.password()
@ -265,7 +262,6 @@ class PositionFile:
""" """
GPS = 1 GPS = 1
GEO = 2 GEO = 2
PAWGPS = 3
def __init__(self, path): def __init__(self, path):
self._file = path self._file = path
@ -282,7 +278,7 @@ class PositionFile:
""" """
Returns the mac from filename Returns the mac from filename
""" """
parsed_mac = re.search(r'.*_?([a-zA-Z0-9]{12})\.(?:gps|geo|paw-gps)\.json', self._filename) parsed_mac = re.search(r'.*_?([a-zA-Z0-9]{12})\.(?:gps|geo)\.json', self._filename)
if parsed_mac: if parsed_mac:
mac = parsed_mac.groups()[0] mac = parsed_mac.groups()[0]
return mac return mac
@ -292,7 +288,7 @@ class PositionFile:
""" """
Returns the ssid from filename Returns the ssid from filename
""" """
parsed_ssid = re.search(r'(.+)_[a-zA-Z0-9]{12}\.(?:gps|geo|paw-gps)\.json', self._filename) parsed_ssid = re.search(r'(.+)_[a-zA-Z0-9]{12}\.(?:gps|geo)\.json', self._filename)
if parsed_ssid: if parsed_ssid:
return parsed_ssid.groups()[0] return parsed_ssid.groups()[0]
return None return None
@ -333,7 +329,7 @@ class PositionFile:
return_pass = None return_pass = None
# 2do: make better filename split/remove extension because this one has problems with "." in path # 2do: make better filename split/remove extension because this one has problems with "." in path
base_filename, ext1, ext2 = re.split('\.', self._file) base_filename, ext1, ext2 = re.split('\.', self._file)
password_file_path = base_filename + ".pcap.cracked" password_file_path = base_filename + ".pcapng.cracked"
if os.path.isfile(password_file_path): if os.path.isfile(password_file_path):
try: try:
password_file = open(password_file_path, 'r') password_file = open(password_file_path, 'r')
@ -354,8 +350,6 @@ class PositionFile:
return PositionFile.GPS return PositionFile.GPS
if self._file.endswith('.geo.json'): if self._file.endswith('.geo.json'):
return PositionFile.GEO return PositionFile.GEO
if self._file.endswith('.paw-gps.json'):
return PositionFile.PAWGPS
return None return None
def lat(self): def lat(self):
@ -402,9 +396,7 @@ class PositionFile:
def accuracy(self): def accuracy(self):
if self.type() == PositionFile.GPS: if self.type() == PositionFile.GPS:
return 50.0 # a default return 50.0 # a default
if self.type() == PositionFile.PAWGPS:
return 50.0 # a default
if self.type() == PositionFile.GEO: if self.type() == PositionFile.GEO:
try: try:
return self._json['accuracy'] return self._json['accuracy']

View File

@ -7,7 +7,7 @@ import pwnagotchi
from io import StringIO from io import StringIO
from datetime import datetime from datetime import datetime
from pwnagotchi.utils import WifiInfo, FieldNotFoundError, extract_from_pcap, StatusFile, remove_whitelisted from pwnagotchi.utils import WifiInfo, FieldNotFoundError, extract_from_pcapng, StatusFile, remove_whitelisted
from threading import Lock from threading import Lock
from pwnagotchi import plugins from pwnagotchi import plugins
from pwnagotchi._version import __version__ as __pwnagotchi_version__ from pwnagotchi._version import __version__ as __pwnagotchi_version__
@ -153,11 +153,11 @@ class Wigle(plugins.Plugin):
no_err_entries = list() no_err_entries = list()
for gps_file in new_gps_files: for gps_file in new_gps_files:
if gps_file.endswith('.gps.json'): if gps_file.endswith('.gps.json'):
pcap_filename = gps_file.replace('.gps.json', '.pcap') pcap_filename = gps_file.replace('.gps.json', '.pcapng')
if gps_file.endswith('.geo.json'): if gps_file.endswith('.geo.json'):
pcap_filename = gps_file.replace('.geo.json', '.pcap') pcap_filename = gps_file.replace('.geo.json', '.pcapng')
if not os.path.exists(pcap_filename): if not os.path.exists(pcap_filename):
logging.debug("WIGLE: Can't find pcap for %s", gps_file) logging.debug("WIGLE: Can't find pcapng for %s", gps_file)
self.skip.append(gps_file) self.skip.append(gps_file)
continue continue
try: try:
@ -175,7 +175,7 @@ class Wigle(plugins.Plugin):
self.skip.append(gps_file) self.skip.append(gps_file)
continue continue
try: try:
pcap_data = extract_from_pcap(pcap_filename, [WifiInfo.BSSID, pcap_data = extract_from_pcapng(pcap_filename, [WifiInfo.BSSID,
WifiInfo.ESSID, WifiInfo.ESSID,
WifiInfo.ENCRYPTION, WifiInfo.ENCRYPTION,
WifiInfo.CHANNEL, WifiInfo.CHANNEL,

View File

@ -98,7 +98,7 @@ class WpaSec(plugins.Plugin):
reported = self.report.data_field_or('reported', default=list()) reported = self.report.data_field_or('reported', default=list())
handshake_dir = config['bettercap']['handshakes'] handshake_dir = config['bettercap']['handshakes']
handshake_filenames = os.listdir(handshake_dir) handshake_filenames = os.listdir(handshake_dir)
handshake_paths = [os.path.join(handshake_dir, filename) for filename in handshake_filenames if filename.endswith('.pcap')] handshake_paths = [os.path.join(handshake_dir, filename) for filename in handshake_filenames if filename.endswith('.pcapng')]
handshake_paths = remove_whitelisted(handshake_paths, config['main']['whitelist']) handshake_paths = remove_whitelisted(handshake_paths, config['main']['whitelist'])
handshake_new = set(handshake_paths) - set(reported) - set(self.skip) handshake_new = set(handshake_paths) - set(reported) - set(self.skip)

View File

@ -82,7 +82,7 @@ def remove_whitelisted(list_of_handshakes, list_of_whitelisted_strings, valid_on
for handshake in list_of_handshakes: for handshake in list_of_handshakes:
try: try:
normalized_handshake = normalize(os.path.basename(handshake).rstrip('.pcap')) normalized_handshake = normalize(os.path.basename(handshake).rstrip('.pcapng'))
for whitelist in list_of_whitelisted_strings: for whitelist in list_of_whitelisted_strings:
normalized_whitelist = normalize(whitelist) normalized_whitelist = normalize(whitelist)
if normalized_whitelist in normalized_handshake: if normalized_whitelist in normalized_handshake:
@ -440,7 +440,7 @@ def secs_to_hhmmss(secs):
def total_unique_handshakes(path): def total_unique_handshakes(path):
expr = os.path.join(path, "*.pcap") expr = os.path.join(path, "*.pcapng")
return len(glob.glob(expr)) return len(glob.glob(expr))
@ -498,11 +498,11 @@ def md5(fname):
return hash_md5.hexdigest() return hash_md5.hexdigest()
def extract_from_pcap(path, fields): def extract_from_pcapng(path, fields):
""" """
Search in pcap-file for specified information Search in pcapng-file for specified information
path: Path to pcap file path: Path to pcapng file
fields: Array of fields that should be extracted fields: Array of fields that should be extracted
If a field is not found, FieldNotFoundError is raised If a field is not found, FieldNotFoundError is raised