def __init__(self):
     self.ready = False
     self.tries = 0
     logging.debug("GIT BACKUP")
     self.status = StatusFile('/root/.git_backup')
Example #2
0
class AutoUpdate(plugins.Plugin):
    __author__ = '*****@*****.**'
    __version__ = '1.1.1'
    __name__ = 'auto-update'
    __license__ = 'GPL3'
    __description__ = 'This plugin checks when updates are available and applies them when internet is available.'

    def __init__(self):
        self.ready = False
        self.status = StatusFile('/root/.auto-update')

    def on_loaded(self):
        if 'interval' not in self.options or (
                'interval' in self.options
                and self.options['interval'] is None):
            logging.error(
                "[update] main.plugins.auto-update.interval is not set")
            return
        self.ready = True
        logging.info("[update] plugin loaded.")

    def on_internet_available(self, agent):
        logging.debug(
            "[update] internet connectivity is available (ready %s)" %
            self.ready)

        if not self.ready:
            return

        if self.status.newer_then_hours(self.options['interval']):
            logging.debug(
                "[update] last check happened less than %d hours ago" %
                self.options['interval'])
            return

        logging.info("[update] checking for updates ...")

        display = agent.view()
        prev_status = display.get('status')

        try:
            display.update(force=True,
                           new_data={'status': 'Checking for updates ...'})

            to_install = []
            to_check = [
                ('bettercap/bettercap', parse_version('bettercap -version'),
                 True, 'bettercap'),
                ('evilsocket/pwngrid', parse_version('pwngrid -version'), True,
                 'pwngrid-peer'),
                ('evilsocket/pwnagotchi', pwnagotchi.version, False,
                 'pwnagotchi')
            ]

            for repo, local_version, is_native, svc_name in to_check:
                info = check(local_version, repo, is_native)
                if info['url'] is not None:
                    logging.warning(
                        "update for %s available (local version is '%s'): %s" %
                        (repo, info['current'], info['url']))
                    info['service'] = svc_name
                    to_install.append(info)

            num_updates = len(to_install)
            num_installed = 0

            if num_updates > 0:
                if self.options['install']:
                    for update in to_install:
                        if install(display, update):
                            num_installed += 1
                else:
                    prev_status = '%d new update%c available!' % (
                        num_updates, 's' if num_updates > 1 else '')

            logging.info("[update] done")

            self.status.update()

            if num_installed > 0:
                display.update(force=True,
                               new_data={'status': 'Rebooting ...'})
                pwnagotchi.reboot()

        except Exception as e:
            logging.error("[update] %s" % e)

        display.update(force=True,
                       new_data={
                           'status':
                           prev_status if prev_status is not None else ''
                       })
 def __init__(self):
     self.ready = False
     self.report = StatusFile('/root/.wigle_uploads', data_format='json')
     self.skip = list()
     self.lock = Lock()
     self.shutdown = False
Example #4
0
__version__ = '2.0.0'
__name__ = 'wigle'
__license__ = 'GPL3'
__description__ = 'This plugin automatically uploades collected wifis to wigle.net'

import os
import logging
import json
from io import StringIO
import csv
from datetime import datetime
import requests
from pwnagotchi.utils import WifiInfo, FieldNotFoundError, extract_from_pcap, StatusFile

READY = False
REPORT = StatusFile('/root/.wigle_uploads', data_format='json')
SKIP = list()
OPTIONS = dict()


def on_loaded():
    """
    Gets called when the plugin gets loaded
    """
    global READY

    if 'api_key' not in OPTIONS or ('api_key' in OPTIONS and OPTIONS['api_key'] is None):
        logging.error("WIGLE: api_key isn't set. Can't upload to wigle.net")
        return

    READY = True
Example #5
0
 def __init__(self):
     self.ready = False
     self.status = StatusFile('/root/.auto-backup')
class OnlineHashCrack(plugins.Plugin):
    __author__ = '*****@*****.**'
    __version__ = '2.0.1'
    __license__ = 'GPL3'
    __description__ = 'This plugin automatically uploads handshakes to https://onlinehashcrack.com'

    def __init__(self):
        self.ready = False
        try:
            self.report = StatusFile('/root/.ohc_uploads', data_format='json')
        except JSONDecodeError as json_err:
            os.remove('/root/.ohc_uploads')
            self.report = StatusFile('/root/.ohc_uploads', data_format='json')
        self.skip = list()
        self.lock = Lock()

    def on_loaded(self):
        """
        Gets called when the plugin gets loaded
        """
        if 'email' not in self.options or ('email' in self.options and not self.options['email']):
            logging.error("OHC: Email isn't set. Can't upload to onlinehashcrack.com")
            return

        if 'whitelist' not in self.options:
            self.options['whitelist'] = []

        # remove special characters from whitelist APs to match on-disk format
        self.options['whitelist'] = set(map(lambda x: re.sub(r'[^a-zA-Z0-9]', '', x), self.options['whitelist']))

        self.ready = True
        logging.info("OHC: OnlineHashCrack plugin loaded.")

    def _filter_handshake_file(self, handshake_filename):
        try:
            basename = os.path.basename(handshake_filename)
            ssid, bssid = basename.split('_')
            # remove the ".pcap" from the bssid (which is really just the end of the filename)
            bssid = bssid[:-5]
        except:
            # something failed in our parsing of the filename. let the file through
            return True

        return ssid not in self.options['whitelist'] and bssid not in self.options['whitelist']

    def _upload_to_ohc(self, path, timeout=30):
        """
        Uploads the file to onlinehashcrack.com
        """
        with open(path, 'rb') as file_to_upload:
            data = {'email': self.options['email']}
            payload = {'file': file_to_upload}

            try:
                result = requests.post('https://api.onlinehashcrack.com',
                                       data=data,
                                       files=payload,
                                       timeout=timeout)
                if 'already been sent' in result.text:
                    logging.warning(f"{path} was already uploaded.")
            except requests.exceptions.RequestException as e:
                logging.error(f"OHC: Got an exception while uploading {path} -> {e}")
                raise e

    def _download_cracked(self, save_file, timeout=120):
        """
        Downloads the cracked passwords and saves them

        returns the number of downloaded passwords
        """
        try:
            s = requests.Session()
            dashboard = s.get(self.options['dashboard'], timeout=timeout)
            result = s.get('https://www.onlinehashcrack.com/wpa-exportcsv', timeout=timeout)
            result.raise_for_status()
            with open(save_file, 'wb') as output_file:
                output_file.write(result.content)
        except requests.exceptions.RequestException as req_e:
            raise req_e
        except OSError as os_e:
            raise os_e

    def on_internet_available(self, agent):
        """
        Called in manual mode when there's internet connectivity
        """
        with self.lock:
            if self.ready:
                display = agent.view()
                config = agent.config()
                reported = self.report.data_field_or('reported', default=list())

                handshake_dir = config['bettercap']['handshakes']
                handshake_filenames = os.listdir(handshake_dir)
                handshake_paths = [os.path.join(handshake_dir, filename) for filename in handshake_filenames if
                                   filename.endswith('.pcap')]

                # pull out whitelisted APs
                handshake_paths = filter(lambda path: self._filter_handshake_file(path), handshake_paths)

                handshake_new = set(handshake_paths) - set(reported) - set(self.skip)

                if handshake_new:
                    logging.info("OHC: Internet connectivity detected. Uploading new handshakes to onlinehashcrack.com")

                    for idx, handshake in enumerate(handshake_new):
                        display.set('status',
                                    f"Uploading handshake to onlinehashcrack.com ({idx + 1}/{len(handshake_new)})")
                        display.update(force=True)
                        try:
                            self._upload_to_ohc(handshake)
                            if handshake not in reported:
                                reported.append(handshake)
                                self.report.update(data={'reported': reported})
                                logging.info(f"OHC: Successfully uploaded {handshake}")
                        except requests.exceptions.RequestException as req_e:
                            self.skip.append(handshake)
                            logging.error("OHC: %s", req_e)
                            continue
                        except OSError as os_e:
                            self.skip.append(handshake)
                            logging.error("OHC: %s", os_e)
                            continue

                if 'dashboard' in self.options and self.options['dashboard']:
                    cracked_file = os.path.join(handshake_dir, 'onlinehashcrack.cracked')
                    if os.path.exists(cracked_file):
                        last_check = datetime.fromtimestamp(os.path.getmtime(cracked_file))
                        if last_check is not None and ((datetime.now() - last_check).seconds / (60 * 60)) < 1:
                            return

                    try:
                        self._download_cracked(cracked_file)
                        logging.info("OHC: Downloaded cracked passwords.")
                    except requests.exceptions.RequestException as req_e:
                        logging.debug("OHC: %s", req_e)
                    except OSError as os_e:
                        logging.debug("OHC: %s", os_e)

                    if 'single_files' in self.options and self.options['single_files']:
                        with open(cracked_file, 'r') as cracked_list:
                            for row in csv.DictReader(cracked_list):
                                if row['password']:
                                    filename = re.sub(r'[^a-zA-Z0-9]', '', row['ESSID']) + '_' + row['BSSID'].replace(':','')
                                    if os.path.exists( os.path.join(handshake_dir, filename+'.pcap') ):
                                        with open(os.path.join(handshake_dir, filename+'.pcap.cracked'), 'w') as f:
                                            f.write(row['password'])
Example #7
0
class OnlineHashCrack(plugins.Plugin):
    __author__ = '*****@*****.**'
    __version__ = '2.0.1'
    __license__ = 'GPL3'
    __description__ = 'This plugin automatically uploads handshakes to https://onlinehashcrack.com'

    def __init__(self):
        self.ready = False
        try:
            self.report = StatusFile('/root/.ohc_uploads', data_format='json')
        except JSONDecodeError as json_err:
            os.remove('/root/.ohc_uploads')
            self.report = StatusFile('/root/.ohc_uploads', data_format='json')
        self.skip = list()
        self.lock = Lock()

    def on_loaded(self):
        """
        Gets called when the plugin gets loaded
        """
        if 'email' not in self.options or ('email' in self.options
                                           and not self.options['email']):
            logging.error(
                "OHC: Email isn't set. Can't upload to onlinehashcrack.com")
            return

        if 'whitelist' not in self.options:
            self.options['whitelist'] = []

        # remove special characters from whitelist APs to match on-disk format
        self.options['whitelist'] = set(
            map(lambda x: re.sub(r'[^a-zA-Z0-9]', '', x),
                self.options['whitelist']))

        self.ready = True

    def _filter_handshake_file(self, handshake_filename):
        try:
            basename = os.path.basename(handshake_filename)
            ssid, bssid = basename.split('_')
            # remove the ".pcap" from the bssid (which is really just the end of the filename)
            bssid = bssid[:-5]
        except:
            # something failed in our parsing of the filename. let the file through
            return True

        return ssid not in self.options[
            'whitelist'] and bssid not in self.options['whitelist']

    def _upload_to_ohc(self, path, timeout=30):
        """
        Uploads the file to onlinehashcrack.com
        """
        with open(path, 'rb') as file_to_upload:
            data = {'email': self.options['email']}
            payload = {'file': file_to_upload}

            try:
                result = requests.post('https://api.onlinehashcrack.com',
                                       data=data,
                                       files=payload,
                                       timeout=timeout)
                if 'already been sent' in result.text:
                    logging.warning(f"{path} was already uploaded.")
            except requests.exceptions.RequestException as e:
                logging.error(
                    f"OHC: Got an exception while uploading {path} -> {e}")
                raise e

    def on_internet_available(self, agent):
        """
        Called in manual mode when there's internet connectivity
        """
        with self.lock:
            if self.ready:
                display = agent.view()
                config = agent.config()
                reported = self.report.data_field_or('reported',
                                                     default=list())

                handshake_dir = config['bettercap']['handshakes']
                handshake_filenames = os.listdir(handshake_dir)
                handshake_paths = [
                    os.path.join(handshake_dir, filename)
                    for filename in handshake_filenames
                    if filename.endswith('.pcap')
                ]

                # pull out whitelisted APs
                handshake_paths = filter(
                    lambda path: self._filter_handshake_file(path),
                    handshake_paths)

                handshake_new = set(handshake_paths) - set(reported) - set(
                    self.skip)

                if handshake_new:
                    logging.info(
                        "OHC: Internet connectivity detected. Uploading new handshakes to onelinehashcrack.com"
                    )

                    for idx, handshake in enumerate(handshake_new):
                        display.set(
                            'status',
                            f"Uploading handshake to onlinehashcrack.com ({idx + 1}/{len(handshake_new)})"
                        )
                        display.update(force=True)
                        try:
                            self._upload_to_ohc(handshake)
                            if handshake not in reported:
                                reported.append(handshake)
                                self.report.update(data={'reported': reported})
                                logging.info(
                                    f"OHC: Successfully uploaded {handshake}")
                        except requests.exceptions.RequestException as req_e:
                            self.skip.append(handshake)
                            logging.error("OHC: %s", req_e)
                            continue
                        except OSError as os_e:
                            self.skip.append(handshake)
                            logging.error("OHC: %s", os_e)
                            continue
Example #8
0
class Grid(plugins.Plugin):
    __author__ = '*****@*****.**'
    __version__ = '1.0.1'
    __license__ = 'GPL3'
    __description__ = 'This plugin signals the unit cryptographic identity and list of pwned networks and list of pwned ' \
                      'networks to api.pwnagotchi.ai '

    def __init__(self):
        self.options = dict()
        self.report = StatusFile('/root/.api-report.json', data_format='json')

        self.unread_messages = 0
        self.total_messages = 0

    def is_excluded(self, what):
        for skip in self.options['exclude']:
            skip = skip.lower()
            what = what.lower()
            if skip in what or skip.replace(':', '') in what:
                return True
        return False

    def on_loaded(self):
        logging.info("grid plugin loaded.")

    def set_reported(self, reported, net_id):
        reported.append(net_id)
        self.report.update(data={'reported': reported})

    def check_inbox(self, agent):
        logging.debug("checking mailbox ...")
        messages = grid.inbox()
        self.total_messages = len(messages)
        self.unread_messages = len(
            [m for m in messages if m['seen_at'] is None])

        if self.unread_messages:
            plugins.on('unread_inbox', self.unread_messages)
            logging.debug("[grid] unread:%d total:%d" %
                          (self.unread_messages, self.total_messages))
            agent.view().on_unread_messages(self.unread_messages,
                                            self.total_messages)

    def check_handshakes(self, agent):
        logging.debug("checking pcaps")

        pcap_files = glob.glob(
            os.path.join(agent.config()['bettercap']['handshakes'], "*.pcap"))
        num_networks = len(pcap_files)
        reported = self.report.data_field_or('reported', default=[])
        num_reported = len(reported)
        num_new = num_networks - num_reported

        if num_new > 0:
            if self.options['report']:
                logging.info("grid: %d new networks to report" % num_new)
                logging.debug("self.options: %s" % self.options)
                logging.debug("  exclude: %s" % self.options['exclude'])

                for pcap_file in pcap_files:
                    net_id = os.path.basename(pcap_file).replace('.pcap', '')
                    if net_id not in reported:
                        if self.is_excluded(net_id):
                            logging.debug(
                                "skipping %s due to exclusion filter" %
                                pcap_file)
                            self.set_reported(reported, net_id)
                            continue

                        essid, bssid = parse_pcap(pcap_file)
                        if bssid:
                            if self.is_excluded(essid) or self.is_excluded(
                                    bssid):
                                logging.debug(
                                    "not reporting %s due to exclusion filter"
                                    % pcap_file)
                                self.set_reported(reported, net_id)
                            else:
                                if grid.report_ap(essid, bssid):
                                    self.set_reported(reported, net_id)
                                time.sleep(1.5)
                        else:
                            logging.warning("no bssid found?!")
            else:
                logging.debug("grid: reporting disabled")

    def on_internet_available(self, agent):
        logging.debug("internet available")

        try:
            grid.update_data(agent.last_session)
        except Exception as e:
            logging.error("error connecting to the pwngrid-peer service: %s" %
                          e)
            logging.debug(e, exc_info=True)
            return

        try:
            self.check_inbox(agent)
        except Exception as e:
            logging.error("[grid] error while checking inbox: %s" % e)
            logging.debug(e, exc_info=True)

        try:
            self.check_handshakes(agent)
        except Exception as e:
            logging.error("[grid] error while checking pcaps: %s" % e)
            logging.debug(e, exc_info=True)
Example #9
0
class OnlineHashCrack(plugins.Plugin):
    __author__ = '*****@*****.**'
    __version__ = '2.1.5'
    __license__ = 'GPL3'
    __description__ = 'This plugin automatically uploads handshakes to https://onlinehashcrack.com'
    __dependencies__ = {'pip': ['requests']}
    __defaults__ = {
        'enabled': False,
        'email': '',
        'dashboard': '',
        'single_files': False,
        'whitelist': [],
    }

    def __init__(self):
        self.ready = False
        try:
            self.report = StatusFile('/root/.ohc_uploads', data_format='json')
        except JSONDecodeError:
            os.remove('/root/.ohc_uploads')
            self.report = StatusFile('/root/.ohc_uploads', data_format='json')
        self.skip = list()
        self.lock = Lock()
        self.shutdown = False

    def on_config_changed(self, config):
        with self.lock:
            self.options['whitelist'] = list(
                set(self.options['whitelist'] + config['main']['whitelist']))

    def on_before_shutdown(self):
        self.shutdown = True

    def on_loaded(self):
        """
        Gets called when the plugin gets loaded
        """
        if not self.options['email']:
            logging.error(
                "[ohc] Email isn't set. Can't upload to onlinehashcrack.com")
            return

        self.ready = True
        logging.info("[ohc] OnlineHashCrack plugin loaded.")

    def _upload_to_ohc(self, path, timeout=30):
        """
        Uploads the file to onlinehashcrack.com
        """
        with open(path, 'rb') as file_to_upload:
            data = {'email': self.options['email']}
            payload = {'file': file_to_upload}

            try:
                result = requests.post('https://api.onlinehashcrack.com',
                                       data=data,
                                       files=payload,
                                       timeout=timeout)
                if 'already been sent' in result.text:
                    logging.debug(f"[ohc] {path} was already uploaded.")
            except requests.exceptions.RequestException as e:
                logging.debug(
                    f"[ohc] Got an exception while uploading {path} -> {e}")
                raise e

    def _download_cracked(self, save_file, timeout=120):
        """
        Downloads the cracked passwords and saves them

        returns the number of downloaded passwords
        """
        try:
            s = requests.Session()
            s.get(self.options['dashboard'], timeout=timeout)
            result = s.get('https://www.onlinehashcrack.com/wpa-exportcsv',
                           timeout=timeout)
            result.raise_for_status()
            with open(save_file, 'wb') as output_file:
                output_file.write(result.content)
        except requests.exceptions.RequestException as req_e:
            raise req_e
        except OSError as os_e:
            raise os_e

    def on_webhook(self, path, request):
        import requests
        from flask import redirect
        s = requests.Session()
        s.get('https://www.onlinehashcrack.com/dashboard')
        r = s.post('https://www.onlinehashcrack.com/dashboard',
                   data={
                       'emailTasks': self.options['email'],
                       'submit': ''
                   })
        return redirect(r.url, code=302)

    def on_internet_available(self, agent):
        """
        Called in manual mode when there's internet connectivity
        """

        if not self.ready or self.lock.locked() or self.shutdown:
            return

        with self.lock:
            display = agent.view()
            config = agent.config()
            reported = self.report.data_field_or('reported', default=list())
            handshake_dir = config['bettercap']['handshakes']
            handshake_filenames = os.listdir(handshake_dir)
            handshake_paths = [
                os.path.join(handshake_dir, filename)
                for filename in handshake_filenames
                if filename.endswith('.pcap')
            ]
            # pull out whitelisted APs
            handshake_paths = remove_whitelisted(handshake_paths,
                                                 self.options['whitelist'])
            handshake_new = set(handshake_paths) - set(reported) - set(
                self.skip)
            if handshake_new:
                logging.info(
                    "[ohc] Internet connectivity detected. Uploading new handshakes to onlinehashcrack.com"
                )
                for idx, handshake in enumerate(handshake_new):
                    if self.shutdown:
                        return
                    display.set(
                        'status',
                        f"Uploading handshake to onlinehashcrack.com ({idx + 1}/{len(handshake_new)})"
                    )
                    display.update(force=True)
                    try:
                        self._upload_to_ohc(handshake)
                        if handshake not in reported:
                            reported.append(handshake)
                            self.report.update(data={'reported': reported})
                            logging.debug(
                                f"[ohc] Successfully uploaded {handshake}")
                    except requests.exceptions.RequestException as req_e:
                        self.skip.append(handshake)
                        logging.debug("[ohc] %s", req_e)
                        continue
                    except OSError as os_e:
                        self.skip.append(handshake)
                        logging.debug("[ohc] %s", os_e)
                        continue
            if 'dashboard' in self.options and self.options['dashboard']:
                cracked_file = os.path.join(handshake_dir,
                                            'onlinehashcrack.cracked')
                if os.path.exists(cracked_file):
                    last_check = datetime.fromtimestamp(
                        os.path.getmtime(cracked_file))
                    if last_check is not None and (
                        (datetime.now() - last_check).seconds / (60 * 60)) < 1:
                        return
                try:
                    self._download_cracked(cracked_file)
                    logging.info("[ohc] Downloaded cracked passwords.")
                except requests.exceptions.RequestException as req_e:
                    logging.debug("[ohc] %s", req_e)
                except OSError as os_e:
                    logging.debug("[ohc] %s", os_e)
                if 'single_files' in self.options and self.options[
                        'single_files']:
                    with open(cracked_file, 'r') as cracked_list:
                        for row in csv.DictReader(cracked_list):
                            if row['password']:
                                filename = re.sub(
                                    r'[^a-zA-Z0-9]', '',
                                    row['ESSID']) + '_' + row['BSSID'].replace(
                                        ':', '')
                                if os.path.exists(
                                        os.path.join(handshake_dir,
                                                     filename + '.pcap')):
                                    with open(
                                            os.path.join(
                                                handshake_dir,
                                                filename + '.pcap.cracked'),
                                            'w') as f:
                                        f.write(row['password'])
Example #10
0
 def __init__(self):
     self.ready = False
     self.report = StatusFile('/root/.ohc_uploads', data_format='json')
     self.skip = list()
Example #11
0
class WpaSec(plugins.Plugin):
    __author__ = '*****@*****.**'
    __version__ = '2.0.1'
    __license__ = 'GPL3'
    __description__ = 'This plugin automatically uploads handshakes to https://wpa-sec.stanev.org'

    def __init__(self):
        self.ready = False
        self.report = StatusFile('/root/.wpa_sec_uploads', data_format='json')
        self.options = dict()
        self.skip = list()

    def _upload_to_wpasec(self, path, timeout=30):
        """
        Uploads the file to https://wpa-sec.stanev.org, or another endpoint.
        """
        with open(path, 'rb') as file_to_upload:
            cookie = {'key': self.options['api_key']}
            payload = {'file': file_to_upload}

            try:
                result = requests.post(self.options['api_url'],
                                       cookies=cookie,
                                       files=payload,
                                       timeout=timeout)
                if ' already submitted' in result.text:
                    logging.warning("%s was already submitted.", path)
            except requests.exceptions.RequestException as req_e:
                raise req_e

    def on_loaded(self):
        """
        Gets called when the plugin gets loaded
        """
        if 'api_key' not in self.options or ('api_key' in self.options and
                                             self.options['api_key'] is None):
            logging.error(
                "WPA_SEC: API-KEY isn't set. Can't upload to wpa-sec.stanev.org"
            )
            return

        if 'api_url' not in self.options or ('api_url' in self.options and
                                             self.options['api_url'] is None):
            logging.error(
                "WPA_SEC: API-URL isn't set. Can't upload, no endpoint configured."
            )
            return

        self.ready = True

    def on_internet_available(self, agent):
        """
        Called in manual mode when there's internet connectivity
        """
        if self.ready:
            config = agent.config()
            display = agent.view()
            reported = self.report.data_field_or('reported', default=list())

            handshake_dir = config['bettercap']['handshakes']
            handshake_filenames = os.listdir(handshake_dir)
            handshake_paths = [
                os.path.join(handshake_dir, filename)
                for filename in handshake_filenames
                if filename.endswith('.pcap')
            ]
            handshake_new = set(handshake_paths) - set(reported) - set(
                self.skip)

            if handshake_new:
                logging.info(
                    "WPA_SEC: Internet connectivity detected. Uploading new handshakes to wpa-sec.stanev.org"
                )

                for idx, handshake in enumerate(handshake_new):
                    display.set(
                        'status',
                        f"Uploading handshake to wpa-sec.stanev.org ({idx + 1}/{len(handshake_new)})"
                    )
                    display.update(force=True)
                    try:
                        self._upload_to_wpasec(handshake)
                        reported.append(handshake)
                        self.report.update(data={'reported': reported})
                        logging.info("WPA_SEC: Successfully uploaded %s",
                                     handshake)
                    except requests.exceptions.RequestException as req_e:
                        self.skip.append(handshake)
                        logging.error("WPA_SEC: %s", req_e)
                        continue
                    except OSError as os_e:
                        logging.error("WPA_SEC: %s", os_e)
                        continue
Example #12
0
 def __init__(self):
     self.ready = False
     self.report = StatusFile('/root/.wpa_sec_uploads', data_format='json')
     self.options = dict()
     self.skip = list()
class GitBackup(plugins.Plugin):
    __author__ = '*****@*****.**'
    __version__ = '1.0.0'
    __license__ = 'GPL3'
    __description__ = 'git_backup'

    def __init__(self):
        self.ready = False
        self.tries = 0
        logging.debug("GIT BACKUP")
        self.status = StatusFile('/root/.git_backup')

    # called when http://<host>:<port>/plugins/<plugin>/ is called
    # must return a html page
    # IMPORTANT: If you use "POST"s, add a csrf-token (via csrf_token() and render_template_string)
    def on_webhook(self, path, request):
        pass

    # called when the plugin is loaded
    def on_loaded(self):
        self.ready = True
        logging.info("GIT-BACKUP: Successfully loaded.")

    # called before the plugin is unloaded
    def on_unload(self, ui):
        pass

    # called hen there's internet connectivity
    def on_internet_available(self, agent):
        if not self.ready:
            return
        if self.tries >= 2:
            return

        if self.status.newer_then_days(self.options['interval']):
            return
        try:
            f = open("/home/pi/git_err.txt", "a+")
            display = agent.view()
            logging.info("GITBACKUP: Backing up ...")
            display.set('status', 'Backing up ...')
            display.update()
            logging.info(f"GIT-BACKUP: Running")
            process = subprocess.Popen([
                'sudo cp -r /root/brain.nn /root/brain.json /root/.api-report.json /root/handshakes/ /root/peers/ /etc/pwnagotchi/ /var/log/pwnagotchi.log /root/Pwnagotchi/ && cd /root/Pwnagotchi/ && sudo git pull && sudo  git add . && sudo  git commit -am "backup" && sudo git push'
            ],
                                       shell=True,
                                       stderr=f,
                                       stdin=f)
            process.wait()
            f.close()
            logging.info("GIT-BACKUP: backup done")
            display.set('status', 'GIT-Backup done!')
            display.update()
            self.status.update()
        except OSError as os_e:
            self.tries += 1
            logging.info(f"GIT-BACKUP: Error: {os_e}")
            display.set('status', 'Backup failed!')
            display.update()

    # called to setup the ui elements
    def on_ui_setup(self, ui):
        pass
        # called when the ui is updated
    def on_ui_update(self, ui):
        pass  # update those elements

    # called when the hardware display setup is done, display is an hardware specific object
    def on_display_setup(self, display):
        pass

    # called when everything is ready and the main loop is about to start
    def on_ready(self, agent):
        logging.info("unit is ready")
        # you can run custom bettercap commands if you want
        #   agent.run('ble.recon on')
        # or set a custom state
        #   agent.set_bored()

    # called when the AI finished loading
    def on_ai_ready(self, agent):
        pass

    # called when the AI finds a new set of parameters
    def on_ai_policy(self, agent, policy):
        pass

    # called when the AI starts training for a given number of epochs
    def on_ai_training_start(self, agent, epochs):
        pass

    # called after the AI completed a training epoch
    def on_ai_training_step(self, agent, _locals, _globals):
        pass

    # called when the AI has done training
    def on_ai_training_end(self, agent):
        pass

    # called when the AI got the best reward so far
    def on_ai_best_reward(self, agent, reward):
        pass

    # called when the AI got the worst reward so far
    def on_ai_worst_reward(self, agent, reward):
        pass

    # called when a non overlapping wifi channel is found to be free
    def on_free_channel(self, agent, channel):
        pass

    # called when the status is set to bored
    def on_bored(self, agent):
        pass

    # called when the status is set to sad
    def on_sad(self, agent):
        pass

    # called when the status is set to excited
    def on_excited(self, agent):
        pass

    # called when the status is set to lonely
    def on_lonely(self, agent):
        pass

    # called when the agent is rebooting the board
    def on_rebooting(self, agent):
        pass

    # called when the agent is waiting for t seconds
    def on_wait(self, agent, t):
        pass

    # called when the agent is sleeping for t seconds
    def on_sleep(self, agent, t):
        pass

    # called when the agent refreshed its access points list
    def on_wifi_update(self, agent, access_points):
        pass

    # called when the agent refreshed an unfiltered access point list
    # this list contains all access points that were detected BEFORE filtering
    def on_unfiltered_ap_list(self, agent, access_points):
        pass

    # called when the agent is sending an association frame
    def on_association(self, agent, access_point):
        pass

    # called when the agent is deauthenticating a client station from an AP
    def on_deauthentication(self, agent, access_point, client_station):
        pass

    # callend when the agent is tuning on a specific channel
    def on_channel_hop(self, agent, channel):
        pass

    # called when a new handshake is captured, access_point and client_station are json objects
    # if the agent could match the BSSIDs to the current list, otherwise they are just the strings of the BSSIDs
    def on_handshake(self, agent, filename, access_point, client_station):
        pass

    # called when an epoch is over (where an epoch is a single loop of the main algorithm)
    def on_epoch(self, agent, epoch, epoch_data):
        pass

    # called when a new peer is detected
    def on_peer_detected(self, agent, peer):
        pass

    # called when a known peer is lost
    def on_peer_lost(self, agent, peer):
        pass
Example #14
0
 def __init__(self):
     self.ready = False
     self.status = StatusFile('/root/.auto-update')
Example #15
0
class SessionStats(plugins.Plugin):
    __author__ = '*****@*****.**'
    __version__ = '0.1.0'
    __license__ = 'GPL3'
    __description__ = 'This plugin displays stats of the current session.'

    def __init__(self):
        self.lock = threading.Lock()
        self.options = dict()
        self.stats = dict()
        self.clock = GhettoClock()

    def on_loaded(self):
        """
        Gets called when the plugin gets loaded
        """
        # this has to happen in "loaded" because the options are not yet
        # available in the __init__
        os.makedirs(self.options['save_directory'], exist_ok=True)
        self.session_name = "stats_{}.json".format(
            self.clock.now().strftime("%Y_%m_%d_%H_%M"))
        self.session = StatusFile(os.path.join(self.options['save_directory'],
                                               self.session_name),
                                  data_format='json')
        logging.info("[session-stats] Plugin loaded.")

    def on_epoch(self, agent, epoch, epoch_data):
        """
        Save the epoch_data to self.stats
        """
        with self.lock:
            self.stats[self.clock.now().strftime("%H:%M:%S")] = epoch_data
            self.session.update(data={'data': self.stats})

    @staticmethod
    def extract_key_values(data, subkeys):
        result = dict()
        result['values'] = list()
        result['labels'] = subkeys
        for plot_key in subkeys:
            v = [[ts, d[plot_key]] for ts, d in data.items()]
            result['values'].append(v)
        return result

    def on_webhook(self, path, request):
        if not path or path == "/":
            return render_template_string(TEMPLATE)

        session_param = request.args.get('session')

        if path == "os":
            extract_keys = ['cpu_load', 'mem_usage']
        elif path == "temp":
            extract_keys = ['temperature']
        elif path == "wifi":
            extract_keys = [
                'missed_interactions',
                'num_hops',
                'num_peers',
                'tot_bond',
                'avg_bond',
                'num_deauths',
                'num_associations',
                'num_handshakes',
            ]
        elif path == "duration":
            extract_keys = [
                'duration_secs',
                'slept_for_secs',
            ]
        elif path == "reward":
            extract_keys = [
                'reward',
            ]
        elif path == "epoch":
            extract_keys = [
                'active_for_epochs',
            ]
        elif path == "session":
            return jsonify(
                {'files': os.listdir(self.options['save_directory'])})

        with self.lock:
            data = self.stats
            if session_param and session_param != 'Current':
                file_stats = StatusFile(os.path.join(
                    self.options['save_directory'], session_param),
                                        data_format='json')
                data = file_stats.data_field_or('data', default=dict())
            return jsonify(SessionStats.extract_key_values(data, extract_keys))
class AutoBackup(plugins.Plugin):
    __author__ = '*****@*****.**'
    __version__ = '2.0.0'
    __license__ = 'GPL3'
    __description__ = 'This plugin backups files when internet is available.'
    __defaults__ = {
        'enabled':
        False,
        'interval':
        1,
        'max_tries':
        0,
        'files': [
            '/root/brain.nn',
            '/root/brain.json',
            '/root/.api-report.json',
            '/root/handshakes/',
            '/etc/pwnagotchi/',
            '/var/log/pwnagotchi.log',
        ],
        'commands': ['tar czf /root/pwnagotchi-backup.tar.gz {files}'],
    }

    def __init__(self):
        self.ready = False
        self.tries = 0
        self.status = StatusFile('/root/.auto-backup')

    def on_loaded(self):
        for opt in ['files', 'interval', 'commands', 'max_tries']:
            if opt not in self.options or (opt in self.options
                                           and self.options[opt] is None):
                logging.error(f"[autobackup] Option {opt} is not set.")
                return

        self.ready = True
        logging.info('[autobackup] Successfully loaded.')

    def on_internet_available(self, agent):
        if not self.ready:
            return

        if self.options[
                'max_tries'] and self.tries >= self.options['max_tries']:
            return

        if self.status.newer_then_days(self.options['interval']):
            return

        # Only backup existing files to prevent errors
        existing_files = list(
            filter(lambda f: os.path.exists(f), self.options['files']))
        files_to_backup = " ".join(existing_files)

        try:
            display = agent.view()

            logging.info('[autobackup] Backing up ...')
            display.set('status', 'Backing up ...')
            display.update()

            for cmd in self.options['commands']:
                logging.info(
                    f"[autobackup] Running {cmd.format(files=files_to_backup)}"
                )
                process = subprocess.Popen(cmd.format(files=files_to_backup),
                                           shell=True,
                                           stdin=None,
                                           stdout=open("/dev/null", "w"),
                                           stderr=None,
                                           executable="/bin/bash")
                process.wait()
                if process.returncode > 0:
                    raise OSError(f"Command failed (rc: {process.returncode})")

            logging.info('[autobackup] backup done')
            display.set('status', 'Backup done!')
            display.update()
            self.status.update()
        except OSError as os_e:
            self.tries += 1
            logging.info(f"[autobackup] Error: {os_e}")
            display.set('status', 'Backup failed!')
            display.update()
Example #17
0
class WpaSec(plugins.Plugin):
    __author__ = '*****@*****.**'
    __version__ = '2.1.0'
    __license__ = 'GPL3'
    __description__ = 'This plugin automatically uploads handshakes to https://wpa-sec.stanev.org'

    def __init__(self):
        self.ready = False
        self.lock = Lock()
        try:
            self.report = StatusFile('/root/.wpa_sec_uploads',
                                     data_format='json')
        except JSONDecodeError:
            os.remove("/root/.wpa_sec_uploads")
            self.report = StatusFile('/root/.wpa_sec_uploads',
                                     data_format='json')
        self.options = dict()
        self.skip = list()

    def _upload_to_wpasec(self, path, timeout=30):
        """
        Uploads the file to https://wpa-sec.stanev.org, or another endpoint.
        """
        with open(path, 'rb') as file_to_upload:
            cookie = {'key': self.options['api_key']}
            payload = {'file': file_to_upload}

            try:
                result = requests.post(self.options['api_url'],
                                       cookies=cookie,
                                       files=payload,
                                       timeout=timeout)
                if ' already submitted' in result.text:
                    logging.debug("%s was already submitted.", path)
            except requests.exceptions.RequestException as req_e:
                raise req_e

    def _download_from_wpasec(self, output, timeout=30):
        """
        Downloads the results from wpasec and safes them to output

        Output-Format: bssid, station_mac, ssid, password
        """
        api_url = self.options['api_url']
        if not api_url.endswith('/'):
            api_url = f"{api_url}/"
        api_url = f"{api_url}?api&dl=1"

        cookie = {'key': self.options['api_key']}
        try:
            result = requests.get(api_url, cookies=cookie, timeout=timeout)
            with open(output, 'wb') as output_file:
                output_file.write(result.content)
        except requests.exceptions.RequestException as req_e:
            raise req_e
        except OSError as os_e:
            raise os_e

    def on_loaded(self):
        """
        Gets called when the plugin gets loaded
        """
        if 'api_key' not in self.options or ('api_key' in self.options
                                             and not self.options['api_key']):
            logging.error(
                "WPA_SEC: API-KEY isn't set. Can't upload to wpa-sec.stanev.org"
            )
            return

        if 'api_url' not in self.options or ('api_url' in self.options
                                             and not self.options['api_url']):
            logging.error(
                "WPA_SEC: API-URL isn't set. Can't upload, no endpoint configured."
            )
            return

        if 'whitelist' not in self.options:
            self.options['whitelist'] = list()

        self.ready = True

    def on_webhook(self, path, request):
        from flask import make_response, redirect
        response = make_response(redirect(self.options['api_url'], code=302))
        response.set_cookie('key', self.options['api_key'])
        return response

    def on_internet_available(self, agent):
        """
        Called in manual mode when there's internet connectivity
        """
        if not self.ready or self.lock.locked():
            return

        with self.lock:
            config = agent.config()
            display = agent.view()
            reported = self.report.data_field_or('reported', default=list())
            handshake_dir = config['bettercap']['handshakes']
            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 = remove_whitelisted(handshake_paths,
                                                 self.options['whitelist'])
            handshake_new = set(handshake_paths) - set(reported) - set(
                self.skip)

            if handshake_new:
                logging.info(
                    "WPA_SEC: Internet connectivity detected. Uploading new handshakes to wpa-sec.stanev.org"
                )
                for idx, handshake in enumerate(handshake_new):
                    display.set(
                        'status',
                        f"Uploading handshake to wpa-sec.stanev.org ({idx + 1}/{len(handshake_new)})"
                    )
                    display.update(force=True)
                    try:
                        self._upload_to_wpasec(handshake)
                        reported.append(handshake)
                        self.report.update(data={'reported': reported})
                        logging.debug("WPA_SEC: Successfully uploaded %s",
                                      handshake)
                    except requests.exceptions.RequestException as req_e:
                        self.skip.append(handshake)
                        logging.debug("WPA_SEC: %s", req_e)
                        continue
                    except OSError as os_e:
                        logging.debug("WPA_SEC: %s", os_e)
                        continue

            if 'download_results' in self.options and self.options[
                    'download_results']:
                cracked_file = os.path.join(handshake_dir,
                                            'wpa-sec.cracked.potfile')
                if os.path.exists(cracked_file):
                    last_check = datetime.fromtimestamp(
                        os.path.getmtime(cracked_file))
                    if last_check is not None and (
                        (datetime.now() - last_check).seconds / (60 * 60)) < 1:
                        return
                try:
                    self._download_from_wpasec(
                        os.path.join(handshake_dir, 'wpa-sec.cracked.potfile'))
                    logging.info("WPA_SEC: Downloaded cracked passwords.")
                except requests.exceptions.RequestException as req_e:
                    logging.debug("WPA_SEC: %s", req_e)
                except OSError as os_e:
                    logging.debug("WPA_SEC: %s", os_e)
Example #18
0
    def __init__(self):
        self.options = dict()
        self.report = StatusFile('/root/.api-report.json', data_format='json')

        self.unread_messages = 0
        self.total_messages = 0
Example #19
0
__author__ = '*****@*****.**'
__version__ = '1.0.0'
__name__ = 'wpa-sec'
__license__ = 'GPL3'
__description__ = 'This plugin automatically uploades handshakes to https://wpa-sec.stanev.org'

import os
import logging
import requests
from pwnagotchi.utils import StatusFile

READY = False
REPORT = StatusFile('/root/.wpa_sec_uploads', data_format='json')
OPTIONS = dict()
SKIP = list()


def on_loaded():
    """
    Gets called when the plugin gets loaded
    """
    global READY

    if 'api_key' not in OPTIONS or ('api_key' in OPTIONS
                                    and OPTIONS['api_key'] is None):
        logging.error(
            "WPA_SEC: API-KEY isn't set. Can't upload to wpa-sec.stanev.org")
        return

    READY = True
Example #20
0
class AutoBackup(plugins.Plugin):
    __author__ = '*****@*****.**'
    __version__ = '1.0.0'
    __license__ = 'GPL3'
    __description__ = 'This plugin backups files when internet is available.'

    def __init__(self):
        self.ready = False
        self.status = StatusFile('/root/.auto-backup')

    def on_loaded(self):
        if 'files' not in self.options or ('files' in self.options
                                           and self.options['files'] is None):
            logging.error("AUTO-BACKUP: No files to backup.")
            return

        if 'interval' not in self.options or (
                'interval' in self.options
                and self.options['interval'] is None):
            logging.error("AUTO-BACKUP: Interval is not set.")
            return

        if 'commands' not in self.options or (
                'commands' in self.options
                and self.options['commands'] is None):
            logging.error("AUTO-BACKUP: No commands given.")
            return

        self.ready = True
        logging.info("AUTO-BACKUP: Successfully loaded.")

    def on_internet_available(self, agent):
        if not self.ready:
            return

        if self.status.newer_then_days(self.options['interval']):
            return

        # Only backup existing files to prevent errors
        existing_files = list(
            filter(lambda f: os.path.exists(f), self.options['files']))
        files_to_backup = " ".join(existing_files)

        try:
            display = agent.view()

            logging.info("AUTO-BACKUP: Backing up ...")
            display.set('status', 'Backing up ...')
            display.update()

            for cmd in self.options['commands']:
                logging.info(
                    f"AUTO-BACKUP: Running {cmd.format(files=files_to_backup)}"
                )
                process = subprocess.Popen(cmd.format(files=files_to_backup),
                                           shell=True,
                                           stdin=None,
                                           stdout=open("/dev/null", "w"),
                                           stderr=None,
                                           executable="/bin/bash")
                process.wait()
                if process.returncode > 0:
                    raise OSError(f"Command failed (rc: {process.returncode})")

            logging.info("AUTO-BACKUP: backup done")
            display.set('status', 'Backup done!')
            display.update()
            self.status.update()
        except OSError as os_e:
            logging.info(f"AUTO-BACKUP: Error: {os_e}")
            display.set('status', 'Backup failed!')
            display.update()
Example #21
0
__author__ = '*****@*****.**'
__version__ = '1.0.0'
__name__ = 'auto-backup'
__license__ = 'GPL3'
__description__ = 'This plugin backups files when internet is availaible.'

from pwnagotchi.utils import StatusFile
import logging
import os
import subprocess

OPTIONS = dict()
READY = False
STATUS = StatusFile('/root/.auto-backup')


def on_loaded():
    global READY

    if 'files' not in OPTIONS or ('files' in OPTIONS
                                  and OPTIONS['files'] is None):
        logging.error("AUTO-BACKUP: No files to backup.")
        return

    if 'interval' not in OPTIONS or ('interval' in OPTIONS
                                     and OPTIONS['interval'] is None):
        logging.error("AUTO-BACKUP: Interval is not set.")
        return

    if 'commands' not in OPTIONS or ('commands' in OPTIONS
                                     and OPTIONS['commands'] is None):
class Wigle(plugins.Plugin):
    __author__ = '*****@*****.**'
    __version__ = '3.0.1'
    __license__ = 'GPL3'
    __description__ = 'This plugin automatically uploads collected wifis to wigle.net'
    __dependencies__ = {'pip': ['requests']}
    __defaults__ = {
        'enabled': False,
        'api_key': '',
        'whitelist': [],
    }

    def __init__(self):
        self.ready = False
        self.report = StatusFile('/root/.wigle_uploads', data_format='json')
        self.skip = list()
        self.lock = Lock()
        self.shutdown = False

    def on_config_changed(self, config):
        with self.lock:
            self.options['whitelist'] = list(
                set(self.options['whitelist'] + config['main']['whitelist']))

    def on_before_shutdown(self):
        self.shutdown = True

    def on_loaded(self):
        if not self.options['api_key']:
            logging.debug(
                "WIGLE: api_key isn't set. Can't upload to wigle.net")
            return

        if 'whitelist' not in self.options:
            self.options['whitelist'] = list()

        self.ready = True

    def on_internet_available(self, agent):
        """
        Called in manual mode when there's internet connectivity
        """
        if not self.ready or self.lock.locked() or self.shutdown:
            return

        from scapy.all import Scapy_Exception

        config = agent.config()
        display = agent.view()
        reported = self.report.data_field_or('reported', default=list())
        handshake_dir = config['bettercap']['handshakes']
        all_files = os.listdir(handshake_dir)
        all_gps_files = [
            os.path.join(handshake_dir, filename) for filename in all_files
            if filename.endswith('.gps.json')
        ]

        all_gps_files = remove_whitelisted(all_gps_files,
                                           self.options['whitelist'])
        new_gps_files = set(all_gps_files) - set(reported) - set(self.skip)
        if new_gps_files:
            logging.info(
                "WIGLE: Internet connectivity detected. Uploading new handshakes to wigle.net"
            )
            csv_entries = list()
            no_err_entries = list()
            for gps_file in new_gps_files:
                if self.shutdown:
                    return
                pcap_filename = gps_file.replace('.gps.json', '.pcap')
                if not os.path.exists(pcap_filename):
                    logging.debug("WIGLE: Can't find pcap for %s", gps_file)
                    self.skip.append(gps_file)
                    continue
                try:
                    gps_data = _extract_gps_data(gps_file)
                except OSError as os_err:
                    logging.debug("WIGLE: %s", os_err)
                    self.skip.append(gps_file)
                    continue
                except json.JSONDecodeError as json_err:
                    logging.debug("WIGLE: %s", json_err)
                    self.skip.append(gps_file)
                    continue
                if gps_data['Latitude'] == 0 and gps_data['Longitude'] == 0:
                    logging.debug(
                        "WIGLE: Not enough gps-information for %s. Trying again next time.",
                        gps_file)
                    self.skip.append(gps_file)
                    continue
                try:
                    pcap_data = extract_from_pcap(pcap_filename, [
                        WifiInfo.BSSID, WifiInfo.ESSID, WifiInfo.ENCRYPTION,
                        WifiInfo.CHANNEL, WifiInfo.RSSI
                    ])
                except FieldNotFoundError:
                    logging.debug(
                        "WIGLE: Could not extract all information. Skip %s",
                        gps_file)
                    self.skip.append(gps_file)
                    continue
                except Scapy_Exception as sc_e:
                    logging.debug("WIGLE: %s", sc_e)
                    self.skip.append(gps_file)
                    continue
                new_entry = _transform_wigle_entry(gps_data, pcap_data)
                csv_entries.append(new_entry)
                no_err_entries.append(gps_file)
            if csv_entries:
                display.set('status', "Uploading gps-data to wigle.net ...")
                display.update(force=True)
                try:
                    _send_to_wigle(csv_entries, self.options['api_key'])
                    reported += no_err_entries
                    self.report.update(data={'reported': reported})
                    logging.info("WIGLE: Successfully uploaded %d files",
                                 len(no_err_entries))
                except requests.exceptions.RequestException as re_e:
                    self.skip += no_err_entries
                    logging.debug("WIGLE: Got an exception while uploading %s",
                                  re_e)
                except OSError as os_e:
                    self.skip += no_err_entries
                    logging.debug("WIGLE: Got the following error: %s", os_e)
Example #23
0
class NetPos(plugins.Plugin):
    __author__ = 'zenzen san'
    __version__ = '2.0.3'
    __license__ = 'GPL3'
    __description__ = """Saves a json file with the access points with more signal
                         whenever a handshake is captured.
                         When internet is available the files are converted in geo locations
                         using Mozilla LocationService """

    API_URL = 'https://location.services.mozilla.com/v1/geolocate?key={api}'

    def __init__(self):
        self.report = StatusFile('/root/.net_pos_saved', data_format='json')
        self.skip = list()
        self.ready = False
        self.lock = threading.Lock()

    def on_loaded(self):
        if 'api_key' not in self.options or ('api_key' in self.options
                                             and not self.options['api_key']):
            logging.error(
                "NET-POS: api_key isn't set. Can't use mozilla's api.")
            return
        if 'api_url' in self.options:
            self.API_URL = self.options['api_url']
        self.ready = True
        logging.info("net-pos plugin loaded.")
        logging.debug(f"net-pos: use api_url: {self.API_URL}")

    def _append_saved(self, path):
        to_save = list()
        if isinstance(path, str):
            to_save.append(path)
        elif isinstance(path, list):
            to_save += path
        else:
            raise TypeError("Expected list or str, got %s" % type(path))

        with open('/root/.net_pos_saved', 'a') as saved_file:
            for x in to_save:
                saved_file.write(x + "\n")

    def on_internet_available(self, agent):
        with self.lock:
            if self.ready:
                config = agent.config()
                display = agent.view()
                reported = self.report.data_field_or('reported',
                                                     default=list())
                handshake_dir = config['bettercap']['handshakes']

                all_files = os.listdir(handshake_dir)
                all_np_files = [
                    os.path.join(handshake_dir, filename)
                    for filename in all_files
                    if filename.endswith('.net-pos.json')
                ]
                new_np_files = set(all_np_files) - set(reported) - set(
                    self.skip)

                if new_np_files:
                    logging.debug(
                        "NET-POS: Found %d new net-pos files. Fetching positions ...",
                        len(new_np_files))
                    display.set(
                        'status',
                        f"Found {len(new_np_files)} new net-pos files. Fetching positions ..."
                    )
                    display.update(force=True)
                    for idx, np_file in enumerate(new_np_files):

                        geo_file = np_file.replace('.net-pos.json',
                                                   '.geo.json')
                        if os.path.exists(geo_file):
                            # got already the position
                            reported.append(np_file)
                            self.report.update(data={'reported': reported})
                            continue

                        try:
                            geo_data = self._get_geo_data(
                                np_file)  # returns json obj
                        except requests.exceptions.RequestException as req_e:
                            logging.error("NET-POS: %s - RequestException: %s",
                                          np_file, req_e)
                            self.skip += np_file
                            continue
                        except json.JSONDecodeError as js_e:
                            logging.error(
                                "NET-POS: %s - JSONDecodeError: %s, removing it...",
                                np_file, js_e)
                            os.remove(np_file)
                            continue
                        except OSError as os_e:
                            logging.error("NET-POS: %s - OSError: %s", np_file,
                                          os_e)
                            self.skip += np_file
                            continue

                        with open(geo_file, 'w+t') as sf:
                            json.dump(geo_data, sf)

                        reported.append(np_file)
                        self.report.update(data={'reported': reported})

                        display.set(
                            'status',
                            f"Fetching positions ({idx + 1}/{len(new_np_files)})"
                        )
                        display.update(force=True)

    def on_handshake(self, agent, filename, access_point, client_station):
        netpos = self._get_netpos(agent)
        if not netpos['wifiAccessPoints']:
            return

        netpos["ts"] = int("%.0f" % time.time())
        netpos_filename = filename.replace('.pcap', '.net-pos.json')
        logging.debug("NET-POS: Saving net-location to %s", netpos_filename)

        try:
            with open(netpos_filename, 'w+t') as net_pos_file:
                json.dump(netpos, net_pos_file)
        except OSError as os_e:
            logging.error("NET-POS: %s", os_e)

    def _get_netpos(self, agent):
        aps = agent.get_access_points()
        netpos = dict()
        netpos['wifiAccessPoints'] = list()
        # 6 seems a good number to save a wifi networks location
        for access_point in sorted(aps, key=lambda i: i['rssi'],
                                   reverse=True)[:6]:
            netpos['wifiAccessPoints'].append({
                'macAddress':
                access_point['mac'],
                'signalStrength':
                access_point['rssi']
            })
        return netpos

    def _get_geo_data(self, path, timeout=30):
        geourl = self.API_URL.format(api=self.options['api_key'])

        try:
            with open(path, "r") as json_file:
                data = json.load(json_file)
        except json.JSONDecodeError as js_e:
            raise js_e
        except OSError as os_e:
            raise os_e

        try:
            result = requests.post(geourl, json=data, timeout=timeout)
            return_geo = result.json()
            if data["ts"]:
                return_geo["ts"] = data["ts"]
            return return_geo
        except requests.exceptions.RequestException as req_e:
            raise req_e
Example #24
0
__license__ = 'GPL3'
__description__ = 'This makes the display reachable over bluetooth'

import os
import time
import re
import logging
import subprocess
import dbus
from pwnagotchi.ui.components import LabeledValue
from pwnagotchi.ui.view import BLACK
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.utils import StatusFile

READY = False
INTERVAL = StatusFile('/root/.bt-tether')
OPTIONS = dict()


class BTError(Exception):
    """
    Custom bluetooth exception
    """
    pass


class BTNap:
    """
    This class creates a bluetooth connection to the specified bt-mac

    see https://github.com/bablokb/pi-btnap/blob/master/files/usr/local/sbin/btnap.service.py
Example #25
0
 def __init__(self):
     self.report = StatusFile('/root/.net_pos_saved', data_format='json')
     self.skip = list()
     self.ready = False
     self.lock = threading.Lock()
Example #26
0
import os
import logging
import subprocess
import requests
import platform
import shutil
import glob
import pkg_resources

import pwnagotchi
from pwnagotchi.utils import StatusFile

OPTIONS = dict()
READY = False
STATUS = StatusFile('/root/.auto-update')


def on_loaded():
    global READY
    if 'interval' not in OPTIONS or ('interval' in OPTIONS
                                     and OPTIONS['interval'] is None):
        logging.error("[update] main.plugins.auto-update.interval is not set")
        return
    READY = True
    logging.info("[update] plugin loaded.")


def check(version, repo, native=True):
    logging.debug("checking remote version for %s, local is %s" %
                  (repo, version))
Example #27
0
__name__ = 'grid'
__license__ = 'GPL3'
__description__ = 'This plugin signals the unit cryptographic identity and list of pwned networks and list of pwned ' \
                  'networks to api.pwnagotchi.ai '

import os
import logging
import time
import glob
import re

import pwnagotchi.grid as grid
from pwnagotchi.utils import StatusFile, WifiInfo, extract_from_pcap

OPTIONS = dict()
REPORT = StatusFile('/root/.api-report.json', data_format='json')

UNREAD_MESSAGES = 0
TOTAL_MESSAGES = 0


def on_loaded():
    logging.info("grid plugin loaded.")


def parse_pcap(filename):
    logging.info("grid: parsing %s ..." % filename)

    net_id = os.path.basename(filename).replace('.pcap', '')

    if '_' in net_id: