From ddf64cb0b3ef46312d8682903fbfc95cc052948b Mon Sep 17 00:00:00 2001 From: Jeroen Oudshoorn Date: Thu, 21 Sep 2023 12:13:41 +0200 Subject: [PATCH 01/14] multiple edits Signed-off-by: Jeroen Oudshoorn --- builder/data/etc/dphys-swapfile | 26 ++++++++++++++++ pwnagotchi/_version.py | 2 +- pwnagotchi/bettercap.py | 5 ++-- pwnagotchi/log.py | 8 ++--- pwnagotchi/plugins/__init__.py | 10 +++---- pwnagotchi/plugins/default/bt-tether.py | 4 +-- .../plugins/default/internet-connection.py | 30 ++++++++++++------- pwnagotchi/utils.py | 3 +- 8 files changed, 61 insertions(+), 27 deletions(-) create mode 100644 builder/data/etc/dphys-swapfile diff --git a/builder/data/etc/dphys-swapfile b/builder/data/etc/dphys-swapfile new file mode 100644 index 00000000..1c908a10 --- /dev/null +++ b/builder/data/etc/dphys-swapfile @@ -0,0 +1,26 @@ +# /etc/dphys-swapfile - user settings for dphys-swapfile package +# author Neil Franklin, last modification 2010.05.05 +# copyright ETH Zuerich Physics Departement +# use under either modified/non-advertising BSD or GPL license + +# this file is sourced with . so full normal sh syntax applies + +# the default settings are added as commented out CONF_*=* lines + + +# where we want the swapfile to be, this is the default +#CONF_SWAPFILE=/var/swap + +# set size to absolute value, leaving empty (default) then uses computed value +# you most likely don't want this, unless you have an special disk situation +CONF_SWAPSIZE=2048 + +# set size to computed value, this times RAM size, dynamically adapts, +# guarantees that there is enough swap without wasting disk space on excess +#CONF_SWAPFACTOR=2 + +# restrict size (computed and absolute!) to maximally this limit +# can be set to empty for no limit, but beware of filled partitions! +# this is/was a (outdated?) 32bit kernel limit (in MBytes), do not overrun it +# but is also sensible on 64bit to prevent filling /var or even / partition +#CONF_MAXSWAP=2048 \ No newline at end of file diff --git a/pwnagotchi/_version.py b/pwnagotchi/_version.py index cb9dc8a9..9a0e3da6 100644 --- a/pwnagotchi/_version.py +++ b/pwnagotchi/_version.py @@ -1 +1 @@ -__version__ = '2.4.2' +__version__ = '2.4.3' diff --git a/pwnagotchi/bettercap.py b/pwnagotchi/bettercap.py index 243e00a6..acb4e673 100644 --- a/pwnagotchi/bettercap.py +++ b/pwnagotchi/bettercap.py @@ -70,7 +70,8 @@ class Client(object): while True: logging.info("[bettercap] creating new websocket...") try: - async with websockets.connect(s, ping_interval=ping_interval, ping_timeout=ping_timeout, max_queue=max_queue) as ws: + async with websockets.connect(s, ping_interval=ping_interval, ping_timeout=ping_timeout, + max_queue=max_queue) as ws: # listener loop while True: try: @@ -78,7 +79,7 @@ class Client(object): try: await consumer(msg) except Exception as ex: - logging.debug("error while parsing event (%s)", ex) + logging.debug("error while parsing event (%s)", ex) except websockets.ConnectionClosedError: try: pong = await ws.ping() diff --git a/pwnagotchi/log.py b/pwnagotchi/log.py index 00cc13b8..5cf120e9 100644 --- a/pwnagotchi/log.py +++ b/pwnagotchi/log.py @@ -17,8 +17,8 @@ LAST_SESSION_FILE = '/root/.pwnagotchi-last-session' class LastSession(object): EPOCH_TOKEN = '[epoch ' - EPOCH_PARSER = re.compile(r'^.+\[epoch (\d+)\] (.+)') - EPOCH_DATA_PARSER = re.compile(r'([a-z_]+)=([^\s]+)') + EPOCH_PARSER = re.compile(r'^.+\[epoch (\d+)] (.+)') + EPOCH_DATA_PARSER = re.compile(r'([a-z_]+)=(\S+)') TRAINING_TOKEN = ' training epoch ' START_TOKEN = 'connecting to http' DEAUTH_TOKEN = 'deauthing ' @@ -46,7 +46,7 @@ class LastSession(object): self.max_reward = -1000 self.avg_reward = 0 self._peer_parser = re.compile( - 'detected unit (.+)@(.+) \(v.+\) on channel \d+ \(([\d\-]+) dBm\) \[sid:(.+) pwnd_tot:(\d+) uptime:(\d+)\]') + 'detected unit (.+)@(.+) \(v.+\) on channel \d+ \(([\d\-]+) dBm\) \[sid:(.+) pwnd_tot:(\d+) uptime:(\d+)]') self.parsed = False def _get_last_saved_session_id(self): @@ -197,7 +197,7 @@ class LastSession(object): lines.reverse() if len(lines) == 0: - lines.append("Initial Session"); + lines.append("Initial Session") ui.on_reading_logs() diff --git a/pwnagotchi/plugins/__init__.py b/pwnagotchi/plugins/__init__.py index 57e86976..f161b9dd 100644 --- a/pwnagotchi/plugins/__init__.py +++ b/pwnagotchi/plugins/__init__.py @@ -1,10 +1,10 @@ -import os -import glob import _thread -import threading -import importlib, importlib.util +import glob +import importlib +import importlib.util import logging - +import os +import threading default_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "default") loaded = {} diff --git a/pwnagotchi/plugins/default/bt-tether.py b/pwnagotchi/plugins/default/bt-tether.py index fa7c867f..547c6473 100644 --- a/pwnagotchi/plugins/default/bt-tether.py +++ b/pwnagotchi/plugins/default/bt-tether.py @@ -473,7 +473,7 @@ class BTTether(plugins.Plugin): devices_to_try = list() connected_priorities = list() - any_device_connected = False # if this is true, last status on screen should be C + any_device_connected = False # if this is true, last status on screen should be C for _, device in self.devices.items(): if device.connected(): @@ -579,7 +579,7 @@ class BTTether(plugins.Plugin): def on_ui_setup(self, ui): with ui._lock: ui.add_element('bluetooth', LabeledValue(color=BLACK, label='BT', value='-', - position=(ui.width() / 2 - 10, 0), + position=(ui.width() / 2 - 5, 0), label_font=fonts.Bold, text_font=fonts.Medium)) def on_ui_update(self, ui): diff --git a/pwnagotchi/plugins/default/internet-connection.py b/pwnagotchi/plugins/default/internet-connection.py index 2678d27f..4f23957a 100644 --- a/pwnagotchi/plugins/default/internet-connection.py +++ b/pwnagotchi/plugins/default/internet-connection.py @@ -3,14 +3,13 @@ import pwnagotchi.ui.components as components import pwnagotchi.ui.view as view import pwnagotchi.ui.fonts as fonts import pwnagotchi.plugins as plugins -import pwnagotchi -import subprocess import socket +import os class InternetConnectionPlugin(plugins.Plugin): __author__ = 'adi1708, edited by jayofelony' - __version__ = '1.1' + __version__ = '1.2' __license__ = 'GPL3' __description__ = 'A plugin that displays the Internet connection status on the pwnagotchi display.' __name__ = 'InternetConnectionPlugin' @@ -21,35 +20,44 @@ class InternetConnectionPlugin(plugins.Plugin): 'pip': ['scapy'] } __defaults__ = { - 'enabled': False, + 'enabled': True, } def on_loaded(self): logging.info("[Internet-Connection] plugin loaded.") def on_ui_setup(self, ui): + if ui.is_waveshare35lcd(): + v_pos = (180, 61) + with ui._lock: + ui.add_element('connection_ip', components.LabeledValue(color=view.BLACK, label='eth0:', value='', + position=v_pos, label_font=fonts.Bold, + text_font=fonts.Small)) with ui._lock: # add a LabeledValue element to the UI with the given label and value # the position and font can also be specified ui.add_element('connection_status', components.LabeledValue(color=view.BLACK, label='WWW', value='-', - position=(ui.width() / 2 - 40, 0), + position=(ui.width() / 2 - 35, 0), label_font=fonts.Bold, text_font=fonts.Medium)) def on_ui_update(self, ui): + if ui.is_wavehare35lcd(): + ip = os.popen('ifconfig eth0 | grep inet | awk \'{print $2}\'').read() + ui.set('connection_ip', ip) # check if there is an active Internet connection try: - # See if we can resolve the host name - tells us if there is - # A DNS listening - host = socket.gethostbyname("1.1.1.1") # Connect to the host - tells us if the host is actually reachable - s = socket.create_connection((host, 80), 2) - s.close() + socket.create_connection(("1.1.1.1", 80), 2).close() ui.set('connection_status', 'C') - except: + except TimeoutError as err: # if the command failed, it means there is no active Internet connection + # we could log the error, but no need really + # logging.error('[Internet-Connection] Socket creation failed: %s' % err) ui.set('connection_status', 'D') def on_unload(self, ui): with ui._lock: logging.info("[Internet-Connection] plugin unloaded") ui.remove_element('connection_status') + if ui.is_waveshare35lcd(): + ui.remove_element('connection_ip') diff --git a/pwnagotchi/utils.py b/pwnagotchi/utils.py index 19084572..f8f38677 100644 --- a/pwnagotchi/utils.py +++ b/pwnagotchi/utils.py @@ -58,8 +58,7 @@ class DottedTomlEncoder(TomlEncoder): if not retstr.endswith('\n\n'): retstr += '\n' else: - retstr += (pre + qsection + " = " + - str(self.dump_value(value)) + '\n') + retstr += (pre + qsection + " = " + str(self.dump_value(value)) + '\n') return retstr, self._dict() From 2080bfc0d57a29603a03e5c6415a3300590df1d0 Mon Sep 17 00:00:00 2001 From: Jeroen Oudshoorn Date: Thu, 21 Sep 2023 21:37:50 +0200 Subject: [PATCH 02/14] Version 2.3.8 Signed-off-by: Jeroen Oudshoorn --- .idea/misc.xml | 2 +- .idea/pwnagotchi.iml | 2 +- pwnagotchi/plugins/default/internet-connection.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index d95f6c4d..6178365c 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/.idea/pwnagotchi.iml b/.idea/pwnagotchi.iml index b258c893..7e680cfc 100644 --- a/.idea/pwnagotchi.iml +++ b/.idea/pwnagotchi.iml @@ -4,7 +4,7 @@ - + diff --git a/pwnagotchi/plugins/default/internet-connection.py b/pwnagotchi/plugins/default/internet-connection.py index 4f23957a..ea4819d7 100644 --- a/pwnagotchi/plugins/default/internet-connection.py +++ b/pwnagotchi/plugins/default/internet-connection.py @@ -28,7 +28,7 @@ class InternetConnectionPlugin(plugins.Plugin): def on_ui_setup(self, ui): if ui.is_waveshare35lcd(): - v_pos = (180, 61) + v_pos = (280, 61) with ui._lock: ui.add_element('connection_ip', components.LabeledValue(color=view.BLACK, label='eth0:', value='', position=v_pos, label_font=fonts.Bold, From 4c3282d20529866e21f29d258e249e9b3e0364ed Mon Sep 17 00:00:00 2001 From: Jeroen Oudshoorn Date: Fri, 22 Sep 2023 07:50:11 +0200 Subject: [PATCH 03/14] Version 2.4.3 Signed-off-by: Jeroen Oudshoorn --- Makefile | 35 +++++++++++++++++++++++++---------- builder/pwnagotchi.yml | 42 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 61 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index 5d0491cb..c6679b65 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,21 @@ -PACKER_VERSION=1.9.4 -PWN_HOSTNAME=pwnagotchi -PWN_VERSION:=$(shell cut -d"'" -f2 < pwnagotchi/_version.py) +PACKER_VERSION := 1.9.4 +PWN_HOSTNAME := pwnagotchi +PWN_VERSION := $(shell cut -d"'" -f2 < pwnagotchi/_version.py) +PWN_RELEASE := pwnagotchi-raspios-lite-$(PWN_VERSION) + +MACHINE_TYPE := $(shell uname -m) +ifneq (,$(filter x86_64,$(MACHINE_TYPE))) +GOARCH := amd64 +else ifneq (,$(filter i686,$(MACHINE_TYPE))) +GOARCH := 386 +else ifneq (,$(filter arm64% aarch64%,$(MACHINE_TYPE))) +GOARCH := arm64 +else ifneq (,$(filter arm%,$(MACHINE_TYPE))) +GOARCH := arm +else +GOARCH := amd64 +$(warning Unable to detect CPU arch from machine type $(MACHINE_TYPE), assuming $(GOARCH)) +endif # The Ansible part of the build can inadvertently change the active hostname of # the build machine while updating the permanent hostname of the build image. @@ -19,9 +34,8 @@ langs: ./scripts/language.sh compile $$(basename $$lang); \ done -install: -PACKER := ~/packer -PACKER_URL := https://releases.hashicorp.com/packer/$(PACKER_VERSION)/packer_$(PACKER_VERSION)_linux_amd64.zip +PACKER := /tmp/pwnagotchi/packer +PACKER_URL := https://releases.hashicorp.com/packer/$(PACKER_VERSION)/packer_$(PACKER_VERSION)_linux_$(GOARCH).zip $(PACKER): mkdir -p $(@D) curl -L "$(PACKER_URL)" -o $(PACKER).zip @@ -38,9 +52,9 @@ $(PWN_RELEASE).img: | $(PACKER) # If the packer or ansible files are updated, rebuild the image. $(PWN_RELEASE).img: $(SDIST) builder/pwnagotchi.json builder/pwnagotchi.yml $(shell find builder/data -type f) - $(PACKER) plugins install github.com/solo-io/arm-image + sudo $(PACKER) plugins install github.com/solo-io/arm-image cd builder && sudo $(UNSHARE) $(PACKER) build -var "pwn_hostname=$(PWN_HOSTNAME)" -var "pwn_version=$(PWN_VERSION)" pwnagotchi.json - sudo chown -R $$USER:$$USER ../builder/output-pwnagotchi + sudo chown -R $$USER:$$USER builder/output-pwnagotchi mv builder/output-pwnagotchi/image $@ # If any of these files are updated, rebuild the checksums. @@ -57,6 +71,7 @@ image: $(PWN_RELEASE).zip clean: - python3 setup.py clean --all - rm -rf dist pwnagotchi.egg-info - - rm -rf $(PACKER) - - rm -rf $(PWN_RELEASE).* + - rm -f $(PACKER) + - rm -f $(PWN_RELEASE).* - sudo rm -rf builder/output-pwnagotchi builder/packer_cache + diff --git a/builder/pwnagotchi.yml b/builder/pwnagotchi.yml index fcdabbe5..66fd5b07 100644 --- a/builder/pwnagotchi.yml +++ b/builder/pwnagotchi.yml @@ -204,7 +204,6 @@ git: repo: https://github.com/DrSchottky/nexmon.git dest: /usr/local/src/nexmon -# version: bfb3fe90c881498d7ee245b38f16722c1de26fa1 register: nexmongit - name: make firmware @@ -234,11 +233,17 @@ replace: "KERNEL_RELEASE" - name: make firmware patch (bcm43436b0) - shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43436b0/9_88_4_65/nexmon/ && make && make install-firmware" + shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43436b0/9_88_4_65/nexmon/ && make" args: executable: /bin/bash chdir: /usr/local/src/nexmon/ + - name: install new firmware (bcm43436b0) + copy: + src: /usr/local/src/nexmon/patches/bcm43436b0/9_88_4_65/nexmon/brcmfmac43436-sdio.bin + dest: /lib/firmware/brcm/brcmfmac43436-sdio.bin + + - name: choose the right kernel version (bcm43430a1) replace: dest: /usr/local/src/nexmon/patches/bcm43430a1/7_45_41_46/nexmon/Makefile @@ -260,11 +265,31 @@ replace: "KERNEL_RELEASE" - name: make firmware patch (bcm43430a1) - shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43430a1/7_45_41_46/nexmon/ && make && make install-firmware" + shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43430a1/7_45_41_46/nexmon/ && make" args: executable: /bin/bash chdir: /usr/local/src/nexmon/ + - name: install new firmware (bcm43430a1) + copy: + src: /usr/local/src/nexmon/patches/bcm43430a1/7_45_41_46/nexmon/brcmfmac43430-sdio.bin + dest: /lib/firmware/brcm/brcmfmac43430-sdio.bin + + - name: Delete the firmware blob to avoid it crashing + file: + state: absent + path: /lib/firmware/brcm/brcmfmac43430-sdio.clm_blob + + - name: Delete the RPiZW firmware blob to avoid it crashing + file: + state: absent + path: /lib/firmware/brcm/brcmfmac43430-sdio.raspberrypi,model-zero-w.clm_blob + + - name: Delete the RPi3 firmware blob to avoid it crashing + file: + state: absent + path: /lib/firmware/brcm/brcmfmac43430-sdio.raspberrypi,3-model-b.clm_blob + - name: choose the right kernel version (bcm43455c0) replace: dest: /usr/local/src/nexmon/patches/bcm43455c0/7_45_206/nexmon/Makefile @@ -286,15 +311,20 @@ replace: "KERNEL_RELEASE" - name: make firmware patch (bcm43455c0) - shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43455c0/7_45_206/nexmon/ && make && make install-firmware" + shell: "source ./setup_env.sh && cd /usr/local/src/nexmon/patches/bcm43455c0/7_45_206/nexmon/ && make" args: executable: /bin/bash chdir: /usr/local/src/nexmon/ + - name: install new firmware (bcm43455c0) + copy: + src: /usr/local/src/nexmon/patches/bcm43455c0/7_45_206/nexmon/brcmfmac43455-sdio.bin + dest: /lib/firmware/brcm/brcmfmac43455-sdio.bin + - name: copy modified driver (everyone but RPiZW) copy: - src: /lib/modules/6.1.21-v8+/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko - dest: /lib/modules/6.1.21-v8+/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko.orig + src: /lib/modules/6.1.21-v8+/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko.xz + dest: /lib/modules/6.1.21-v8+/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko.xz.orig - name: copy modified driver (everyone but RPiZW) copy: From 174f6e72b64e26abaaae6c548a4ba2abca7e04e2 Mon Sep 17 00:00:00 2001 From: Jeroen Oudshoorn Date: Fri, 22 Sep 2023 07:53:15 +0200 Subject: [PATCH 04/14] Version 2.4.3 Signed-off-by: Jeroen Oudshoorn --- pwnagotchi/defaults.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/pwnagotchi/defaults.toml b/pwnagotchi/defaults.toml index 6988ef77..1aed4564 100644 --- a/pwnagotchi/defaults.toml +++ b/pwnagotchi/defaults.toml @@ -40,8 +40,6 @@ main.plugins.pisugar2.enabled = false main.plugins.pisugar2.shutdown = 5 main.plugins.pisugar2.sync_rtc_on_boot = false -main.plugins.internet-connection.enabled = true - main.plugins.grid.enabled = true main.plugins.grid.report = true main.plugins.grid.exclude = [ From 5ca40e04ca62642787148f08f620c0fefb2df1b3 Mon Sep 17 00:00:00 2001 From: Jeroen Oudshoorn Date: Fri, 22 Sep 2023 07:56:06 +0200 Subject: [PATCH 05/14] Version 2.4.3 Signed-off-by: Jeroen Oudshoorn --- .../plugins/default/internet-connection.py | 63 ------------------- 1 file changed, 63 deletions(-) delete mode 100644 pwnagotchi/plugins/default/internet-connection.py diff --git a/pwnagotchi/plugins/default/internet-connection.py b/pwnagotchi/plugins/default/internet-connection.py deleted file mode 100644 index ea4819d7..00000000 --- a/pwnagotchi/plugins/default/internet-connection.py +++ /dev/null @@ -1,63 +0,0 @@ -import logging -import pwnagotchi.ui.components as components -import pwnagotchi.ui.view as view -import pwnagotchi.ui.fonts as fonts -import pwnagotchi.plugins as plugins -import socket -import os - - -class InternetConnectionPlugin(plugins.Plugin): - __author__ = 'adi1708, edited by jayofelony' - __version__ = '1.2' - __license__ = 'GPL3' - __description__ = 'A plugin that displays the Internet connection status on the pwnagotchi display.' - __name__ = 'InternetConnectionPlugin' - __help__ = """ - A plugin that displays the Internet connection status on the pwnagotchi display. - """ - __dependencies__ = { - 'pip': ['scapy'] - } - __defaults__ = { - 'enabled': True, - } - - def on_loaded(self): - logging.info("[Internet-Connection] plugin loaded.") - - def on_ui_setup(self, ui): - if ui.is_waveshare35lcd(): - v_pos = (280, 61) - with ui._lock: - ui.add_element('connection_ip', components.LabeledValue(color=view.BLACK, label='eth0:', value='', - position=v_pos, label_font=fonts.Bold, - text_font=fonts.Small)) - with ui._lock: - # add a LabeledValue element to the UI with the given label and value - # the position and font can also be specified - ui.add_element('connection_status', components.LabeledValue(color=view.BLACK, label='WWW', value='-', - position=(ui.width() / 2 - 35, 0), - label_font=fonts.Bold, text_font=fonts.Medium)) - - def on_ui_update(self, ui): - if ui.is_wavehare35lcd(): - ip = os.popen('ifconfig eth0 | grep inet | awk \'{print $2}\'').read() - ui.set('connection_ip', ip) - # check if there is an active Internet connection - try: - # Connect to the host - tells us if the host is actually reachable - socket.create_connection(("1.1.1.1", 80), 2).close() - ui.set('connection_status', 'C') - except TimeoutError as err: - # if the command failed, it means there is no active Internet connection - # we could log the error, but no need really - # logging.error('[Internet-Connection] Socket creation failed: %s' % err) - ui.set('connection_status', 'D') - - def on_unload(self, ui): - with ui._lock: - logging.info("[Internet-Connection] plugin unloaded") - ui.remove_element('connection_status') - if ui.is_waveshare35lcd(): - ui.remove_element('connection_ip') From 5d1bce918525132dcfc88fa93ce3db7b34b5a89c Mon Sep 17 00:00:00 2001 From: Jeroen Oudshoorn Date: Fri, 22 Sep 2023 07:56:56 +0200 Subject: [PATCH 06/14] Version 2.4.3 Signed-off-by: Jeroen Oudshoorn --- pwnagotchi/defaults.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pwnagotchi/defaults.toml b/pwnagotchi/defaults.toml index 1aed4564..1c6e94b6 100644 --- a/pwnagotchi/defaults.toml +++ b/pwnagotchi/defaults.toml @@ -2,6 +2,7 @@ main.name = "pwnagotchi" main.lang = "en" main.confd = "/etc/pwnagotchi/conf.d/" main.custom_plugin_repos = [ + "https://github.com/jayofelony/pwnagotchi-torch-plugins/archive/master.zip", "https://github.com/evilsocket/pwnagotchi-plugins-contrib/archive/master.zip", "https://github.com/PwnPeter/pwnagotchi-plugins/archive/master.zip", "https://github.com/tisboyo/pwnagotchi-pisugar2-plugin/archive/master.zip", From c1461c0fa5469997bb6cf09c5759aa1890a0481e Mon Sep 17 00:00:00 2001 From: Jeroen Oudshoorn Date: Fri, 22 Sep 2023 07:57:28 +0200 Subject: [PATCH 07/14] Version 2.4.3 Signed-off-by: Jeroen Oudshoorn --- pwnagotchi/defaults.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pwnagotchi/defaults.toml b/pwnagotchi/defaults.toml index 1c6e94b6..ac9f3541 100644 --- a/pwnagotchi/defaults.toml +++ b/pwnagotchi/defaults.toml @@ -4,7 +4,6 @@ main.confd = "/etc/pwnagotchi/conf.d/" main.custom_plugin_repos = [ "https://github.com/jayofelony/pwnagotchi-torch-plugins/archive/master.zip", "https://github.com/evilsocket/pwnagotchi-plugins-contrib/archive/master.zip", - "https://github.com/PwnPeter/pwnagotchi-plugins/archive/master.zip", "https://github.com/tisboyo/pwnagotchi-pisugar2-plugin/archive/master.zip", "https://github.com/nullm0ose/pwnagotchi-plugin-pisugar3/archive/master.zip" ] From 9cf87f8c4511194bbc379802c5958ff44df55cf2 Mon Sep 17 00:00:00 2001 From: Jeroen Oudshoorn Date: Fri, 22 Sep 2023 10:09:03 +0200 Subject: [PATCH 08/14] Version 2.4.3 Signed-off-by: Jeroen Oudshoorn --- builder/pwnagotchi.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/builder/pwnagotchi.json b/builder/pwnagotchi.json index c051a4d5..76a18d5f 100644 --- a/builder/pwnagotchi.json +++ b/builder/pwnagotchi.json @@ -15,8 +15,7 @@ "type": "shell", "inline": [ "uname -a", - "dpkg-architecture", - "mkdir -p /usr/local/src/pwnagotchi" + "dpkg-architecture" ] }, { From 7404638f5fb85e1e4a3093d196356cfe614eb11f Mon Sep 17 00:00:00 2001 From: Jeroen Oudshoorn Date: Fri, 22 Sep 2023 10:25:36 +0200 Subject: [PATCH 09/14] bluetoothsniffer.py: more pythonic Signed-off-by: Jeroen Oudshoorn --- .../plugins/default/bluetoothsniffer.py | 106 ++++++++++-------- pwnagotchi/plugins/default/watchdog.py | 36 ------ 2 files changed, 57 insertions(+), 85 deletions(-) delete mode 100644 pwnagotchi/plugins/default/watchdog.py diff --git a/pwnagotchi/plugins/default/bluetoothsniffer.py b/pwnagotchi/plugins/default/bluetoothsniffer.py index 3657f063..e249b990 100644 --- a/pwnagotchi/plugins/default/bluetoothsniffer.py +++ b/pwnagotchi/plugins/default/bluetoothsniffer.py @@ -12,7 +12,7 @@ from datetime import datetime class BluetoothSniffer(plugins.Plugin): - __author__ = 'diytechtinker' + __author__ = 'diytechtinker, fixed by Jayofelony' __version__ = '0.1.3' __license__ = 'GPL3' __description__ = 'A plugin that sniffs Bluetooth devices and saves their MAC addresses, name and counts to a JSON file' @@ -70,68 +70,76 @@ class BluetoothSniffer(plugins.Plugin): # Method for scanning the nearby bluetooth devices def scan(self, display): - logging.info("[BtS] Scanning for bluetooths...") + logging.info("[BtS] Scanning for bluetooth devices...") current_time = time.time() changed = False + device_class = None # Running the system command hcitool to scan nearby bluetooth devices cmd_inq = "hcitool inq --flush" try: inq_output = subprocess.check_output(cmd_inq.split()) + for line in inq_output.splitlines()[1:]: + fields = line.split() + mac_address = fields[0].decode() + for i in range(len(fields)): + if fields[i].decode() == "class:" and i + 1 < len(fields): + device_class = fields[i + 1].decode() + logging.info("[BtS] Found bluetooth %s", mac_address) + + # Update the count, first_seen, and last_seen time of the device + if mac_address in self.data and len(self.data) > 0: + if 'Unknown' == self.data[mac_address]['name']: + name = self.get_device_name(mac_address) + self.data[mac_address]['name'] = name + self.data[mac_address]['new_info'] = 2 + logging.info("[BtS] Updated bluetooth name: %s", name) + changed = True + + if 'Unknown' == self.data[mac_address]['manufacturer']: + manufacturer = self.get_device_manufacturer(mac_address) + self.data[mac_address]['manufacturer'] = manufacturer + self.data[mac_address]['new_info'] = 2 + logging.info("[BtS] Updated bluetooth manufacturer: %s", manufacturer) + changed = True + + if device_class != self.data[mac_address]['class']: + self.data[mac_address]['class'] = device_class + self.data[mac_address]['new_info'] = 2 + logging.info("[BtS] Updated bluetooth class: %s", device_class) + changed = True + + last_seen_time = int( + datetime.strptime(self.data[mac_address]['last_seen'], '%H:%M:%S %d-%m-%Y').timestamp()) + if current_time - last_seen_time >= self.options['count_interval']: + self.data[mac_address]['count'] += 1 + self.data[mac_address]['last_seen'] = time.strftime('%H:%M:%S %d-%m-%Y', + time.localtime(current_time)) + self.data[mac_address]['new_info'] = 2 + logging.info("[BtS] Updated bluetooth count.") + changed = True + else: + name = self.get_device_name(mac_address) + manufacturer = self.get_device_manufacturer(mac_address) + self.data[mac_address] = {'name': name, 'count': 1, 'class': device_class, + 'manufacturer': manufacturer, + 'first_seen': time.strftime('%H:%M:%S %d-%m-%Y', + time.localtime(current_time)), + 'last_seen': time.strftime('%H:%M:%S %d-%m-%Y', + time.localtime(current_time)), + 'new_info': True} + logging.info("[BtS] Added new bluetooth device %s with MAC: %s", name, mac_address) + changed = True + except subprocess.CalledProcessError as e: logging.error("[BtS] Error running command: %s", e) - for line in inq_output.splitlines()[1:]: - fields = line.split() - mac_address = fields[0].decode() - for i in range(len(fields)): - if fields[i].decode() == "class:" and i+1 < len(fields): - device_class = fields[i+1].decode() - logging.info("[BtS] Found bluetooth %s", mac_address) - - # Update the count, first_seen, and last_seen time of the device - if mac_address in self.data and len(self.data) > 0: - if 'Unknown' == self.data[mac_address]['name']: - name = self.get_device_name(mac_address) - self.data[mac_address]['name'] = name - self.data[mac_address]['new_info'] = 2 - logging.info("[BtS] Updated bluetooth name: %s", name) - changed = True - - if 'Unknown' == self.data[mac_address]['manufacturer']: - manufacturer = self.get_device_manufacturer(mac_address) - self.data[mac_address]['manufacturer'] = manufacturer - self.data[mac_address]['new_info'] = 2 - logging.info("[BtS] Updated bluetooth manufacturer: %s", manufacturer) - changed = True - - if device_class != self.data[mac_address]['class']: - self.data[mac_address]['class'] = device_class - self.data[mac_address]['new_info'] = 2 - logging.info("[BtS] Updated bluetooth class: %s", device_class) - changed = True - - last_seen_time = int(datetime.strptime(self.data[mac_address]['last_seen'], '%H:%M:%S %d-%m-%Y').timestamp()) - if current_time - last_seen_time >= self.options['count_interval']: - self.data[mac_address]['count'] += 1 - self.data[mac_address]['last_seen'] = time.strftime('%H:%M:%S %d-%m-%Y', time.localtime(current_time)) - self.data[mac_address]['new_info'] = 2 - logging.info("[BtS] Updated bluetooth count.") - changed = True - else: - name = self.get_device_name(mac_address) - manufacturer = self.get_device_manufacturer(mac_address) - self.data[mac_address] = {'name': name, 'count': 1, 'class': device_class, 'manufacturer': manufacturer, 'first_seen': time.strftime('%H:%M:%S %d-%m-%Y', time.localtime(current_time)), 'last_seen': time.strftime('%H:%M:%S %d-%m-%Y', time.localtime(current_time)), 'new_info': True} - logging.info("[BtS] Added new bluetooth device %s with MAC: %s", name, mac_address) - changed = True - # Save the updated devices to the JSON file if changed: with open(self.options['devices_file'], 'w') as f: logging.info("[BtS] Saving bluetooths %s into json.", name) json.dump(self.data, f) - display.set('status', 'Bluetooth sniffed and stored!') - display.update(force=True) + display.set('status', 'Bluetooth sniffed and stored!').update(force=True) # Method to get the device name def get_device_name(self, mac_address): @@ -174,4 +182,4 @@ class BluetoothSniffer(plugins.Plugin): return_text = "%s|%s" % (num_devices, num_known) else: return_text = "0|0" - return return_text \ No newline at end of file + return return_text diff --git a/pwnagotchi/plugins/default/watchdog.py b/pwnagotchi/plugins/default/watchdog.py deleted file mode 100644 index 8ebb6b8e..00000000 --- a/pwnagotchi/plugins/default/watchdog.py +++ /dev/null @@ -1,36 +0,0 @@ -import os -import logging -import re -import subprocess -from io import TextIOWrapper -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.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): - # get last 10 lines - last_lines = ''.join(list(TextIOWrapper(subprocess.Popen(['journalctl','-n10','-k', '--since', '-5m'], - stdout=subprocess.PIPE).stdout))[-10:]) - if len(self.pattern.findall(last_lines)) >= 5: - display = agent.view() - display.set('status', 'Blind-Bug detected. Restarting.') - display.update(force=True) - logging.info('[WATCHDOG] Blind-Bug detected. Restarting.') - mode = 'MANU' if agent.mode == 'manual' else 'AUTO' - import pwnagotchi - pwnagotchi.reboot(mode=mode) From adf87583299875cc3a87b8d793c7453180f735b1 Mon Sep 17 00:00:00 2001 From: Jeroen Oudshoorn Date: Fri, 22 Sep 2023 10:47:53 +0200 Subject: [PATCH 10/14] moved BtS to plugins repo, edited defaults.toml Signed-off-by: Jeroen Oudshoorn --- pwnagotchi/defaults.toml | 7 - .../plugins/default/bluetoothsniffer.py | 185 ------------------ 2 files changed, 192 deletions(-) delete mode 100644 pwnagotchi/plugins/default/bluetoothsniffer.py diff --git a/pwnagotchi/defaults.toml b/pwnagotchi/defaults.toml index ac9f3541..ea8fc151 100644 --- a/pwnagotchi/defaults.toml +++ b/pwnagotchi/defaults.toml @@ -57,13 +57,6 @@ main.plugins.gps.enabled = false main.plugins.gps.speed = 19200 main.plugins.gps.device = "/dev/ttyUSB0" -main.plugins.bluetoothsniffer.enabled = false -main.plugins.bluetoothsniffer.timer = 45 # On how may seconds to scan for bluetooth devices -main.plugins.bluetoothsniffer.devices_file = "/root/handshakes/bluetooth_devices.json" # Path to the JSON file with bluetooth devices -main.plugins.bluetoothsniffer.count_interval = 86400 # On how may seconds to update count bluetooth devices -main.plugins.bluetoothsniffer.bt_x_coord = 160 -main.plugins.bluetoothsniffer.bt_y_coord = 66 - main.plugins.webgpsmap.enabled = false main.plugins.onlinehashcrack.enabled = false diff --git a/pwnagotchi/plugins/default/bluetoothsniffer.py b/pwnagotchi/plugins/default/bluetoothsniffer.py deleted file mode 100644 index e249b990..00000000 --- a/pwnagotchi/plugins/default/bluetoothsniffer.py +++ /dev/null @@ -1,185 +0,0 @@ -import logging -import os -import subprocess -import json -import time - -import pwnagotchi.plugins as plugins -import pwnagotchi.ui.fonts as fonts -from pwnagotchi.ui.components import LabeledValue -from pwnagotchi.ui.view import BLACK -from datetime import datetime - - -class BluetoothSniffer(plugins.Plugin): - __author__ = 'diytechtinker, fixed by Jayofelony' - __version__ = '0.1.3' - __license__ = 'GPL3' - __description__ = 'A plugin that sniffs Bluetooth devices and saves their MAC addresses, name and counts to a JSON file' - - def __init__(self): - # Defining the instance variables - self.options = { - 'timer': 45, - 'devices_file': '/root/handshakes/bluetooth_devices.json', - 'count_interval': 86400, - 'bt_x_coord': 160, - 'bt_y_coord': 66 - } - self.data = {} - self.last_scan_time = 0 - - def on_loaded(self): - logging.info("[BtS] bluetoothsniffer plugin loaded.") - logging.info("[BtS] Bluetooth devices file location: %s", self.options['devices_file']) - # Creating the device file path if it does not exist - if not os.path.exists(os.path.dirname(self.options['devices_file'])): - os.makedirs(os.path.dirname(self.options['devices_file'])) - - # Creating the device file if it does not exist - if not os.path.exists(self.options['devices_file']): - with open(self.options['devices_file'], 'w') as f: - json.dump({}, f) - - # Loading the data from the device file - with open(self.options['devices_file'], 'r') as f: - self.data = json.load(f) - - def on_ui_setup(self, ui): - with ui._lock: - ui.add_element('BtS', LabeledValue(color=BLACK, - label='BT SNFD', - value=" ", - position=(int(self.options["bt_x_coord"]), - int(self.options["bt_y_coord"])), - label_font=fonts.Small, - text_font=fonts.Small)) - - def on_unload(self, ui): - with ui._lock: - ui.remove_element('BtS') - - def on_ui_update(self, ui): - current_time = time.time() - # Checking the time elapsed since last scan - if current_time - self.last_scan_time >= self.options['timer']: - self.last_scan_time = current_time - # logging.info("[BtS] Bluetooth sniffed: %s", str(self.bt_sniff_info())) - ui.set('BtS', str(self.bt_sniff_info())) - self.scan(ui) - - # Method for scanning the nearby bluetooth devices - def scan(self, display): - logging.info("[BtS] Scanning for bluetooth devices...") - current_time = time.time() - changed = False - device_class = None - - # Running the system command hcitool to scan nearby bluetooth devices - cmd_inq = "hcitool inq --flush" - try: - inq_output = subprocess.check_output(cmd_inq.split()) - for line in inq_output.splitlines()[1:]: - fields = line.split() - mac_address = fields[0].decode() - for i in range(len(fields)): - if fields[i].decode() == "class:" and i + 1 < len(fields): - device_class = fields[i + 1].decode() - logging.info("[BtS] Found bluetooth %s", mac_address) - - # Update the count, first_seen, and last_seen time of the device - if mac_address in self.data and len(self.data) > 0: - if 'Unknown' == self.data[mac_address]['name']: - name = self.get_device_name(mac_address) - self.data[mac_address]['name'] = name - self.data[mac_address]['new_info'] = 2 - logging.info("[BtS] Updated bluetooth name: %s", name) - changed = True - - if 'Unknown' == self.data[mac_address]['manufacturer']: - manufacturer = self.get_device_manufacturer(mac_address) - self.data[mac_address]['manufacturer'] = manufacturer - self.data[mac_address]['new_info'] = 2 - logging.info("[BtS] Updated bluetooth manufacturer: %s", manufacturer) - changed = True - - if device_class != self.data[mac_address]['class']: - self.data[mac_address]['class'] = device_class - self.data[mac_address]['new_info'] = 2 - logging.info("[BtS] Updated bluetooth class: %s", device_class) - changed = True - - last_seen_time = int( - datetime.strptime(self.data[mac_address]['last_seen'], '%H:%M:%S %d-%m-%Y').timestamp()) - if current_time - last_seen_time >= self.options['count_interval']: - self.data[mac_address]['count'] += 1 - self.data[mac_address]['last_seen'] = time.strftime('%H:%M:%S %d-%m-%Y', - time.localtime(current_time)) - self.data[mac_address]['new_info'] = 2 - logging.info("[BtS] Updated bluetooth count.") - changed = True - else: - name = self.get_device_name(mac_address) - manufacturer = self.get_device_manufacturer(mac_address) - self.data[mac_address] = {'name': name, 'count': 1, 'class': device_class, - 'manufacturer': manufacturer, - 'first_seen': time.strftime('%H:%M:%S %d-%m-%Y', - time.localtime(current_time)), - 'last_seen': time.strftime('%H:%M:%S %d-%m-%Y', - time.localtime(current_time)), - 'new_info': True} - logging.info("[BtS] Added new bluetooth device %s with MAC: %s", name, mac_address) - changed = True - - except subprocess.CalledProcessError as e: - logging.error("[BtS] Error running command: %s", e) - - # Save the updated devices to the JSON file - if changed: - with open(self.options['devices_file'], 'w') as f: - logging.info("[BtS] Saving bluetooths %s into json.", name) - json.dump(self.data, f) - display.set('status', 'Bluetooth sniffed and stored!').update(force=True) - - # Method to get the device name - def get_device_name(self, mac_address): - logging.info("[BtS] Trying to get name for %s", mac_address) - name = 'Unknown' - hcitool_process = subprocess.Popen(["hcitool", "name", mac_address], stdout=subprocess.PIPE) - output, error = hcitool_process.communicate() - if output.decode().strip() != '': - name = output.decode().strip() - logging.info("[BtS] Got name %s for %s", name, mac_address) - return name - - # Method to get the device manufacturer - def get_device_manufacturer(self, mac_address): - manufacturer = 'Unknown' - cmd_info = f"hcitool info {mac_address} | grep 'Manufacturer:' | cut -d ' ' -f 2-" - try: - logging.info("[BtS] Trying to get manufacturer for %s", mac_address) - start_time = time.time() - process = subprocess.Popen(cmd_info, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) - while process.poll() is None: - time.sleep(0.1) - if time.time() - start_time > 7: - logging.info("[BtS] Timeout while trying to get manufacturer for %s", mac_address) - process.kill() - return manufacturer - output, error = process.communicate(timeout=1) - if output.decode().strip() != '': - manufacturer = output.decode().strip() - logging.info("[BtS] Got manufacturer %s for %s", manufacturer, mac_address) - except Exception as e: - logging.info("[BtS] Error while trying to get manufacturer for %s: %s", mac_address, str(e)) - return manufacturer - - def bt_sniff_info(self): - num_devices = len(self.data) - if num_devices > 0: - num_unknown = sum(1 for device in self.data.values() if device['name'] == 'Unknown' or device['manufacturer'] == 'Unknown') - num_known = num_devices - num_unknown - return_text = "%s|%s" % (num_devices, num_known) - else: - return_text = "0|0" - return return_text From 9f251a92e6e95845175222bfe8d3eb8b32f44112 Mon Sep 17 00:00:00 2001 From: Jeroen Oudshoorn Date: Fri, 22 Sep 2023 22:09:26 +0200 Subject: [PATCH 11/14] edit ansible build Signed-off-by: Jeroen Oudshoorn --- builder/pwnagotchi.json | 10 ++++++++- builder/pwnagotchi.yml | 46 +++-------------------------------------- 2 files changed, 12 insertions(+), 44 deletions(-) diff --git a/builder/pwnagotchi.json b/builder/pwnagotchi.json index 76a18d5f..e958dd8b 100644 --- a/builder/pwnagotchi.json +++ b/builder/pwnagotchi.json @@ -15,9 +15,17 @@ "type": "shell", "inline": [ "uname -a", - "dpkg-architecture" + "dpkg-architecture", + "mkdir -p /usr/local/src/pwnagotchi" ] }, + { + "type": "file", + "sources": [ + "../dist/pwnagotchi-{{user `pwn_version`}}.tar.gz" + ], + "destination": "/usr/local/src/pwnagotchi/" + }, { "type": "file", "source": "../builder/data/usr/bin/pwnlib", diff --git a/builder/pwnagotchi.yml b/builder/pwnagotchi.yml index 66fd5b07..7e4558fd 100644 --- a/builder/pwnagotchi.yml +++ b/builder/pwnagotchi.yml @@ -347,50 +347,10 @@ path: /usr/local/share/pwnagotchi/custom-plugins/ state: directory - - name: collect python pip package list - command: "pip3 list" - register: pip_output - - - name: set python pip package facts - set_fact: - pip_packages: > - {{ pip_packages | default({}) | combine( { item.split()[0]: item.split()[1] } ) }} - with_items: "{{ pip_output.stdout_lines }}" - - - name: acquire python3 pip target - command: "python3 -c 'import sys;print(sys.path.pop())'" - register: pip_target - - - name: clone pwnagotchi repository - git: - repo: https://github.com/jayofelony/pwnagotchi.git - dest: /usr/local/src/pwnagotchi - register: pwnagotchigit - - - name: create /usr/local/share/pwnagotchi/ folder - file: - path: /usr/local/share/pwnagotchi/ - state: directory - - - name: fetch pwnagotchi version - set_fact: - pwnagotchi_version: "{{ lookup('file', '/usr/local/src/pwnagotchi/pwnagotchi/_version.py') | regex_replace('.*__version__.*=.*''([0-9]+\\.[0-9]+\\.[0-9]+[A-Za-z0-9]*)''.*', '\\1') }}" - - - name: pwnagotchi version found - debug: - msg: "{{ pwnagotchi_version }}" - - - name: build pwnagotchi wheel - command: "python3 setup.py sdist bdist_wheel" - args: - chdir: /usr/local/src/pwnagotchi - when: (pwnagotchigit.changed) or (pip_packages['pwnagotchi'] is undefined) or (pip_packages['pwnagotchi'] != pwnagotchi_version) - - - name: install pwnagotchi wheel and dependencies + - name: Install pwnagotchi from source archive pip: - name: "{{ lookup('fileglob', '/usr/local/src/pwnagotchi/dist/pwnagotchi*.whl') }}" - extra_args: "--no-cache-dir" - when: (pwnagotchigit.changed) or (pip_packages['pwnagotchi'] is undefined) or (pip_packages['pwnagotchi'] != pwnagotchi_version) + name: /usr/local/src/pwnagotchi/pwnagotchi-{{ pwnagotchi.version }}.tar.gz + extra_args: --verbose --prefer-binary --ignore-installed # Install go-1.20.6 - name: Install go-1.21 From 3435e6ccec679da4a844dac3068b9074882bd560 Mon Sep 17 00:00:00 2001 From: Jeroen Oudshoorn Date: Fri, 22 Sep 2023 22:28:49 +0200 Subject: [PATCH 12/14] edit bettercap.py Signed-off-by: Jeroen Oudshoorn --- pwnagotchi/bettercap.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/pwnagotchi/bettercap.py b/pwnagotchi/bettercap.py index acb4e673..695c20ce 100644 --- a/pwnagotchi/bettercap.py +++ b/pwnagotchi/bettercap.py @@ -79,27 +79,26 @@ class Client(object): try: await consumer(msg) except Exception as ex: - logging.debug("error while parsing event (%s)", ex) + logging.debug("[bettercap] error while parsing event (%s)", ex) except websockets.ConnectionClosedError: try: pong = await ws.ping() await asyncio.wait_for(pong, timeout=ping_timeout) - logging.warning('ping OK, keeping connection alive...') + logging.warning('[bettercap] ping OK, keeping connection alive...') continue except: sleep_time = min_sleep + max_sleep*random.random() - logging.warning('ping error - retrying connection in {} sec'.format(sleep_time)) + logging.warning('[bettercap] ping error - retrying connection in {} sec'.format(sleep_time)) await asyncio.sleep(sleep_time) break except ConnectionRefusedError: sleep_time = min_sleep + max_sleep*random.random() - logging.warning('nobody seems to be listening at the bettercap endpoint...') - logging.warning('retrying connection in {} sec'.format(sleep_time)) + logging.warning('[bettercap] nobody seems to be listening at the bettercap endpoint...') + logging.warning('[bettercap] retrying connection in {} sec'.format(sleep_time)) await asyncio.sleep(sleep_time) continue except OSError: - sleep_time = min_sleep + max_sleep*random.random() - logging.warning('connection to the bettercap endpoint failed...') + logging.warning('[bettercap] connection to the bettercap endpoint failed...') pwnagotchi.reboot() def run(self, command, verbose_errors=True): @@ -108,8 +107,8 @@ class Client(object): r = requests.post("%s/session" % self.url, auth=self.auth, json={'cmd': command}) except requests.exceptions.ConnectionError as e: sleep_time = min_sleep + max_sleep*random.random() - logging.warning("can't run my request... connection to the bettercap endpoint failed...") - logging.warning('retrying run in {} sec'.format(sleep_time)) + logging.warning("[bettercap] can't run my request... connection to the bettercap endpoint failed...") + logging.warning('[bettercap] retrying run in {} sec'.format(sleep_time)) sleep(sleep_time) else: break From bf4aec75f3613583091b05b83539a4cee8cac51b Mon Sep 17 00:00:00 2001 From: Jeroen Oudshoorn Date: Sun, 24 Sep 2023 00:28:55 +0200 Subject: [PATCH 13/14] edit bettercap.py Signed-off-by: Jeroen Oudshoorn --- builder/data/usr/bin/pwnlib | 9 ++++-- builder/pwnagotchi.json | 10 +----- builder/pwnagotchi.yml | 52 ++++++++++++++++++++++++++---- pwnagotchi/grid.py | 5 +-- pwnagotchi/plugins/__init__.py | 3 ++ pwnagotchi/plugins/default/grid.py | 2 +- 6 files changed, 61 insertions(+), 20 deletions(-) diff --git a/builder/data/usr/bin/pwnlib b/builder/data/usr/bin/pwnlib index e439e097..2046ac55 100755 --- a/builder/data/usr/bin/pwnlib +++ b/builder/data/usr/bin/pwnlib @@ -39,12 +39,17 @@ start_monitor_interface() { rfkill unblock all ifconfig wlan0 up iw dev wlan0 set power_save off - airmon-ng start wlan0 + airmon-ng check kill + iw phy "$(iw phy | head -1 | cut -d" " -f2)" interface add wlan0mon type monitor && ifconfig wlan0mon up + + # If wlan0 is NOT taken down after bringing up mon0, then when switching to AUTO you will get: + # error 400: error while initializing wlan0mon to channel 1: iw: out=command failed: Device or resource busy (-16) err=exit status 240 + ifconfig wlan0 down } # stops mon0 stop_monitor_interface() { - airmon-ng stop wlan0mon + ifconfig wlan0mon down && iw dev wlan0mon del ifconfig wlan0 up } diff --git a/builder/pwnagotchi.json b/builder/pwnagotchi.json index e958dd8b..76a18d5f 100644 --- a/builder/pwnagotchi.json +++ b/builder/pwnagotchi.json @@ -15,17 +15,9 @@ "type": "shell", "inline": [ "uname -a", - "dpkg-architecture", - "mkdir -p /usr/local/src/pwnagotchi" + "dpkg-architecture" ] }, - { - "type": "file", - "sources": [ - "../dist/pwnagotchi-{{user `pwn_version`}}.tar.gz" - ], - "destination": "/usr/local/src/pwnagotchi/" - }, { "type": "file", "source": "../builder/data/usr/bin/pwnlib", diff --git a/builder/pwnagotchi.yml b/builder/pwnagotchi.yml index 7e4558fd..efa9f062 100644 --- a/builder/pwnagotchi.yml +++ b/builder/pwnagotchi.yml @@ -347,10 +347,50 @@ path: /usr/local/share/pwnagotchi/custom-plugins/ state: directory - - name: Install pwnagotchi from source archive + - name: collect python pip package list + command: "pip3 list" + register: pip_output + + - name: set python pip package facts + set_fact: + pip_packages: > + {{ pip_packages | default({}) | combine( { item.split()[0]: item.split()[1] } ) }} + with_items: "{{ pip_output.stdout_lines }}" + + - name: acquire python3 pip target + command: "python3 -c 'import sys;print(sys.path.pop())'" + register: pip_target + + - name: clone pwnagotchi repository + git: + repo: https://github.com/jayofelony/pwnagotchi.git + dest: /usr/local/src/pwnagotchi + register: pwnagotchigit + + - name: create /usr/local/share/pwnagotchi/ folder + file: + path: /usr/local/share/pwnagotchi/ + state: directory + + - name: fetch pwnagotchi version + set_fact: + pwnagotchi_version: "{{ lookup('file', '/usr/local/src/pwnagotchi/pwnagotchi/_version.py') | regex_replace('.*__version__.*=.*''([0-9]+\\.[0-9]+\\.[0-9]+[A-Za-z0-9]*)''.*', '\\1') }}" + + - name: pwnagotchi version found + debug: + msg: "{{ pwnagotchi_version }}" + + - name: build pwnagotchi wheel + command: "python3 setup.py sdist bdist_wheel" + args: + chdir: /usr/local/src/pwnagotchi + when: (pwnagotchigit.changed) or (pip_packages['pwnagotchi'] is undefined) or (pip_packages['pwnagotchi'] != pwnagotchi_version) + + - name: install pwnagotchi wheel and dependencies pip: - name: /usr/local/src/pwnagotchi/pwnagotchi-{{ pwnagotchi.version }}.tar.gz - extra_args: --verbose --prefer-binary --ignore-installed + name: "{{ lookup('fileglob', '/usr/local/src/pwnagotchi/dist/pwnagotchi*.whl') }}" + extra_args: "--no-cache-dir" + when: (pwnagotchigit.changed) or (pip_packages['pwnagotchi'] is undefined) or (pip_packages['pwnagotchi'] != pwnagotchi_version) # Install go-1.20.6 - name: Install go-1.21 @@ -372,7 +412,7 @@ - name: download pwngrid git: repo: https://github.com/jayofelony/pwngrid.git - dest: /usr/local/src/ + dest: /usr/local/src/pwngrid register: pwngrid - name: install pwngrid @@ -509,10 +549,10 @@ echo "- sudo pwnagotchi --check-update, to see if there is a new version available" echo echo "If you want to know if I'm running, you can use" - echo "systemctl status pwnagotchi" + echo "sudo systemctl status pwnagotchi" echo echo "You can restart me using" - echo "systemctl restart pwnagotchi" + echo "sudo systemctl restart pwnagotchi" echo echo "You learn more about me at https://pwnagotchi.ai/" when: hostname.changed diff --git a/pwnagotchi/grid.py b/pwnagotchi/grid.py index 78edb804..dab0034f 100644 --- a/pwnagotchi/grid.py +++ b/pwnagotchi/grid.py @@ -60,7 +60,7 @@ def closest_peer(): return all[0] if len(all) else None -def update_data(last_session): +def update_data(last_session, plugin_data): brain = {} try: with open('/root/brain.json') as fp: @@ -84,7 +84,8 @@ def update_data(last_session): 'uname': subprocess.getoutput("uname -a"), 'brain': brain, 'version': pwnagotchi.__version__, - 'build': "Pwnagotchi-Torch by Jayofelony" + 'build': "Pwnagotchi-Torch by Jayofelony", + 'plugins': plugin_data } logging.debug("updating grid data: %s" % data) diff --git a/pwnagotchi/plugins/__init__.py b/pwnagotchi/plugins/__init__.py index f161b9dd..00595e02 100644 --- a/pwnagotchi/plugins/__init__.py +++ b/pwnagotchi/plugins/__init__.py @@ -5,6 +5,7 @@ import importlib.util import logging import os import threading +import pwnagotchi.grid default_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "default") loaded = {} @@ -130,6 +131,8 @@ def load(config): enabled = [name for name, options in config['main']['plugins'].items() if 'enabled' in options and options['enabled']] + pwnagotchi.grid.update_data(None, enabled) + # load default plugins load_from_path(default_path, enabled=enabled) diff --git a/pwnagotchi/plugins/default/grid.py b/pwnagotchi/plugins/default/grid.py index acf80927..f4bf48af 100644 --- a/pwnagotchi/plugins/default/grid.py +++ b/pwnagotchi/plugins/default/grid.py @@ -129,7 +129,7 @@ class Grid(plugins.Plugin): with self.lock: try: - grid.update_data(agent.last_session) + grid.update_data(agent.last_session, None) except Exception as e: logging.error("error connecting to the pwngrid-peer service: %s" % e) logging.debug(e, exc_info=True) From a816c88ce3eb1dfa5a668bcab6075c433229d67f Mon Sep 17 00:00:00 2001 From: Jeroen Oudshoorn Date: Sun, 24 Sep 2023 00:43:14 +0200 Subject: [PATCH 14/14] Enabled plugin stats Signed-off-by: Jeroen Oudshoorn --- builder/pwnagotchi.yml | 17 ++++++++++++----- pwnagotchi/plugins/__init__.py | 2 +- pwnagotchi/plugins/default/grid.py | 1 + 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/builder/pwnagotchi.yml b/builder/pwnagotchi.yml index efa9f062..ec8366c2 100644 --- a/builder/pwnagotchi.yml +++ b/builder/pwnagotchi.yml @@ -409,24 +409,31 @@ export PATH=/usr/local/go/bin:$PATH:$GOPATH/bin when: golang.changed - - name: download pwngrid + - name: download pwngrid 1.10.4 git: repo: https://github.com/jayofelony/pwngrid.git dest: /usr/local/src/pwngrid register: pwngrid - - name: install pwngrid - shell: "export GOPATH=$HOME/go && export PATH=/usr/local/go/bin:$PATH:$GOPATH/bin && make && sudo make install" + - name: install pwngrid 1.10.4 + shell: "export GOPATH=$HOME/go && export PATH=/usr/local/go/bin:$PATH:$GOPATH/bin && sudo make && sudo make install" args: executables: /bin/bash chdir: /usr/local/src/pwngrid when: pwngrid.changed + - name: download bettercap v2.32.1 + git: + repo: https://github.com/jayofelony/bettercap.git + dest: /usr/local/src/bettercap + register: bettercap + - name: Install bettercap v2.32.1 - shell: "export GOPATH=$HOME/go && export PATH=/usr/local/go/bin:$PATH:$GOPATH/bin && go env -w GO111MODULE=off && go get github.com/jayofelony/bettercap && cd $GOPATH/src/github.com/jayofelony/bettercap && make build && make install" + shell: "export GOPATH=$HOME/go && export PATH=/usr/local/go/bin:$PATH:$GOPATH/bin && sudo make && sudo make install" args: executable: /bin/bash - register: bettercap + chdir: /usr/local/src/bettercap + when: bettercap.changed - name: clone bettercap caplets git: diff --git a/pwnagotchi/plugins/__init__.py b/pwnagotchi/plugins/__init__.py index 00595e02..c5d2efd7 100644 --- a/pwnagotchi/plugins/__init__.py +++ b/pwnagotchi/plugins/__init__.py @@ -44,7 +44,7 @@ def toggle_plugin(name, enable=True): global loaded, database if pwnagotchi.config: - if not name in pwnagotchi.config['main']['plugins']: + if name not in pwnagotchi.config['main']['plugins']: pwnagotchi.config['main']['plugins'][name] = dict() pwnagotchi.config['main']['plugins'][name]['enabled'] = enable save_config(pwnagotchi.config, '/etc/pwnagotchi/config.toml') diff --git a/pwnagotchi/plugins/default/grid.py b/pwnagotchi/plugins/default/grid.py index f4bf48af..79259a3a 100644 --- a/pwnagotchi/plugins/default/grid.py +++ b/pwnagotchi/plugins/default/grid.py @@ -5,6 +5,7 @@ import glob import re import pwnagotchi.grid as grid +import pwnagotchi.plugins import pwnagotchi.plugins as plugins from pwnagotchi.utils import StatusFile, WifiInfo, extract_from_pcap from threading import Lock