Содержание

Воскрешение Pwnagotchi после года в ящике

Автоматический перевод

Эта статья переведена автоматически с английский на русский. Оригинал доступен на английский.

Мой pwnagotchi пролежал в ящике год с мёртвой батареей и устаревшей прошивкой. E-ink дисплей застыл на полуулыбке. Пора это исправить.

Pwnagotchi за 30 секунд

Pwnagotchi — это ИИ, работающий на Raspberry Pi, который перехватывает WPA handshake’и от ближайших WiFi-сетей. Он использует обучение с подкреплением (A2C), чтобы со временем лучше выбирать цели. Построен поверх bettercap, имеет маленький e-ink дисплей с мордочкой тамагочи и работает полностью автономно от батареи. Кладёшь его в рюкзак, гуляешь — и он делает своё дело.

Железо

КомпонентДетали
ПлатаRaspberry Pi Zero 2 W
ДисплейWaveshare 2.13" V4 e-ink (250x122)
RTCDS3231 на I2C, с батарейкой
БатареяWaveshare UPS HAT (C)
GPSVK-172 USB-донгл (u-blox 7)

Всё собрано в стопку через 40-пиновый GPIO header passthrough. Свободных GPIO-пинов не осталось, что убило план использовать UART GPS-модуль — пришлось переходить на USB-донгл.

Софт

Работает Pwnagotchi 2.8.9 из форка jayofelony на Debian 12 bookworm. Ядро зафиксировано на 6.6.20.

Почему зафиксировано? Потому что стоковое ядро поставляется с драйвером brcmfmac размером 138 КБ, который не поддерживает режим монитора. Пропатченный — 582 КБ. Я узнал это весёлым способом — запустил apt upgrade, увидел как драйвер заменился, и провёл час в раздумьях, почему ничего не работает.

Никогда не запускайте apt upgrade на этой штуке. Плагин автообновления тоже отключён.

Примечание: PEP 668 в Debian 12 означает, что нельзя сделать pip install без --break-system-packages. Pwnagotchi 2.9.x требует полную перепрошивку на Trixie, а не простое обновление. Так что остаёмся на 2.8.9.

Что сломалось и как я это починил

RTC не загружается при старте. Потратил на это непозволительно много времени. Overlay DS3231 был в секции [pi5] файла config.txt. Pi Zero 2W требует его в [all]. Два символа разницы, час отладки. Из тех вещей, которые заставляют задуматься о жизненных выборах.

hwclock.service замаскирован. Стандартный systemd-сервис синхронизации аппаратных часов замаскирован в этом образе. Без объяснений. Написал кастомный сервис, который записывает системное время в RTC при выключении:

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/true
ExecStop=/sbin/hwclock -w

DNS через VPN. Мой Mac маршрутизирует трафик через корпоративный VPN, и стандартный NAT с UDP-форвардингом просто умирает на utun-интерфейсах. Ни ошибок, ни логов — просто тишина. Решение — запустить dnsmasq на стороне Mac как локальный DNS-прокси:

sudo dnsmasq --no-daemon --listen-address="$MAC_IP" --bind-interfaces \
    --no-resolv --server="$DNS_SERVER" --log-queries

Разбирался с этим дольше, чем хотелось бы признать.

Что он захватывает

Устройство работает от батареи, автономно. ИИ управляет переключением каналов и решает, когда делать deauth или ассоциироваться с ближайшими точками доступа. Перехваченные handshake’и отправляются на:

  • wpa-sec.stanev.org — бесплатный взлом WPA handshake’ов
  • onlinehashcrack.com — облачный взлом с дашбордом
  • wigle.net — глобальная карта WiFi с GPS-координатами

Также он участвует в PwnGrid — mesh-сети, где pwnagotchi обнаруживают друг друга по воздуху.

Скрипты управления

Я управляю устройством с Mac через USB. Написал несколько скриптов, потому что набирать одни и те же SSH-команды быстро надоело.

connect.sh — находит USB Ethernet, назначает IP, подключается по SSH:

#!/bin/bash
set -e

PI_IP="10.0.0.2"
MAC_IP="10.0.0.1"
SSH_KEY="$HOME/.ssh/pwnagotchi"

for iface in en5 en6 en7 en8; do
    if ifconfig "$iface" 2>/dev/null | grep -q "status: active"; then
        IFACE="$iface"
        break
    fi
done

[ -z "$IFACE" ] && echo "No USB Ethernet interface found." && exit 1

if ! ifconfig "$IFACE" | grep -q "$MAC_IP"; then
    sudo ifconfig "$IFACE" "$MAC_IP" netmask 255.255.255.0 up
fi

for i in $(seq 1 10); do
    ping -c 1 -W 1 "$PI_IP" &>/dev/null && break
    [ "$i" -eq 10 ] && echo "Pwnagotchi not reachable" && exit 1
    sleep 1
done

ssh -i "$SSH_KEY" pi@"$PI_IP"

share-internet.sh — NAT + dnsmasq, работает через VPN:

#!/bin/bash
set -e

PI_IP="10.0.0.2"
MAC_IP="10.0.0.1"

OUT_IFACE=$(route -n get default 2>/dev/null | grep interface | awk '{print $2}')
DNS_SERVER=$(scutil --dns | grep 'nameserver\[0\]' | head -1 | awk '{print $3}')

sudo sysctl -w net.inet.ip.forwarding=1
echo "nat on $OUT_IFACE from 10.0.0.0/24 to any -> ($OUT_IFACE)" | sudo pfctl -ef -

sudo dnsmasq --no-daemon --listen-address="$MAC_IP" --bind-interfaces \
    --no-resolv --server="$DNS_SERVER" --log-queries

sync-time.sh — отправляет UTC с Mac на Pi и аппаратные часы (RTC):

#!/bin/bash
set -e
PI_IP="10.0.0.2"
SSH_KEY="$HOME/.ssh/pwnagotchi"
CURRENT_UTC=$(date -u '+%Y-%m-%d %H:%M:%S')

ssh -i "$SSH_KEY" pi@"$PI_IP" \
    "sudo date -u -s '$CURRENT_UTC' && sudo hwclock -w && echo 'RTC synced:' && sudo hwclock -r"

backup.sh — конфиг, плагины, мозг ИИ, handshake’и:

#!/bin/bash
set -e
PI_IP="10.0.0.2"
SSH_KEY="$HOME/.ssh/pwnagotchi"
DATE=$(date +%Y%m%d)
BACKUP_DIR="./backups/$DATE"
mkdir -p "$BACKUP_DIR"

scp -i "$SSH_KEY" pi@"$PI_IP":/etc/pwnagotchi/config.toml "$BACKUP_DIR/"

ssh -i "$SSH_KEY" pi@"$PI_IP" "sudo tar czf /tmp/pwnagotchi-backup.tar.gz /etc/pwnagotchi/"
scp -i "$SSH_KEY" pi@"$PI_IP":/tmp/pwnagotchi-backup.tar.gz "$BACKUP_DIR/"

ssh -i "$SSH_KEY" pi@"$PI_IP" "sudo tar czf /tmp/custom-plugins.tar.gz /usr/local/share/pwnagotchi/custom-plugins/"
scp -i "$SSH_KEY" pi@"$PI_IP":/tmp/custom-plugins.tar.gz "$BACKUP_DIR/"

scp -i "$SSH_KEY" pi@"$PI_IP":/root/brain.nn "$BACKUP_DIR/" 2>/dev/null || true

ssh -i "$SSH_KEY" pi@"$PI_IP" "sudo tar czf /tmp/handshakes.tar.gz /root/handshakes/" 2>/dev/null
scp -i "$SSH_KEY" pi@"$PI_IP":/tmp/handshakes.tar.gz "$BACKUP_DIR/" 2>/dev/null || true

Плагин часов

Встроенные варианты часов не показывали нужный мне формат. 28 строк на Python это исправили:

from pwnagotchi.ui.components import LabeledValue
from pwnagotchi.ui.view import BLACK
import pwnagotchi.ui.fonts as fonts
import pwnagotchi.plugins as plugins
import datetime

class PwnClock(plugins.Plugin):
    __author__ = "originally https://github.com/LoganMD redone by NeonLightning"
    __version__ = "1.0.4"
    __license__ = "GPL3"
    __description__ = "Clock/Calendar for pwnagotchi"

    def on_loaded(self):
        pass

    def on_ui_setup(self, ui):
        ui.add_element("clock", LabeledValue(
            color=BLACK, label="", value="--/--  --:--",
            position=(148, 109),
            label_font=fonts.Small, text_font=fonts.Small))

    def on_ui_update(self, ui):
        now = datetime.datetime.now()
        ui.set("clock", now.strftime("%d/%m %H:%M"))

    def on_unload(self, ui):
        with ui._lock:
            ui.remove_element("clock")

PwnGrid

Если ваш pwnagotchi встретит моего по воздуху, вы увидите gumeniukcom. Или найдите меня напрямую:

opwngrid.xyz/search/f4548ccf636ea7a2fa2b642ea99db5d32592a49a8944903aa53b6e8b38ae8490

Что дальше

GPS-донгл VK-172 уже в пути. Он подключается через micro-USB OTG — тот же порт, что используется для подключения к Mac, поэтому GPS работает только в автономном режиме. Меня это устраивает. Как только он приедет, handshake’и будут геотегироваться и отправляться на wigle.net.

Вся сборка лежит в git-репозитории. Конфиг, плагины, скрипты, документация. Потому что если этого нет в git — этого не существует.