Example #1
0
    def on_webhook(self, path, request):
        if not self.ready:
            return "Plugin not ready"

        if path == "/" or not path:
            pcapfiles = glob.glob(
                os.path.join(self.config['bettercap']['handshakes'], "*.pcap"))

            data = []
            for path in pcapfiles:
                name = os.path.basename(path)[:-5]
                fullpathNoExt = path[:-5]
                possibleExt = ['.2500', '.16800', '.22000']
                foundExt = ['.pcap']
                for ext in possibleExt:
                    if os.path.isfile(fullpathNoExt + ext):
                        foundExt.append(ext)
                data.append(handshakes(name, fullpathNoExt, foundExt))
            return render_template_string(TEMPLATE,
                                          title="Handshakes | " +
                                          pwnagotchi.name(),
                                          handshakes=data)
        else:
            dir = self.config['bettercap']['handshakes']
            try:
                logging.info(f"[HandshakesDL] serving {dir}/{path}")
                return send_from_directory(directory=dir,
                                           filename=path,
                                           as_attachment=True)
            except FileNotFoundError:
                abort(404)
Example #2
0
    def on_webhook(self, path, request):
        if not self.ready:
            return "Plugin not ready"

        if path == "/" or not path:
            handshakes = glob.glob(os.path.join(self.config['bettercap']['handshakes'], "*.pcap"))
            handshakes = [os.path.basename(path)[:-5] for path in handshakes]
            return render_template_string(TEMPLATE,
                                    title="Handshakes | " + pwnagotchi.name(),
                                    handshakes=handshakes)    
        elif path == "all":
            logging.info(f"[hndshk-dl-all] creating Zip-File in memory")
            memory_file = BytesIO()
            with zipfile.ZipFile(memory_file, 'w') as zf:
                files = glob.glob(os.path.join(self.config['bettercap']['handshakes'], "*.*"))
                try:
                    for individualFile in files:
                        zf.write(individualFile)
                except Exception as e:
                    logging.error(f"[hndshk-dl-all] {e}")
                    abort(404)
            memory_file.seek(0)
            logging.info(f"[hndshk-dl-all] serving handshakes.zip")
            return send_file(memory_file, attachment_filename='handshakesALL.zip', as_attachment=True)
        else:
            dir = self.config['bettercap']['handshakes']
            try:
                logging.info(f"[hndshk-dl-all] serving {dir}/{path}.pcap")
                return send_from_directory(directory=dir, filename=path+'.pcap', as_attachment=True)
            except FileNotFoundError:
                abort(404)
Example #3
0
    def do_GET(self):
        if self.path == '/':
            self.send_response(200)
            self.send_header('Content-type', 'text/html')
            self.end_headers()
            try:
                self.wfile.write(
                    bytes(self._index % (pwnagotchi.name(), 1000), "utf8"))
            except:
                pass

        elif self.path.startswith('/shutdown'):
            pwnagotchi.shutdown()

        elif self.path.startswith('/ui'):
            with self._lock:
                self.send_response(200)
                self.send_header('Content-type', 'image/png')
                self.end_headers()
                try:
                    with open("/root/pwnagotchi.png", 'rb') as fp:
                        shutil.copyfileobj(fp, self.wfile)
                except:
                    pass
        else:
            self.send_response(404)
Example #4
0
    def __init__(self, view, config, keypair):
        Client.__init__(self, config['bettercap']['hostname'],
                        config['bettercap']['scheme'],
                        config['bettercap']['port'],
                        config['bettercap']['username'],
                        config['bettercap']['password'])
        Automata.__init__(self, config, view)
        AsyncAdvertiser.__init__(self, config, view, keypair)
        AsyncTrainer.__init__(self, config)

        self._started_at = time.time()
        self._filter = None if not config['main']['filter'] else re.compile(config['main']['filter'])
        self._current_channel = 0
        self._tot_aps = 0
        self._aps_on_channel = 0
        self._supported_channels = utils.iface_channels(config['main']['iface'])
        self._view = view
        self._view.set_agent(self)
        self._web_ui = Server(self, config['ui'])

        self._access_points = []
        self._last_pwnd = None
        self._history = {}
        self._handshakes = {}
        self.last_session = LastSession(self._config)
        self.mode = 'auto'

        if not os.path.exists(config['bettercap']['handshakes']):
            os.makedirs(config['bettercap']['handshakes'])

        logging.info("%s@%s (v%s)", pwnagotchi.name(), self.fingerprint(), pwnagotchi.__version__)
        for _, plugin in plugins.loaded.items():
            logging.debug("plugin '%s' v%s", plugin.__class__.__name__, plugin.__version__)
Example #5
0
 def shutdown(self):
     try:
         return render_template('status.html',
                                title=pwnagotchi.name(),
                                go_back_after=60,
                                message='Shutting down ...')
     finally:
         _thread.start_new_thread(pwnagotchi.shutdown, ())
Example #6
0
 def reboot(self):
     try:
         return render_template('status.html',
                                title=pwnagotchi.name(),
                                go_back_after=60,
                                message='Rebooting ...')
     finally:
         _thread.start_new_thread(pwnagotchi.reboot, ())
Example #7
0
    def index(self):
        theme = self._config['theme']
        theme_page = "theme-" + theme + ".html"

        return render_template(
            theme_page,
            title=pwnagotchi.name(),
            other_mode='AUTO' if self._agent.mode == 'manual' else 'MANU',
            fingerprint=self._agent.fingerprint())
Example #8
0
    def restart(self):
        mode = request.form['mode']
        if mode not in ('AUTO', 'MANU'):
            mode = 'MANU'

        try:
            return render_template('status.html', title=pwnagotchi.name(), go_back_after=30,
                                   message='Restarting in %s mode ...' % mode)
        finally:
            _thread.start_new_thread(pwnagotchi.restart, (mode,))
Example #9
0
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"]
Example #10
0
    def inbox_peers(self):
        peers = {}
        error = None

        try:
            peers = grid.memory()
        except Exception as e:
            logging.exception('error while reading pwngrid peers')
            error = str(e)

        return render_template('peers.html',
                               name=pwnagotchi.name(),
                               peers=peers,
                               error=error)
Example #11
0
    def inbox_profile(self):
        data = {}
        error = None

        try:
            data = grid.get_advertisement_data()
        except Exception as e:
            logging.exception('error while reading pwngrid data')
            error = str(e)

        return render_template('profile.html',
                               name=pwnagotchi.name(),
                               fingerprint=self._agent.fingerprint(),
                               data=json.dumps(data, indent=2),
                               error=error)
Example #12
0
    def inbox(self):
        page = request.args.get("p", default=1, type=int)
        inbox = {"pages": 1, "records": 0, "messages": []}
        error = None

        try:
            inbox = grid.inbox(page, with_pager=True)
        except Exception as e:
            logging.exception('error while reading pwnmail inbox')
            error = str(e)

        return render_template('inbox.html',
                               name=pwnagotchi.name(),
                               page=page,
                               error=error,
                               inbox=inbox)
Example #13
0
 def exec_update(self, ui):
     try:
         Beacons._busy = True
         #TODO parse and send peers in another beacon frame
         packedInfo = self.pack_info(self.get_unsafe_unsync(ui, 'channel'),
                                     self.get_unsafe_unsync(ui, 'aps'),
                                     self.get_unsafe_unsync(ui, 'shakes'),
                                     pwnagotchi.uptime(),
                                     self.get_unsafe_unsync(ui, 'face'),
                                     self.get_unsafe_unsync(ui, 'mode'),
                                     pwnagotchi.name())
         self.broadcast_info(packedInfo, self._packet_type['report'])
     except Exception as e:
         logging.warning(" *beacons* -> exec_update exception: ")
         logging.warning(" *beacons* -> " + str(type(e)))
         logging.warning(" *beacons* -> " + str(e))
     Beacons._busy = False
Example #14
0
 def __init__(self, config, view, keypair):
     self._config = config
     self._view = view
     self._keypair = keypair
     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
Example #15
0
    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)
        else:
            logging.warning("advertising is disabled")
Example #16
0
    def show_message(self, id):
        message = {}
        error = None

        try:
            message = grid.inbox_message(id)
            if message['data']:
                message['data'] = base64.b64decode(
                    message['data']).decode("utf-8")
        except Exception as e:
            logging.exception('error while reading pwnmail message %d' %
                              int(id))
            error = str(e)

        return render_template('message.html',
                               name=pwnagotchi.name(),
                               error=error,
                               message=message)
Example #17
0
    def on_webhook(self, path, request):
        if not self.ready:
            return "Plugin not ready"

        if path == "/" or not path:
            handshakes = glob.glob(os.path.join(
                self.config['bettercap']['handshakes'], "*.pcap"))
            handshakes = [os.path.basename(path)[:-5] for path in handshakes]
            return render_template_string(TEMPLATE,
                                          title="Handshakes | " + pwnagotchi.name(),
                                          handshakes=handshakes)

        else:
            dir = self.config['bettercap']['handshakes']
            try:
                logging.info(f"[HandshakesDL] serving {dir}/{path}.pcap")
                return send_from_directory(directory=dir, filename=path + '.pcap', as_attachment=True)
            except FileNotFoundError:
                abort(404)
Example #18
0
    def do_GET(self):
        if self._buffer is None:
            self.send_response(404)

        elif self.path == '/':
            self.send_response(200)
            self.send_header('Content-type', 'text/html')
            self.end_headers()
            self._w(bytes(self._index % (pwnagotchi.name(), 1000), "utf8"))

        elif self.path.startswith('/ui'):
            with self._lock:
                self.send_response(200)
                self.send_header('Content-type', 'image/png')
                self.send_header('Content-length', '%d' % len(self._buffer))
                self.end_headers()
                self._w(self._buffer)
        else:
            self.send_response(404)
    def _return_json(self):
        if self.DISPLAY is None:
            return jsonify({"initialised": "false"})

        # All these fall under the local API
        # https://pwnagotchi.ai/api/local/
        # Typically on http://127.0.0.1:8666
        # BUT the local API can trigger calls to the wider grid
        # so bear in mind that grid calls could fail

        # TODO: Break this up into function calls! Keep it SOLID.

        total_messages = "-"
        unread_messages = "-"

        peers_response = None
        try:
            response = requests.get('http://0.0.0.0:8666/api/v1/mesh/peers')
            peers_response = response.json()
        except HTTPError as http_err:
            logging.error(f'HTTP error occurred: {http_err}')
        except Exception as err:
            logging.error(f'Other error occurred: {err}')

        peers = []
        for peer in peers_response:
            peers.append({
                "fingerprint": peer['advertisement']['identity'],
                "name": peer['advertisement']['name'],
                "face": peer['advertisement']['face'],
                "pwnd_run": peer['advertisement']['pwnd_run'],
                "pwnd_tot": peer['advertisement']['pwnd_tot']
            })

        mesh_data_response = None
        try:
            response = requests.get('http://0.0.0.0:8666/api/v1/mesh/data')
            mesh_data_response = response.json()
        except HTTPError as http_err:
            logging.error(f'HTTP error occurred: {http_err}')
        except Exception as err:
            logging.error(f'Other error occurred: {err}')

        # Get mail data (if connected to internet)
        try:
            if grid.is_connected:
                messages = grid.inbox()
                total_messages = len(messages)
                unread_messages = len([m for m in messages if m['seen_at'] is None])
        except Exception as e:
            logging.exception('error while reading state-api: %s' % str(e))

        # TODO: Need a better way of getting this rather than referencing the display
        handshakes_display = self.DISPLAY.get('shakes').split(" ", 2)
        # In general, any underlying state within the state machine should be used.
        # The display is fluid and unreliable.
        pwnd_run = handshakes_display[0]
        pwnd_tot = utils.total_unique_handshakes(self.AGENT.config()['bettercap']['handshakes'])

        pwnd_last = None
        if len(handshakes_display) > 2:
            pwnd_last = handshakes_display[2][1:-1]

        result = {
            "fingerprint": self.AGENT.fingerprint(),
            "epoch": "-" if mesh_data_response is None else mesh_data_response["epoch"],
            "status": self.DISPLAY.get('status'),
            "channel_text": self.DISPLAY.get('channel'),
            "aps_text": self.DISPLAY.get('aps'),
            "apt_tot": self.AGENT.get_total_aps(),
            "aps_on_channel": self.AGENT.get_aps_on_channel(),
            "channel": self.AGENT.get_current_channel(),
            "uptime": self.DISPLAY.get('uptime'),
            "mode": self.DISPLAY.get('mode'),
            "name": pwnagotchi.name(),
            "face": self.DISPLAY.get('face'),
            "num_peers": len(peers),
            "peers": peers,
            "total_messages": total_messages,
            "unread_messages": unread_messages,
            "friend_face_text": self.DISPLAY.get('friend_face'),
            "friend_name_text": self.DISPLAY.get('friend_name'),
            "pwnd_last": pwnd_last,
            "pwnd_run": pwnd_run,
            "pwnd_tot": pwnd_tot,
            "version": pwnagotchi.__version__,
            "memory": pwnagotchi.mem_usage(),  # Scale 0-1
            "cpu": pwnagotchi.cpu_load(),  # Scale 0-1
            "temperature": pwnagotchi.temperature()  # Degrees C
        }

        # TODO See if there is any way of getting a list of plugins and their associated UI components
        # so we can incorporate it into the feedback.
        return jsonify(result)
Example #20
0
 def _shutdown(self):
     self._html(SHUTDOWN % pwnagotchi.name())
     pwnagotchi.shutdown()
Example #21
0
 def _index(self):
     self._html(INDEX % (pwnagotchi.name(), 1000))
Example #22
0
 def index(self):
     return render_template('index.html',
                            title=pwnagotchi.name(),
                            other_mode='AUTO' if self._agent.mode == 'manual' else 'MANU',
                            dark_theme=self._config['dark'])
Example #23
0
 def index(self):
     return render_template('index.html',
                            title=pwnagotchi.name(),
                            other_mode='AUTO' if self._agent.mode == 'manual' else 'MANU',
                            fingerprint=self._agent.fingerprint())
Example #24
0
args = parser.parse_args()

if args.do_clear:
    print("clearing the display ...")
    from pwnagotchi.ui.waveshare import EPD

    epd = EPD()
    epd.init(epd.FULL_UPDATE)
    epd.Clear(0xff)
    quit()

with open(args.config, 'rt') as fp:
    config = yaml.safe_load(fp)

display = Display(config=config, state={'name': '%s>' % pwnagotchi.name()})
agent = Agent(view=display, config=config)

core.log("%s@%s (v%s)" % (pwnagotchi.name(), agent._identity, pwnagotchi.version))
# for key, value in config['personality'].items():
#    core.log("  %s: %s" % (key, value))

if args.do_manual:
    core.log("entering manual mode ...")

    log = SessionParser(config['main']['log'])

    core.log("the last session lasted %s (%d completed epochs, trained for %d), average reward:%s (min:%s max:%s)" % (
        log.duration_human,
        log.epochs,
        log.train_epochs,
Example #25
0
            epd.init(epd.lut_full_update)
            epd.Clear(0xFF)
        elif cleardisplay in ('waveshare_2', 'ws_2', 'waveshare2', 'ws2'):
            print("waveshare v2 display")
            from pwnagotchi.ui.waveshare.v2.waveshare import EPD
            epd = EPD()
            epd.init(epd.FULL_UPDATE)
            epd.Clear(0xff)
        else:
            print("unknown display type %s" % cleardisplay)
        quit()

with open(args.config, 'rt') as fp:
    config = yaml.safe_load(fp)

display = Display(config=config, state={'name': '%s>' % pwnagotchi.name()})
agent = Agent(view=display, config=config)

core.log("%s@%s (v%s)" %
         (pwnagotchi.name(), agent._identity, pwnagotchi.version))
# for key, value in config['personality'].items():
#    core.log("  %s: %s" % (key, value))

if args.do_manual:
    core.log("entering manual mode ...")

    log = SessionParser(config['main']['log'])

    core.log(
        "the last session lasted %s (%d completed epochs, trained for %d), average reward:%s (min:%s max:%s)"
        % (log.duration_human, log.epochs, log.train_epochs, log.avg_reward,