Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
pyrmax — Decodificador/codificador para frames do protocolo sem fio AirMAX da Ubiquiti; analisar capturas pcap/ao vivo, descobrir dispositivos, procurar firmware vulnerável, forjar pacotes malformados e emular alvos AirMAX AC/M. | Kitploit
Ferramentas/GitHubGitHub/infobyte/pyrmax
Scanners de VulnerabilidadesEngenharia ReversaFuzzingSegurança de RedeSegurança Sem Fio
GitHubinfobyte/pyrmax

pyrmax

Decodificador/codificador para frames do protocolo sem fio AirMAX da Ubiquiti; analisar capturas pcap/ao vivo, descobrir dispositivos, procurar firmware vulnerável, forjar pacotes malformados e emular alvos AirMAX AC/M.

Ver Repositório
3há 13 diasAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

pyrmax

Decodificador e codificador para frames do protocolo wire Ubiquiti AirMAX, cobrindo tanto a série AC (firmware WA) quanto a M (firmware XW/XM).

  • Decodificação dos cabeçalhos externos em texto claro é conduzida por schemas Kaitai Struct sob ksy/. O payload AC (controlado por versão, alternado em msg_type, com o deauth XOR-unmask) é escrito à mão em ac.py — essa lógica não cabe em Kaitai somente-parse.
  • Codificação é escrita à mão para espelhar o caminho de decodificação campo por campo.

Status

VarianteDecodeEncodeiteração de pcap
AC✅ todos os 5 tipos de msg (beacon, assoc req/resp, probe req, deauth)✅ inverso byte-exato + builders + seal✅
Mparcial (9 bytes documentados; resto como unknown_rest)✅ round-trip da cabeça documentada + unknown_rest✅
IE Routerboard.com (companheiro de M)✅ nome do dispositivo + lista de sub-IEsn/a✅

O formato wire AC segue docs/ac_wire_format.md (confirmado [P]-contra ubnt_poll_host.ko). Todos os inteiros multi-byte AC são big-endian.

TODO

  • pyrmax.ac.encode(AcPacket) -> bytes — inverso byte-exato escrito à mão de decode() (+ seal(), to_ie(), e construtores build_*).
  • pyrmax.m.encode(MPacket) -> bytes — o mesmo para M (+ build_m, seal, to_ie).
  • Fixar os campos AC [open] — mapa de bits exato de cap_flags, mixed_mode, / (assoc_req), / (assoc_resp), e o do deauth (extraível, mas sua chave ainda não foi reverse-engineered, então não pode ser verificado). Veja §11-§12.

Ferramenta de linha de comando

O pacote inclui uma CLI dirigida por sub-comandos. Execute-a como 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` e `discover` aceitam **ou** um arquivo pcap/pcapng (posicional)
**ou** uma interface sem fio ativa via `-i / --iface IFACE`. Os dois são
mutuamente exclusivos. `scan` aceita as mesmas opções de origem (além de um
modo `--active` que só se aplica a uma interface ativa); `emulate` é
apenas para interface ativa.```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

A captura ao vivo pressupõe que a interface já está em modo monitor no canal de interesse — o pyrmax não configura nenhum dos dois. Ela requer o extra opcional [live] (pip install pyrmax[live]), que inclui pcapy-ng. Pressione Ctrl-C para parar: parse informa quantos quadros processou; discover imprime o resumo agregado dos dispositivos ao sair.

Códigos de saída (compartilhados por ambos os comandos e ambos os modos de origem): 0 em caso de sucesso (incluindo "nenhum quadro AirMAX" — um resultado válido), 1 para erros de formato de captura (tipo de enlace incorreto, arquivo malformado, não foi possível abrir a interface), 2 para arquivo ausente ou argumentos de origem inválidos.

parse — dump por quadro```sh

python -m pyrmax parse capture.pcap

root@kitploit:~
Cada quadro de gerenciamento 802.11 que carrega um IE de fornecedor AirMAX produz um bloco: pacote AC, pacote M e qualquer IE companheiro do Routerboard.com encontrado no mesmo quadro.```
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

O mesmo percorredor de passagem única é exposto programaticamente como pyrmax.pcap.iter_airmax(path) — ele gera um AirmaxRecord(meta, ac, m, routerboard) por quadro com AirMAX, então você não precisa correlacionar manualmente os IEs M e Routerboard.

discover — resumo de dispositivos```sh

python -m pyrmax discover capture.pcap

root@kitploit:~
Os frames são agrupados por MAC de origem 802.11, os peers são acumulados, e as
observações de payload AC / payload M / nome de dispositivo Routerboard são consolidadas
em um único bloco por dispositivo.```
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

A mesma agregação também é uma função pública:```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:~
## Uso

### Decodificar uma única mensagem AirMAX AC

O decodificador espera os bytes da IE Específica do Fornecedor 802.11 **começando na
OUI** — o invólucro da IE (Element ID `0xDD` + Length) já deve ter sido
removido. `src_mac` / `dst_mac` são obtidos do SA / DA do quadro 802.11
externo.```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 é um de BEACON / ASSOC_REQ / ASSOC_RESP / PROBE_REQ / DEAUTH. Campos de cauda controlados por versão (field_9c, rssi, fwname, txpower, …) são None quando o version do frame está abaixo do seu limite. Deauth desfaz o XOR de src_mac com o nonce de jiffies antes da verificação de integridade e expõe o enc_token de 16 bytes como bytes opacos (sua chave ainda não foi revertida, então não pode ser verificado).

Percorrer a lista de TLV do AC

Corpos que carregam TLVs de nome (beacon, assoc_req) preservam o fluxo — incluindo a entrada Padding final — na íntegra em body.tlvs. radioname, ssid e fwname são expostos como propriedades de conveniência no pacote; todo o resto permanece bruto.```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:~
### Decodificar uma única mensagem AirMAX M

Mesma forma, superfície menor — apenas 9 bytes do payload M são documentados;
o restante é preservado verbatim em `unknown_rest`. **Nota:** o payload M
em si não possui campo SSID — para isso, veja a IE SSID padrão 802.11
no beacon ou resposta de probe adjacente (exposta como
`FrameMeta.ssid` ao iterar via `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

Criar mensagens (encode)

encode(packet, dst_mac=…) é o inverso exato em bytes de decode — encode(decode(x)) == x para um frame bem formado. Ele serializa o corpo (reaplicando as portas de versão e, para deauth, a máscara XOR de src_mac), faz padding até o bloco AES, criptografa com a chave derivada de packet.src_mac e emite os bytes a partir do OUI. Encapsule com to_ie() para uma IE de fornecedor 0xDD completa.

Os construtores build_* evitam que você monte os corpos aninhados manualmente:```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:~
For fuzzing / PoCs, `seal()` criptografa texto simples **arbitrário** e constrói o cabeçalho externo — para que você possa criar payloads deliberadamente malformados (`msg_type` falso, comprimentos errados, corpos de sub-bloco) que o codificador estruturado nunca produziria:```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

O encode estruturado levanta EncodeError para qualquer coisa que não possa ir para o fio (um valor TLV > 255 bytes, texto cifrado ≥ 0x101); seal é permissivo por design.

Fluxo de pacotes de um pcap ou pcapng

pyrmax.pcap encontra IEs de fornecedor AirMAX dentro de quadros de gerenciamento 802.11, extrai os MACs do cabeçalho 802.11 externo e passa tudo para o decodificador adequado. Tanto .pcap quanto .pcapng são detectados automaticamente. Quadros que falham na decodificação (chave errada, corrompidos, IE de fornecedor não relacionado) são ignorados silenciosamente — a iteração só para no 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` é um `FrameMeta(timestamp, src_mac, dst_mac, bssid)`. A extração de canal/RSSI do radiotap está na lista de TODO.

### Recuperar o nome do dispositivo a partir de uma IE Routerboard.com

Quadros AirMAX M são quase sempre acompanhados por uma IE de fornecedor Mikrotik / Routerboard.com (OUI `00:0C:42`) no mesmo quadro de gerenciamento 802.11. Sua sub-IE de subtipo 1 carrega o nome do dispositivo.```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"

O decodificador Routerboard também está disponível de forma independente — passe os dados do IE começando pelo 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:~
Correlacione pacotes Routerboard com pacotes M na mesma captura
correspondendo a `meta.timestamp` + `meta.src_mac`.

### `scan` — encontre dispositivos vulneráveis

Capture o tráfego de uma interface em modo monitor (ou de um pcap)
para procurar dispositivos AirMAX e sinalize quais são vulneráveis. Requer o extra
`[scan]` (`scapy`) e, para captura ao vivo, root.```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

A versão determina a vulnerabilidade de forma diferente por variante. Dois números de versão estão envolvidos: a versão do protocolo wire-format transportada em cada AirMAX IE (incluindo beacons), e a versão do firmware AC (fwname) que viaja apenas na troca de associação.``` 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:~
Como `proto` está no beacon, dispositivos **antigos** (epoch AC < 9, M
versão < 15) são detectados **passivamente**. Chegar a um veredito `PATCHED` para
AC exige a versão do firmware, portanto é necessário ter uma associação capturada
ou usar `--active` (o handshake ativo — auth → assoc → ler o assoc-resp
`fwname` — é uma troca de estação Ubiquiti completa e fiel byte a byte).

Flags: `--channel N` (fixar um canal, caso contrário alternar), `--seconds N`,
`--cutoff X.Y.Z` (vulnerável a AC se `fw <= cutoff`, padrão `8.7.20`),
`--src MAC` (origem para a sonda ativa, ex. o peer PTP), `--vuln-only`,
`--no-set-channel`. O código de saída é **3** quando qualquer dispositivo vulnerável é encontrado
(útil para scripts), caso contrário `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 — alvos AirMAX falsos

Emita beacons como um ou mais dispositivos AirMAX AC/M falsos e, para AC, responda ao handshake de descoberta para que um scanner ativo leia a versão de firmware emulada. Requer o extra [emulate] (scapy), uma interface em modo monitor e root. Útil para testar scan sem hardware real.```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:~
Cada `-d` (repetível) é `TYPE/VERSION[/SSID[/MAC]]`, separado por `/`, de modo que os
dois-pontos do MAC ficam seguros:

- `ac/8.7.19` — AC moderno, firmware `8.7.19` (epoch 9, divulga `fwname`)
- `ac/9` — epoch do AC moderno, **sem** string de firmware → o scanner vê
  `undetermined`
- `ac/7` — AC **antigo**, epoch 7 do wire-format (< 9) → vulnerável, detectado a partir
  do beacon
- `m/14` — AirMAX M, versão 14 (< 15) → vulnerável
- `m/15` — AirMAX M no epoch corrigido → undetermined

Sem `-d`, uma frota de demonstração é emulada. `--no-respond` envia apenas beacons (o
firmware do AC então não divulgará a versão). A versão do firmware do AC só existe na
assoc-resp, e é por isso que o responder existe.

### Teste ambos juntos em uma máquina

`scripts/hwsim_testbed.sh` cria duas rádios virtuais via `mac80211_hwsim`
para que você possa executar `emulate` em uma e `scan` na outra sem hardware:```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 faz tudo de ponta a ponta — inicia as rádios, emula a frota de 5 dispositivos acima, executa scan --active e encerra:```sh sudo ./scripts/demo_5_devices.sh 36

root@kitploit:~
### Tratamento de erros

Incompatibilidades de esquema e falhas de integridade geram `pyrmax.DecodeError`. A
causa mais comum é uma chave errada (`src_mac` / `dst_mac` fornecidos a
`decode()` para o quadro em questão).```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}")

Extras opcionais

  • pip install pyrmax[pcap] (ou uv sync --extra pcap) — puxa dpkt para que pyrmax.pcap.iter_ac(path) / iter_m(path) possam transmitir pacotes de capturas .pcap ou .pcapng (tipo de link DLT_IEEE802_11_RADIO). O formato é detectado automaticamente pelo número mágico do arquivo.
  • pip install pyrmax[live] — adiciona pcapy-ng para captura ao vivo de uma interface sem fio em modo monitor. Usado pela flag -i / --iface da CLI e pelo gerador programático pyrmax.pcap.iter_airmax_live(iface).
  • pip install pyrmax[scan] — adiciona scapy para o comando scan (sniff/decode ao vivo + o handshake ativo force-assoc).

Instale vários de uma vez, ex.: uv sync --extra scan --extra emulate.

Estrutura```

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:~
## Desenvolvimento```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

Configuration lives in pyproject.toml ([tool.pyright]):

  • typeCheckingMode = "basic" — detecta problemas estruturais sem lutar com o limite dpkt / kaitaistruct / pycryptodome (esses pacotes não fornecem stubs de tipos).
  • src/pyrmax/_generated/ é excluído — os arquivos gerados por Kaitai já contêm # type: ignore e são sobrescritos a cada execução do kaitai-struct-compiler.
  • Os limites com dpkt que tocam atributos dinâmicos (por exemplo, MGMT_Frame.src) são atravessados com uma anotação Any na ligação local, em vez de comentários de ignore espalhados.

Regenerando parsers Kaitai

Os arquivos Python gerados em src/pyrmax/_generated/ são versionados para que o pacote seja instalado sem um toolchain Kaitai. Para regenerar após editar um .ksy:```sh kaitai-struct-compiler -t python --outdir src/pyrmax/_generated/ ksy/*.ksy

root@kitploit:~
Baixar ferramenta
field_14
field_9c
sta_field_68
ic_6b8
enc_token
docs/ac_wire_format.md
  • Verificar os decodificadores AC version < 9 contra capturas reais — o builder TX só emite a versão 9, então os caminhos de versão inferior (nome sem tag, campos de cauda ausentes) são implementados a partir da spec, mas não verificados no wire.
  • Fazer reverse-engineer do resto do payload M (bytes 9+ em unknown_rest) — atualmente opaco.
  • Expor metadados radiotap em pcap.FrameMeta: canal, RSSI, taxa. Atualmente apenas timestamp/MACs/BSSID são preenchidos.
  • Fixtures de captura reais em tests/samples/ — atualmente: airmax_ac_beacon.pcap (1 frame, beacon) e airmax_m_probe_response.pcap (1 frame, probe response). Mais variantes (assoc req/resp, capturas multi-frame) ainda são bem-vindas.
  • Envio de pacotes — os comandos scan (force-assoc ativa) e emulate injetam via scapy (os extras [scan] / [emulate]). Veja scan.py / emulate.py.
  • pip install pyrmax[emulate] — adiciona scapy para o comando emulate (injetar beacons + responder ao handshake de descoberta como dispositivos falsos).