From b47f3c6b285f4c26ce6e152de9b521c52a42533f Mon Sep 17 00:00:00 2001 From: Simone Margaritelli Date: Sat, 12 Oct 2019 22:01:52 +0200 Subject: [PATCH 01/19] fix: fixed restored status after rsa keys generation --- pwnagotchi/identity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pwnagotchi/identity.py b/pwnagotchi/identity.py index 7ea7652..9be375b 100644 --- a/pwnagotchi/identity.py +++ b/pwnagotchi/identity.py @@ -47,7 +47,7 @@ class KeyPair(object): self.fingerprint = hashlib.sha256(pem_ascii).hexdigest() # no exception, keys loaded correctly. - self._view.on_normal() + self._view.on_starting() return except Exception as e: From 99d70177859c4b869ae96eb88811c52eb5f0a4c1 Mon Sep 17 00:00:00 2001 From: Simone Margaritelli Date: Sun, 13 Oct 2019 00:07:50 +0200 Subject: [PATCH 02/19] releasing v1.0.0RC3 --- pwnagotchi/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pwnagotchi/__init__.py b/pwnagotchi/__init__.py index a1b6a32..11fa0d8 100644 --- a/pwnagotchi/__init__.py +++ b/pwnagotchi/__init__.py @@ -4,7 +4,7 @@ import logging import time import pwnagotchi.ui.view as view -version = '1.0.0RC2' +version = '1.0.0RC3' _name = None From 77c16c38f4415914be961cbd473d47a8681f8de1 Mon Sep 17 00:00:00 2001 From: Simone Margaritelli Date: Sun, 13 Oct 2019 12:18:35 +0200 Subject: [PATCH 03/19] fix: using /proc/uptime to correctly calculate uptime in seconds (fixes #264) --- pwnagotchi/__init__.py | 5 +++++ pwnagotchi/agent.py | 12 +++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/pwnagotchi/__init__.py b/pwnagotchi/__init__.py index 11fa0d8..a26d337 100644 --- a/pwnagotchi/__init__.py +++ b/pwnagotchi/__init__.py @@ -17,6 +17,11 @@ def name(): return _name +def uptime(): + with open('/proc/uptime') as fp: + return int(fp.read().split('.')[0]) + + def mem_usage(): out = subprocess.getoutput("free -m") for line in out.split("\n"): diff --git a/pwnagotchi/agent.py b/pwnagotchi/agent.py index dd1e257..b5c876f 100644 --- a/pwnagotchi/agent.py +++ b/pwnagotchi/agent.py @@ -7,6 +7,7 @@ from datetime import datetime import logging import _thread +import pwnagotchi import pwnagotchi.utils as utils import pwnagotchi.plugins as plugins from pwnagotchi.log import LastSession @@ -241,9 +242,9 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer): return None def _update_uptime(self, s): - secs = time.time() - self._started_at + secs = pwnagotchi.uptime() self._view.set('uptime', utils.secs_to_hhmmss(secs)) - self._view.set('epoch', '%04d' % self._epoch.epoch) + # self._view.set('epoch', '%04d' % self._epoch.epoch) def _update_counters(self): tot_aps = len(self._access_points) @@ -276,13 +277,10 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer): def _update_advertisement(self, s): run_handshakes = len(self._handshakes) tot_handshakes = utils.total_unique_handshakes(self._config['bettercap']['handshakes']) - started = s['started_at'].split('.')[0] - started = datetime.strptime(started, '%Y-%m-%dT%H:%M:%S') - started = time.mktime(started.timetuple()) - self._advertiser.update({ \ + self._advertiser.update({ 'pwnd_run': run_handshakes, 'pwnd_tot': tot_handshakes, - 'uptime': time.time() - started, + 'uptime': pwnagotchi.uptime(), 'epoch': self._epoch.epoch}) def _update_peers(self): From e08b633c8891510a40e869dab9b6f8075906fc28 Mon Sep 17 00:00:00 2001 From: dadav <33197631+dadav@users.noreply.github.com> Date: Sun, 13 Oct 2019 13:14:22 +0200 Subject: [PATCH 04/19] add bluetooth plugin --- pwnagotchi/defaults.yml | 5 + pwnagotchi/plugins/default/bt-tether.py | 408 ++++++++++++++++++++++++ 2 files changed, 413 insertions(+) create mode 100644 pwnagotchi/plugins/default/bt-tether.py diff --git a/pwnagotchi/defaults.yml b/pwnagotchi/defaults.yml index a9e4c82..b529160 100644 --- a/pwnagotchi/defaults.yml +++ b/pwnagotchi/defaults.yml @@ -66,6 +66,11 @@ main: wordlist_folder: /opt/wordlists/ AircrackOnly: enabled: false + bt-tether: + enabled: false # if you want to use this, set ui.display.video.address to 0.0.0.0 + mac: ~ # mac of your bluetooth device + ip: '192.168.44.44' # ip from which your pwnagotchi should be reachable + netmask: 24 # monitor interface to use iface: mon0 # command to run to bring the mon interface up in case it's not up already diff --git a/pwnagotchi/plugins/default/bt-tether.py b/pwnagotchi/plugins/default/bt-tether.py new file mode 100644 index 0000000..0305ba9 --- /dev/null +++ b/pwnagotchi/plugins/default/bt-tether.py @@ -0,0 +1,408 @@ +__author__ = '33197631+dadav@users.noreply.github.com' +__version__ = '1.0.0' +__name__ = 'bt-tether' +__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 + """ + + IFACE_BASE = 'org.bluez' + IFACE_DEV = 'org.bluez.Device1' + IFACE_ADAPTER = 'org.bluez.Adapter1' + IFACE_PROPS = 'org.freedesktop.DBus.Properties' + + def __init__(self, mac): + self._mac = mac + + + @staticmethod + def get_bus(): + """ + Get systembus obj + """ + bus = getattr(BTNap.get_bus, 'cached_obj', None) + if not bus: + bus = BTNap.get_bus.cached_obj = dbus.SystemBus() + return bus + + @staticmethod + def get_manager(): + """ + Get manager obj + """ + manager = getattr(BTNap.get_manager, 'cached_obj', None) + if not manager: + manager = BTNap.get_manager.cached_obj = dbus.Interface( + BTNap.get_bus().get_object(BTNap.IFACE_BASE, '/'), + 'org.freedesktop.DBus.ObjectManager' ) + return manager + + @staticmethod + def prop_get(obj, k, iface=None): + """ + Get a property of the obj + """ + if iface is None: + iface = obj.dbus_interface + return obj.Get(iface, k, dbus_interface=BTNap.IFACE_PROPS) + + @staticmethod + def prop_set(obj, k, v, iface=None): + """ + Set a property of the obj + """ + if iface is None: + iface = obj.dbus_interface + return obj.Set(iface, k, v, dbus_interface=BTNap.IFACE_PROPS) + + + @staticmethod + def find_adapter(pattern=None): + """ + Find the bt adapter + """ + + return BTNap.find_adapter_in_objects(BTNap.get_manager().GetManagedObjects(), pattern) + + @staticmethod + def find_adapter_in_objects(objects, pattern=None): + """ + Finds the obj with a pattern + """ + bus, obj = BTNap.get_bus(), None + for path, ifaces in objects.items(): + adapter = ifaces.get(BTNap.IFACE_ADAPTER) + if adapter is None: + continue + if not pattern or pattern == adapter['Address'] or path.endswith(pattern): + obj = bus.get_object(BTNap.IFACE_BASE, path) + yield dbus.Interface(obj, BTNap.IFACE_ADAPTER) + if obj is None: + raise BTError('Bluetooth adapter not found') + + @staticmethod + def find_device(device_address, adapter_pattern=None): + """ + Finds the device + """ + return BTNap.find_device_in_objects(BTNap.get_manager().GetManagedObjects(), + device_address, adapter_pattern) + + @staticmethod + def find_device_in_objects(objects, device_address, adapter_pattern=None): + """ + Finds the device in objects + """ + bus = BTNap.get_bus() + path_prefix = '' + if adapter_pattern: + if not isinstance(adapter_pattern, str): + adapter = adapter_pattern + else: + adapter = BTNap.find_adapter_in_objects(objects, adapter_pattern) + path_prefix = adapter.object_path + for path, ifaces in objects.items(): + device = ifaces.get(BTNap.IFACE_DEV) + if device is None: + continue + if device['Address'] == device_address and path.startswith(path_prefix): + obj = bus.get_object(BTNap.IFACE_BASE, path) + return dbus.Interface(obj, BTNap.IFACE_DEV) + raise BTError('Bluetooth device not found') + + def power(self, on=True): + """ + Set power of devices to on/off + """ + + devs = list(BTNap.find_adapter()) + devs = dict((BTNap.prop_get(dev, 'Address'), dev) for dev in devs) + + for dev_addr, dev in devs.items(): + BTNap.prop_set(dev, 'Powered', on) + logging.debug('Set power of %s (addr %s) to %s', dev.object_path, dev_addr, str(on)) + + if devs: + return list(devs.values())[0] + + return None + + def wait_for_device(self, timeout=30): + """ + Wait for device + + returns device if found None if not + """ + bt_dev = self.power(True) + + if not bt_dev: + return None + + # could be set to 0, so check if > -1 + while timeout > -1: + try: + dev_remote = BTNap.find_device(self._mac, bt_dev) + logging.debug('Using remote device (addr: %s): %s', + BTNap.prop_get(dev_remote, 'Address'), dev_remote.object_path ) + return dev_remote + except BTError: + pass + + time.sleep(1) + timeout -= 1 + + # Device not found :( + return None + + + def connect(self, reconnect=False): + """ + Connect to device + + return True if connected; False if failed + """ + + # power up devices + bt_dev = self.power(True) + if not bt_dev: + return False + + # check if device is close + dev_remote = self.wait_for_device() + + if not dev_remote: + return False + + #wait_iter = lambda: time.sleep(3600) + # signal.signal(signal.SIGTERM, lambda sig,frm: sys.exit(0)) + + try: + dev_remote.ConnectProfile('nap') + except Exception: + pass + + net = dbus.Interface(dev_remote, 'org.bluez.Network1') + + try: + net.Connect('nap') + except dbus.exceptions.DBusException as err: + if err.get_dbus_name() != 'org.bluez.Error.Failed': + raise + + connected = BTNap.prop_get(net, 'Connected') + + if not connected: + return False + + if reconnect: + net.Disconnect() + return self.connect(reconnect=False) + + return True + + +################################################# +################################################# +################################################# + +class SystemdUnitWrapper: + """ + systemd wrapper + """ + + def __init__(self, unit): + self.unit = unit + + @staticmethod + def _action_on_unit(action, unit): + process = subprocess.Popen(f"systemctl {action} {unit}", shell=True, stdin=None, + stdout=open("/dev/null", "w"), stderr=None, executable="/bin/bash") + process.wait() + if process.returncode > 0: + return False + return True + + @staticmethod + def daemon_reload(): + """ + Calls systemctl daemon-reload + """ + process = subprocess.Popen("systemctl daemon-reload", shell=True, stdin=None, + stdout=open("/dev/null", "w"), stderr=None, executable="/bin/bash") + process.wait() + if process.returncode > 0: + return False + return True + + def is_active(self): + """ + Checks if unit is active + """ + return SystemdUnitWrapper._action_on_unit('is-active', self.unit) + + def is_enabled(self): + """ + Checks if unit is enabled + """ + return SystemdUnitWrapper._action_on_unit('is-enabled', self.unit) + + def is_failed(self): + """ + Checks if unit is failed + """ + return SystemdUnitWrapper._action_on_unit('is-failed', self.unit) + + def enable(self): + """ + Enables the unit + """ + return SystemdUnitWrapper._action_on_unit('enable', self.unit) + + def disable(self): + """ + Disables the unit + """ + return SystemdUnitWrapper._action_on_unit('disable', self.unit) + + def start(self): + """ + Starts the unit + """ + return SystemdUnitWrapper._action_on_unit('start', self.unit) + + def stop(self): + """ + Stops the unit + """ + return SystemdUnitWrapper._action_on_unit('stop', self.unit) + + def restart(self): + """ + Restarts the unit + """ + return SystemdUnitWrapper._action_on_unit('restart', self.unit) + + +class IfaceWrapper: + """ + Small wrapper to check and manage ifaces + + see: https://github.com/rlisagor/pynetlinux/blob/master/pynetlinux/ifconfig.py + """ + + def __init__(self, iface): + self.iface = iface + self.path = f"/sys/class/net/{iface}" + + def exists(self): + """ + Checks if iface exists + """ + return os.path.exists(self.path) + + def is_up(self): + """ + Checks if iface is ip + """ + return open(f"{self.path}/operstate", 'r').read().rsplit('\n') == 'up' + + + def set_addr(self, addr): + """ + Set the netmask + """ + process = subprocess.Popen(f"ip addr add {addr} dev {self.iface}", shell=True, stdin=None, + stdout=open("/dev/null", "w"), stderr=None, executable="/bin/bash") + process.wait() + + if process.returncode == 2 or process.returncode == 0: # 2 = already set + return True + + return False + + +def on_loaded(): + """ + Gets called when the plugin gets loaded + """ + global READY + global INTERVAL + + for opt in ['mac', 'ip', 'netmask', 'interval']: + if opt not in OPTIONS or (opt in OPTIONS and OPTIONS[opt] is None): + logging.error("BT-TET: Pleace specify the %s in your config.yml.", opt) + return + + # ensure bluetooth is running + bt_unit = SystemdUnitWrapper('bluetooth.service') + if not bt_unit.is_active(): + if not bt_unit.start(): + logging.error("BT-TET: Can't start bluetooth.service") + return + + INTERVAL.update() + READY = True + + +def on_ui_update(ui): + """ + Try to connect to device + """ + + if READY: + global INTERVAL + if INTERVAL.newer_then_minutes(OPTIONS['interval']): + return + + INTERVAL.update() + + bt = BTNap(OPTIONS['mac']) + if bt.connect(): + btnap_iface = IfaceWrapper('bnep0') + + if btnap_iface.exists(): + # check ip + addr = f"{OPTIONS['ip']}/{OPTIONS['netmask']}" + + if not btnap_iface.set_addr(addr): + ui.set('bluetooth', 'ERR1') + logging.error("Could not set ip of bnep0 to %s", addr) + return + + ui.set('bluetooth', 'CON') + else: + ui.set('bluetooth', 'ERR2') + else: + ui.set('bluetooth', 'NF') + + +def on_ui_setup(ui): + ui.add_element('bluetooth', LabeledValue(color=BLACK, label='BT', value='-', position=(ui.width() / 2 - 30, 0), + label_font=fonts.Bold, text_font=fonts.Medium)) From 1691896531401fc66c46d0fa19d4b63b3df0bb81 Mon Sep 17 00:00:00 2001 From: dadav <33197631+dadav@users.noreply.github.com> Date: Sun, 13 Oct 2019 13:23:38 +0200 Subject: [PATCH 05/19] add config param --- pwnagotchi/defaults.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/pwnagotchi/defaults.yml b/pwnagotchi/defaults.yml index b529160..65bb5c6 100644 --- a/pwnagotchi/defaults.yml +++ b/pwnagotchi/defaults.yml @@ -71,6 +71,7 @@ main: mac: ~ # mac of your bluetooth device ip: '192.168.44.44' # ip from which your pwnagotchi should be reachable netmask: 24 + interval: 1 # check every x minutes for device # monitor interface to use iface: mon0 # command to run to bring the mon interface up in case it's not up already From 5d2855760859030b2cd36b27e42a36f2b95877f0 Mon Sep 17 00:00:00 2001 From: Simone Margaritelli Date: Sun, 13 Oct 2019 17:24:47 +0200 Subject: [PATCH 06/19] new: using pwngrid for mesh advertising (we got rid of scapy loading times) --- bin/pwnagotchi | 6 +- builder/pwnagotchi.yml | 6 +- pwnagotchi/agent.py | 32 +----- pwnagotchi/grid.py | 97 ++++++++++++++++ pwnagotchi/mesh/__init__.py | 4 - pwnagotchi/mesh/advertise.py | 176 ----------------------------- pwnagotchi/mesh/peer.py | 30 +++-- pwnagotchi/mesh/utils.py | 96 +++++++++++----- pwnagotchi/mesh/wifi.py | 37 ------ pwnagotchi/plugins/default/grid.py | 79 ++----------- 10 files changed, 197 insertions(+), 366 deletions(-) create mode 100644 pwnagotchi/grid.py delete mode 100644 pwnagotchi/mesh/advertise.py delete mode 100644 pwnagotchi/mesh/wifi.py diff --git a/bin/pwnagotchi b/bin/pwnagotchi index 297bce6..a7d3c97 100755 --- a/bin/pwnagotchi +++ b/bin/pwnagotchi @@ -2,10 +2,10 @@ if __name__ == '__main__': import argparse import time - import os import logging import pwnagotchi + import pwnagtochi.grid as grid import pwnagotchi.utils as utils import pwnagotchi.plugins as plugins @@ -64,7 +64,7 @@ if __name__ == '__main__': display.on_manual_mode(agent.last_session) time.sleep(1) - if Agent.is_connected(): + if grid.is_connected(): plugins.on('internet_available', agent) else: @@ -102,7 +102,7 @@ if __name__ == '__main__': # affect ours ... neat ^_^ agent.next_epoch() - if Agent.is_connected(): + if grid.is_connected(): plugins.on('internet_available', agent) except Exception as e: diff --git a/builder/pwnagotchi.yml b/builder/pwnagotchi.yml index 219948e..8079d60 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.6.3/pwngrid_linux_armv6l_v1.6.3.zip" + url: "https://github.com/evilsocket/pwngrid/releases/download/v1.7.1/pwngrid_linux_armv6l_1.7.1.zip" apt: hold: - firmware-atheros @@ -497,12 +497,12 @@ Description=pwngrid peer service. Documentation=https://pwnagotchi.ai Wants=network.target - After=network.target + After=bettercap.service [Service] Type=simple PermissionsStartOnly=true - ExecStart=/usr/bin/pwngrid -keys /etc/pwnagotchi -address 127.0.0.1:8666 -wait -log /var/log/pwngrid-peer.log + ExecStart=/usr/bin/pwngrid -keys /etc/pwnagotchi -address 127.0.0.1:8666 -wait -log /var/log/pwngrid-peer.log -iface mon0 Restart=always RestartSec=30 diff --git a/pwnagotchi/agent.py b/pwnagotchi/agent.py index b5c876f..41680df 100644 --- a/pwnagotchi/agent.py +++ b/pwnagotchi/agent.py @@ -2,8 +2,6 @@ import time import json import os import re -import socket -from datetime import datetime import logging import _thread @@ -42,15 +40,6 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer): if not os.path.exists(config['bettercap']['handshakes']): os.makedirs(config['bettercap']['handshakes']) - @staticmethod - def is_connected(): - try: - socket.create_connection(("www.google.com", 80)) - return True - except OSError: - pass - return False - def config(self): return self._config @@ -193,7 +182,7 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer): def set_access_points(self, aps): self._access_points = aps plugins.on('wifi_update', self, aps) - self._epoch.observe(aps, self._advertiser.peers() if self._advertiser is not None else ()) + self._epoch.observe(aps, list(self._peers.values())) return self._access_points def get_access_points(self): @@ -274,19 +263,8 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer): if new_shakes > 0: self._view.on_handshakes(new_shakes) - def _update_advertisement(self, s): - run_handshakes = len(self._handshakes) - tot_handshakes = utils.total_unique_handshakes(self._config['bettercap']['handshakes']) - self._advertiser.update({ - 'pwnd_run': run_handshakes, - 'pwnd_tot': tot_handshakes, - 'uptime': pwnagotchi.uptime(), - 'epoch': self._epoch.epoch}) - def _update_peers(self): - peer = self._advertiser.closest_peer() - tot = self._advertiser.num_peers() - self._view.set_closest_peer(peer, tot) + self._view.set_closest_peer(self._closest_peer, len(self._peers)) def _save_recovery_data(self): logging.warning("writing recovery data to %s ..." % RECOVERY_DATA_FILE) @@ -331,10 +309,8 @@ class Agent(Client, AsyncAdvertiser, AsyncTrainer): s = self.session() self._update_uptime(s) - if self._advertiser is not None: - self._update_advertisement(s) - self._update_peers() - + self._update_advertisement(s) + self._update_peers() self._update_counters() try: diff --git a/pwnagotchi/grid.py b/pwnagotchi/grid.py new file mode 100644 index 0000000..93bc08a --- /dev/null +++ b/pwnagotchi/grid.py @@ -0,0 +1,97 @@ +import subprocess +import socket +import requests +import json +import logging + +import pwnagotchi + +# pwngrid-peer is running on port 8666 +API_ADDRESS = "http://127.0.0.1:8666/api/v1" + + +def is_connected(): + try: + socket.create_connection(("www.google.com", 80)) + return True + except OSError: + pass + return False + + +def call(path, obj=None): + url = '%s%s' % (API_ADDRESS, path) + if obj is None: + r = requests.get(url, headers=None) + else: + r = requests.post(url, headers=None, json=obj) + + if r.status_code != 200: + raise Exception("(status %d) %s" % (r.status_code, r.text)) + return r.json() + + +def advertise(enabled=True): + return call("/mesh/%s" % 'true' if enabled else 'false') + + +def set_advertisement_data(data): + return call("/mesh/data", obj=data) + + +def peers(): + return call("/mesh/peers") + + +def closest_peer(): + all = peers() + return all[0] if len(all) else None + + +def update_data(last_session): + brain = {} + try: + with open('/root/brain.json') as fp: + brain = json.load(fp) + except: + pass + + data = { + 'session': { + '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: %s" % data) + + call("/data", data) + + +def report_ap(essid, bssid): + try: + 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 inbox(page=1, with_pager=False): + obj = call("/inbox?p=%d" % page) + return obj["messages"] if not with_pager else obj diff --git a/pwnagotchi/mesh/__init__.py b/pwnagotchi/mesh/__init__.py index e1c033f..e69de29 100644 --- a/pwnagotchi/mesh/__init__.py +++ b/pwnagotchi/mesh/__init__.py @@ -1,4 +0,0 @@ -import os - -def new_session_id(): - return ':'.join(['%02x' % b for b in os.urandom(6)]) diff --git a/pwnagotchi/mesh/advertise.py b/pwnagotchi/mesh/advertise.py deleted file mode 100644 index a4f88b7..0000000 --- a/pwnagotchi/mesh/advertise.py +++ /dev/null @@ -1,176 +0,0 @@ -import time -import json -import _thread -import threading -import logging -from scapy.all import Dot11, Dot11Elt, RadioTap, sendp, sniff - -import pwnagotchi.ui.faces as faces - -import pwnagotchi.mesh.wifi as wifi -from pwnagotchi.mesh import new_session_id -from pwnagotchi.mesh.peer import Peer - - -def _dummy_peer_cb(peer): - pass - - -class Advertiser(object): - MAX_STALE_TIME = 300 - - def __init__(self, iface, name, version, identity, period=0.3, data={}): - self._iface = iface - self._period = period - self._running = False - self._stopped = threading.Event() - self._peers_lock = threading.Lock() - self._adv_lock = threading.Lock() - self._new_peer_cb = _dummy_peer_cb - self._lost_peer_cb = _dummy_peer_cb - self._peers = {} - self._frame = None - self._me = Peer(new_session_id(), 0, 0, { - 'name': name, - 'version': version, - 'identity': identity, - 'face': faces.FRIEND, - 'pwnd_run': 0, - 'pwnd_tot': 0, - 'uptime': 0, - 'epoch': 0, - 'data': data - }) - self.update() - - def update(self, values={}): - with self._adv_lock: - for field, value in values.items(): - self._me.adv[field] = value - self._frame = wifi.encapsulate(payload=json.dumps(self._me.adv), addr_from=self._me.session_id) - - def on_peer(self, new_cb, lost_cb): - self._new_peer_cb = new_cb - self._lost_peer_cb = lost_cb - - def on_face_change(self, old, new): - self.update({'face': new}) - - def start(self): - self._running = True - _thread.start_new_thread(self._sender, ()) - _thread.start_new_thread(self._listener, ()) - _thread.start_new_thread(self._pruner, ()) - - def num_peers(self): - with self._peers_lock: - return len(self._peers) - - def peers(self): - with self._peers_lock: - return list(self._peers.values()) - - def closest_peer(self): - closest = None - with self._peers_lock: - for ident, peer in self._peers.items(): - if closest is None or peer.is_closer(closest): - closest = peer - return closest - - def stop(self): - self._running = False - self._stopped.set() - - def _sender(self): - logging.info("started advertiser thread (period:%s sid:%s) ..." % (str(self._period), self._me.session_id)) - while self._running: - try: - sendp(self._frame, iface=self._iface, verbose=False, count=1, inter=self._period) - except OSError as ose: - logging.warning("non critical issue while sending advertising packet: %s" % ose) - except Exception as e: - logging.exception("error") - time.sleep(self._period) - - def _on_advertisement(self, src_session_id, channel, rssi, adv): - ident = adv['identity'] - with self._peers_lock: - if ident not in self._peers: - peer = Peer(src_session_id, channel, rssi, adv) - logging.info("detected unit %s (v%s) on channel %d (%s dBm) [sid:%s pwnd_tot:%d uptime:%d]" % ( \ - peer.full_name(), - peer.version(), - channel, - rssi, - src_session_id, - peer.pwnd_total(), - peer.uptime())) - - self._peers[ident] = peer - self._new_peer_cb(peer) - else: - self._peers[ident].update(src_session_id, channel, rssi, adv) - - def _parse_identity(self, radio, dot11, dot11elt): - payload = b'' - while dot11elt: - payload += dot11elt.info - dot11elt = dot11elt.payload.getlayer(Dot11Elt) - - if payload != b'': - adv = json.loads(payload) - self._on_advertisement( \ - dot11.addr3, - wifi.freq_to_channel(radio.Channel), - radio.dBm_AntSignal, - adv) - - def _is_broadcasted_advertisement(self, dot11): - # dst bcast + protocol signature + not ours - return dot11 is not None and \ - dot11.addr1 == wifi.BroadcastAddress and \ - dot11.addr2 == wifi.SignatureAddress and \ - dot11.addr3 != self._me.session_id - - def _is_frame_for_us(self, dot11): - # dst is us + protocol signature + not ours (why would we send a frame to ourself anyway?) - return dot11 is not None and \ - dot11.addr1 == self._me.session_id and \ - dot11.addr2 == wifi.SignatureAddress and \ - dot11.addr3 != self._me.session_id - - def _on_packet(self, p): - dot11 = p.getlayer(Dot11) - - if self._is_broadcasted_advertisement(dot11): - try: - dot11elt = p.getlayer(Dot11Elt) - if dot11elt.ID == wifi.Dot11ElemID_Whisper: - self._parse_identity(p[RadioTap], dot11, dot11elt) - - else: - raise Exception("unknown frame id %d" % dot11elt.ID) - - except Exception as e: - logging.exception("error decoding packet from %s" % dot11.addr3) - - def _listener(self): - # logging.info("started advertisements listener ...") - expr = "type mgt subtype beacon and ether src %s" % wifi.SignatureAddress - sniff(iface=self._iface, filter=expr, prn=self._on_packet, store=0, stop_filter=lambda x: self._stopped.isSet()) - - def _pruner(self): - while self._running: - time.sleep(10) - with self._peers_lock: - stale = [] - for ident, peer in self._peers.items(): - inactive_for = peer.inactive_for() - if inactive_for >= Advertiser.MAX_STALE_TIME: - logging.info("peer %s lost (inactive for %ds)" % (peer.full_name(), inactive_for)) - self._lost_peer_cb(peer) - stale.append(ident) - - for ident in stale: - del self._peers[ident] diff --git a/pwnagotchi/mesh/peer.py b/pwnagotchi/mesh/peer.py index 0d3b061..14f0057 100644 --- a/pwnagotchi/mesh/peer.py +++ b/pwnagotchi/mesh/peer.py @@ -1,32 +1,28 @@ import time import logging -import pwnagotchi.mesh.wifi as wifi import pwnagotchi.ui.faces as faces class Peer(object): - def __init__(self, sid, channel, rssi, adv): + def __init__(self, obj): self.first_seen = time.time() self.last_seen = self.first_seen - self.session_id = sid - self.last_channel = channel - self.presence = [0] * wifi.NumChannels - self.adv = adv - self.rssi = rssi - self.presence[channel - 1] = 1 + self.session_id = obj['session_id'] + self.last_channel = obj['channel'] + self.rssi = obj['rssi'] + self.adv = obj['advertisement'] - def update(self, sid, channel, rssi, adv): - if self.name() != adv['name']: - logging.info("peer %s changed name: %s -> %s" % (self.full_name(), self.name(), adv['name'])) + def update(self, new): + if self.name() != new.name(): + logging.info("peer %s changed name: %s -> %s" % (self.full_name(), self.name(), new.name())) - if self.session_id != sid: - logging.info("peer %s changed session id: %s -> %s" % (self.full_name(), self.session_id, sid)) + if self.session_id != new.session_id: + logging.info("peer %s changed session id: %s -> %s" % (self.full_name(), self.session_id, new.session_id)) - self.presence[channel - 1] += 1 - self.adv = adv - self.rssi = rssi - self.session_id = sid + self.adv = new.adv + self.rssi = new.rssi + self.session_id = new.session_id self.last_seen = time.time() def inactive_for(self): diff --git a/pwnagotchi/mesh/utils.py b/pwnagotchi/mesh/utils.py index 3a67ed9..d28f04d 100644 --- a/pwnagotchi/mesh/utils.py +++ b/pwnagotchi/mesh/utils.py @@ -2,7 +2,11 @@ import _thread import logging import pwnagotchi +import pwnagotchi.utils as utils +import pwnagotchi.ui.faces as faces import pwnagotchi.plugins as plugins +import pwnagotchi.grid as grid +from pwnagotchi.mesh.peer import Peer class AsyncAdvertiser(object): @@ -10,38 +14,76 @@ class AsyncAdvertiser(object): self._config = config self._view = view self._keypair = keypair - self._advertiser = None + self._advertisement = { + 'name': pwnagotchi.name(), + 'version': pwnagotchi.version, + 'identity': self._keypair.fingerprint, + 'face': faces.FRIEND, + 'pwnd_run': 0, + 'pwnd_tot': 0, + 'uptime': 0, + 'epoch': 0, + 'policy': self._config['personality'] + } + self._peers = {} + self._closest_peer = None - def keypair(self): - return self._keypair + _thread.start_new_thread(self._adv_poller, ()) + + def _update_advertisement(self, s): + self._advertisement['pwnd_run'] = len(self._handshakes) + self._advertisement['pwnd_tot'] = utils.total_unique_handshakes(self._config['bettercap']['handshakes']) + self._advertisement['uptime'] = pwnagotchi.uptime() + self._advertisement['epoch'] = self._epoch.epoch + grid.set_advertisement_data(self._advertisement) def start_advertising(self): - _thread.start_new_thread(self._adv_worker, ()) - - def _adv_worker(self): - # this will take some time due to scapy being slow to be imported ... - from pwnagotchi.mesh.advertise import Advertiser - - self._advertiser = Advertiser( - self._config['main']['iface'], - pwnagotchi.name(), - pwnagotchi.version, - self._keypair.fingerprint, - period=0.3, - data=self._config['personality']) - - self._advertiser.on_peer(self._on_new_unit, self._on_lost_unit) - if self._config['personality']['advertise']: - self._advertiser.start() - self._view.on_state_change('face', self._advertiser.on_face_change) + grid.set_advertisement_data(self._advertisement) + grid.advertise(True) + self._view.on_state_change('face', self._on_face_change) else: logging.warning("advertising is disabled") - def _on_new_unit(self, peer): - self._view.on_new_peer(peer) - plugins.on('peer_detected', self, peer) + def _on_face_change(self, old, new): + self._advertisement['face'] = new + grid.set_advertisement_data(self._advertisement) - def _on_lost_unit(self, peer): - self._view.on_lost_peer(peer) - plugins.on('peer_lost', self, peer) + def _adv_poller(self): + while True: + logging.debug("polling pwngrid-peer for peers ...") + + try: + grid_peers = grid.peers() + new_peers = {} + + self._closest_peer = None + for obj in grid_peers: + peer = Peer(obj) + new_peers[peer.identity()] = peer + if self._closest_peer is None: + self._closest_peer = peer + + # check who's gone + to_delete = [] + for ident, peer in self._peers.items(): + if ident not in new_peers: + self._view.on_lost_peer(peer) + plugins.on('peer_lost', self, peer) + to_delete.append(ident) + + for ident in to_delete: + del self._peers[ident] + + for ident, peer in new_peers: + # check who's new + if ident not in self._peers: + self._peers[ident] = peer + self._view.on_new_peer(peer) + plugins.on('peer_detected', self, peer) + # update the rest + else: + self._peers[ident].update(peer) + + except Exception as e: + logging.error("error while polling pwngrid-peer: %s" % e) diff --git a/pwnagotchi/mesh/wifi.py b/pwnagotchi/mesh/wifi.py deleted file mode 100644 index 6fe231e..0000000 --- a/pwnagotchi/mesh/wifi.py +++ /dev/null @@ -1,37 +0,0 @@ -SignatureAddress = 'de:ad:be:ef:de:ad' -BroadcastAddress = 'ff:ff:ff:ff:ff:ff' -Dot11ElemID_Whisper = 222 -NumChannels = 140 - -def freq_to_channel(freq): - if freq <= 2472: - return int(((freq - 2412) / 5) + 1) - elif freq == 2484: - return int(14) - elif 5035 <= freq <= 5865: - return int(((freq - 5035) / 5) + 7) - else: - return 0 - - -def encapsulate(payload, addr_from, addr_to=BroadcastAddress): - from scapy.all import Dot11, Dot11Beacon, Dot11Elt, RadioTap - - radio = RadioTap() - dot11 = Dot11(type=0, subtype=8, addr1=addr_to, addr2=SignatureAddress, addr3=addr_from) - beacon = Dot11Beacon(cap='ESS') - frame = radio / dot11 / beacon - - data_size = len(payload) - data_left = data_size - data_off = 0 - chunk_size = 255 - - while data_left > 0: - sz = min(chunk_size, data_left) - chunk = payload[data_off: data_off + sz] - frame /= Dot11Elt(ID=Dot11ElemID_Whisper, info=chunk, len=sz) - data_off += sz - data_left -= sz - - return frame diff --git a/pwnagotchi/plugins/default/grid.py b/pwnagotchi/plugins/default/grid.py index 516a6a2..4b62a55 100644 --- a/pwnagotchi/plugins/default/grid.py +++ b/pwnagotchi/plugins/default/grid.py @@ -6,11 +6,9 @@ __description__ = 'This plugin signals the unit cryptographic identity and list import os import logging -import requests import glob -import json -import subprocess -import pwnagotchi + +import pwnagotchi.grid as grid import pwnagotchi.utils as utils from pwnagotchi.ui.components import LabeledValue from pwnagotchi.ui.view import BLACK @@ -65,74 +63,13 @@ def is_excluded(what): return False -def grid_call(path, obj=None): - # pwngrid-peer is running on port 8666 - api_address = 'http://127.0.0.1:8666/api/v1%s' % path - if obj is None: - r = requests.get(api_address, headers=None) - else: - r = requests.post(api_address, headers=None, json=obj) - - if r.status_code != 200: - raise Exception("(status %d) %s" % (r.status_code, r.text)) - return r.json() - - -def grid_update_data(last_session): - brain = {} - try: - with open('/root/brain.json') as fp: - brain = json.load(fp) - except: - pass - - data = { - 'session': { - '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: %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 grid_inbox(): - return grid_call("/inbox")["messages"] - - def on_ui_update(ui): new_value = ' %d (%d)' % (UNREAD_MESSAGES, TOTAL_MESSAGES) if not ui.has_element('mailbox') and TOTAL_MESSAGES > 0: if ui.is_inky(): - pos=(80, 0) + pos = (80, 0) else: - pos=(100,0) + pos = (100, 0) ui.add_element('mailbox', LabeledValue(color=BLACK, label='MSG', value=new_value, position=pos, @@ -147,7 +84,7 @@ def on_internet_available(agent): logging.debug("internet available") try: - grid_update_data(agent.last_session) + grid.update_data(agent.last_session) except Exception as e: logging.error("error connecting to the pwngrid-peer service: %s" % e) return @@ -155,13 +92,13 @@ def on_internet_available(agent): try: logging.debug("checking mailbox ...") - messages = grid_inbox() + messages = grid.inbox() TOTAL_MESSAGES = len(messages) UNREAD_MESSAGES = len([m for m in messages if m['seen_at'] is None]) if TOTAL_MESSAGES: on_ui_update(agent.view()) - logging.debug( " %d unread messages of %d total" % (UNREAD_MESSAGES, TOTAL_MESSAGES)) + logging.debug(" %d unread messages of %d total" % (UNREAD_MESSAGES, TOTAL_MESSAGES)) logging.debug("checking pcaps") @@ -189,7 +126,7 @@ 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 grid_report_ap(essid, bssid): + elif grid.report_ap(essid, bssid): reported.append(net_id) REPORT.update(data={'reported': reported}) else: From ac5ee1ba7b39b5ead95853cfafdfbbc0e3fa2068 Mon Sep 17 00:00:00 2001 From: Simone Margaritelli Date: Sun, 13 Oct 2019 17:38:00 +0200 Subject: [PATCH 07/19] misc: small fix or general refactoring i did not bother commenting --- bin/pwnagotchi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/pwnagotchi b/bin/pwnagotchi index a7d3c97..ce02bbc 100755 --- a/bin/pwnagotchi +++ b/bin/pwnagotchi @@ -5,7 +5,7 @@ if __name__ == '__main__': import logging import pwnagotchi - import pwnagtochi.grid as grid + import pwnagotchi.grid as grid import pwnagotchi.utils as utils import pwnagotchi.plugins as plugins From 77efeafd6596669050685c06a3ae74e0a92b3aaf Mon Sep 17 00:00:00 2001 From: Simone Margaritelli Date: Sun, 13 Oct 2019 17:39:25 +0200 Subject: [PATCH 08/19] misc: small fix or general refactoring i did not bother commenting --- pwnagotchi/mesh/wifi.py | 1 + 1 file changed, 1 insertion(+) create mode 100644 pwnagotchi/mesh/wifi.py diff --git a/pwnagotchi/mesh/wifi.py b/pwnagotchi/mesh/wifi.py new file mode 100644 index 0000000..93fe9ab --- /dev/null +++ b/pwnagotchi/mesh/wifi.py @@ -0,0 +1 @@ +NumChannels = 140 From 1808392a1dcdaabc4241241c4f2bb1ad6cd2f7e6 Mon Sep 17 00:00:00 2001 From: Simone Margaritelli Date: Sun, 13 Oct 2019 17:40:30 +0200 Subject: [PATCH 09/19] misc: small fix or general refactoring i did not bother commenting --- pwnagotchi/mesh/wifi.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pwnagotchi/mesh/wifi.py b/pwnagotchi/mesh/wifi.py index 93fe9ab..3bc714b 100644 --- a/pwnagotchi/mesh/wifi.py +++ b/pwnagotchi/mesh/wifi.py @@ -1 +1,12 @@ NumChannels = 140 + + +def freq_to_channel(freq): + if freq <= 2472: + return int(((freq - 2412) / 5) + 1) + elif freq == 2484: + return int(14) + elif 5035 <= freq <= 5865: + return int(((freq - 5035) / 5) + 7) + else: + return 0 From 1215fda45967d64a7b7d4aa9f20a77b7dfd7b589 Mon Sep 17 00:00:00 2001 From: Simone Margaritelli Date: Sun, 13 Oct 2019 17:45:34 +0200 Subject: [PATCH 10/19] misc: small fix or general refactoring i did not bother commenting --- pwnagotchi/mesh/utils.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pwnagotchi/mesh/utils.py b/pwnagotchi/mesh/utils.py index d28f04d..6d17f4e 100644 --- a/pwnagotchi/mesh/utils.py +++ b/pwnagotchi/mesh/utils.py @@ -1,5 +1,6 @@ import _thread import logging +import time import pwnagotchi import pwnagotchi.utils as utils @@ -87,3 +88,5 @@ class AsyncAdvertiser(object): except Exception as e: logging.error("error while polling pwngrid-peer: %s" % e) + + time.sleep(1) From ad2fbdb9ddfea38b1751ef8291af94f4e4b7fc8d Mon Sep 17 00:00:00 2001 From: Simone Margaritelli Date: Sun, 13 Oct 2019 17:54:33 +0200 Subject: [PATCH 11/19] misc: small fix or general refactoring i did not bother commenting --- pwnagotchi/defaults.yml | 2 +- pwnagotchi/mesh/utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pwnagotchi/defaults.yml b/pwnagotchi/defaults.yml index 65bb5c6..621a4c3 100644 --- a/pwnagotchi/defaults.yml +++ b/pwnagotchi/defaults.yml @@ -173,7 +173,7 @@ ui: color: 'black' video: enabled: true - address: '10.0.0.2' + address: '0.0.0.0' port: 8080 diff --git a/pwnagotchi/mesh/utils.py b/pwnagotchi/mesh/utils.py index 6d17f4e..fb7f523 100644 --- a/pwnagotchi/mesh/utils.py +++ b/pwnagotchi/mesh/utils.py @@ -87,6 +87,6 @@ class AsyncAdvertiser(object): self._peers[ident].update(peer) except Exception as e: - logging.error("error while polling pwngrid-peer: %s" % e) + logging.exception("error while polling pwngrid-peer") time.sleep(1) From 5989d2571c8a3fed0c8e69b2bf089f759f53f2d3 Mon Sep 17 00:00:00 2001 From: Simone Margaritelli Date: Sun, 13 Oct 2019 17:55:10 +0200 Subject: [PATCH 12/19] misc: small fix or general refactoring i did not bother commenting --- pwnagotchi/mesh/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pwnagotchi/mesh/utils.py b/pwnagotchi/mesh/utils.py index fb7f523..fbe8271 100644 --- a/pwnagotchi/mesh/utils.py +++ b/pwnagotchi/mesh/utils.py @@ -76,7 +76,7 @@ class AsyncAdvertiser(object): for ident in to_delete: del self._peers[ident] - for ident, peer in new_peers: + for ident, peer in new_peers.items(): # check who's new if ident not in self._peers: self._peers[ident] = peer From 6793312691044a8aab2990c366d1f0ee2b10a7ca Mon Sep 17 00:00:00 2001 From: Simone Margaritelli Date: Sun, 13 Oct 2019 18:02:11 +0200 Subject: [PATCH 13/19] misc: small fix or general refactoring i did not bother commenting --- pwnagotchi/defaults.yml | 1 + scripts/backup.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/pwnagotchi/defaults.yml b/pwnagotchi/defaults.yml index 621a4c3..c1d03a5 100644 --- a/pwnagotchi/defaults.yml +++ b/pwnagotchi/defaults.yml @@ -27,6 +27,7 @@ main: files: - /root/brain.nn - /root/brain.json + - /root/.api-report.json - /root/handshakes/ - /etc/pwnagotchi/ - /etc/hostname diff --git a/scripts/backup.sh b/scripts/backup.sh index 213ed94..c943058 100755 --- a/scripts/backup.sh +++ b/scripts/backup.sh @@ -10,6 +10,7 @@ TEMP_BACKUP_FOLDER=/tmp/pwnagotchi_backup FILES_TO_BACKUP=( /root/brain.nn /root/brain.json + /root/.api-report.json /root/handshakes /etc/pwnagotchi/ /etc/hostname From 8d2cbee8df4c0b739783c8f11a9514d0ff156d76 Mon Sep 17 00:00:00 2001 From: Simone Margaritelli Date: Sun, 13 Oct 2019 18:09:33 +0200 Subject: [PATCH 14/19] fix: fixed log flooding with whitelisten networks for grid report --- pwnagotchi/plugins/default/grid.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/pwnagotchi/plugins/default/grid.py b/pwnagotchi/plugins/default/grid.py index 4b62a55..264de46 100644 --- a/pwnagotchi/plugins/default/grid.py +++ b/pwnagotchi/plugins/default/grid.py @@ -78,6 +78,12 @@ def on_ui_update(ui): ui.set('mailbox', new_value) +def set_reported(reported, net_id): + global REPORT + reported.append(net_id) + REPORT.update(data={'reported': reported}) + + def on_internet_available(agent): global REPORT, UNREAD_MESSAGES, TOTAL_MESSAGES @@ -118,17 +124,19 @@ def on_internet_available(agent): net_id = os.path.basename(pcap_file).replace('.pcap', '') if net_id not in reported: if is_excluded(net_id): - logging.info("skipping %s due to exclusion filter" % pcap_file) + logging.debug("skipping %s due to exclusion filter" % pcap_file) + set_reported(reported, net_id) continue essid, bssid = parse_pcap(pcap_file) if bssid: + add_as_reported = False if is_excluded(essid) or is_excluded(bssid): logging.debug("not reporting %s due to exclusion filter" % pcap_file) - - elif grid.report_ap(essid, bssid): - reported.append(net_id) - REPORT.update(data={'reported': reported}) + set_reported(reported, net_id) + else: + if grid.report_ap(essid, bssid): + set_reported(reported, net_id) else: logging.warning("no bssid found?!") else: From ba7c0ee4e6443594494c9d2783abf5bcbfdbec19 Mon Sep 17 00:00:00 2001 From: Simone Margaritelli Date: Sun, 13 Oct 2019 18:29:56 +0200 Subject: [PATCH 15/19] misc: small fix or general refactoring i did not bother commenting --- pwnagotchi/log.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pwnagotchi/log.py b/pwnagotchi/log.py index fa3ddc1..560a6ce 100644 --- a/pwnagotchi/log.py +++ b/pwnagotchi/log.py @@ -129,10 +129,12 @@ class LastSession(object): if m: name, pubkey, rssi, sid, pwnd_tot, uptime = m[0] if pubkey not in cache: - self.last_peer = Peer(sid, 1, int(rssi), - {'name': name, - 'identity': pubkey, - 'pwnd_tot': int(pwnd_tot)}) + self.last_peer = Peer({ + 'session_id': sid, + 'channel': 1, + 'rssi': int(rssi), + 'identity': pubkey, + 'advertisement':{'pwnd_tot': int(pwnd_tot)}}) self.peers += 1 cache[pubkey] = self.last_peer else: From b539a761241a5d99b1a87003904f44bd586d4449 Mon Sep 17 00:00:00 2001 From: Simone Margaritelli Date: Sun, 13 Oct 2019 18:32:14 +0200 Subject: [PATCH 16/19] misc: small fix or general refactoring i did not bother commenting --- pwnagotchi/mesh/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pwnagotchi/mesh/utils.py b/pwnagotchi/mesh/utils.py index fbe8271..6129e82 100644 --- a/pwnagotchi/mesh/utils.py +++ b/pwnagotchi/mesh/utils.py @@ -29,8 +29,6 @@ class AsyncAdvertiser(object): self._peers = {} self._closest_peer = None - _thread.start_new_thread(self._adv_poller, ()) - def _update_advertisement(self, s): self._advertisement['pwnd_run'] = len(self._handshakes) self._advertisement['pwnd_tot'] = utils.total_unique_handshakes(self._config['bettercap']['handshakes']) @@ -40,6 +38,8 @@ class AsyncAdvertiser(object): def start_advertising(self): if self._config['personality']['advertise']: + _thread.start_new_thread(self._adv_poller, ()) + grid.set_advertisement_data(self._advertisement) grid.advertise(True) self._view.on_state_change('face', self._on_face_change) From 2430b4a13406e10e803eeb59f171b2544e420f9c Mon Sep 17 00:00:00 2001 From: Simone Margaritelli Date: Sun, 13 Oct 2019 18:35:09 +0200 Subject: [PATCH 17/19] misc: small fix or general refactoring i did not bother commenting --- pwnagotchi/log.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pwnagotchi/log.py b/pwnagotchi/log.py index 560a6ce..c81a17c 100644 --- a/pwnagotchi/log.py +++ b/pwnagotchi/log.py @@ -134,7 +134,10 @@ class LastSession(object): 'channel': 1, 'rssi': int(rssi), 'identity': pubkey, - 'advertisement':{'pwnd_tot': int(pwnd_tot)}}) + 'advertisement':{ + 'name': name, + 'pwnd_tot': int(pwnd_tot) + }}) self.peers += 1 cache[pubkey] = self.last_peer else: From 1ce361a8397cab995704724b13fa7a552003f995 Mon Sep 17 00:00:00 2001 From: Simone Margaritelli Date: Sun, 13 Oct 2019 18:49:50 +0200 Subject: [PATCH 18/19] misc: small fix or general refactoring i did not bother commenting --- builder/pwnagotchi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builder/pwnagotchi.yml b/builder/pwnagotchi.yml index 8079d60..21a15dd 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.7.1/pwngrid_linux_armv6l_1.7.1.zip" + url: "https://github.com/evilsocket/pwngrid/releases/download/v1.7.3/pwngrid_linux_armv6l_1.7.3.zip" apt: hold: - firmware-atheros From e15d0f33239c4f4b3ec58a813e53fd9f767b345c Mon Sep 17 00:00:00 2001 From: Simone Margaritelli Date: Sun, 13 Oct 2019 19:07:29 +0200 Subject: [PATCH 19/19] releasing v1.0.0RC4 --- pwnagotchi/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pwnagotchi/__init__.py b/pwnagotchi/__init__.py index a26d337..c75af90 100644 --- a/pwnagotchi/__init__.py +++ b/pwnagotchi/__init__.py @@ -4,7 +4,7 @@ import logging import time import pwnagotchi.ui.view as view -version = '1.0.0RC3' +version = '1.0.0RC4' _name = None