Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
pyrmax — Decoder/Encoder für Ubiquiti-AirMAX-Funkprotokoll-Frames; pcap-/Live-Captures parsen, Geräte erkennen, nach verwundbarer Firmware scannen, fehlerhafte Pakete erzeugen und AirMAX-AC/M-Ziele emulieren. | Kitploit
Tools/GitHubGitHub/infobyte/pyrmax
SchwachstellenscannerReverse EngineeringFuzzingNetzwerksicherheitDrahtlose Sicherheit
GitHubinfobyte/pyrmax

pyrmax

Decoder/Encoder für Ubiquiti-AirMAX-Funkprotokoll-Frames; pcap-/Live-Captures parsen, Geräte erkennen, nach verwundbarer Firmware scannen, fehlerhafte Pakete erzeugen und AirMAX-AC/M-Ziele emulieren.

Repository anzeigen
3vor 13 TagenNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

pyrmax

Decoder und Encoder für Ubiquiti-AirMAX-Wire-Protokoll-Frames, die sowohl die AC-Serie (WA-Firmware) als auch die M-Serie (XW/XM-Firmware) abdecken.

  • Dekodierung der Klartext-äußeren Header erfolgt über Kaitai Struct-Schemata unter ksy/. Die AC-Nutzlast (versionsabhängig, umgeschaltet über msg_type, mit Deauth-XOR-Entmaskierung) ist manuell in ac.py geschrieben — diese Logik passt nicht in ein reines Parse-Kaitai.
  • Kodierung ist manuell geschrieben und spiegelt den Dekodierungspfad Feld für Feld wider.

Status

VarianteDekodierungKodierungpcap-Durchlauf
AC✅ alle 5 msg-Typen (Beacon, Assoc-Req/Resp, Probe-Req, Deauth)✅ byteexakte Umkehrung + Builder + seal✅
Mteilweise (9 dokumentierte Bytes; Rest als unknown_rest)✅ Round-Trip für den dokumentierten Kopf + unknown_rest✅
Routerboard.com-IE (Begleiter zu M)✅ Gerätename + Sub-IE-Listen/a✅

Das AC-Wire-Format folgt docs/ac_wire_format.md (mit [P] gegen ubnt_poll_host.ko bestätigt). Alle AC-Multibyte-Ganzzahlen sind Big-Endian.

TODO

  • pyrmax.ac.encode(AcPacket) -> bytes — manuell geschriebene byteexakte Umkehrung von decode() (+ seal(), to_ie() und build_*-Konstruktoren).
  • pyrmax.m.encode(MPacket) -> bytes — dasselbe für M (+ build_m, seal, to_ie).
  • Die [open]-AC-Felder exakt bestimmen — cap_flags-Bitmap, mixed_mode, / (assoc_req), / (assoc_resp) sowie das Deauth- (extrahierbar, aber sein Schlüssel ist noch nicht reverse-engineered, daher nicht verifizierbar). Siehe §11-§12.

Befehlszeilenwerkzeug

Das Paket enthält eine CLI mit Unterbefehlen. Führe sie wie folgt aus: python -m pyrmax COMMAND ....``` usage: python -m pyrmax [-h] [--version] COMMAND ...

COMMAND parse Print each AirMAX frame in detail. discover Summarize devices observed in the capture. scan Live-scan for AirMAX devices and flag vulnerable firmware. emulate Emulate AirMAX AC/M devices (fake targets for scanners).

root@kitploit:~
`parse` und `discover` akzeptieren **entweder** eine pcap/pcapng-Datei (als Positionsargument)
**oder** eine Live-Wireless-Schnittstelle über `-i / --iface IFACE`. Diese beiden
schließen sich gegenseitig aus. `scan` akzeptiert dieselben Quelloptionen (plus einen
`--active`-Modus, der nur auf eine Live-Schnittstelle anwendbar ist); `emulate` ist
ausschließlich für Live-Schnittstellen.```sh
python -m pyrmax parse     capture.pcap          # offline
python -m pyrmax discover  capture.pcap

sudo python -m pyrmax parse     -i wlan0mon      # live (needs root)
sudo python -m pyrmax discover  -i wlan0mon

Live-Erfassung setzt voraus, dass sich die Schnittstelle bereits im Monitor-Modus auf dem gewünschten Kanal befindet – pyrmax konfiguriert keines von beiden. Es erfordert das optionale [live]-Extra (pip install pyrmax[live]), das pcapy-ng nachzieht. Drücken Sie Strg-C zum Beenden: parse meldet, wie viele Frames gestreamt wurden; discover gibt beim Beenden die aggregierte Geräteübersicht aus.

Exit-Codes (gelten für beide Befehle und beide Quellenmodi): 0 bei Erfolg (einschließlich „keine AirMAX-Frames“ – ein gültiges Ergebnis), 1 bei Fehlern im Erfassungsformat (falscher Link-Typ, beschädigte Datei, Schnittstelle kann nicht geöffnet werden), 2 bei fehlender Datei oder ungültigen Quellenargumenten.

parse — Dump pro Frame```sh

python -m pyrmax parse capture.pcap

root@kitploit:~
Jeder 802.11-Management-Frame, der eine AirMAX-Vendor-IE trägt, erzeugt einen
Block: AC-Paket, M-Paket und jede Routerboard.com-Begleit-IE, die
im selben Frame gefunden wird.```
Found 1 AirMAX frame(s) in capture.pcap: 0 AC, 1 M (1 with Routerboard companion).

=== Frame #0  [M]  ts=1765494974.955358 ===
  802.11   src=04:18:d6:0e:0c:42  dst=24:a4:3c:88:d8:22  bssid=04:18:d6:0e:0c:42
  AirMAX M
    version      15
    msg_type     BEACON  (raw=1)
    src_mac      04:18:d6:0e:0c:42
    enable       1
    unknown_rest b700000000000000000000040418d60e0c420000000000  (23B)
  Routerboard.com IE
    oui_type     0
    unknown      0000
    device_name  'AP Sur HY1315'
    sub_ie       subtype=1  (30B) 040000001f660902ff0f4150205375722048593133313500000000000000

The same single-pass walker is exposed programmatically as pyrmax.pcap.iter_airmax(path) — it yields one AirmaxRecord(meta, ac, m, routerboard) per AirMAX-bearing frame, so you don't need to correlate M and Routerboard IEs by hand.

discover — Geräteübersicht```sh

python -m pyrmax discover capture.pcap

root@kitploit:~
Frames werden nach 802.11-Quell-MAC gruppiert, Peers werden akkumuliert, und AC-Payload- / M-Payload- / Routerboard-Gerätename-Beobachtungen werden zu einem einzigen Block pro Gerät zusammengefasst.```
2 device(s) observed in capture.pcap across 12 AirMAX frame(s).

  24:5a:4c:44:57:fd  (AC)
    radioname    'LB1'
    ssid         'labalUBI2'
    ac_msg_types BEACON
    ac_version   9
    cap_flags    0x0000003e
    mixed_mode   0
    frames       8
    first seen   1767046123.708745
    last seen    1767046129.012448
    peers        (broadcast only)

  04:18:d6:0e:0c:42  (M)
    device_name  'AP Sur HY1315'
    msg_types    BEACON
    m_version    15
    m_enable     1
    frames       4
    first seen   1765494974.955358
    last seen    1765494980.341110
    peers        24:a4:3c:88:d8:22

Dieselbe Aggregation ist auch eine öffentliche Funktion:```python from pyrmax.devices import summarize from pyrmax.pcap import iter_airmax

devices = summarize(iter_airmax("capture.pcap")) for mac, dev in devices.items(): print(mac.hex(":"), dev.device_name or dev.radioname, dev.peers)

root@kitploit:~
## Verwendung

### Eine einzelne AirMAX-AC-Nachricht dekodieren

Der Dekoder erwartet die Bytes der 802.11-Vendor-Specific-IE **ab der OUI** –
der IE-Wrapper (Element-ID `0xDD` + Länge) muss bereits entfernt worden sein.
`src_mac` / `dst_mac` werden aus der SA / DA des äußeren 802.11-Frames übernommen.```python
from pyrmax import ac

packet = ac.decode(
    data,                              # bytes starting at b"\x00\x27\x22"
    src_mac="aa:bb:cc:dd:ee:ff",       # accepts str ("aa:bb:..." or "aa-bb-..."
                                       # or "aabbcc...") and raw 6-byte bytes
    dst_mac="ff:ff:ff:ff:ff:ff",       # optional — defaults to broadcast
)

packet.msg_type          # <MsgType.BEACON: 1>
packet.version           # 9 (the wire-format epoch / version gate)
packet.src_mac           # b'\xaa\xbb\xcc\xdd\xee\xff'  (integrity-checked)
packet.radioname         # "lab-rx-1"   (convenience prop, delegates to body)
packet.ssid              # "NetA"
packet.cap_flags         # 0x3e  (None for msg types that have no cap_flags)

# The per-message-type fields live on packet.body, one of:
#   BeaconBody | AssocReqBody | AssocRespBody | ProbeReqBody | DeauthBody
body = packet.body
if isinstance(body, ac.BeaconBody):
    body.mac_0c          # the radio's own MAC / BSSID
    body.cap_flags       # u32 capability bitfield (§11)
    body.mixed_mode      # u32 [open]

msg_type ist einer von BEACON / ASSOC_REQ / ASSOC_RESP / PROBE_REQ / DEAUTH. Versionsabhängige Endfelder (field_9c, rssi, fwname, txpower, …) sind None, wenn die version des Frames unter deren Schwelle liegt. Deauth ent-XORt src_mac mit der jiffies-Nonce vor der Integritätsprüfung und macht den 16-Byte-enc_token als opake Bytes verfügbar (sein Schlüssel ist noch nicht reversiert, daher kann er nicht verifiziert werden).

Die AC-TLV-Liste durchlaufen

Bodies, die Namens-TLVs tragen (beacon, assoc_req), erhalten den Stream — einschließlich des abschließenden Padding-Eintrags — unverändert auf body.tlvs. radioname, ssid und fwname werden als Komfort-Eigenschaften auf dem Paket verfügbar gemacht; alles andere bleibt roh.```python body = packet.body for tlv in getattr(body, "tlvs", ()): if tlv.tag == ac.TlvTag.PADDING: continue print(f"{tlv.tag.name:<10} ({len(tlv.data)} bytes): {tlv.data!r}")

root@kitploit:~
### Eine einzelne AirMAX-M-Nachricht dekodieren

Gleiche Form, kleinere Oberfläche — nur 9 Bytes der M-Payload sind dokumentiert;
der Rest wird unverändert in `unknown_rest` bewahrt. **Hinweis:** Die M-Payload
selbst enthält kein SSID-Feld — dafür siehe die standardmäßige 802.11-SSID-IE
im umgebenden Beacon oder in der Probe-Response (verfügbar als
`FrameMeta.ssid` bei der Iteration über `pyrmax.pcap`).```python
from pyrmax import m

packet = m.decode(data, src_mac="aa:bb:cc:dd:ee:ff")

packet.version           # 1
packet.msg_type          # <MsgType.BEACON: 1>
packet.src_mac           # b'\xaa\xbb\xcc\xdd\xee\xff'
packet.enable            # 1
packet.unknown_rest      # b'\xde\xad\xbe\xef...'   # opaque, RE pending

Nachrichten erstellen (encode)

encode(packet, dst_mac=…) ist die bytegenaue Umkehrung von decode — encode(decode(x)) == x für einen wohlgeformten Frame. Es serialisiert den Body (wendet die Versions-Gates erneut an und, für deauth, die src_mac-XOR-Maske), füllt auf den AES-Block auf, verschlüsselt mit dem aus packet.src_mac abgeleiteten Schlüssel und gibt die Bytes ab OUI aus. Ummanteln Sie es mit to_ie() für eine vollständige 0xDD-Vendor-IE.

Die build_*-Konstruktoren ersparen Ihnen, die verschachtelten Bodies von Hand zusammenzusetzen:```python from pyrmax import ac

A beacon (mac_0c defaults to src_mac; broadcast key, as beacons use)

pkt = ac.build_beacon(src_mac="24:5a:4c:44:57:fd", radioname="LB1", ssid="labalUBI2", cap_flags=0x3e) ie = ac.to_ie(ac.encode(pkt)) # full 802.11 vendor IE, ready to embed

An authenticated deauth — the encoder XOR-masks the src with the jiffies nonce

deauth = ac.build_deauth(src_mac="24:5a:4c:44:57:fd", jiffies_nonce=0xdeadbeef) raw = ac.encode(deauth, dst_mac="24:a4:3c:88:d8:22")

Others: ac.build_assoc_req / build_assoc_resp / build_probe_req, and m.build_m

root@kitploit:~
Für Fuzzing / PoCs verschlüsselt `seal()` **beliebigen** Klartext und baut den
äußeren Header auf — so kannst du absichtlich fehlerhafte Payloads erzeugen
(falscher `msg_type`, falsche Längen, Sub-Block-Bodies), die der strukturierte Encoder
nie produzieren würde:```python
frame = ac.seal(b"\xde\xad\xbe\xef", src_mac="aa:bb:cc:dd:ee:ff",
                dst_mac="ff:ff:ff:ff:ff:ff", msg_type=0xEE)  # zero-padded to 16

Das strukturierte encode wirft EncodeError, wenn etwas nicht über die Leitung geschickt werden kann (ein TLV-Wert > 255 Bytes, Chiffrat ≥ 0x101); seal ist per Design permissiv.

Pakete aus einer pcap- oder pcapng-Datei streamen

pyrmax.pcap findet AirMAX-Vendor-IEs in 802.11-Management-Frames, extrahiert die MACs aus dem äußeren 802.11-Header und speist alles in den richtigen Decoder ein. Sowohl .pcap als auch .pcapng werden automatisch erkannt. Frames, die nicht dekodiert werden können (falscher Schlüssel, verstümmelt, nicht zugehöriges Vendor-IE), werden stillschweigend übersprungen — die Iteration endet erst bei EOF.```python from pyrmax import pcap

for meta, packet in pcap.iter_ac("capture.pcap"): print( f"{meta.timestamp:.3f} " f"{meta.src_mac.hex(':')} → {meta.dst_mac.hex(':')} " f"{packet.msg_type.name:<10} " f"radio={packet.radioname!r} ssid={packet.ssid!r}" )

for meta, packet in pcap.iter_m("capture.pcapng"): print( f"{meta.timestamp:.3f} " f"{packet.msg_type.name:<10} " f"src={packet.src_mac.hex(':')} enable={packet.enable}" )

root@kitploit:~
`meta` ist ein `FrameMeta(timestamp, src_mac, dst_mac, bssid)`. Die Extraktion von Kanal/RSSI
aus Radiotap steht auf der TODO-Liste.

### Den Gerätenamen aus einer Routerboard.com-IE ermitteln

AirMAX-M-Frames werden fast immer von einer Mikrotik-/Routerboard.com-
Vendor-IE (OUI `00:0C:42`) im selben 802.11-Management-
Frame begleitet. Die Sub-IE des Subtyps 1 enthält den Gerätenamen.```python
from pyrmax import pcap

for meta, packet in pcap.iter_routerboard("capture.pcap"):
    print(f"{meta.src_mac.hex(':')}  →  {packet.device_name!r}")
    # "AP Sur HY1315"

Der Routerboard-Decoder ist auch eigenständig verfügbar — übergeben Sie die IE-Daten ab der OUI:```python from pyrmax import routerboard

packet = routerboard.decode(ie_data) packet.device_name # "AP Sur HY1315" packet.sub_ies # tuple of SubIe(subtype, data)

root@kitploit:~
Korrelieren Sie Routerboard-Pakete mit M-Paketen im selben Capture, indem
Sie `meta.timestamp` + `meta.src_mac` abgleichen.

### `scan` — verwundbare Geräte finden

Belauschen Sie eine Monitor-Mode-Schnittstelle (oder eine pcap) nach AirMAX-Geräten und markieren
Sie, welche verwundbar sind. Benötigt das `[scan]`-Extra (`scapy`) und für Live
Capture, Root-Rechte.```sh
# offline — scan a capture (no root)
python -m pyrmax scan capture.pcap

# live, passive — read versions only from traffic that happens to fly
sudo python -m pyrmax scan -i wlan0mon --channel 36

# live, active — force AirMAX AC APs to disclose their firmware
sudo python -m pyrmax scan -i wlan0mon --channel 36 --active

Die Version bestimmt die Verwundbarkeit je nach Variante unterschiedlich. Zwei Versionsnummern sind beteiligt: die Drahtformat-Protokollversion, die in jedem AirMAX-IE (einschließlich Beacons) übertragen wird, und die AC-Firmware-Version (fwname), die nur im Assoziierungsaustausch mitgeführt wird.``` AirMAX AC ──> proto < 9 ? ──yes──────────────┐ │no ├──> VULNERABLE ▼ │ fw <= 8.7.20 ? ──yes───────────┘ ├──no───────> PATCHED └──unknown──> UNDETERMINED

AirMAX M ───> proto < 15 ? ──yes──> VULNERABLE └──no───────────> UNDETERMINED

root@kitploit:~
Da `proto` im Beacon enthalten ist, werden **alte** Geräte (AC-Epoche < 9,
M-Version < 15) **passiv** erfasst. Um für AC ein `PATCHED`-Urteil zu erreichen,
wird die Firmware-Version benötigt, also ist entweder eine erfasste Assoziation
oder `--active` nötig (der aktive Handshake — auth → assoc → Auslesen des assoc-resp
`fwname` — ist ein vollständiger, byte-treuer Ubiquiti-Stationsaustausch).

Flags: `--channel N` (einen Kanal sperren, sonst springen), `--seconds N`,
`--cutoff X.Y.Z` (AC-anfällig, falls `fw <= cutoff`, Standard `8.7.20`),
`--src MAC` (Quelle für die aktive Sonde, z. B. der PTP-Peer), `--vuln-only`,
`--no-set-channel`. Der Exit-Code ist **3**, wenn ein anfälliges Gerät gefunden wird
(praktisch für Skripte), sonst `0`.```
AirMAX: 5 device(s) (3 AC, 2 M), 2 vulnerable (AC fw <= 8.7.20 or protocol version below the fixed epoch).

  1c:6a:1b:00:00:01  AC  VulnAC            ch36   v8.7.19    VULNERABLE     rssi=-40dBm  peers=0
  1c:6a:1b:00:00:04  M   VulnM             ch36   v14        VULNERABLE     rssi=-42dBm  peers=0
  1c:6a:1b:00:00:03  AC  PatchedAC         ch36   v8.7.24    patched        rssi=-41dBm  peers=0
  1c:6a:1b:00:00:02  AC  UndetAC           ch36   epoch9     undetermined   rssi=-41dBm  peers=0
  1c:6a:1b:00:00:05  M   UndetM            ch36   v15        undetermined   rssi=-43dBm  peers=0

emulate — gefälschte AirMAX-Ziele

Sende Beacons als ein oder mehrere gefälschte AirMAX-AC/M-Geräte und beantworte bei AC den Discovery-Handshake, sodass ein aktiver Scanner die emulierte Firmware-Version ausliest. Benötigt die Zusatzoption [emulate] (scapy), eine Monitor-Mode-Schnittstelle und Root-Rechte. Nützlich zum Testen von scan ohne echte Hardware.```sh sudo python -m pyrmax emulate -i wlan1mon --channel 36
-d ac/8.7.19/VulnAC -d ac/9/UndetAC -d ac/8.7.24/PatchedAC
-d m/14/VulnM -d m/15/UndetM

root@kitploit:~
Jedes `-d` (wiederholbar) ist `TYPE/VERSION[/SSID[/MAC]]`, `/`-getrennt, sodass die
Doppelpunkte der MAC sicher sind:

- `ac/8.7.19` — modernes AC, Firmware `8.7.19` (Epoche 9, gibt `fwname` preis)
- `ac/9` — moderne AC-Epoche, **keine** Firmware-Zeichenkette → Scanner sieht
  `undetermined`
- `ac/7` — **altes** AC, Drahtformat-Epoche 7 (< 9) → verwundbar, aus
  dem Beacon erkannt
- `m/14` — AirMAX M, Version 14 (< 15) → verwundbar
- `m/15` — AirMAX M bei der korrigierten Epoche → unbestimmt

Ohne `-d` wird eine Demo-Flotte emuliert. `--no-respond` sendet nur Beacons (die
AC-Firmware gibt dann nichts preis). Die AC-Firmware-Version lebt nur in der
assoc-resp, weshalb der Responder existiert.

### Beides zusammen auf einer Maschine testen

`scripts/hwsim_testbed.sh` erstellt zwei virtuelle Funkgeräte über `mac80211_hwsim`
sodass du `emulate` auf dem einen und `scan` auf dem anderen ohne Hardware ausführen kannst:```sh
sudo ./scripts/hwsim_testbed.sh up 36    # prints EMU_IFACE / SCAN_IFACE
# ...run emulate on EMU_IFACE and scan on SCAN_IFACE (two terminals)...
sudo ./scripts/hwsim_testbed.sh down

scripts/demo_5_devices.sh erledigt das Ganze von Anfang bis Ende – startet die Funkgeräte, emuliert die oben genannte Flotte aus 5 Geräten, führt scan --active aus und fährt wieder herunter:```sh sudo ./scripts/demo_5_devices.sh 36

root@kitploit:~
### Fehlerbehandlung

Schemaabweichungen und Integritätsfehler lösen `pyrmax.DecodeError` aus. Die
häufigste Ursache ist ein falscher Schlüssel (falsche `src_mac` / `dst_mac`, die
`decode()` für den jeweiligen Frame übergeben wurden).```python
from pyrmax import ac, DecodeError

try:
    packet = ac.decode(data, src_mac=src, dst_mac=dst)
except DecodeError as exc:
    print(f"skipping frame: {exc}")

Optionale Extras

  • pip install pyrmax[pcap] (oder uv sync --extra pcap) — bindet dpkt ein, sodass pyrmax.pcap.iter_ac(path) / iter_m(path) Pakete aus .pcap- oder .pcapng-Erfassungen streamen können (Link-Typ DLT_IEEE802_11_RADIO). Das Format wird automatisch anhand der magischen Zahl der Datei erkannt.
  • pip install pyrmax[live] — fügt pcapy-ng für die Live-Erfassung von einer Monitor-Modus-Wireless-Schnittstelle hinzu. Wird vom -i / --iface-Flag der CLI und vom programmatischen Generator pyrmax.pcap.iter_airmax_live(iface) verwendet.
  • pip install pyrmax[scan] — fügt scapy für den Befehl scan hinzu (Live-Sniffen/Dekodieren + der aktive Force-Assoc-Handshake).

Mehrere auf einmal installieren, z. B. uv sync --extra scan --extra emulate.

Layout```

pyrmax/ ├── ksy/ # Kaitai Struct source schemas │ ├── airmax_ac.ksy # AC cleartext outer header (payload decode is hand-written in ac.py) │ ├── airmax_m.ksy # M outer (OUI marker + encrypted blob) │ ├── airmax_m_payload.ksy # M decrypted payload (9 documented bytes) │ └── routerboard.ksy # Mikrotik / Routerboard.com vendor IE ├── src/pyrmax/ │ ├── init.py │ ├── ac.py # AC decode/encode API + AcPacket dataclass │ ├── m.py # M decode/encode API + MPacket dataclass │ ├── routerboard.py # Routerboard IE decoder + RouterboardPacket │ ├── pcap.py # iter_ac / iter_m / iter_routerboard / iter_airmax / iter_airmax_live │ ├── devices.py # summarize() — per-device aggregation │ ├── vuln.py # firmware-version parse + is_vulnerable() │ ├── scan.py # Scanner — live/pcap discovery + active handshake + vuln verdict │ ├── emulate.py # Emulator — fake AC/M targets (scapy) │ ├── main.py # python -m pyrmax CLI │ ├── exceptions.py │ ├── _crypto.py # AES-128-ECB + HMAC-SHA1 KDF (internal) │ └── _generated/ # kaitai-struct-compiler output (committed) ├── scripts/ │ ├── hwsim_testbed.sh # two virtual radios (mac80211_hwsim) for scan<->emulate │ └── demo_5_devices.sh # end-to-end 5-device emulate + scan demo └── tests/ ├── samples/ # raw frame captures (currently empty) ├── test_ac.py ├── test_m.py ├── test_crypto.py ├── test_pcap.py ├── test_routerboard.py ├── test_devices.py ├── test_cli.py └── test_integration.py # real-capture round-trips

root@kitploit:~
## Entwicklung```sh
uv sync                    # create .venv and install runtime + dev deps
uv run pytest              # run tests
uv run ruff check          # lint
uv run pyright             # static type check

Konfiguration liegt in pyproject.toml ([tool.pyright]):

  • typeCheckingMode = "basic" — erkennt strukturelle Probleme, ohne gegen die dpkt-/kaitaistruct-/pycryptodome-Grenzen anzukämpfen (diese Pakete liefern keine Typ-Stubs).
  • src/pyrmax/_generated/ ist ausgeschlossen — Kaitai-generierte Dateien enthalten bereits # type: ignore und werden bei jedem kaitai-struct-compiler-Lauf überschrieben.
  • Grenzen zu dpkt, die dynamische Attribute berühren (z. B. MGMT_Frame.src), werden mit einer Any-Annotation auf der lokalen Bindung überquert, statt mit verstreuten Ignore-Kommentaren.

Regenerieren der Kaitai-Parser

Die generierten Python-Dateien unter src/pyrmax/_generated/ sind eingecheckt, damit das Paket ohne Kaitai-Toolchain installiert werden kann. Zum Regenerieren nach dem Bearbeiten einer .ksy:```sh kaitai-struct-compiler -t python --outdir src/pyrmax/_generated/ ksy/*.ksy

root@kitploit:~
Tool herunterladen
field_14
field_9c
sta_field_68
ic_6b8
enc_token
docs/ac_wire_format.md
  • Die version < 9-AC-Dekoder anhand echter Captures verifizieren — der TX-Builder erzeugt immer nur Version 9, daher sind die Pfade der niedrigeren Versionen (ungetaggter Name, fehlende Tail-Felder) gemäß Spezifikation implementiert, aber nicht auf der Leitung verifiziert.
  • Den Rest der M-Nutzlast per Reverse Engineering aufklären (Bytes 9+ in unknown_rest) — derzeit undurchsichtig.
  • Radiotap-Metadaten auf pcap.FrameMeta verfügbar machen: Kanal, RSSI, Rate. Derzeit sind nur Zeitstempel/MACs/BSSID befüllt.
  • Echte Capture-Fixtures in tests/samples/ — derzeit: airmax_ac_beacon.pcap (1 Frame, Beacon) und airmax_m_probe_response.pcap (1 Frame, Probe-Response). Weitere Varianten (Assoc-Req/Resp, Multi-Frame-Captures) sind weiterhin willkommen.
  • Paketversand — die Befehle scan (aktives Force-Assoc) und emulate injizieren über Scapy (die [scan]-/[emulate]-Extras). Siehe scan.py / emulate.py.
  • pip install pyrmax[emulate] — fügt scapy für den Befehl emulate hinzu (Beacons injizieren + den Discovery-Handshake als Fake-Geräte beantworten).