Ana içeriğe geç
友田 陽大
実践ネットワーク攻撃と防御
セキュリティ
ネットワーク
TCP/IP
脆弱性診断
ホワイトハッカー
可観測性

ポートスキャン・サービス偵察(nmap)の仕組みと防御【2026】— 攻撃面の可視化とRFC準拠の縮小

ネットワーク偵察の中核『ポートスキャン』を、nmap 公式ドキュメントと NIST SP 800-115 に忠実に解説。ホスト発見・TCP SYN スキャン・バージョン/OS 検出の仕組みと、ステルススキャンがなぜ検知されるかを、TCP の状態遷移から説明。すべて自分のラボに閉じた合法手順で、攻撃面の最小化・IDS 検知・セキュリティグループ設計という防御まで型安全なコードで示します。

Published
Reading time
9 min read
Author
友田 陽大
Paylaş

ネットワーク攻撃は、ほぼ例外なくポートスキャンから始まります。攻撃者がまずやることは「どのホストが生きていて、どのポートが開いていて、そこで何が動いているか」を知ること——NIST SP 800-115発見(Discovery)フェーズの中核です。逆に言えば、防御側が自分の攻撃面を nmap で正確に把握していないなら、攻撃者の方が自社のネットワークに詳しいという危険な状態にあります。

この記事は、ネットワークペンテストの全体像に続き、ポートスキャンの仕組みを nmap 公式ドキュメントに忠実に解説し、その上で攻撃面の最小化と検知という防御を型安全なコードで示します。

安全地帯の徹底:本記事の nmap コマンドは、すべて自宅ラボの**自分が管理するVM(例 10.10.10.10)**に対してのみ実行します。無許可の第三者ホスト・公開サーバーへのスキャンは、不正アクセス禁止法の問題に加え、相手のIDSに記録され通報されうる実害ある行為です。スキャンしてよいのは「自分の資産・CTF・書面で許可されたスコープ」だけ——法律の記事を必ず先に。


1. ポートスキャンの原理 — TCP の握手を「途中でやめる」

ポートスキャンは、TCPの3ウェイハンドシェイクの挙動を逆手に取ります。ポートに SYN を送ったとき、相手の反応で状態が分かるのです。

■ ポートが「開いている(open)」場合
  scanner ── SYN ──► target:port      "開いてる?"
  scanner ◄─ SYN/ACK ─ target         "うん、開いてるよ"   ← これで「open」と判定
  scanner ── RST ──► target           "やっぱやめた"(接続を張らずに中断)

■ ポートが「閉じている(closed)」場合
  scanner ── SYN ──► target:port
  scanner ◄─ RST ──── target          "そのポートは閉じてる"   ← 「closed」と判定

■ ファイアウォールに「遮断されている(filtered)」場合
  scanner ── SYN ──► target:port
  (無応答 / ICMP unreachable)          ← 「filtered」と判定(FWの存在が分かる)

この「SYN を送って SYN/ACK が返れば開、ただし ACK は返さず RST で中断する」のが **TCP SYN スキャン(-sS、ハーフオープンスキャン)**です。完全な接続(ESTABLISHED)を張らないため、かつては「ステルス」と呼ばれました。

1.1 「ステルススキャン」は現代では筒抜け

重要な誤解を正します。SYN スキャンは現代のIDS/ファイアウォールには容易に検知されます。理由は単純で、「短時間に大量のポートへSYNだけを送り、SYN/ACKに対してACKを返さずRSTで中断する」という挙動自体が、正常な通信ではありえない明確なシグネチャだからです。攻撃側に「ステルス」の幻想を持たせないことが、防御側の出発点です(§4でこの検知を実装します)。

1.2 状態の3分類が「防御の地図」になる

状態意味防御側の読み方
openサービスが待ち受け中攻撃面。本当に公開が必要かを問う
closed応答するがサービスなしホストの存在は露見。FWで隠す余地
filteredFW/SGが遮断理想の状態。攻撃者に情報を与えない

防御の目標は明確です——公開すべきでないポートを open から filtered へ移すこと。


2. 偵察の手順 — ラボで「自分の攻撃面」を見る

自分のVMに対して、攻撃者と同じ視点で攻撃面を可視化します。

# ① ホスト発見:ラボのセグメントで「生きているホスト」を洗い出す(自分のVMのみ)
nmap -sn 10.10.10.0/24
#   -sn = ポートスキャンせずホスト発見だけ(ping sweep)

# ② TCP SYN スキャン:開いているポートを特定(自分のVM 10.10.10.10 のみ)
sudo nmap -sS 10.10.10.10
#   sudo が要るのは raw socket で SYN を直接組み立てるため

# ③ サービス・バージョン検出:開いたポートで「何が動いているか」を特定
nmap -sV 10.10.10.10
#   例: 22/tcp open ssh OpenSSH 8.9 / 80/tcp open http nginx 1.24.0
#   ↑ 版数が分かると、その版の既知脆弱性(CVE)に直結する=最も危険な情報漏れ

# ④ OS 推定 + デフォルトスクリプト(軽い既知チェック)
sudo nmap -O -sC 10.10.10.10
#   -O  = TCP/IP スタックの癖から OS を推定
#   -sC = 安全寄りのデフォルトNSEスクリプト(バナー取得等)

防御側にとっての最大の学びは ③ です。-sVnginx 1.24.0 のようにバージョンまで露出させると、攻撃者は「その版の既知CVE」を即座に引けます。サービスバナーの版数を隠す/最新に保つことが、いかに重要かが体感できます。

nmap の出力は -oX scan.xml でXML保存できます。診断レポートや、後述の「自分の攻撃面の継続監視」に使えます。自分の資産の棚卸しとしての nmap は、防御側の正当な必須スキルです。


3. 防御①:攻撃面の最小化 — 設定で機械的に潰す

スキャンへの最強の防御は、そもそも開いているポートを減らすことです。これは設計と設定で機械的に達成できます。

3.1 原則 — 「必要最小限の公開」

  • 管理ポート(SSH:22・RDP:3389・DB:5432/3306)を公開しない。踏み台(bastion)か、AWS なら SSM Session Manager(ポートを一切開けずに接続)を使う。
  • データベース・内部APIはプライベートサブネットへ。インターネットから到達不能にする。
  • 公開は 443(HTTPS)に集約し、その背後で経路を分岐させる。

3.2 AWS セキュリティグループを「最小許可」で書く

クラウドでは、ファイアウォール=セキュリティグループ(SG)の設計がそのまま攻撃面になります。0.0.0.0/0 でSSHを開けるのは典型的な事故です。

# ❌ 事故の典型:SSH を全世界に開放(スキャンで即発見され総当たりの的に)
resource "aws_security_group_rule" "bad_ssh" {
  type        = "ingress"
  from_port   = 22
  to_port     = 22
  protocol    = "tcp"
  cidr_blocks = ["0.0.0.0/0"] # ← 攻撃面を全世界に晒している
  security_group_id = aws_security_group.app.id
}

# ✅ 正:公開は 443 のみ。管理は SSM 経由でポートを開けない
resource "aws_security_group" "app" {
  name        = "app-minimal-surface"
  description = "Public 443 only; admin via SSM (no inbound SSH)"
  vpc_id      = var.vpc_id

  ingress {
    description = "HTTPS from anywhere (terminate at ALB/WAF)"
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  # SSH(22) の ingress は「無い」のが正解。SSM がポートレスで代替する。

  egress {
    description = "Allow outbound (tighten per workload)"
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
  tags = { Name = "app-minimal-surface" }
}

ポイント:攻撃面の最小化は「気をつける」ではなくコード(IaC)で表現し、レビューと差分で守る。これは私が AWS で多層ネットワークを設計・運用してきた中核の考え方です。


4. 防御②:スキャンを検知する — 型安全な検知ロジック

予防(攻撃面の縮小)をすり抜けても、スキャンには明確な行動シグネチャがあります:「短時間に、1つの送信元が、多数の異なるポート/ホストへ接続を試みる」。これを検知します。

4.1 本番では IDS(Suricata)が定石

本番では SuricataSnort のようなIDS/IPSが、ポートスキャンを既製ルールで検知します。AWS なら VPC フローログ+GuardDuty が Recon:* の finding を上げます。まずはマネージド/既製の検知に乗るのが正解です。

4.2 仕組みを理解するための最小実装(型安全)

検知の原理を理解するため、フローログ(または接続イベント)から「スキャンらしさ」を判定する純粋関数を書きます。本番ロジックではなく原理の可視化です。

/** 1件の接続試行(フローログの1行を正規化したもの)。 */
interface ConnectionAttempt {
  readonly srcIp: string;
  readonly dstPort: number;
  readonly timestamp: number; // epoch ms
}

interface ScanVerdict {
  readonly srcIp: string;
  readonly distinctPorts: number;
  readonly isLikelyScan: boolean;
}

/**
 * 「短時間に同一送信元が多数の異なるポートへ接続を試みた」かを判定する純粋関数。
 * 副作用なし=単体テスト・ゴールデンベクタ固定が容易(テスト容易性)。
 *
 * @param windowMs 観測窓(既定60秒)
 * @param portThreshold この窓で触れた異なるポート数の閾値(既定15)
 */
export function detectPortScan(
  attempts: readonly ConnectionAttempt[],
  now: number,
  windowMs = 60_000,
  portThreshold = 15,
): readonly ScanVerdict[] {
  const since = now - windowMs;
  const portsBySrc = new Map<string, Set<number>>();

  for (const a of attempts) {
    if (a.timestamp < since) continue; // 窓の外は無視
    const ports = portsBySrc.get(a.srcIp) ?? new Set<number>();
    ports.add(a.dstPort);
    portsBySrc.set(a.srcIp, ports);
  }

  return [...portsBySrc.entries()]
    .map(([srcIp, ports]) => ({
      srcIp,
      distinctPorts: ports.size,
      isLikelyScan: ports.size >= portThreshold,
    }))
    .filter((v) => v.isLikelyScan)
    .sort((a, b) => b.distinctPorts - a.distinctPorts); // 重い順に並べる(決定的)
}

この純粋関数なら、フローログのバッチや CloudWatch Logs のサブスクリプションから呼び出して、Slack 通知や自動ブロック(許可リストを壊さない範囲で)につなげられます。検知ロジックを副作用から切り離すことで、テストで挙動を固定でき、誤検知(自社の正当なスキャン・ヘルスチェック)を許可リストで安全に除外できます。

予防と検知は別物・両方要る:攻撃面の最小化(§3)は「そもそも見せない」予防、スキャン検知(§4)は「見られたら気づく」発見。どちらか一方では不十分です。これは多層防御の基本姿勢です。


5. まとめ

  • ポートスキャンは全攻撃の起点。SYN スキャン(-sS)は握手を途中でやめて open/closed/filtered を判定する。「ステルス」は幻想で、現代のIDSには筒抜け。
  • 最も危険な情報漏れはサービスの版数-sV)。既知CVEに直結する。版数を隠し、最新に保つ。
  • 防御①=攻撃面の最小化:管理ポートを公開せず、SGを最小許可でIaC化し、SSM/踏み台で代替。openfiltered に移す。
  • 防御②=検知:スキャンの行動シグネチャ(短時間・多ポート・単一送信元)をIDS/フローログで捉える。検知ロジックは純粋関数で分離しテスト可能に。
  • 自分の nmap で自社を棚卸しするのは、防御側の正当な必須スキル。攻撃者より自社に詳しくあれ。

次は、L2 で経路そのものに割り込む**ARPスプーフィング / 中間者攻撃(MITM)**を扱います。


私(友田 陽大)は、AWS のセキュリティグループ・NACL・VPC 設計を最小権限で IaC 化し、GuardDuty・フローログによる偵察検知まで含めた攻撃面管理を実装してきました。「自社の公開ポートを棚卸ししたい」「SG が 0.0.0.0/0 だらけで不安」「スキャン/偵察を検知したい」——こうした攻撃面の可視化と縮小を、攻撃者の視点で診断し、設定(IaC)と検知の両輪で根治します。お気軽にご相談ください。

友田

友田 陽大

Bakanlık (METI) Ödülü kazanan bir ürünün geliştiricisi. TypeScript + Python + AWS ile SaaS, endüstriyel dijital dönüşüm ve üretime hazır üretken yapay zekâyı (RAG) gereksinimlerden altyapıya ve işletmeye kadar tek başıma uçtan uca sunuyorum.

Could this attack succeed on your network?

Network / infrastructure penetration testing & hardening

The L2–L4 attacks covered here — ARP spoofing, DNS poisoning, session hijacking, SYN flood, sniffing — I diagnose where your configuration breaks from an attacker's perspective, and design and implement RFC-compliant defenses (DAI, DNSSEC, RFC 5961, BCP 38, TLS/mTLS, WAF/DDoS protection). With experience building multi-layered networks on AWS multi-account (VPC, least-privilege IAM, GuardDuty, WAF), I help minimize the attack surface and move toward zero trust.

Hem proje bazlı işler hem de teknik danışmanlık için uygunum. 30 dakikalık ücretsiz bir görüşmeyle başlayın.

最短ルート:カレンダーから直接予約

相談内容が固まっている方は、フォーム送信よりその場で日程を確定する方がスムーズです。下記から空き時間をお選びください。

  • 30分のオンライン無料相談
  • Google Meet / Zoom / Microsoft Teams
  • NDA 商談前締結可・無理な営業はいたしません
無料相談の空き枠を予約する

Bunlar da ilginizi çekebilir