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/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/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/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 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" ] }, { diff --git a/builder/pwnagotchi.yml b/builder/pwnagotchi.yml index fcdabbe5..ec8366c2 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: @@ -379,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/ + 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: @@ -519,10 +556,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/_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..695c20ce 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,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): @@ -107,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 diff --git a/pwnagotchi/defaults.toml b/pwnagotchi/defaults.toml index 6988ef77..ea8fc151 100644 --- a/pwnagotchi/defaults.toml +++ b/pwnagotchi/defaults.toml @@ -2,8 +2,8 @@ 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", "https://github.com/nullm0ose/pwnagotchi-plugin-pisugar3/archive/master.zip" ] @@ -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 = [ @@ -59,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/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/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..c5d2efd7 100644 --- a/pwnagotchi/plugins/__init__.py +++ b/pwnagotchi/plugins/__init__.py @@ -1,10 +1,11 @@ -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 +import pwnagotchi.grid default_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "default") loaded = {} @@ -43,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') @@ -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/bluetoothsniffer.py b/pwnagotchi/plugins/default/bluetoothsniffer.py deleted file mode 100644 index 3657f063..00000000 --- a/pwnagotchi/plugins/default/bluetoothsniffer.py +++ /dev/null @@ -1,177 +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' - __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 bluetooths...") - current_time = time.time() - changed = False - - # Running the system command hcitool to scan nearby bluetooth devices - cmd_inq = "hcitool inq --flush" - try: - inq_output = subprocess.check_output(cmd_inq.split()) - 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) - - # 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 \ No newline at end of file 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/grid.py b/pwnagotchi/plugins/default/grid.py index acf80927..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 @@ -129,7 +130,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) 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) 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()