diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..fec25bfd --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,212 @@ +name: Publish + +on: + workflow_dispatch: + inputs: + version: + description: 'Version number' + required: true + +jobs: + + publish: + runs-on: ubuntu-latest + steps: + + - name: Remove unnecessary directories + run: | + sudo rm -rf /usr/share/dotnet + sudo rm -rf /opt/ghc + sudo rm -rf /usr/local/share/boost + sudo rm -rf "$AGENT_TOOLSDIRECTORY" + + - name: Check disk space + run: df -BG + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Validate tag + id: tag-setter + run: | + TAG=${{ github.event.inputs.version }} + if [[ $TAG =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Tag $TAG is valid." + echo "TAG=$TAG" >> $GITHUB_OUTPUT + else + echo "Tag $TAG is not a valid semantic version. Aborting." + exit 1 + fi + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: 3.9 + + - name: Install dependencies + run: | + sudo apt-get update && sudo apt-get install -y libdbus-1-dev curl unzip gettext qemu-utils qemu qemu-user-static binfmt-support + pip install -r requirements.txt + + - name: Update QEMU + run: | + sudo update-binfmts --enable qemu-aarch64 + echo $(ls /usr/bin/qemu-aarch64-static) + + - name: Restart binfmt-support + run: sudo service binfmt-support restart + + - name: Mount binfmt_misc + run: | + if ! grep -qs '/proc/sys/fs/binfmt_misc ' /proc/mounts; then + echo "Mounting binfmt_misc" + sudo mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc + fi + + - name: Restart binfmt-support + run: sudo service binfmt-support restart + + - name: Update Languages + run: make update_langs + + - name: Compile Languages + run: make compile_langs + + - name: Check disk space + run: df -BG + + - name: Check qemu-user-static package + run: | + echo "Checking qemu-user-static package..." + dpkg -s qemu-user-static && echo "qemu-user-static is installed." || echo "qemu-user-static is NOT installed." + + - name: Check binfmt-support service + run: | + echo "Checking binfmt-support service..." + service binfmt-support status && echo "binfmt-support service is running." || echo "binfmt-support service is NOT running." + + - name: Check binfmt_misc filesystem + run: | + echo "Checking binfmt_misc filesystem..." + mount | grep binfmt_misc && echo "binfmt_misc is mounted." || echo "binfmt_misc is NOT mounted." + echo $(ls /proc/sys/fs/binfmt_misc | grep qemu-aarch64) + + - name: Run Makefile + run: make + env: + PWN_VERSION: ${{ steps.tag-setter.outputs.TAG }} + + - name: PiShrink + run: | + wget https://raw.githubusercontent.com/Drewsif/PiShrink/master/pishrink.sh + chmod +x pishrink.sh + sudo mv pishrink.sh /usr/local/bin + find /home/runner/work/ -type f -name "*.img" -exec sudo pishrink.sh {} \; + + - name: Compress .img files + run: | + find /home/runner/work/ -type f -name "*.img" -exec xz --no-warn {} \; + + - name: Create tag + uses: actions/github-script@v7 + with: + script: | + const version = "${{ steps.tag-setter.outputs.TAG }}" + console.log(`Creating tag ${version}`) + await github.rest.git.createRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: `refs/tags/${version}`, + sha: context.sha + }) + + - name: Create Release + id: create_release + uses: actions/github-script@v7 + with: + script: | + const tag = "${{ steps.tag-setter.outputs.TAG }}" + console.log(`Creating release with tag: ${tag}`) + const release = await github.rest.repos.createRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + tag_name: tag, + name: tag, + draft: false, + prerelease: true, + generate_release_notes: true + }) + console.log(`Created release with id: ${release.data.id}`) + return release.data.id + + - name: Upload Release Asset + id: upload-release-asset + uses: actions/github-script@v7 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + script: | + const fs = require('fs'); + const path = require('path'); + const release_id = "${{ steps.create_release.outputs.result }}"; + const asset_content_type = 'application/octet-stream'; + const distDir = '/home/runner/work/'; + + const uploadFile = async (filePath) => { + if (fs.lstatSync(filePath).isDirectory()) { + const files = fs.readdirSync(filePath); + for (const file of files) { + await uploadFile(path.join(filePath, file)); + } + } else { + // Check if the file has a .xz extension + if (path.extname(filePath) === '.xz') { + console.log(`Uploading ${filePath}...`); + + const asset_name = path.basename(filePath); + const asset_size = fs.statSync(filePath).size; + const asset = fs.createReadStream(filePath); + + const response = await github.rest.repos.uploadReleaseAsset({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: release_id, + name: asset_name, + data: asset, + headers: { + 'content-type': asset_content_type, + 'content-length': asset_size + } + }); + + console.log(`Uploaded ${filePath}: ${response.data.browser_download_url}`); + } + } + } + + await uploadFile(distDir); + + - name: Update Release + uses: actions/github-script@v7 + with: + script: | + const release_id = "${{ steps.create_release.outputs.result }}" + console.log(`Updating release with id: ${release_id}`) + github.rest.repos.updateRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: release_id, + tag_name: "${{ steps.tag-setter.outputs.TAG }}", + name: "${{ steps.tag-setter.outputs.TAG }}", + draft: false, + prerelease: false + }) + + - name: Save environment variable + run: echo "${{ steps.tag-setter.outputs.TAG }}" > env_var.txt + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: env-var + path: env_var.txt \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index ad36a12d..88826ebc 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,7 +3,7 @@ - + diff --git a/.idea/pwnagotchi.iml b/.idea/pwnagotchi.iml index a931bffa..38d1fd89 100644 --- a/.idea/pwnagotchi.iml +++ b/.idea/pwnagotchi.iml @@ -4,7 +4,7 @@ - + diff --git a/Makefile b/Makefile index 3f10ad8d..fd796371 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ PACKER_VERSION := 1.10.0 PWN_HOSTNAME := pwnagotchi -PWN_VERSION := $(shell cut -d"'" -f2 < pwnagotchi/_version.py) +PWN_VERSION := ${PWN_VERSION} MACHINE_TYPE := $(shell uname -m) ifneq (,$(filter x86_64,$(MACHINE_TYPE))) @@ -48,15 +48,11 @@ $(PACKER): rm $(PACKER).zip chmod +x $@ -SDIST := dist/pwnagotchi-$(PWN_VERSION).tar.gz -$(SDIST): setup.py pwnagotchi - python3 setup.py sdist - # Building the image requires packer, but don't rebuild the image just because packer updated. pwnagotchi: | $(PACKER) # If the packer or ansible files are updated, rebuild the image. -pwnagotchi: $(SDIST) builder/pwnagotchi.json.pkr.hcl builder/raspberrypi64.yml $(shell find builder/data -type f) +pwnagotchi: builder/pwnagotchi.json.pkr.hcl builder/raspberrypi64.yml $(shell find builder/data -type f) cd builder && $(PACKER) init pwnagotchi.json.pkr.hcl && sudo $(UNSHARE) $(PACKER) build -var "pwn_hostname=$(PWN_HOSTNAME)" -var "pwn_version=$(PWN_VERSION)" pwnagotchi.json.pkr.hcl @@ -64,5 +60,5 @@ pwnagotchi: $(SDIST) builder/pwnagotchi.json.pkr.hcl builder/raspberrypi64.yml $ image: pwnagotchi clean: - - rm -rf build dist pwnagotchi.egg-info - - rm -f $(PACKER) + - rm -rf dist pwnagotchi.egg-info + - rm -f $(PACKER) \ No newline at end of file diff --git a/README.md b/README.md index 9ffd1deb..aa005160 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,9 @@ Release
**This fork of [Pwnagotchi](https://www.pwnagotchi.ai) is only for 64-bit Raspberry Pi's. Such as the 02W, 3(b+) and 4(b) and the new Raspberry Pi 5!!.** +The RPi5 can only be used headless currently. (without display.) + + If you are using an older 32-bit version Raspberry Pi, ZeroWH, use this [fork](https://github.com/jayofelony/pwnagotchi-torch/releases/tag/v2.6.4) and make sure you download the `armhf` version. --- diff --git a/builder/pwnagotchi.json.pkr.hcl b/builder/pwnagotchi.json.pkr.hcl index c08ff651..363e7f0c 100644 --- a/builder/pwnagotchi.json.pkr.hcl +++ b/builder/pwnagotchi.json.pkr.hcl @@ -1,11 +1,9 @@ -# This is not working quite yet -# https://github.com/mkaczanowski/packer-builder-arm/pull/172 packer { required_plugins { - #arm = { - # version = "~> 1" - # source = "github.com/cdecoux/builder-arm" - #} + arm = { + version = "1.0.0" + source = "github.com/cdecoux/builder-arm" + } ansible = { source = "github.com/hashicorp/ansible" version = "~> 1" @@ -28,8 +26,8 @@ source "arm" "rpi64-pwnagotchi" { file_target_extension = "xz" file_unarchive_cmd = ["unxz", "$ARCHIVE_PATH"] image_path = "../../../pwnagotchi-rpi-bookworm-${var.pwn_version}-arm64.img" - qemu_binary_source_path = "/usr/bin/qemu-aarch64-static" - qemu_binary_destination_path = "/usr/bin/qemu-aarch64-static" + qemu_binary_source_path = "/usr/libexec/qemu-binfmt/aarch64-binfmt-P" + qemu_binary_destination_path = "/usr/libexec/qemu-binfmt/aarch64-binfmt-P" image_build_method = "resize" image_size = "9G" image_type = "dos" @@ -51,6 +49,8 @@ source "arm" "rpi64-pwnagotchi" { } } + + # a build block invokes sources and runs provisioning steps on them. The # documentation for build blocks can be found here: # https://www.packer.io/docs/from-1.5/blocks/build @@ -86,7 +86,6 @@ build { "data/etc/systemd/system/pwngrid-peer.service", ] } - provisioner "file" { destination = "/etc/update-motd.d/01-motd" source = "data/etc/update-motd.d/01-motd" @@ -95,11 +94,7 @@ build { inline = ["chmod +x /etc/update-motd.d/*"] } provisioner "shell" { - inline = [ - "apt-get -y --allow-releaseinfo-change update", - "apt-get -y dist-upgrade", - "apt-get install -y --no-install-recommends ansible" - ] + inline = ["apt-get -y --allow-releaseinfo-change update", "apt-get -y dist-upgrade", "apt-get install -y --no-install-recommends ansible"] } provisioner "ansible-local" { command = "ANSIBLE_FORCE_COLOR=1 PYTHONUNBUFFERED=1 PWN_VERSION=${var.pwn_version} PWN_HOSTNAME=${var.pwn_hostname} ansible-playbook" diff --git a/builder/raspberrypi64.yml b/builder/raspberrypi64.yml index ec2115b6..6b7e8973 100644 --- a/builder/raspberrypi64.yml +++ b/builder/raspberrypi64.yml @@ -40,11 +40,11 @@ source: "https://github.com/jayofelony/caplets.git" bettercap: source: "https://github.com/jayofelony/bettercap.git" - url: "https://github.com/jayofelony/bettercap/releases/download/2.32.2/bettercap-2.32.2.zip" + url: "https://github.com/jayofelony/bettercap/releases/download/v2.32.4/bettercap-2.32.4-aarch64.zip" ui: "https://github.com/bettercap/ui/releases/download/v1.3.0/ui.zip" pwngrid: source: "https://github.com/jayofelony/pwngrid.git" - url: "https://github.com/jayofelony/pwngrid/releases/download/v1.10.5/pwngrid-1.10.5-aarch64.zip" + url: "https://github.com/jayofelony/pwngrid/releases/download/v1.11.0/pwngrid-1.11.0-aarch64.zip" apt: downgrade: - libpcap-dev_1.9.1-4_arm64.deb @@ -174,7 +174,10 @@ - xxd - zlib1g-dev - zram-tools - + environment: + ARCHFLAGS: "-arch aarch64" + QEMU_UNAME: "{{ kernel.full }}" + tasks: # First we install packages - name: install packages diff --git a/pwnagotchi/_version.py b/pwnagotchi/_version.py index 80e22f7a..964a32ab 100644 --- a/pwnagotchi/_version.py +++ b/pwnagotchi/_version.py @@ -1 +1 @@ -__version__ = '2.8.1' +__version__ = '2.8.2' diff --git a/pwnagotchi/plugins/default/gps.py b/pwnagotchi/plugins/default/gps.py index a351406b..0e5f958d 100644 --- a/pwnagotchi/plugins/default/gps.py +++ b/pwnagotchi/plugins/default/gps.py @@ -48,7 +48,7 @@ class GPS(plugins.Plugin): if self.running: info = agent.session() self.coordinates = info["gps"] - gps_filename = filename.replace(".pcap", ".gps.json") + gps_filename = filename.replace(".pcapng", ".gps.json") if self.coordinates and all([ # avoid 0.000... measurements diff --git a/pwnagotchi/plugins/default/grid.py b/pwnagotchi/plugins/default/grid.py index cdca794e..fbc3374e 100644 --- a/pwnagotchi/plugins/default/grid.py +++ b/pwnagotchi/plugins/default/grid.py @@ -5,22 +5,21 @@ 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 pwnagotchi.utils import StatusFile, WifiInfo, extract_from_pcapng from threading import Lock def parse_pcap(filename): logging.info("grid: parsing %s ..." % filename) - net_id = os.path.basename(filename).replace('.pcap', '') + net_id = os.path.basename(filename).replace('.pcapng', '') if '_' in net_id: - # /root/handshakes/ESSID_BSSID.pcap + # /root/handshakes/ESSID_BSSID.pcapng essid, bssid = net_id.split('_') else: - # /root/handshakes/BSSID.pcap + # /root/handshakes/BSSID.pcapng essid, bssid = '', net_id mac_re = re.compile('[0-9a-fA-F]{12}') @@ -36,7 +35,7 @@ def parse_pcap(filename): } try: - info = extract_from_pcap(filename, [WifiInfo.BSSID, WifiInfo.ESSID]) + info = extract_from_pcapng(filename, [WifiInfo.BSSID, WifiInfo.ESSID]) except Exception as e: logging.error("grid: %s" % e) @@ -87,10 +86,10 @@ class Grid(plugins.Plugin): agent.view().on_unread_messages(self.unread_messages, self.total_messages) def check_handshakes(self, agent): - logging.debug("checking pcaps") + logging.debug("checking pcapng's") config = agent.config() - pcap_files = glob.glob(os.path.join(agent.config()['bettercap']['handshakes'], "*.pcap")) + pcap_files = glob.glob(os.path.join(agent.config()['bettercap']['handshakes'], "*.pcapng")) num_networks = len(pcap_files) reported = self.report.data_field_or('reported', default=[]) num_reported = len(reported) @@ -103,7 +102,7 @@ class Grid(plugins.Plugin): logging.debug(" exclude: %s" % config['main']['whitelist']) for pcap_file in pcap_files: - net_id = os.path.basename(pcap_file).replace('.pcap', '') + net_id = os.path.basename(pcap_file).replace('.pcapng', '') if net_id not in reported: if self.is_excluded(net_id, agent): logging.debug("skipping %s due to exclusion filter" % pcap_file) diff --git a/pwnagotchi/plugins/default/hashie.py b/pwnagotchi/plugins/default/hashie.py index cd41122b..b5c8e18a 100644 --- a/pwnagotchi/plugins/default/hashie.py +++ b/pwnagotchi/plugins/default/hashie.py @@ -82,12 +82,12 @@ class Hashie(plugins.Plugin): if os.path.isfile(fullpathNoExt + '.22000'): handshake_status.append('Already have {}.22000 (EAPOL)'.format(name)) elif self._writeEAPOL(filename): - handshake_status.append('Created {}.22000 (EAPOL) from pcap'.format(name)) + handshake_status.append('Created {}.22000 (EAPOL) from pcapng'.format(name)) if os.path.isfile(fullpathNoExt + '.16800'): handshake_status.append('Already have {}.16800 (PMKID)'.format(name)) elif self._writePMKID(filename): - handshake_status.append('Created {}.16800 (PMKID) from pcap'.format(name)) + handshake_status.append('Created {}.16800 (PMKID) from pcapng'.format(name)) if handshake_status: logging.info('[Hashie] Good news:\n\t' + '\n\t'.join(handshake_status)) @@ -111,7 +111,7 @@ class Hashie(plugins.Plugin): return False def _process_stale_pcaps(self, handshake_dir): - handshakes_list = [os.path.join(handshake_dir, filename) for filename in os.listdir(handshake_dir) if filename.endswith('.pcap')] + handshakes_list = [os.path.join(handshake_dir, filename) for filename in os.listdir(handshake_dir) if filename.endswith('.pcapng')] failed_jobs = [] successful_jobs = [] lonely_pcaps = [] diff --git a/pwnagotchi/plugins/default/net-pos.py b/pwnagotchi/plugins/default/net-pos.py index 3f226204..ef5f0c59 100644 --- a/pwnagotchi/plugins/default/net-pos.py +++ b/pwnagotchi/plugins/default/net-pos.py @@ -108,7 +108,7 @@ class NetPos(plugins.Plugin): return netpos["ts"] = int("%.0f" % time.time()) - netpos_filename = filename.replace('.pcap', '.net-pos.json') + netpos_filename = filename.replace('.pcapng', '.net-pos.json') logging.debug("NET-POS: Saving net-location to %s", netpos_filename) try: diff --git a/pwnagotchi/plugins/default/onlinehashcrack.py b/pwnagotchi/plugins/default/onlinehashcrack.py index aeb01dda..1eafb9fa 100644 --- a/pwnagotchi/plugins/default/onlinehashcrack.py +++ b/pwnagotchi/plugins/default/onlinehashcrack.py @@ -142,6 +142,6 @@ class OnlineHashCrack(plugins.Plugin): for row in csv.DictReader(cracked_list): if row['password']: filename = re.sub(r'[^a-zA-Z0-9]', '', row['ESSID']) + '_' + row['BSSID'].replace(':','') - if os.path.exists( os.path.join(handshake_dir, filename+'.pcap') ): - with open(os.path.join(handshake_dir, filename+'.pcap.cracked'), 'w') as f: + if os.path.exists( os.path.join(handshake_dir, filename+'.pcapng')): + with open(os.path.join(handshake_dir, filename+'.pcapng.cracked'), 'w') as f: f.write(row['password']) diff --git a/pwnagotchi/plugins/default/webgpsmap.py b/pwnagotchi/plugins/default/webgpsmap.py index f9f513d9..b03fef50 100644 --- a/pwnagotchi/plugins/default/webgpsmap.py +++ b/pwnagotchi/plugins/default/webgpsmap.py @@ -13,8 +13,8 @@ from dateutil.parser import parse webgpsmap shows existing position data stored in your /handshakes/ directory the plugin does the following: - - search for *.pcap files in your /handshakes/ dir - - for every found .pcap file it looks for a .geo.json or .gps.json or .paw-gps.json file with + - search for *.pcapng files in your /handshakes/ dir + - for every found .pcapng file it looks for a .geo.json or .gps.json or file with latitude+longitude data inside and shows this position on the map - if also an .cracked file with a plaintext password inside exist, it reads the content and shows the position as green instead of red and the password inside the infopox of the position @@ -87,7 +87,8 @@ class Webgpsmap(plugins.Plugin): # returns all positions try: self.ALREADY_SENT = list() - response_data = bytes(json.dumps(self.load_gps_from_dir(self.config['bettercap']['handshakes'])), "utf-8") + response_data = bytes( + json.dumps(self.load_gps_from_dir(self.config['bettercap']['handshakes'])), "utf-8") response_status = 200 response_mimetype = "application/json" response_header_contenttype = 'application/json' @@ -100,7 +101,8 @@ class Webgpsmap(plugins.Plugin): self.ALREADY_SENT = list() json_data = json.dumps(self.load_gps_from_dir(self.config['bettercap']['handshakes'])) html_data = self.get_html() - html_data = html_data.replace('var positions = [];', 'var positions = ' + json_data + ';positionsLoaded=true;drawPositions();') + html_data = html_data.replace('var positions = [];', + 'var positions = ' + json_data + ';positionsLoaded=true;drawPositions();') response_data = bytes(html_data, "utf-8") response_status = 200 response_mimetype = "application/xhtml+xml" @@ -163,7 +165,8 @@ class Webgpsmap(plugins.Plugin): all_files = os.listdir(handshake_dir) # print(all_files) - all_pcap_files = [os.path.join(handshake_dir, filename) for filename in all_files if filename.endswith('.pcap')] + all_pcap_files = [os.path.join(handshake_dir, filename) for filename in all_files if + filename.endswith('.pcapng')] all_geo_or_gps_files = [] for filename_pcap in all_pcap_files: filename_base = filename_pcap[:-5] # remove ".pcap" @@ -180,22 +183,18 @@ class Webgpsmap(plugins.Plugin): if check_for in all_files: filename_position = str(os.path.join(handshake_dir, check_for)) - logging.debug("[webgpsmap] search for .paw-gps.json") - check_for = os.path.basename(filename_base) + ".paw-gps.json" - if check_for in all_files: - filename_position = str(os.path.join(handshake_dir, check_for)) - logging.debug(f"[webgpsmap] end search for position data files and use {filename_position}") if filename_position is not None: all_geo_or_gps_files.append(filename_position) - # all_geo_or_gps_files = set(all_geo_or_gps_files) - set(SKIP) # remove skipped networks? No! + # all_geo_or_gps_files = set(all_geo_or_gps_files) - set(SKIP) # remove skipped networks? No! if newest_only: all_geo_or_gps_files = set(all_geo_or_gps_files) - set(self.ALREADY_SENT) - logging.info(f"[webgpsmap] Found {len(all_geo_or_gps_files)} position-data files from {len(all_pcap_files)} handshakes. Fetching positions ...") + logging.info( + f"[webgpsmap] Found {len(all_geo_or_gps_files)} position-data files from {len(all_pcap_files)} handshakes. Fetching positions ...") for pos_file in all_geo_or_gps_files: try: @@ -213,9 +212,7 @@ class Webgpsmap(plugins.Plugin): pos_type = 'gps' elif pos.type() == PositionFile.GEO: pos_type = 'geo' - elif pos.type() == PositionFile.PAWGPS: - pos_type = 'paw' - gps_data[ssid+"_"+mac] = { + gps_data[ssid + "_" + mac] = { 'ssid': ssid, 'mac': mac, 'type': pos_type, @@ -224,10 +221,10 @@ class Webgpsmap(plugins.Plugin): 'acc': pos.accuracy(), 'ts_first': pos.timestamp_first(), 'ts_last': pos.timestamp_last(), - } + } # get ap password if exist - check_for = os.path.basename(pos_file).split(".")[0] + ".pcap.cracked" + check_for = os.path.basename(pos_file).split(".")[0] + ".pcapng.cracked" if check_for in all_files: gps_data[ssid + "_" + mac]["pass"] = pos.password() @@ -265,7 +262,6 @@ class PositionFile: """ GPS = 1 GEO = 2 - PAWGPS = 3 def __init__(self, path): self._file = path @@ -282,7 +278,7 @@ class PositionFile: """ Returns the mac from filename """ - parsed_mac = re.search(r'.*_?([a-zA-Z0-9]{12})\.(?:gps|geo|paw-gps)\.json', self._filename) + parsed_mac = re.search(r'.*_?([a-zA-Z0-9]{12})\.(?:gps|geo)\.json', self._filename) if parsed_mac: mac = parsed_mac.groups()[0] return mac @@ -292,7 +288,7 @@ class PositionFile: """ Returns the ssid from filename """ - parsed_ssid = re.search(r'(.+)_[a-zA-Z0-9]{12}\.(?:gps|geo|paw-gps)\.json', self._filename) + parsed_ssid = re.search(r'(.+)_[a-zA-Z0-9]{12}\.(?:gps|geo)\.json', self._filename) if parsed_ssid: return parsed_ssid.groups()[0] return None @@ -333,7 +329,7 @@ class PositionFile: return_pass = None # 2do: make better filename split/remove extension because this one has problems with "." in path base_filename, ext1, ext2 = re.split('\.', self._file) - password_file_path = base_filename + ".pcap.cracked" + password_file_path = base_filename + ".pcapng.cracked" if os.path.isfile(password_file_path): try: password_file = open(password_file_path, 'r') @@ -354,8 +350,6 @@ class PositionFile: return PositionFile.GPS if self._file.endswith('.geo.json'): return PositionFile.GEO - if self._file.endswith('.paw-gps.json'): - return PositionFile.PAWGPS return None def lat(self): @@ -402,9 +396,7 @@ class PositionFile: def accuracy(self): if self.type() == PositionFile.GPS: - return 50.0 # a default - if self.type() == PositionFile.PAWGPS: - return 50.0 # a default + return 50.0 # a default if self.type() == PositionFile.GEO: try: return self._json['accuracy'] diff --git a/pwnagotchi/plugins/default/wigle.py b/pwnagotchi/plugins/default/wigle.py index 353660ea..11805c3b 100644 --- a/pwnagotchi/plugins/default/wigle.py +++ b/pwnagotchi/plugins/default/wigle.py @@ -7,7 +7,7 @@ import pwnagotchi from io import StringIO from datetime import datetime -from pwnagotchi.utils import WifiInfo, FieldNotFoundError, extract_from_pcap, StatusFile, remove_whitelisted +from pwnagotchi.utils import WifiInfo, FieldNotFoundError, extract_from_pcapng, StatusFile, remove_whitelisted from threading import Lock from pwnagotchi import plugins from pwnagotchi._version import __version__ as __pwnagotchi_version__ @@ -153,11 +153,11 @@ class Wigle(plugins.Plugin): no_err_entries = list() for gps_file in new_gps_files: if gps_file.endswith('.gps.json'): - pcap_filename = gps_file.replace('.gps.json', '.pcap') + pcap_filename = gps_file.replace('.gps.json', '.pcapng') if gps_file.endswith('.geo.json'): - pcap_filename = gps_file.replace('.geo.json', '.pcap') + pcap_filename = gps_file.replace('.geo.json', '.pcapng') if not os.path.exists(pcap_filename): - logging.debug("WIGLE: Can't find pcap for %s", gps_file) + logging.debug("WIGLE: Can't find pcapng for %s", gps_file) self.skip.append(gps_file) continue try: @@ -175,7 +175,7 @@ class Wigle(plugins.Plugin): self.skip.append(gps_file) continue try: - pcap_data = extract_from_pcap(pcap_filename, [WifiInfo.BSSID, + pcap_data = extract_from_pcapng(pcap_filename, [WifiInfo.BSSID, WifiInfo.ESSID, WifiInfo.ENCRYPTION, WifiInfo.CHANNEL, diff --git a/pwnagotchi/plugins/default/wpa-sec.py b/pwnagotchi/plugins/default/wpa-sec.py index 696b53b4..42f1c29f 100644 --- a/pwnagotchi/plugins/default/wpa-sec.py +++ b/pwnagotchi/plugins/default/wpa-sec.py @@ -98,7 +98,7 @@ class WpaSec(plugins.Plugin): reported = self.report.data_field_or('reported', default=list()) handshake_dir = config['bettercap']['handshakes'] handshake_filenames = os.listdir(handshake_dir) - handshake_paths = [os.path.join(handshake_dir, filename) for filename in handshake_filenames if filename.endswith('.pcap')] + handshake_paths = [os.path.join(handshake_dir, filename) for filename in handshake_filenames if filename.endswith('.pcapng')] handshake_paths = remove_whitelisted(handshake_paths, config['main']['whitelist']) handshake_new = set(handshake_paths) - set(reported) - set(self.skip) diff --git a/pwnagotchi/ui/hw/waveshare3in52.py b/pwnagotchi/ui/hw/waveshare3in52.py index b2252a0b..3489728a 100644 --- a/pwnagotchi/ui/hw/waveshare3in52.py +++ b/pwnagotchi/ui/hw/waveshare3in52.py @@ -9,36 +9,39 @@ class Waveshare3in52(DisplayImpl): super(Waveshare3in52, self).__init__(config, 'waveshare3in52') def layout(self): - fonts.setup(10, 8, 10, 18, 25, 9) - self._layout['width'] = 240 - self._layout['height'] = 360 - self._layout['face'] = (0, 43) - self._layout['name'] = (0, 14) - self._layout['channel'] = (0, 0) - self._layout['aps'] = (0, 71) - self._layout['uptime'] = (0, 25) - self._layout['line1'] = [0, 12, 240, 12] - self._layout['line2'] = [0, 116, 240, 116] - self._layout['friend_face'] = (12, 88) - self._layout['friend_name'] = (1, 103) - self._layout['shakes'] = (26, 117) - self._layout['mode'] = (0, 117) + fonts.setup(16, 14, 16, 100, 31, 15) + self._layout['width'] = 360 + self._layout['height'] = 240 + self._layout['face'] = (0, 40) + self._layout['name'] = (0, 0) + self._layout['channel'] = (300, 0) + self._layout['aps'] = (0, 220) + self._layout['uptime'] = (120, 0) + self._layout['line1'] = [0, 24, 360, 24] + self._layout['line2'] = [0, 220, 360, 220] + self._layout['friend_face'] = (0, 195) + self._layout['friend_name'] = (0, 185) + self._layout['shakes'] = (100, 220) + self._layout['mode'] = (0,200) self._layout['status'] = { - 'pos': (65, 26), + 'pos': (3, 170), 'font': fonts.status_font(fonts.Small), - 'max': 12 + 'max': 100 } return self._layout def initialize(self): - logging.info("initializing waveshare 3.52 inch lcd display") + logging.info("initializing waveshare 3.52 inch display") from pwnagotchi.ui.hw.libs.waveshare.v3in52.epd3in52 import EPD self._display = EPD() self._display.init() self._display.Clear() def render(self, canvas): - self._display.display(canvas) + buf = self._display.getbuffer(canvas) + self._display.display(buf) + self._display.refresh() + def clear(self): self._display.Clear() diff --git a/pwnagotchi/utils.py b/pwnagotchi/utils.py index 4158f94b..eacf8899 100644 --- a/pwnagotchi/utils.py +++ b/pwnagotchi/utils.py @@ -82,7 +82,7 @@ def remove_whitelisted(list_of_handshakes, list_of_whitelisted_strings, valid_on for handshake in list_of_handshakes: try: - normalized_handshake = normalize(os.path.basename(handshake).rstrip('.pcap')) + normalized_handshake = normalize(os.path.basename(handshake).rstrip('.pcapng')) for whitelist in list_of_whitelisted_strings: normalized_whitelist = normalize(whitelist) if normalized_whitelist in normalized_handshake: @@ -440,7 +440,7 @@ def secs_to_hhmmss(secs): def total_unique_handshakes(path): - expr = os.path.join(path, "*.pcap") + expr = os.path.join(path, "*.pcapng") return len(glob.glob(expr)) @@ -498,11 +498,11 @@ def md5(fname): return hash_md5.hexdigest() -def extract_from_pcap(path, fields): +def extract_from_pcapng(path, fields): """ - Search in pcap-file for specified information + Search in pcapng-file for specified information - path: Path to pcap file + path: Path to pcapng file fields: Array of fields that should be extracted If a field is not found, FieldNotFoundError is raised