Version 2.2.9:

Signed-off-by: Jeroen Oudshoorn <oudshoorn.jeroen@gmail.com>
This commit is contained in:
Jeroen Oudshoorn
2023-09-05 20:29:09 +02:00
parent 173c0eced2
commit 8c9519f2ee
10 changed files with 66 additions and 217 deletions

View File

@ -12,7 +12,7 @@ from pwnagotchi.plugins import cmd as plugins_cmd
from pwnagotchi import log from pwnagotchi import log
from pwnagotchi import restart from pwnagotchi import restart
from pwnagotchi import fs from pwnagotchi import fs
from pwnagotchi.utils import DottedTomlEncoder from pwnagotchi.utils import DottedTomlEncoder, parse_version as version_to_tuple
def do_clear(display): def do_clear(display):
@ -118,6 +118,11 @@ if __name__ == '__main__':
parser.add_argument('--print-config', dest="print_config", action="store_true", default=False, parser.add_argument('--print-config', dest="print_config", action="store_true", default=False,
help="Print the configuration.") help="Print the configuration.")
parser.add_argument('--check-update', dest="check_update", action="store_true", default=False,
help="Check for updates on Pwnagotchi.")
parser.add_argument('--donate', dest="donate", action="store_true", default=False,
help="How to donate to this project.")
args = parser.parse_args() args = parser.parse_args()
if plugins_cmd.used_plugin_cmd(args): if plugins_cmd.used_plugin_cmd(args):
@ -126,6 +131,26 @@ if __name__ == '__main__':
rc = plugins_cmd.handle_cmd(args, config) rc = plugins_cmd.handle_cmd(args, config)
sys.exit(rc) sys.exit(rc)
if args.donate:
print("Donations can made @ https://www.patreon.com/pwnagotchi_torch \n\nBut only if you really want to!")
if args.check_update:
resp = requests.get("https://api.github.com/repos/jayofelony/pwnagotchi/releases/latest")
latest = resp.json()
latest_ver = latest['tag_name'].replace('v', '')
local = version_to_tuple(pwnagotchi.__version__)
remote = version_to_tuple(latest_ver)
if remote > local:
user_input = input("There is a new version available! Update to %s? [y(es)/n(o)]" % latest_ver)
# input validation
if user_input.lower() in ('y', 'yes'):
os.system("rm /root/.auto-update && systemctl restart pwnagotchi")
elif user_input.lower() in ('n', 'no'): # using this elif for readability
print("Okay, guess not!")
else:
print("You are currently on the latest release, %s." % pwnagotchi.__version__)
if args.version: if args.version:
print(pwnagotchi.__version__) print(pwnagotchi.__version__)
sys.exit(0) sys.exit(0)

View File

@ -1 +1 @@
__version__ = '2.2.8' __version__ = '2.2.9'

View File

@ -51,7 +51,18 @@ class Client(object):
logging.debug("Lost websocket connection. Reconnecting...") logging.debug("Lost websocket connection. Reconnecting...")
except websockets.exceptions.WebSocketException as wex: except websockets.exceptions.WebSocketException as wex:
logging.debug("Websocket exception (%s)", wex) logging.debug("Websocket exception (%s)", wex)
except Exception as e:
logging.exception("Other error while opening websocket (%s) with parameter %s", e, s)
def run(self, command, verbose_errors=True):
r = requests.post("%s/session" % self.url, auth=self.auth, json={'cmd': command}) def run(self, command, verbose_errors=True):
return decode(r, verbose_errors=verbose_errors) for _ in range(0, 2):
try:
r = requests.post("%s/session" % self.url, auth=self.auth, json={'cmd': command})
except requests.exceptions.ConnectionError as e:
logging.exception("Request connection error (%s) while running command (%s)", e, command)
sleep(1) # Sleep for 1-s before trying a second time
else:
break
return decode(r, verbose_errors=verbose_errors)

View File

@ -46,9 +46,9 @@ main.plugins.grid.exclude = [
"YourHomeNetworkHere" "YourHomeNetworkHere"
] ]
main.plugins.auto-update.enabled = false main.plugins.auto-update.enabled = true
main.plugins.auto-update.install = false main.plugins.auto-update.install = true
main.plugins.auto-update.interval = 24 main.plugins.auto-update.interval = 1
main.plugins.net-pos.enabled = false main.plugins.net-pos.enabled = false
main.plugins.net-pos.api_key = "test" main.plugins.net-pos.api_key = "test"
@ -119,32 +119,6 @@ main.plugins.ups_lite.shutdown = 2
main.plugins.gpio_buttons.enabled = false main.plugins.gpio_buttons.enabled = false
main.plugins.led.enabled = false
main.plugins.led.led = 0
main.plugins.led.delay = 200
main.plugins.led.patterns.loaded = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.updating = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.unread_inbox = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.ready = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.ai_ready = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.ai_training_start = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.ai_best_reward = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.ai_worst_reward = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.bored = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.sad = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.excited = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.lonely = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.rebooting = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.wait = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.sleep = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.wifi_update = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.association = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.deauthentication = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.handshake = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.epoch = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.peer_detected = "oo oo oo oo oo oo oo"
main.plugins.led.patterns.peer_lost = "oo oo oo oo oo oo oo"
main.plugins.webcfg.enabled = true main.plugins.webcfg.enabled = true
main.plugins.logtail.enabled = false main.plugins.logtail.enabled = false

View File

@ -10,7 +10,7 @@ from pwnagotchi.utils import download_file, unzip, save_config, parse_version, m
from pwnagotchi.plugins import default_path from pwnagotchi.plugins import default_path
SAVE_DIR = '/usr/local/share/pwnagotchi/availaible-plugins/' SAVE_DIR = '/usr/local/share/pwnagotchi/available-plugins/'
DEFAULT_INSTALL_PATH = '/usr/local/share/pwnagotchi/installed-plugins/' DEFAULT_INSTALL_PATH = '/usr/local/share/pwnagotchi/installed-plugins/'

View File

@ -123,8 +123,13 @@ def install(display, update):
if not os.path.exists(source_path): if not os.path.exists(source_path):
source_path = "%s-%s" % (source_path, update['available']) source_path = "%s-%s" % (source_path, update['available'])
# setup.py is going to install data files for us if "pwngrid" in source_path:
os.system("cd %s && pip3 install ." % source_path) os.system("cd %s && make && make install" % source_path)
elif "bettercap" in source_path:
os.system("cd %s && make && make install" % source_path)
else:
# setup.py is going to install data files for us
os.system("cd %s && pip3 install ." % source_path)
return True return True
@ -182,7 +187,7 @@ class AutoUpdate(plugins.Plugin):
to_install = [] to_install = []
to_check = [ to_check = [
('jayofelony/bettercap', parse_version('bettercap -version'), True, 'bettercap'), ('jayofelony/bettercap', parse_version('bettercap -version'), True, 'bettercap'),
('evilsocket/pwngrid', parse_version('pwngrid -version'), True, 'pwngrid-peer'), ('jayofelony/pwngrid', parse_version('pwngrid -version'), True, 'pwngrid-peer'),
('jayofelony/pwnagotchi', pwnagotchi.__version__, False, 'pwnagotchi') ('jayofelony/pwnagotchi', pwnagotchi.__version__, False, 'pwnagotchi')
] ]

View File

@ -35,9 +35,8 @@ class Fix_BRCMF(plugins.Plugin):
self.options = dict() self.options = dict()
self.pattern = re.compile(r'brcmf_cfg80211_nexmon_set_channel.*?Set Channel failed') self.pattern = re.compile(r'brcmf_cfg80211_nexmon_set_channel.*?Set Channel failed')
self.pattern2 = re.compile(r'wifi error while hopping to channel') self.pattern2 = re.compile(r'wifi error while hopping to channel')
self.pattern3 = re.compile(r'Firmware has halted or crashed') self.pattern3 = re.compile(r'error 400: could not find interface wlan0mon')
self.pattern4 = re.compile(r'AI not loaded!') self.pattern4 = re.compile(r'AI not loaded!')
self.pattern5 = re.compile(r'ConnectionError')
self.isReloadingMon = False self.isReloadingMon = False
self.connection = None self.connection = None
self.LASTTRY = 0 self.LASTTRY = 0
@ -113,6 +112,8 @@ class Fix_BRCMF(plugins.Plugin):
stdout=subprocess.PIPE).stdout))[-10:]) stdout=subprocess.PIPE).stdout))[-10:])
other_last_lines = ''.join(list(TextIOWrapper(subprocess.Popen(['journalctl', '-n10'], other_last_lines = ''.join(list(TextIOWrapper(subprocess.Popen(['journalctl', '-n10'],
stdout=subprocess.PIPE).stdout))[-10:]) stdout=subprocess.PIPE).stdout))[-10:])
other_other_last_lines = ''.join(list(TextIOWrapper(subprocess.Popen(['tail', '-n10', '/var/log/pwnagotchi.log'],
stdout=subprocess.PIPE).stdout))[-10:])
# don't check if we ran a reset recently # don't check if we ran a reset recently
logging.debug("[FixBRCMF]**** epoch") logging.debug("[FixBRCMF]**** epoch")
if time.time() - self.LASTTRY > 180: if time.time() - self.LASTTRY > 180:
@ -159,7 +160,7 @@ class Fix_BRCMF(plugins.Plugin):
logging.error("[FixBRCMF wifi.recon flip] %s" % repr(err)) logging.error("[FixBRCMF wifi.recon flip] %s" % repr(err))
# Look for pattern 3 # Look for pattern 3
elif len(self.pattern3.findall(other_last_lines)) >= 1: elif len(self.pattern3.findall(other_other_last_lines)) >= 1:
logging.info("[FixBRCMF] Firmware has halted or crashed. Restarting wlan0mon.") logging.info("[FixBRCMF] Firmware has halted or crashed. Restarting wlan0mon.")
if hasattr(agent, 'view'): if hasattr(agent, 'view'):
display = agent.view() display = agent.view()
@ -167,14 +168,14 @@ class Fix_BRCMF(plugins.Plugin):
display.update(force=True) display.update(force=True)
try: try:
# Run the monstart command to restart wlan0mon # Run the monstart command to restart wlan0mon
cmd_output = restart("AUTO") cmd_output = subprocess.check_output("monstart", shell=True)
self._status = "up" self._status = "up"
logging.info("[FixBRCMF monstart]: %s" % repr(cmd_output)) logging.info("[FixBRCMF monstart]: %s" % repr(cmd_output))
except Exception as err: except Exception as err:
logging.error("[FixBRCMF monstart]: %s" % repr(err)) logging.error("[FixBRCMF monstart]: %s" % repr(err))
# Look for pattern 4 # Look for pattern 4
elif len(self.pattern4.findall(other_last_lines)) >= 1: elif len(self.pattern4.findall(other_other_last_lines)) >= 1:
logging.info("[FixBRCMF] Having a brain meltdown. Deleting myself.") logging.info("[FixBRCMF] Having a brain meltdown. Deleting myself.")
if hasattr(agent, 'view'): if hasattr(agent, 'view'):
display = agent.view() display = agent.view()
@ -190,20 +191,6 @@ class Fix_BRCMF(plugins.Plugin):
except Exception as err: except Exception as err:
logging.error("[FixBRCMF brain]: %s" % repr(err)) logging.error("[FixBRCMF brain]: %s" % repr(err))
# Look for pattern 5
elif len(self.pattern5.findall(other_last_lines)) >= 1:
logging.info("[FixBRCMF] Bettercap connection failure. Restarting Bettercap.")
if hasattr(agent, 'view'):
display = agent.view()
display.set('status', 'Bettercap connection failure. Restarting Bettercap.')
try:
# Delete brain /root/brain.nn and restarting pwnagotchi service
cmd_output = subprocess.check_output("systemctl restart bettercap",
shell=True)
self._status = "up"
logging.info("[FixBRCMF bettercap]: %s" % repr(cmd_output))
except Exception as err:
logging.error("[FixBRCMF bettercap]: %s" % repr(err))
else: else:
print("logs look good") print("logs look good")

View File

@ -1,159 +0,0 @@
from threading import Event
import _thread
import logging
import time
import pwnagotchi.plugins as plugins
class Led(plugins.Plugin):
__author__ = 'evilsocket@gmail.com'
__version__ = '1.0.0'
__license__ = 'GPL3'
__description__ = 'This plugin blinks the PWR led with different patterns depending on the event.'
def __init__(self):
self._is_busy = False
self._event = Event()
self._event_name = None
self._led_file = "/sys/class/leds/led0/brightness"
self._delay = 200
# called when the plugin is loaded
def on_loaded(self):
self._led_file = "/sys/class/leds/led%d/brightness" % self.options['led']
self._delay = int(self.options['delay'])
logging.info("[led] plugin loaded for %s" % self._led_file)
self._on_event('loaded')
_thread.start_new_thread(self._worker, ())
def _on_event(self, event):
if not self._is_busy:
self._event_name = event
self._event.set()
logging.debug("[led] event '%s' set", event)
else:
logging.debug("[led] skipping event '%s' because the worker is busy", event)
def _led(self, on):
with open(self._led_file, 'wt') as fp:
fp.write(str(on))
def _blink(self, pattern):
logging.debug("[led] using pattern '%s' ..." % pattern)
for c in pattern:
if c == ' ':
self._led(1)
else:
self._led(0)
time.sleep(self._delay / 1000.0)
# reset
self._led(0)
def _worker(self):
while True:
self._event.wait()
self._event.clear()
self._is_busy = True
try:
if self._event_name in self.options['patterns']:
pattern = self.options['patterns'][self._event_name]
self._blink(pattern)
else:
logging.debug("[led] no pattern defined for %s" % self._event_name)
except Exception as e:
logging.exception("[led] error while blinking")
finally:
self._is_busy = False
# called when the unit is updating its software
def on_updating(self):
self._on_event('updating')
# called when there's one or more unread pwnmail messages
def on_unread_inbox(self, num_unread):
self._on_event('unread_inbox')
# called when there's internet connectivity
def on_internet_available(self, agent):
self._on_event('internet_available')
# called when everything is ready and the main loop is about to start
def on_ready(self, agent):
self._on_event('ready')
# called when the AI finished loading
def on_ai_ready(self, agent):
self._on_event('ai_ready')
# called when the AI starts training for a given number of epochs
def on_ai_training_start(self, agent, epochs):
self._on_event('ai_training_start')
# called when the AI got the best reward so far
def on_ai_best_reward(self, agent, reward):
self._on_event('ai_best_reward')
# called when the AI got the worst reward so far
def on_ai_worst_reward(self, agent, reward):
self._on_event('ai_worst_reward')
# called when the status is set to bored
def on_bored(self, agent):
self._on_event('bored')
# called when the status is set to sad
def on_sad(self, agent):
self._on_event('sad')
# called when the status is set to excited
def on_excited(self, agent):
self._on_event('excited')
# called when the status is set to lonely
def on_lonely(self, agent):
self._on_event('lonely')
# called when the agent is rebooting the board
def on_rebooting(self, agent):
self._on_event('rebooting')
# called when the agent is waiting for t seconds
def on_wait(self, agent, t):
self._on_event('wait')
# called when the agent is sleeping for t seconds
def on_sleep(self, agent, t):
self._on_event('sleep')
# called when the agent refreshed its access points list
def on_wifi_update(self, agent, access_points):
self._on_event('wifi_update')
# called when the agent is sending an association frame
def on_association(self, agent, access_point):
self._on_event('association')
# called when the agent is deauthenticating a client station from an AP
def on_deauthentication(self, agent, access_point, client_station):
self._on_event('deauthentication')
# called when a new handshake is captured, access_point and client_station are json objects
# if the agent could match the BSSIDs to the current list, otherwise they are just the strings of the BSSIDs
def on_handshake(self, agent, filename, access_point, client_station):
self._on_event('handshake')
# called when an epoch is over (where an epoch is a single loop of the main algorithm)
def on_epoch(self, agent, epoch, epoch_data):
self._on_event('epoch')
# called when a new peer is detected
def on_peer_detected(self, agent, peer):
self._on_event('peer_detected')
# called when a known peer is lost
def on_peer_lost(self, agent, peer):
self._on_event('peer_lost')

View File

@ -3,6 +3,8 @@ import pwnagotchi.ui.fonts as fonts
class DisplayImpl(object): class DisplayImpl(object):
def __init__(self, config, name): def __init__(self, config, name):
if fonts.Medium is None:
fonts.init(config)
self.name = name self.name = name
self.config = config['ui']['display'] self.config = config['ui']['display']
self._layout = { self._layout = {

View File

@ -101,6 +101,10 @@ def main():
main: main:
lang: {lang} lang: {lang}
ui: ui:
font:
name: 'DejaVuSansMono'
size_offset: 0
size: 0
fps: 0.3 fps: 0.3
display: display:
enabled: false enabled: false
@ -110,7 +114,7 @@ def main():
type: {display} type: {display}
web: web:
enabled: true enabled: true
address: "0.0.0.0" address: '::'
port: 8080 port: 8080
faces: faces: