diff --git a/builder/pwnagotchi.yml b/builder/pwnagotchi.yml index f47f285..f212a8f 100644 --- a/builder/pwnagotchi.yml +++ b/builder/pwnagotchi.yml @@ -34,7 +34,7 @@ url: "https://github.com/bettercap/bettercap/releases/download/v2.25/bettercap_linux_armv6l_2.25.zip" ui: "https://github.com/bettercap/ui/releases/download/v1.3.0/ui.zip" pwngrid: - url: "https://github.com/evilsocket/pwngrid/releases/download/v1.5.3/pwngrid_linux_armv6l_v1.5.3.zip" + url: "https://github.com/evilsocket/pwngrid/releases/download/v1.5.4/pwngrid_linux_armv6l_v1.5.4.zip" apt: hold: - firmware-atheros @@ -502,7 +502,7 @@ [Service] Type=simple PermissionsStartOnly=true - ExecStart=/usr/bin/pwngrid -keys /etc/pwnagotchi -address 127.0.0.1:8666 -wait + ExecStart=/usr/bin/pwngrid -keys /etc/pwnagotchi -address 127.0.0.1:8666 -wait -log /var/log/pwngrid-peer.log Restart=always RestartSec=30 diff --git a/pwnagotchi/plugins/default/grid.py b/pwnagotchi/plugins/default/grid.py index e77e8d6..96d290a 100644 --- a/pwnagotchi/plugins/default/grid.py +++ b/pwnagotchi/plugins/default/grid.py @@ -15,7 +15,6 @@ import pwnagotchi.utils as utils from pwnagotchi.utils import WifiInfo, extract_from_pcap OPTIONS = dict() -AUTH = utils.StatusFile('/root/.api-enrollment.json', data_format='json') REPORT = utils.StatusFile('/root/.api-report.json', data_format='json') @@ -23,61 +22,6 @@ def on_loaded(): logging.info("grid plugin loaded.") -def get_api_token(last_session, keys): - global AUTH - - if AUTH.newer_then_minutes(25) and AUTH.data is not None and 'token' in AUTH.data: - return AUTH.data['token'] - - if AUTH.data is None: - logging.info("grid: enrolling unit ...") - else: - logging.info("grid: refreshing token ...") - - identity = "%s@%s" % (pwnagotchi.name(), keys.fingerprint) - # sign the identity string to prove we own both keys - _, signature_b64 = keys.sign(identity) - - brain = {} - try: - with open('/root/brain.json') as fp: - brain = json.load(fp) - except: - pass - - api_address = 'https://api.pwnagotchi.ai/api/v1/unit/enroll' - enrollment = { - 'identity': identity, - 'public_key': keys.pub_key_pem_b64, - 'signature': signature_b64, - 'data': { - 'duration': last_session.duration, - 'epochs': last_session.epochs, - 'train_epochs': last_session.train_epochs, - 'avg_reward': last_session.avg_reward, - 'min_reward': last_session.min_reward, - 'max_reward': last_session.max_reward, - 'deauthed': last_session.deauthed, - 'associated': last_session.associated, - 'handshakes': last_session.handshakes, - 'peers': last_session.peers, - 'uname': subprocess.getoutput("uname -a"), - 'brain': brain, - 'version': pwnagotchi.version - } - } - - r = requests.post(api_address, json=enrollment) - if r.status_code != 200: - raise Exception("(status %d) %s" % (r.status_code, r.json())) - - AUTH.update(data=r.json()) - - logging.info("grid: done") - - return AUTH.data["token"] - - def parse_pcap(filename): logging.info("grid: parsing %s ..." % filename) @@ -106,32 +50,6 @@ def parse_pcap(filename): return info[WifiInfo.ESSID], info[WifiInfo.BSSID] -def api_report_ap(last_session, keys, token, essid, bssid): - while True: - token = AUTH.data['token'] - logging.info("grid: reporting %s (%s)" % (essid, bssid)) - try: - api_address = 'https://api.pwnagotchi.ai/api/v1/unit/report/ap' - headers = {'Authorization': 'access_token %s' % token} - report = { - 'essid': essid, - 'bssid': bssid, - } - r = requests.post(api_address, headers=headers, json=report) - if r.status_code != 200: - if r.status_code == 401: - logging.warning("token expired") - token = get_api_token(last_session, keys) - continue - else: - raise Exception("(status %d) %s" % (r.status_code, r.text)) - else: - return True - except Exception as e: - logging.error("grid: %s" % e) - return False - - def is_excluded(what): for skip in OPTIONS['exclude']: skip = skip.lower() @@ -141,24 +59,76 @@ def is_excluded(what): return False +def grid_call(path, obj): + # pwngrid-peer is running on port 8666 + api_address = 'http://127.0.0.1:8666/api/v1%s' % path + r = requests.post(api_address, headers=None, json=obj) + if r.status_code != 200: + raise Exception("(status %d) %s" % (r.status_code, r.text)) + + +def grid_update_data(last_session): + brain = {} + try: + with open('/root/brain.json') as fp: + brain = json.load(fp) + except: + pass + + data = { + 'duration': last_session.duration, + 'epochs': last_session.epochs, + 'train_epochs': last_session.train_epochs, + 'avg_reward': last_session.avg_reward, + 'min_reward': last_session.min_reward, + 'max_reward': last_session.max_reward, + 'deauthed': last_session.deauthed, + 'associated': last_session.associated, + 'handshakes': last_session.handshakes, + 'peers': last_session.peers, + 'uname': subprocess.getoutput("uname -a"), + 'brain': brain, + 'version': pwnagotchi.version + } + + logging.debug("updating grid data:\n%s" % data) + + grid_call("/data", data) + + +def grid_report_ap(essid, bssid): + try: + grid_call("/report/ap", { + 'essid': essid, + 'bssid': bssid, + }) + return True + except Exception as e: + logging.exception("error while reporting ap %s(%s)" % (essid, bssid)) + + return False + + def on_internet_available(agent): global REPORT + logging.debug("internet available") + try: - logging.debug("internet available") - - config = agent.config() - keys = agent.keypair() + grid_update_data(agent.last_session) + except Exception as e: + logging.error("error connecting to the pwngrid-peer service: %s" % e) + return + try: logging.debug("checking pcaps") - pcap_files = glob.glob(os.path.join(config['bettercap']['handshakes'], "*.pcap")) + pcap_files = glob.glob(os.path.join(agent.config()['bettercap']['handshakes'], "*.pcap")) num_networks = len(pcap_files) reported = REPORT.data_field_or('reported', default=[]) num_reported = len(reported) num_new = num_networks - num_reported - token = get_api_token(agent.last_session, agent.keypair()) if num_new > 0: if OPTIONS['report']: logging.info("grid: %d new networks to report" % num_new) @@ -177,11 +147,13 @@ def on_internet_available(agent): if is_excluded(essid) or is_excluded(bssid): logging.debug("not reporting %s due to exclusion filter" % pcap_file) - elif api_report_ap(agent.last_session, keys, token, essid, bssid): - reported.append(net_id) - REPORT.update(data={'reported': reported}) + elif grid_report_ap(essid, bssid): + reported.append(net_id) + REPORT.update(data={'reported': reported}) + else: + logging.warning("no bssid found?!") else: logging.debug("grid: reporting disabled") except Exception as e: - logging.exception("error while enrolling the unit") + logging.exception("grid api error")