From 311931c81d3cccadcf50c0728b71351abbc371d6 Mon Sep 17 00:00:00 2001 From: dadav <33197631+dadav@users.noreply.github.com> Date: Thu, 16 Apr 2020 17:35:41 +0200 Subject: [PATCH 01/32] added watchdog --- builder/data/usr/bin/bettercap-launcher | 6 ++++ builder/data/usr/bin/pwnlib | 16 ++++++++- pwnagotchi/agent.py | 2 +- pwnagotchi/plugins/default/watchdog.py | 43 ++++++++++++++++++++++ pwnagotchi/ui/web/templates/plugins.html | 45 ++++++++++++++++++++++-- 5 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 pwnagotchi/plugins/default/watchdog.py diff --git a/builder/data/usr/bin/bettercap-launcher b/builder/data/usr/bin/bettercap-launcher index 2598a25c..d2dec50f 100755 --- a/builder/data/usr/bin/bettercap-launcher +++ b/builder/data/usr/bin/bettercap-launcher @@ -9,6 +9,12 @@ if is_crypted_mode; then done fi +# check if wifi driver is bugged +if ! check_brcm; then + reload_brcm + sleep 10 +fi + # start mon0 start_monitor_interface diff --git a/builder/data/usr/bin/pwnlib b/builder/data/usr/bin/pwnlib index cbf358c8..15eb8ef3 100755 --- a/builder/data/usr/bin/pwnlib +++ b/builder/data/usr/bin/pwnlib @@ -12,9 +12,23 @@ blink_led() { sleep 0.3 } +# check if brcm is stuck +check_brcm() { + if [[ "$(journalctl -b0 -k --no-pager | tail -10 | grep -c 'brcmf_cfg80211_nexmon_set_channel.*Set Channel failed')" -ge 3 ]]; then + return 1 + fi + return 0 +} + +# reload mod +reload_brcm() { + rmmod brcmfmac + modprobe brcmfmac +} + # starts mon0 start_monitor_interface() { - iw phy phy0 interface add mon0 type monitor && ifconfig mon0 up + iw phy "$(iw phy | head -1 | cut -d" " -f2)" interface add mon0 type monitor && ifconfig mon0 up } # stops mon0 diff --git a/pwnagotchi/agent.py b/pwnagotchi/agent.py index bd884790..d24b09ed 100644 --- a/pwnagotchi/agent.py +++ b/pwnagotchi/agent.py @@ -364,7 +364,7 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer): def start_event_polling(self): # start a thread and pass in the mainloop - _thread.start_new_thread(self._event_poller, (asyncio.new_event_loop(),)) + _thread.start_new_thread(self._event_poller, (asyncio.get_event_loop(),)) def is_module_running(self, module): diff --git a/pwnagotchi/plugins/default/watchdog.py b/pwnagotchi/plugins/default/watchdog.py new file mode 100644 index 00000000..a4e32c92 --- /dev/null +++ b/pwnagotchi/plugins/default/watchdog.py @@ -0,0 +1,43 @@ +import os +import logging +import re +import subprocess +from io import TextIOWrapper +from time import sleep +from threading import Lock +from pwnagotchi import plugins + + +class Watchdog(plugins.Plugin): + __author__ = '33197631+dadav@users.noreply.github.com' + __version__ = '0.1.0' + __license__ = 'GPL3' + __description__ = 'Restart pwnagotchi when blindbug is detected.' + + def __init__(self): + self.options = dict() + self.lock = Lock() + self.pattern = re.compile(r'brcmf_cfg80211_nexmon_set_channel.*?Set Channel failed') + + def on_loaded(self): + """ + Gets called when the plugin gets loaded + """ + logging.info("Watchdog plugin loaded.") + + def on_epoch(self, agent, epoch, epoch_data): + if self.lock.locked(): + return + with self.lock: + # get last 10 lines + last_lines = ''.join(list(TextIOWrapper(subprocess.Popen(['journalctl','-n10','-k'], + stdout=subprocess.PIPE).stdout))[-10:]) + if len(self.pattern.findall(last_lines)) >= 3: + display = agent.view() + display.set('status', 'Blind-Bug detected. Restarting bettercap.') + display.update(force=True) + logging.info('[WATCHDOG] Blind-Bug detected. Restarting.') + mode_file = '/root/.pwnagotchi-manual' if agent.mode == 'manual' else '/root/.pwnagotchi-auto' + os.system(f"touch {mode_file}") + os.system('systemctl restart bettercap') + sleep(10) diff --git a/pwnagotchi/ui/web/templates/plugins.html b/pwnagotchi/ui/web/templates/plugins.html index 5835c180..35b0be56 100644 --- a/pwnagotchi/ui/web/templates/plugins.html +++ b/pwnagotchi/ui/web/templates/plugins.html @@ -5,6 +5,37 @@ Plugins {% endblock %} +{% block styles %} + {{ super() }} + +{% endblock %} + {% block script %} $(function(){ $('input[type=checkbox]').change(function(e) { @@ -28,10 +59,18 @@ $(function(){ {% block content %}
{% for name in database.keys() %} + {% set has_info = name in loaded and loaded[name].__description__ is defined %}
-

- {{name}} -

+
+

+ {{name}} +

+ {% if has_info %} + {{ loaded[name].__description__ }} + {% else %} + Description can't be loaded yet. + {% endif %} +
From 67b4747afa65f356b9a1da22509739f439c9957e Mon Sep 17 00:00:00 2001 From: dadav <33197631+dadav@users.noreply.github.com> Date: Fri, 17 Apr 2020 16:39:31 +0200 Subject: [PATCH 02/32] adjust cmd --- builder/data/usr/bin/pwnlib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builder/data/usr/bin/pwnlib b/builder/data/usr/bin/pwnlib index 15eb8ef3..878b4c12 100755 --- a/builder/data/usr/bin/pwnlib +++ b/builder/data/usr/bin/pwnlib @@ -14,7 +14,7 @@ blink_led() { # check if brcm is stuck check_brcm() { - if [[ "$(journalctl -b0 -k --no-pager | tail -10 | grep -c 'brcmf_cfg80211_nexmon_set_channel.*Set Channel failed')" -ge 3 ]]; then + if [[ "$(journalctl -n10 -k | grep -c 'brcmf_cfg80211_nexmon_set_channel.*Set Channel failed')" -ge 3 ]]; then return 1 fi return 0 From d1411ffa96bcfac46e7253b176639e1216c751d7 Mon Sep 17 00:00:00 2001 From: dadav <33197631+dadav@users.noreply.github.com> Date: Fri, 17 Apr 2020 16:45:04 +0200 Subject: [PATCH 03/32] sort plugins --- pwnagotchi/ui/web/templates/plugins.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pwnagotchi/ui/web/templates/plugins.html b/pwnagotchi/ui/web/templates/plugins.html index 35b0be56..41970fbd 100644 --- a/pwnagotchi/ui/web/templates/plugins.html +++ b/pwnagotchi/ui/web/templates/plugins.html @@ -58,7 +58,7 @@ $(function(){ {% endblock %} {% block content %}
- {% for name in database.keys() %} + {% for name in database.keys() | sort %} {% set has_info = name in loaded and loaded[name].__description__ is defined %}
From fa87e03222ba805853d8c4dfc74db2bdb9980abe Mon Sep 17 00:00:00 2001 From: dadav <33197631+dadav@users.noreply.github.com> Date: Fri, 17 Apr 2020 20:18:12 +0200 Subject: [PATCH 04/32] add max-lines --- pwnagotchi/defaults.toml | 1 + pwnagotchi/plugins/default/logtail.py | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pwnagotchi/defaults.toml b/pwnagotchi/defaults.toml index 937cca19..11835a24 100644 --- a/pwnagotchi/defaults.toml +++ b/pwnagotchi/defaults.toml @@ -110,6 +110,7 @@ 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.logtail.enabled = false +main.plugins.logtail.max-lines = 10000 main.plugins.session-stats.enabled = true main.plugins.session-stats.save_directory = "/var/tmp/pwnagotchi/sessions/" diff --git a/pwnagotchi/plugins/default/logtail.py b/pwnagotchi/plugins/default/logtail.py index 3f633e1a..adc9b20b 100644 --- a/pwnagotchi/plugins/default/logtail.py +++ b/pwnagotchi/plugins/default/logtail.py @@ -207,12 +207,12 @@ TEMPLATE = """ } document.body.style.cursor = 'default'; } - {% endblock %} {% block content %}
+
@@ -254,6 +254,7 @@ class Logtail(plugins.Plugin): """ logging.info("Logtail plugin loaded.") + def on_webhook(self, path, request): if not self.ready: return "Plugin not ready" @@ -266,7 +267,7 @@ class Logtail(plugins.Plugin): with open(self.config['main']['log']['path']) as f: # https://stackoverflow.com/questions/39549426/read-multiple-lines-from-a-file-batch-by-batch/39549901#39549901 n = 1024 - for n_lines in iter(lambda: ''.join(islice(f, n)), ''): + for n_lines in iter(lambda: ''.join(islice(list(f)[-self.options.get('max-lines', 10000):], n)), ''): yield n_lines while True: yield f.readline() From 430172e3ddfbfc4041f04a4cfbc150393450b25b Mon Sep 17 00:00:00 2001 From: dadav <33197631+dadav@users.noreply.github.com> Date: Fri, 17 Apr 2020 20:55:11 +0200 Subject: [PATCH 05/32] remove button --- pwnagotchi/plugins/default/logtail.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pwnagotchi/plugins/default/logtail.py b/pwnagotchi/plugins/default/logtail.py index adc9b20b..b960a468 100644 --- a/pwnagotchi/plugins/default/logtail.py +++ b/pwnagotchi/plugins/default/logtail.py @@ -212,7 +212,6 @@ TEMPLATE = """ {% block content %}
-
From 0b5a63a3d8c6c3aaefc15dcc8c0d8e118d02b94a Mon Sep 17 00:00:00 2001 From: dadav <33197631+dadav@users.noreply.github.com> Date: Fri, 17 Apr 2020 22:31:30 +0200 Subject: [PATCH 06/32] add missing var --- pwnagotchi/agent.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pwnagotchi/agent.py b/pwnagotchi/agent.py index d24b09ed..7fe6a76d 100644 --- a/pwnagotchi/agent.py +++ b/pwnagotchi/agent.py @@ -307,7 +307,7 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer): def start_session_fetcher(self): - _thread.start_new_thread(self._fetch_stats, ()) + _thread.start_new_thread(self._fetch_stats, ()) def _fetch_stats(self): @@ -323,7 +323,7 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer): async def _on_event(self, msg): found_handshake = False jmsg = json.loads(msg) - + if jmsg['tag'] == 'wifi.client.handshake': filename = jmsg['data']['file'] sta_mac = jmsg['data']['station'] @@ -331,6 +331,7 @@ class Agent(Client, Automata, AsyncAdvertiser, AsyncTrainer): key = "%s -> %s" % (sta_mac, ap_mac) if key not in self._handshakes: self._handshakes[key] = jmsg + s = self.session() ap_and_station = self._find_ap_sta_in(sta_mac, ap_mac, s) if ap_and_station is None: logging.warning("!!! captured new handshake: %s !!!", key) From 6038f555fa7fb52b5eb5ddf1138aaa804f3c48b0 Mon Sep 17 00:00:00 2001 From: dadav <33197631+dadav@users.noreply.github.com> Date: Sat, 18 Apr 2020 00:02:25 +0200 Subject: [PATCH 07/32] fix --- pwnagotchi/bettercap.py | 2 ++ pwnagotchi/plugins/default/watchdog.py | 29 ++++++++++---------------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/pwnagotchi/bettercap.py b/pwnagotchi/bettercap.py index 422f9cde..1f9217d0 100644 --- a/pwnagotchi/bettercap.py +++ b/pwnagotchi/bettercap.py @@ -47,6 +47,8 @@ class Client(object): logging.debug("Error while parsing event (%s)", ex) except websockets.exceptions.ConnectionClosedError: logging.debug("Lost websocket connection. Reconnecting...") + except websockets.exceptions.WebSocketException as wex: + logging.debug("Websocket exception (%s)", wex) def run(self, command, verbose_errors=True): r = requests.post("%s/session" % self.url, auth=self.auth, json={'cmd': command}) diff --git a/pwnagotchi/plugins/default/watchdog.py b/pwnagotchi/plugins/default/watchdog.py index a4e32c92..db772483 100644 --- a/pwnagotchi/plugins/default/watchdog.py +++ b/pwnagotchi/plugins/default/watchdog.py @@ -3,8 +3,6 @@ import logging import re import subprocess from io import TextIOWrapper -from time import sleep -from threading import Lock from pwnagotchi import plugins @@ -16,7 +14,6 @@ class Watchdog(plugins.Plugin): def __init__(self): self.options = dict() - self.lock = Lock() self.pattern = re.compile(r'brcmf_cfg80211_nexmon_set_channel.*?Set Channel failed') def on_loaded(self): @@ -26,18 +23,14 @@ class Watchdog(plugins.Plugin): logging.info("Watchdog plugin loaded.") def on_epoch(self, agent, epoch, epoch_data): - if self.lock.locked(): - return - with self.lock: - # get last 10 lines - last_lines = ''.join(list(TextIOWrapper(subprocess.Popen(['journalctl','-n10','-k'], - stdout=subprocess.PIPE).stdout))[-10:]) - if len(self.pattern.findall(last_lines)) >= 3: - display = agent.view() - display.set('status', 'Blind-Bug detected. Restarting bettercap.') - display.update(force=True) - logging.info('[WATCHDOG] Blind-Bug detected. Restarting.') - mode_file = '/root/.pwnagotchi-manual' if agent.mode == 'manual' else '/root/.pwnagotchi-auto' - os.system(f"touch {mode_file}") - os.system('systemctl restart bettercap') - sleep(10) + # get last 10 lines + last_lines = ''.join(list(TextIOWrapper(subprocess.Popen(['journalctl','-n10','-k'], + stdout=subprocess.PIPE).stdout))[-10:]) + if len(self.pattern.findall(last_lines)) >= 3: + display = agent.view() + display.set('status', 'Blind-Bug detected. Restarting bettercap.') + display.update(force=True) + logging.info('[WATCHDOG] Blind-Bug detected. Restarting.') + mode = 'MANU' if agent.mode == 'manual' else 'AUTO' + import pwnagotchi + pwnagotchi.restart(mode=mode) From 44e1e792455ed5dac517b4d876c762d071b3313d Mon Sep 17 00:00:00 2001 From: dadav <33197631+dadav@users.noreply.github.com> Date: Sat, 18 Apr 2020 09:50:40 +0200 Subject: [PATCH 08/32] scorp fix --- pwnagotchi/plugins/default/webgpsmap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pwnagotchi/plugins/default/webgpsmap.py b/pwnagotchi/plugins/default/webgpsmap.py index be536191..413f19a7 100644 --- a/pwnagotchi/plugins/default/webgpsmap.py +++ b/pwnagotchi/plugins/default/webgpsmap.py @@ -230,7 +230,7 @@ class Webgpsmap(plugins.Plugin): } # get ap password if exist - check_for = os.path.basename(pos_file[:-9]) + ".pcap.cracked" + check_for = os.path.basename(pos_file).split(".")[0] + ".pcap.cracked" if check_for in all_files: gps_data[ssid + "_" + mac]["pass"] = pos.password() From 35ea36ef330318a1856950cb7940802fd5be2642 Mon Sep 17 00:00:00 2001 From: dadav <33197631+dadav@users.noreply.github.com> Date: Sat, 18 Apr 2020 10:09:20 +0200 Subject: [PATCH 09/32] auto redirect when decrypted --- builder/data/usr/bin/decryption-webserver | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/builder/data/usr/bin/decryption-webserver b/builder/data/usr/bin/decryption-webserver index 96e7ba6b..f9685682 100755 --- a/builder/data/usr/bin/decryption-webserver +++ b/builder/data/usr/bin/decryption-webserver @@ -88,6 +88,29 @@ POST_RESPONSE = """ text-align: center; } + From eb76cc7023b44879b8034988c23aa6daedb0996c Mon Sep 17 00:00:00 2001 From: dadav <33197631+dadav@users.noreply.github.com> Date: Sat, 18 Apr 2020 10:22:18 +0200 Subject: [PATCH 10/32] fix location --- builder/data/usr/bin/decryption-webserver | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/builder/data/usr/bin/decryption-webserver b/builder/data/usr/bin/decryption-webserver index f9685682..7eb9c52f 100755 --- a/builder/data/usr/bin/decryption-webserver +++ b/builder/data/usr/bin/decryption-webserver @@ -91,15 +91,13 @@ POST_RESPONSE = """