
LuaベースのWiresharkポストディセクタで、Ubiquiti AirMAX/RouterBoard 802.11ベンダーIEを復号・解析し、フィルタ可能なフィールドに変換します。
Ubiquiti AirMAX(AC + M)および付随するMikrotik / RouterBoardベンダー情報要素(IE)用の、Luaで書かれたWireshark/tsharkディセクタです。
これはpyrmaxのオンザワイヤ版です:デコードロジックはそのPythonパッケージをフィールド単位でミラーリングしています。ACパケット形式はAirMAX ACファームウェアバイナリからリバースエンジニアリングされました。MおよびRouterBoardのレイアウトは、以前に公開された旧AirMAX-MベンダーIEに関するノートに基づいています。
AirMAXは802.11のベンダー固有IE(タグ221)内に格納されて運ばれます。Wiresharkは既に802.11フレームを解析し、ベンダーIEを不透明なブロブとして表示します。wiremaxはそのブロブを受け取り、復号し(AES-128-ECB、鍵はフレームのMACから導出)、解析済みのフィルタ可能なサブツリーを描画します。
Tag: Vendor Specific: Ubiquiti Inc (built-in 802.11 dissector)
AirMAX AC (Vendor Specific IE) ← added by wiremax
Flags: 0x02 ( .... ..1. = Encrypted: True )
Message Type: Beacon (1)
Encrypted Length: 48
[Decrypted payload (AES-128-ECB)]
[AES Key …: 1f162a13… (dst=broadcast)]
Version: 9
Source MAC: 24:5a:4c:44:57:fd
Radio MAC (mac_0c): 24:5a:4c:44:57:fd
Capability Flags: 0x0000003e
Mixed Mode: 0
Radioname: LB1
SSID: labalUBI2
TLV: Radioname (1), len 3
TLV: SSID (2), len 9
TLV: Padding (0)
復号後のレイアウトはMessage Typeに依存します:ビーコンはmac_0c / cap_flags / mixed_mode + 名前TLVを運びます(上記参照)。assoc req/respはチェインマスク、cap_flags、およびバージョン依存の末尾フィールド(field_9c、rssi、fwname、txpower)を運びます。probe reqはヘッダのみです。deauthはjiffiesノンスと不透明な認証トークンを運びます(また、その送信元MACはXORマスクされており、wiremaxがマスクを解除します)。
| Variant | Coverage |
|---|---|
| AirMAX AC | アウターヘッダ + 復号された共有ヘッド(version + src_mac)+ メッセージタイプ別・バージョン依存のボディ(beacon、assoc req/resp、probe req、deauth)+ 名前TLV |
| AirMAX M | 外殻 + 復号された文書化済み9バイト(version、msg_type、src_mac、enable)+ 未解釈の残り |
| RouterBoard (Mikrotik) | OUI/タイプ + サブIE + デバイス名(平文) |
未文書化のバイト領域は生のまま(Unknown [n:len])表示され、決して創作されません — pyrmaxおよびac/ナレッジベースと同じ方針です。
ポストディセクタです(組み込みの802.11ディセクタを置き換えるものではなく、その後に実行されます)。各フレームについて、次の処理を行います:
Fieldエクストラクタを介してすべてのwlan.tag.oui、およびwlan.sa / wlan.daを読み取ります。00:27:22)、M(00:15:6d)、またはRouterBoard(00:0c:42)のOUIを照合します — AC/Mの場合はOUIタイプFF FF FFも要求します。なぜなら00:15:6dはMikrotikと、同じフレームに現れる別のUbiquiti IEとで共有されているためです。AES-128-ECBでペイロードを復号します。鍵は= HMAC-SHA1(dst_mac, src_mac)[:16]で、最初にキャプチャされた802.11宛先MACを試し、ブロードキャストにフォールバックします(アイデンティティフレームはユニキャストでもブロードキャスト鍵を使用します)— 復号されたペイロードに埋め込まれた送信元MACが802.11の送信元と一致する鍵が採用されます。暗号処理(SHA-1、HMAC-SHA1、AES-128復号)は自己完結型の純Luaです — WiresharkはLuaに暗号APIを公開していません。ペイロードは16バイトブロック数個分に過ぎないため、パフォーマンスは問題になりません。鍵は公開されているMACから導出されるため、これは難読化であり、セキュリティではありません。
一回限り(インストール不要):
tshark -X lua_script:airmax.lua -r capture.pcap -V
wireshark -X lua_script:airmax.lua capture.pcap
永続的(Wireshark GUI + tshark): wiremax/フォルダ全体をPersonal Lua Pluginsディレクトリに配置します。正確なパスはWiresharkのヘルプ ▸ Wiresharkについて ▸ フォルダー ▸ 個人用Luaプラグインに表示されます。デフォルトは次のとおりです:
| OS | デフォルトのPersonal Lua Pluginsパス |
|---|---|
| Linux | ~/.local/lib/wireshark/plugins/ |
| macOS | ~/.local/lib/wireshark/plugins/(または~/.config/wireshark/plugins/) |
| Windows | %APPDATA%\Wireshark\plugins\ |
反復作業中はシンボリックリンクが理想的です — コピー作業なしで、リロード(Ctrl+Shift+L)時に編集内容が反映されます:
ln -s "$PWD" ~/.local/lib/wireshark/plugins/wiremax
Wiresharkはプラグインフォルダ配下のすべての.luaを再帰的にロードします。wsairmax/配下のサブモジュールは通常のモジュールであり(スタンドアロンでロードしても無害)、test/selftest.luaはWireshark内では何も行いません。
例:
tshark -r cap.pcap -Y 'airmax.ac.ssid' -T fields -e wlan.sa -e airmax.ac.ssid
tshark -r cap.pcap -Y 'airmax.m.msg_type == 1' -T fields -e airmax.m.src_mac
tshark -r cap.pcap -Y 'airmax.rb.device_name' -T fields -e airmax.rb.device_name
キャプチャは802.11モニターモード(radiotap)である必要があります。IEを運ぶ管理フレーム(ビーコン / プローブ応答 / アソシエーション)は802.11レイヤでは暗号化されていません — IE内のAirMAXペイロードのみがAESでラップされており、wiremaxがそれをアンラップします。
test/selftest.luaは、スタンドアロンのLua 5.4インタープリタ(Wiresharkなし)で暗号処理とデコーダを実行し、正解ベクトルに加えて標準SHA-1 / RFC-2202 HMACベクトルと照合します:
lua test/selftest.lua # from this directory
実際のキャプチャに対するエンドツーエンドの検証(pyrmaxはtests/samples/配下にサンプルpcapを同梱しています):
tshark -X lua_script:airmax.lua -r airmax_ac_beacon.pcap -V
tshark -X lua_script:airmax.lua -r airmax_m_probe_response.pcap -V
wiremax/
├── airmax.lua # Wireshark entry: ProtoFields + postdissector + tree
├── wsairmax/ # pure-Lua modules (no Wireshark dependency)
│ ├── util.lua # hex / MAC helpers
│ ├── sha1.lua # SHA-1 + HMAC-SHA1
│ ├── aes.lua # AES-128 ECB decrypt
│ ├── crypto.lua # key derivation + decrypt (mirrors pyrmax/_crypto.py)
│ ├── ac.lua # AirMAX AC decoder (outer ksy: airmax_ac; payload hand-written per 09b)
│ ├── m.lua # AirMAX M decoder (ksy: airmax_m[_payload])
│ └── routerboard.lua # RouterBoard decoder (ksy: routerboard)
├── test/selftest.lua # standalone-Lua test harness
└── README.md
msg_type**は、古いAirMAX-Mのノートに従って1 = Beaconとラベル付けしていますが、値1はプローブ応答でも観測されます — Mのメッセージタイプ空間は完全にはマッピングされていないため、生の数値を信頼してください。enc_lenで、u16ビッグエンディアン(09b §3)です。以前の1バイト読み取りは、ペイロードが256未満の場合にのみ偶然正しくなっていました。version < 9のデコーダも同様に未検証です(TXは9のみを送出します)。test/selftest.lua内の合成ベクトルを参照してください。pyrmax(src/pyrmax/ac.pyまたはそのksy/*.ksyスキーマ)でフィールドが追加・改名された場合は、対応するwsairmax/*.luaデコーダに反映し、ユーザーに見えるものであればairmax.luaにProtoFieldを追加してください。test/selftest.lua内の正解ベクトルはpyrmaxのサンプルpcapに由来するため、差異はそこで明らかになります。
| Filter | Meaning |
|---|
airmax.ac.msg_type | メッセージタイプ:1 Beacon、2 Assoc Req、3 Assoc Resp、4 Probe Req、0xC Deauth |
airmax.ac.flags.encrypted | 暗号化ビット(0x02) |
airmax.ac.version | 復号されたフォーマットバージョン(ゲート。TXは9を送出) |
airmax.ac.src_mac | 復号されたヘッドからの送信元MAC(deauthではマスク解除) |
airmax.ac.mac_0c | ビーコンの無線MAC(BSSID) |
airmax.ac.cap_flags + airmax.ac.cap_flags.chanbw/.high_density/.auth_deauth/.compat_11ax | ケイパビリティビットフィールド(§11) |
airmax.ac.radioname, airmax.ac.ssid, airmax.ac.fwname | AC名 / ファームウェア文字列 |
airmax.ac.jiffies_nonce, airmax.ac.enc_token | deauthノンス + 不透明な認証トークン |
airmax.ac.tlv.tag / .len / .data | 生のTLVウォーク |
airmax.m.version, airmax.m.msg_type, airmax.m.src_mac, airmax.m.enable | Mの文書化済みフィールド |
airmax.m.unknown_rest | 未文書化のM末尾 |
airmax.rb.device_name | RouterBoardデバイス名 |
airmax.ac.key / airmax.m.key | 導出されたAES鍵(検証用に生成) |