はじめに:PCより圧倒的に特定が難しい「スマートフォンの壁」
情シスやネットワーク管理者がLAN内を監査する際、最も頭を悩ませるのが 「スマートフォンやタブレット(iOS / Android)」 です。
WindowsやLinuxサーバーであれば、Pingに応答し、SSH(22)やWinRM(5985)、SMB(445)といったポートが開いているため、簡単にOSやバージョンを特定できます。
しかし、スマートフォンは違います。
- 省電力とセキュリティのため、ほぼすべての受信ポートが閉じている(フルステルス)
- Ping(ICMP)を無視する設定になっていることが多い
- プライベートMACアドレス(ランダムMAC)機能により、ベンダーOUIすら隠蔽される
結果として、資産台帳の画面には 「正体不明のIPアドレス(ポート全閉)」 という不気味なレコードが並ぶことになります。これが管理対象のPCなのか、検証用のスマートフォン(iOS / Android)やタブレットなのか、判断がつきません。
本記事では、端末側に一切アクセスすることなく、端末が送信するパケットの特徴(TTL値、HTTP User-Agent、DHCPオプション55)から「iOS / Android / PC」を高精度に分類する受動特定ロジック を解説します。
1. 手がかり ①:IPパケットの「初期TTL(Time to Live)」
端末がPing応答を返さなくても、WebアクセスやDNS問い合わせなどで外へ送信したパケットのIPヘッダーを見ることで、大まかなOSファミリーが分かります。
| OS種別 | 推定される初期TTL値 |
|---|---|
| Linux / Android / iOS / macOS | 64 |
| Windows (全バージョン) | 128 |
| Cisco / ネットワーク機器 | 255 |
同一L2セグメント内であればルーターを経由しないため、パケットのTTL値がそのまま観測されます。
TTLが 128 であればWindows PCの可能性が極めて高く、64 でポートが閉じていればモバイル端末(またはLinux/Mac)の疑いが生じます。
2. 手がかり ②:HTTPプロキシやDNSでの「User-Agent / トークン検知」
スマホがLAN内Wi-Fiに接続した瞬間、OSは自動的に「キャプティブポータル(認証画面)」の有無をチェックするHTTPリクエストを飛ばします。
- Apple端末:
captive.apple.comへアクセス、User-AgentにCaptiveNetworkSupportやDarwin/xx.x.xが含まれる - Android端末:
connectivitycheck.gstatic.comへアクセス、User-AgentにAndroidやDalvikが含まれる
LAN内のDNSクエリログや透過型HTTPプロキシのログをわずかにフックするだけで、一撃でOS種別が判明します。
💻 コア実装・設定スニペット(抜粋)
# コア実装ロジック(要点抜粋)
import re
def detect_device_by_user_agent(ua_string: str) -> dict:
if not ua_string:
return {"device_type": "UNKNOWN", "os": "UNKNOWN"}
ua = ua_string.lower()
# iOS / iPadOS 検知
if "iphone" in ua:
match = re.search(r"os (\d+[_\d]*) like mac os x", ua)
version = match.group(1).replace("_", ".") if match else "不明"
return {"device_type": "スマートフォン", "os": f"Apple iOS {version}"}
elif "ipad" in ua:
return {"device_type": "タブレット", "os": "Apple iPadOS"}
elif "cfnetwork" in ua or "darwin" in ua:
return {"device_type": "Appleデバイス", "os": "Apple OS (iOS/macOS)"}
# Android 検知
elif "android" in ua:
match = re.search(r"android (\d+[\.\d]*)", ua)
version = match.group(1) if match else "不明"
return {"device_type": "スマートフォン/タブレット", "os": f"Android {version}"}
# PC判定
elif "windows nt" in ua:
return {"device_type": "PC", "os": "Microsoft Windows"}
elif "macintosh" in ua:
return {"device_type": "PC", "os": "macOS"}
return {"device_type": "一般端末", "os": "その他"}
3. 手がかり ③:DHCP Option 55(PRL)によるOSフィンガープリント
最も強力なのが、端末がIPアドレスを要求する際の DHCP Request(Option 55: Parameter Request List) です。
OSごとに要求するDHCPパラメータの「数字の並び順」が世界中で統一されており、ほぼ指紋(フィンガープリント)のように機能します。
-
iOS/iPadOS:
1, 121, 3, 6, 15, 119, 252 -
Android:
1, 3, 6, 15, 26, 28, 51, 58, 59, 43 -
Windows 10/11:
1, 3, 6, 15, 31, 33, 43, 44, 46, 47, 119, 121, 249, 252
パケットスニッファ(scapy 等)でDHCPパケットのOption 55をキャプチャするだけで、端末に1度もパケットを送りつけることなく、画面を触ることもなく、OSの正体を99%の確率で断定 できます。
まとめ:ステルス端末には「パッシブな観察」で対抗する
「ポートが開いていないから分からない」と諦めるのは、アクティブスキャンしか使っていない証拠です。
- TTL値で大まかなOS系(Unix系 vs Windows系)を絞る
- キャプティブポータルへの自己申告通信(User-Agent)を拾う
- DHCP Option 55の指紋からOSを特定する
この受動的(パッシブ)アプローチを組み合わせることで、自宅ラボや検証用Wi-Fi環境内のスマートフォン・タブレットのOS種別をエージェントレスで正確に識別し、資産台帳を整理することができます(※組織のネットワークでトラフィックやヘッダ情報を扱う場合は、電気通信事業法[通信の秘密]・個人情報保護法および社内規程に基づき、利用者への事前周知と同意のもとで実施してください)。
📚 さらに詳しいアーキテクチャ設計・パラメータ表・トラブルシューティング
最後までお読みいただきありがとうございます!
本記事が少しでも「役に立った」「あとで試したい」と感じていただけましたら、ぜひQiitaの 「いいね(♡)」 と 「ストック」、および アカウントのフォロー をいただけると今後の検証・執筆の大きな励みになります!
また、本記事のさらに踏み込んだ 「深層アーキテクチャ解説」「主要パラメータの技術的根拠」「現場アンチパターン・トラブルシューティング対応表」 は、以下のGitHub技術リファレンスにて公開しています。
👉 【第19弾 詳細技術リファレンス (QIITA_ARTICLE_DETAIL_19.md)】
⭐ 全14層・200パターンの自立型インフラ&オンプレAIリファレンス集(おじさんの武器庫)を順次公開中です。ぜひGitHubリポジトリへの Star (★) と X (@OjisanTechnical) のフォローもお願いいたします!
👉 GitHub リポジトリ: ojisantech/ojisan-arsenal
💡 【検証環境・個人研究(PoC)に関する注記】
本記事は、筆者個人の自宅検証環境(ホームラボ/仮想環境)において、公開情報およびOSS(オープンソースソフトウェア)を用いて独自に構築・検証した個人研究(PoC)の記録です。特定の企業・団体の実環境や業務上の非公開情報とは一切関係ありません。