2019-10-05 23:23:31 +02:00
|
|
|
#!/usr/bin/python3
|
2019-11-15 12:27:53 +01:00
|
|
|
import logging
|
|
|
|
import argparse
|
|
|
|
import time
|
2019-12-07 09:36:56 +01:00
|
|
|
import signal
|
2020-01-14 22:23:01 +01:00
|
|
|
import sys
|
2020-01-18 09:30:44 +01:00
|
|
|
import toml
|
2023-09-05 21:10:16 +02:00
|
|
|
import requests
|
2023-09-06 17:01:26 +02:00
|
|
|
import os
|
2019-11-15 12:27:53 +01:00
|
|
|
|
|
|
|
import pwnagotchi
|
2020-01-18 09:29:28 +01:00
|
|
|
from pwnagotchi import utils
|
2020-04-03 19:01:40 +02:00
|
|
|
from pwnagotchi.plugins import cmd as plugins_cmd
|
2020-01-18 09:29:28 +01:00
|
|
|
from pwnagotchi import log
|
2019-12-07 15:44:03 +02:00
|
|
|
from pwnagotchi import restart
|
2020-01-18 09:29:28 +01:00
|
|
|
from pwnagotchi import fs
|
2023-09-05 20:29:09 +02:00
|
|
|
from pwnagotchi.utils import DottedTomlEncoder, parse_version as version_to_tuple
|
2019-11-15 12:27:53 +01:00
|
|
|
|
|
|
|
|
|
|
|
def do_clear(display):
|
|
|
|
logging.info("clearing the display ...")
|
|
|
|
display.clear()
|
2020-01-14 22:23:01 +01:00
|
|
|
sys.exit(0)
|
2019-11-15 12:27:53 +01:00
|
|
|
|
|
|
|
|
|
|
|
def do_manual_mode(agent):
|
|
|
|
logging.info("entering manual mode ...")
|
|
|
|
|
|
|
|
agent.mode = 'manual'
|
|
|
|
agent.last_session.parse(agent.view(), args.skip_session)
|
|
|
|
if not args.skip_session:
|
|
|
|
logging.info(
|
|
|
|
"the last session lasted %s (%d completed epochs, trained for %d), average reward:%s (min:%s max:%s)" % (
|
|
|
|
agent.last_session.duration_human,
|
|
|
|
agent.last_session.epochs,
|
|
|
|
agent.last_session.train_epochs,
|
|
|
|
agent.last_session.avg_reward,
|
|
|
|
agent.last_session.min_reward,
|
|
|
|
agent.last_session.max_reward))
|
|
|
|
|
|
|
|
while True:
|
|
|
|
display.on_manual_mode(agent.last_session)
|
|
|
|
time.sleep(5)
|
|
|
|
if grid.is_connected():
|
|
|
|
plugins.on('internet_available', agent)
|
|
|
|
|
|
|
|
|
|
|
|
def do_auto_mode(agent):
|
|
|
|
logging.info("entering auto mode ...")
|
|
|
|
|
|
|
|
agent.mode = 'auto'
|
|
|
|
agent.start()
|
|
|
|
|
|
|
|
while True:
|
|
|
|
try:
|
|
|
|
# recon on all channels
|
|
|
|
agent.recon()
|
|
|
|
# get nearby access points grouped by channel
|
|
|
|
channels = agent.get_access_points_by_channel()
|
|
|
|
# for each channel
|
|
|
|
for ch, aps in channels:
|
|
|
|
agent.set_channel(ch)
|
|
|
|
|
|
|
|
if not agent.is_stale() and agent.any_activity():
|
|
|
|
logging.info("%d access points on channel %d" % (len(aps), ch))
|
|
|
|
|
|
|
|
# for each ap on this channel
|
|
|
|
for ap in aps:
|
|
|
|
# send an association frame in order to get for a PMKID
|
|
|
|
agent.associate(ap)
|
|
|
|
# deauth all client stations in order to get a full handshake
|
|
|
|
for sta in ap['clients']:
|
|
|
|
agent.deauth(ap, sta)
|
2023-07-03 14:45:38 -07:00
|
|
|
time.sleep(1) # delay to not trigger nexmon firmware bugs
|
2019-11-15 12:27:53 +01:00
|
|
|
|
|
|
|
# An interesting effect of this:
|
|
|
|
#
|
|
|
|
# From Pwnagotchi's perspective, the more new access points
|
|
|
|
# and / or client stations nearby, the longer one epoch of
|
|
|
|
# its relative time will take ... basically, in Pwnagotchi's universe,
|
|
|
|
# WiFi electromagnetic fields affect time like gravitational fields
|
|
|
|
# affect ours ... neat ^_^
|
|
|
|
agent.next_epoch()
|
|
|
|
|
|
|
|
if grid.is_connected():
|
|
|
|
plugins.on('internet_available', agent)
|
2019-10-05 23:23:31 +02:00
|
|
|
|
2019-11-15 12:27:53 +01:00
|
|
|
except Exception as e:
|
2021-06-01 22:42:42 -04:00
|
|
|
if str(e).find("wifi.interface not set") > 0:
|
|
|
|
logging.exception("main loop exception due to unavailable wifi device, likely programmatically disabled (%s)", e)
|
|
|
|
logging.info("sleeping 60 seconds then advancing to next epoch to allow for cleanup code to trigger")
|
|
|
|
time.sleep(60)
|
|
|
|
agent.next_epoch()
|
|
|
|
else:
|
|
|
|
logging.exception("main loop exception (%s)", e)
|
2019-10-05 23:23:31 +02:00
|
|
|
|
2023-08-26 00:54:31 +02:00
|
|
|
|
2019-11-15 12:27:53 +01:00
|
|
|
if __name__ == '__main__':
|
2019-10-05 23:23:31 +02:00
|
|
|
parser = argparse.ArgumentParser()
|
2020-04-03 19:01:40 +02:00
|
|
|
parser = plugins_cmd.add_parsers(parser)
|
2019-10-05 23:23:31 +02:00
|
|
|
|
2019-12-18 18:58:28 +01:00
|
|
|
parser.add_argument('-C', '--config', action='store', dest='config', default='/etc/pwnagotchi/default.toml',
|
2019-10-05 23:23:31 +02:00
|
|
|
help='Main configuration file.')
|
2019-12-18 18:58:28 +01:00
|
|
|
parser.add_argument('-U', '--user-config', action='store', dest='user_config', default='/etc/pwnagotchi/config.toml',
|
2019-10-05 23:23:31 +02:00
|
|
|
help='If this file exists, configuration will be merged and this will override default values.')
|
|
|
|
|
|
|
|
parser.add_argument('--manual', dest="do_manual", action="store_true", default=False, help="Manual mode.")
|
2019-10-20 18:29:36 +02:00
|
|
|
parser.add_argument('--skip-session', dest="skip_session", action="store_true", default=False,
|
|
|
|
help="Skip last session parsing in manual mode.")
|
|
|
|
|
2019-10-05 23:23:31 +02:00
|
|
|
parser.add_argument('--clear', dest="do_clear", action="store_true", default=False,
|
|
|
|
help="Clear the ePaper display and exit.")
|
|
|
|
|
|
|
|
parser.add_argument('--debug', dest="debug", action="store_true", default=False,
|
|
|
|
help="Enable debug logs.")
|
|
|
|
|
2019-11-13 14:37:13 +01:00
|
|
|
parser.add_argument('--print-config', dest="print_config", action="store_true", default=False,
|
|
|
|
help="Print the configuration.")
|
2019-11-01 10:04:36 +01:00
|
|
|
|
2023-09-05 20:29:09 +02:00
|
|
|
parser.add_argument('--check-update', dest="check_update", action="store_true", default=False,
|
2023-09-08 01:09:40 +02:00
|
|
|
help="Check for updates on Pwnagotchi. And tells current version.")
|
2023-09-05 20:29:09 +02:00
|
|
|
parser.add_argument('--donate', dest="donate", action="store_true", default=False,
|
|
|
|
help="How to donate to this project.")
|
|
|
|
|
2019-10-05 23:23:31 +02:00
|
|
|
args = parser.parse_args()
|
2019-11-01 10:04:36 +01:00
|
|
|
|
2020-04-03 19:01:40 +02:00
|
|
|
if plugins_cmd.used_plugin_cmd(args):
|
|
|
|
config = utils.load_config(args)
|
|
|
|
log.setup_logging(args, config)
|
|
|
|
rc = plugins_cmd.handle_cmd(args, config)
|
|
|
|
sys.exit(rc)
|
|
|
|
|
2023-09-05 20:29:09 +02:00
|
|
|
if args.donate:
|
|
|
|
print("Donations can made @ https://www.patreon.com/pwnagotchi_torch \n\nBut only if you really want to!")
|
2023-09-05 21:05:36 +02:00
|
|
|
sys.exit(0)
|
2023-09-05 20:29:09 +02:00
|
|
|
|
|
|
|
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:
|
2023-09-08 01:09:40 +02:00
|
|
|
user_input = input("There is a new version available! Update from v%s to v%s?\n[y(es)/n(o)]" % (pwnagotchi.__version__, latest_ver))
|
2023-09-05 20:29:09 +02:00
|
|
|
# input validation
|
|
|
|
if user_input.lower() in ('y', 'yes'):
|
|
|
|
os.system("rm /root/.auto-update && systemctl restart pwnagotchi")
|
2023-09-08 20:26:12 +02:00
|
|
|
print("Okay, give me a couple minutes. Just watch pwnlog while you wait.")
|
|
|
|
time.sleep(3)
|
|
|
|
os.system("pwnlog")
|
2023-09-05 20:29:09 +02:00
|
|
|
elif user_input.lower() in ('n', 'no'): # using this elif for readability
|
|
|
|
print("Okay, guess not!")
|
|
|
|
else:
|
2023-09-08 01:09:40 +02:00
|
|
|
print("You are currently on the latest release, v%s." % pwnagotchi.__version__)
|
2020-01-14 22:23:01 +01:00
|
|
|
sys.exit(0)
|
2019-11-01 10:04:36 +01:00
|
|
|
|
2019-10-05 23:23:31 +02:00
|
|
|
config = utils.load_config(args)
|
2020-04-03 19:01:40 +02:00
|
|
|
|
2019-11-13 14:37:13 +01:00
|
|
|
if args.print_config:
|
2020-04-01 08:17:22 +02:00
|
|
|
print(toml.dumps(config, encoder=DottedTomlEncoder()))
|
2020-01-14 22:23:01 +01:00
|
|
|
sys.exit(0)
|
2019-11-13 14:37:13 +01:00
|
|
|
|
2020-04-03 19:01:40 +02:00
|
|
|
from pwnagotchi.identity import KeyPair
|
|
|
|
from pwnagotchi.agent import Agent
|
|
|
|
from pwnagotchi.ui import fonts
|
|
|
|
from pwnagotchi.ui.display import Display
|
|
|
|
from pwnagotchi import grid
|
|
|
|
from pwnagotchi import plugins
|
|
|
|
|
2020-04-01 08:17:22 +02:00
|
|
|
pwnagotchi.config = config
|
2020-01-18 09:29:28 +01:00
|
|
|
fs.setup_mounts(config)
|
|
|
|
log.setup_logging(args, config)
|
2020-04-02 19:06:28 +02:00
|
|
|
fonts.init(config)
|
2019-10-05 23:23:31 +02:00
|
|
|
|
2019-10-24 17:48:37 +02:00
|
|
|
pwnagotchi.set_name(config['main']['name'])
|
|
|
|
|
2019-10-05 23:23:31 +02:00
|
|
|
plugins.load(config)
|
|
|
|
|
|
|
|
display = Display(config=config, state={'name': '%s>' % pwnagotchi.name()})
|
|
|
|
|
|
|
|
if args.do_clear:
|
2019-11-15 12:27:53 +01:00
|
|
|
do_clear(display)
|
2020-01-14 22:23:01 +01:00
|
|
|
sys.exit(0)
|
2019-11-15 12:27:53 +01:00
|
|
|
|
|
|
|
agent = Agent(view=display, config=config, keypair=KeyPair(view=display))
|
2019-10-05 23:23:31 +02:00
|
|
|
|
2019-12-07 09:36:56 +01:00
|
|
|
def usr1_handler(*unused):
|
|
|
|
logging.info('Received USR1 singal. Restart process ...')
|
|
|
|
restart("MANU" if args.do_manual else "AUTO")
|
|
|
|
|
|
|
|
signal.signal(signal.SIGUSR1, usr1_handler)
|
|
|
|
|
2019-11-15 12:27:53 +01:00
|
|
|
if args.do_manual:
|
|
|
|
do_manual_mode(agent)
|
2019-10-05 23:23:31 +02:00
|
|
|
else:
|
2019-11-15 12:27:53 +01:00
|
|
|
do_auto_mode(agent)
|