Воскрешение 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) |
| RTC | DS3231 на I2C, с батарейкой |
| Батарея | Waveshare UPS HAT (C) |
| GPS | VK-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 -wDNS через 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-queriessync-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 — этого не существует.