new: using pwngrid for mesh advertising (we got rid of scapy loading times)
This commit is contained in:
parent
77c16c38f4
commit
5d28557608
@ -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:
|
||||
|
@ -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
|
||||
|
||||
|
@ -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:
|
||||
|
97
pwnagotchi/grid.py
Normal file
97
pwnagotchi/grid.py
Normal file
@ -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
|
@ -1,4 +0,0 @@
|
||||
import os
|
||||
|
||||
def new_session_id():
|
||||
return ':'.join(['%02x' % b for b in os.urandom(6)])
|
@ -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]
|
@ -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):
|
||||
|
@ -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)
|
||||
|
@ -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
|
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user