セキュリティコミュニティ「WEST-SEC」

セキュリティ初心者の方でも参加できる「わかりやすい」セキュリティイベント、8割解けるCTFを開催しています。

AIおよびAIエージェントを活用したセキュリティ診断

0.WEST-SEC勉強会

(1)勉強会概要

■タイトル

AIおよびAIエージェントによるセキュリティ診断の基礎

〜情シス・セキュリティ初学者のための「これからの診断」入門〜

■おもなテーマ
・AIとAIエージェントの違い
・セキュリティ診断でAIは何をしているのか
・AIエージェントはどのように診断を進めるのか
・AI診断のメリット・デメリット
・AIによる静的診断と動的診断の実施結果比較
・実際にやってみた!Web脆弱性診断アプリケーション
・実際にやってみた!AIを使ったペネトレーションテスト

(2)開催情報

項目 内容
日時 2026年9月の平日 19時~21時を予定
開催形式 オンライン
参加費 無料
主催 WEST-SEC

(3)タイムスケジュール案

時間 内容 登壇
19:00〜19:10 オープニング、アンケート取得など 事務局
19:10〜19:40 【基礎講義】AIとAIエージェントによるセキュリティ診断とは WEST-SEC
19:40〜20:10 AIを使ったWeb脆弱性診断アプリケーション 登壇者1
20:10〜20:10 休憩
20:10〜20:40 AIを使ったペネトレーションテスト 登壇者2
20:40〜21:00 Q&A・クロージング 全登壇者

1.全体像

1.1 なぜAIを活用すべきなのか

・攻撃側は既にAIを十二分に活用している(防御側が使わない理由がない)
・診断対象システムの数・変化速度に対して、人間の診断員が不足
・モデルの能力向上により、実用レベルに達しつつある
→現に、AnthropicのClaude Mythosが、サイバーセキュリティ分野での能力が照明されている

1.2 AIを活用しないとできない?

「AIを使わないとできない診断」はほぼ存在しません。既存ツール(nmap、Metasploit、SASTツール等)は元々AIなしで動く。
・つまりAIは代替不可能な機能を提供しているわけではなく、スピードと網羅性を底上げする役割です。
・加えて、診断後の対策の優先度の検討も必要だが、その判断の補助にもAIを活用すると便利である。

2. AI活用の基本構造

2.1 AIは診断の補助役

・セキュリティ診断でAIを使うときは、AIを「診断ツールそのもの」と考えない方がよいです。
・実際にスキャンするのは、nmap、ZAP、Burp Suite、Semgrep、CodeQL、CSPM、EDR、SIEMなどの既存ツールです。AIは、それらの結果を読み取り、意味づけし、次に確認すべきことを提案する役割を担います。

2.2 チャット型AIとAIエージェントの違い

AIの使い方は、大きく分けると「チャット型AI」と「AIエージェント」に分けられます。

種類 使い方 向いている場面 補足 特徴
チャット型AI 人間がファイルや結果を渡す 小規模なコード確認、診断結果の整理 チャット型AIは、人間がソースコード、ログ、診断結果などをアップロードし、それをAIに読ませる使い方です。ChatGPTやClaudeのWeb画面にファイルを渡して、「このコードに脆弱性がないか確認して」と依頼するイメージ 手軽
AIエージェント AIがファイル探索やコマンド実行を行う 中~大規模 AIエージェントは、AI自身がリポジトリ内のファイルを探したり、grepを実行したり、テストを動かしたり、必要なファイルを順番に読んだりできます。Claude Code、Codex、Cursor、VS Code統合型のAIツールなどがこの使い方に近い コマンド実行やファイル変更のリスク

2.3 AIエージェントをどこから使うか

使い方 人間が操作する画面・ツール 特徴
チャット画面 ChatGPT、Claude(claude.ai) ファイルや診断結果をアップロードして分析させる
AIエージェント(GUI/IDE統合) Claude Code(VS Code拡張)、Codex(デスクトップアプリ/IDE拡張) 開発画面の中でAIがプロジェクト全体を見ながら調査・修正する
CLIエージェント環境 Linux、WSL、Kali Linuxなど(PowerShell/ターミナルからAIを起動) nmap、ZAP、Semgrepなどのツールを実行しながら、コマンドラインからAIエージェントに診断させる場所
Bedrock連携 社内ツール、CLI、エージェント基盤 企業管理下でAIモデルを利用する

2.4 シェルスクリプトとAIエージェントの違い

Q.AIエージェントはコマンドを実行できる。だったら、シェルスクリプトと何が違う?

A.違いは、結果を見て次の行動を変えられるかどうかです。
シェルスクリプトは、決められたコマンドを決められた順番で実行します。

uname -a
ip addr
ss -tulpen
systemctl list-units --type=service --state=running
lastlog
cat /etc/ssh/sshd_config

これは、最低限の確認項目を漏れなく実行することや、安全に診断できる(システムを壊さない)というメリットがある。

一方、AIエージェントは、結果を見ながら次の調査を変えます。

ssで22番ポートが開いている
  ↓
sshd_configを確認する
  ↓
PermitRootLogin yes を発見する
  ↓
認証ログを確認する
  ↓
不審なログイン失敗が多いか確認する

このように、AIエージェントは「調査の分岐」ができます。単にコマンドを順番に実行するのではなく、結果を解釈し、次に見るべき場所を判断できます。

2.5 AIエージェント利用時のリスクと制御

AIエージェントは便利ですが、リスクもあります。特に注意すべきなのは、AIがコマンドを実行できる場合です。

(1)主なリスク

・機密情報を読んでしまう
・不要な外部通信をしてしまう
・ファイルを書き換えてしまう
・本番環境に負荷をかけてしまう
・危険なコマンドを実行してしまう
・診断範囲外の対象にアクセスしてしまう

(2)必要な制御の例

上記のリスクのため、AIエージェントを使う場合は、最初から自由に操作させるのではなく、以下のような制御を入れる必要があります。
・実行できるコマンドを許可リスト化する
・sudoは禁止、または限定する
・読み取れるファイル範囲を制限する
・外部通信を禁止、または制限する
・ファイル変更系コマンドを禁止する
・実行ログをすべて残す
・本番環境では人間の承認を挟む
・診断対象と診断範囲を明確にする

特に本番環境では、AIエージェントに自由なスキャンや攻撃的な検査をさせるべきではありません。まずは読み取り専用、検証環境、限定された権限で使うのが安全です。

3.システムの対象およびセキュリティ診断でのAIの活用

3.1 全体像

以下のシステムの対象ごとに、診断方法の全体像とAIの使い方を整理します。

項番 分類 内容
1 クラウド・インフラ診断 AWS/Azure/GCP、サーバOS、コンテナ、仮想基盤。CSPM等の既存機能を軸に、AIは分析・トリアージ担当
2 PC・サーバOS診断 エンドポイントの状態確認(パッチ、アカウント、サービス、防御機能、ログ)。読取専用コマンドをAIエージェントに実行させる形が中心
3 ネットワーク機器Config診断 FW/ルータ/L3スイッチ/VPN機器の設定ファイルをテキストとして解析。エージェント化は不要、Configをチャットに投入する形で十分
4 アプリケーション診断 ソースコード(SAST)、動的リクエスト(DAST)、業務ロジックの手動診断。診断方法によりAIとの相性が異なる

3.2 クラウド・インフラ診断

AWS、Azure、GCP、サーバOS、PC、コンテナ、仮想基盤などが対象です。

(1)診断の主なポイント
観点 診断内容
IAM 過剰権限、未使用ユーザ、MFA未設定、アクセスキー放置
ネットワーク 公開ポート、Security Group、NACL、VPN、踏み台
ログ CloudTrail、GuardDuty、VPC Flow Logs、監査ログ
脆弱性 OSパッチ、ミドルウェア、コンテナイメージ
データ保護 S3公開設定、暗号化、バックアップ
(2)AIの役割

・AWSであれば、Security Hub CSPMがGuardDuty、Inspector、Macieなどの検出結果を集約できます。クラウドでは、AIが直接スキャンするより、まずクラウド標準機能やCSPMに診断させ、その結果をAIが分析する形が現実的です。
・AIエージェントを使わず、チャットで十分でしょう。

3.3 PC・サーバOS診断

端末・OSの診断というより、状態確認に近い。

(1)診断の主なポイント(というより、見るべきポイント)
観点 診断内容
パッチ OS、ミドルウェア、ブラウザ、Java、OpenSSLなど
アカウント 不要ユーザ、管理者権限、パスワードポリシー
サービス 不要サービス、待受ポート
防御機能 EDR、ウイルス対策、FW、BitLocker
ログ 認証失敗、不審プロセス、永続化設定
ハードニング SSH、RDP、SMB、sudo、監査設定
(2)AIの役割

・Windowsであれば、PowerShellを使て、イベントログ、インストール済みソフトウェア、ローカルユーザ、管理者グループ、Defender、BitLocker、ファイアウォール設定などを確認します。
・その結果をAI(チャットでもOK)に確認すればいいでしょう。

3.4 【参考】Windows端末の診断情報をPowerShellで取得する

(1)流れ

PowerShellで情報取得

ログファイルに保存

AIにログを渡して分析

必要な場合だけ追加確認

(2)STEP1:PowerShellを管理者として起動する

・スタートメニューを右クリックで「Windows PowerShell(管理者)」を選ぶ。

(3)STEP2:診断用スクリプトを作成する

・デスクトップに `windows_security_check.ps1` というファイルを作成します。
・PowerShellで次のコマンドを実行すると、メモ帳で新規ファイルを開けます。

notepad "$env:USERPROFILE\Desktop\windows_security_check.ps1"

・開いたメモ帳に、次の内容を貼り付けて保存します。

# Windows Security Check Script v3
# Read-only Windows security information collection script
# Default: no online checks. Set $RunOnlineChecks = $true to run winget upgrade check.

$RunOnlineChecks = $false

$TimeStamp = Get-Date -Format "yyyyMMdd_HHmmss"
$OutputDir = Join-Path $env:USERPROFILE "Desktop\windows_security_check_$TimeStamp"

New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null

Start-Transcript -Path (Join-Path $OutputDir "transcript.txt") -Force

function Save-Command {
    param (
        [string]$Name,
        [scriptblock]$Command
    )

    $Path = Join-Path $OutputDir "$Name.txt"

    "### $Name" | Out-File -FilePath $Path -Encoding UTF8
    "### Collected at: $(Get-Date)" | Out-File -FilePath $Path -Append -Encoding UTF8
    "" | Out-File -FilePath $Path -Append -Encoding UTF8

    try {
        & $Command |
            Out-String -Width 4096 |
            Out-File -FilePath $Path -Append -Encoding UTF8
    }
    catch {
        "ERROR: $($_.Exception.Message)" |
            Out-File -FilePath $Path -Append -Encoding UTF8
    }
}

function Save-Events {
    param (
        [string]$Name,
        [hashtable]$Filter,
        [int]$MaxEvents = 50
    )

    $Path = Join-Path $OutputDir "$Name.txt"

    "### $Name" | Out-File -FilePath $Path -Encoding UTF8
    "### Collected at: $(Get-Date)" | Out-File -FilePath $Path -Append -Encoding UTF8
    "" | Out-File -FilePath $Path -Append -Encoding UTF8

    try {
        Get-WinEvent -FilterHashtable $Filter -MaxEvents $MaxEvents -ErrorAction Stop |
            Select-Object TimeCreated, Id, ProviderName, Message |
            Format-List |
            Out-String -Width 4096 |
            Out-File -FilePath $Path -Append -Encoding UTF8
    }
    catch {
        "No matching events or error: $($_.Exception.Message)" |
            Out-File -FilePath $Path -Append -Encoding UTF8
    }
}

# 1. Basic information
Save-Command "01_computer_info" {
    Get-ComputerInfo |
        Select-Object CsName, WindowsProductName, WindowsVersion, OsArchitecture, CsDomain, CsManufacturer, CsModel, TimeZone
}

Save-Command "02_hostname" {
    hostname
}

Save-Command "03_ipconfig" {
    ipconfig /all
}

# 2. Patch information
Save-Command "04_hotfix" {
    Get-HotFix |
        Sort-Object InstalledOn -Descending |
        Select-Object HotFixID, Description, InstalledOn, InstalledBy
}

# 3. Users and administrators
Save-Command "05_local_users" {
    Get-LocalUser |
        Select-Object Name, Enabled, LastLogon, PasswordLastSet, PasswordRequired, UserMayChangePassword
}

Save-Command "06_administrators_group" {
    Get-LocalGroupMember Administrators
}

# 4. Services and listening ports
Save-Command "07_running_services" {
    Get-Service |
        Where-Object {$_.Status -eq "Running"} |
        Sort-Object Name |
        Select-Object Name, DisplayName, Status, StartType
}

Save-Command "08_listening_tcp_ports" {
    Get-NetTCPConnection -State Listen -ErrorAction SilentlyContinue |
        Select-Object LocalAddress, LocalPort, OwningProcess,
            @{Name="ProcessName";Expression={(Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue).ProcessName}} |
        Sort-Object LocalPort
}

Save-Command "08b_watch_tcp_udp_ports" {
    $watchPorts = @(21,22,23,80,135,137,138,139,443,445,3306,3389,5900,8080,8443)

    $tcp = Get-NetTCPConnection -State Listen -ErrorAction SilentlyContinue |
        Where-Object { $_.LocalPort -in $watchPorts } |
        Select-Object @{Name='Proto';Expression={'TCP'}}, LocalAddress, LocalPort, OwningProcess,
            @{Name='ProcessName';Expression={(Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue).ProcessName}}

    $udp = Get-NetUDPEndpoint -ErrorAction SilentlyContinue |
        Where-Object { $_.LocalPort -in $watchPorts } |
        Select-Object @{Name='Proto';Expression={'UDP'}}, LocalAddress, LocalPort, OwningProcess,
            @{Name='ProcessName';Expression={(Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue).ProcessName}}

    ($tcp + $udp) | Sort-Object LocalPort, Proto | Format-Table -AutoSize
}

# 5. Firewall
Save-Command "09_firewall_profiles" {
    Get-NetFirewallProfile |
        Select-Object Name, Enabled, DefaultInboundAction, DefaultOutboundAction
}

Save-Command "10_firewall_inbound_allow_rules" {
    Get-NetFirewallRule |
        Where-Object {$_.Enabled -eq "True" -and $_.Direction -eq "Inbound" -and $_.Action -eq "Allow"} |
        Select-Object DisplayName, Enabled, Direction, Action, Profile
}

Save-Command "10b_firewall_inbound_allow_rules_detailed" {
    $rules = Get-NetFirewallRule -Enabled True -Direction Inbound -Action Allow -ErrorAction SilentlyContinue

    $results = foreach ($rule in $rules) {
        $port = $rule | Get-NetFirewallPortFilter -ErrorAction SilentlyContinue
        $app  = $rule | Get-NetFirewallApplicationFilter -ErrorAction SilentlyContinue
        $addr = $rule | Get-NetFirewallAddressFilter -ErrorAction SilentlyContinue

        [PSCustomObject]@{
            DisplayName   = $rule.DisplayName
            Profile       = $rule.Profile
            Protocol      = $port.Protocol
            LocalPort     = $port.LocalPort
            RemoteAddress = $addr.RemoteAddress
            Program       = $app.Program
            Service       = $app.Service
        }
    }

    $results | Sort-Object DisplayName | Format-Table -AutoSize
}

Save-Command "10c_watch_port_firewall_rules" {
    $targetPorts = @('21','22','23','80','135','137','138','139','443','445','3306','3389','5900','8080','8443')
    $rules = Get-NetFirewallRule -Enabled True -Direction Inbound -Action Allow -ErrorAction SilentlyContinue

    $results = foreach ($rule in $rules) {
        $portFilter = $rule | Get-NetFirewallPortFilter -ErrorAction SilentlyContinue
        $appFilter  = $rule | Get-NetFirewallApplicationFilter -ErrorAction SilentlyContinue

        foreach ($lp in @($portFilter.LocalPort)) {
            if ($targetPorts -contains ([string]$lp)) {
                [PSCustomObject]@{
                    Port        = $lp
                    Protocol    = $portFilter.Protocol
                    DisplayName = $rule.DisplayName
                    Profile     = $rule.Profile
                    Program     = $appFilter.Program
                    Service     = $appFilter.Service
                }
            }
        }
    }

    $results |
        Sort-Object @{Expression = { [int]$_.Port }}, Protocol |
        Format-Table -AutoSize
}

# 6. Defender / BitLocker
Save-Command "11_defender_status" {
    Get-MpComputerStatus |
        Select-Object AMServiceEnabled, AntivirusEnabled, RealTimeProtectionEnabled, AntispywareEnabled, NISEnabled, FullScanAge, QuickScanAge
}

Save-Command "11b_defender_detail" {
    Get-MpComputerStatus |
        Select-Object AntivirusEnabled,
                      RealTimeProtectionEnabled,
                      AntivirusSignatureLastUpdated,
                      AntispywareSignatureLastUpdated,
                      NISSignatureLastUpdated,
                      FullScanAge,
                      QuickScanAge,
                      FullScanEndTime,
                      QuickScanEndTime
}

Save-Command "12_bitlocker_status" {
    Get-BitLockerVolume |
        Select-Object MountPoint, VolumeStatus, ProtectionStatus, EncryptionPercentage
}

# 7. RDP / SMB
Save-Command "13_rdp_setting" {
    Get-ItemProperty "HKLM:\System\CurrentControlSet\Control\Terminal Server" |
        Select-Object fDenyTSConnections
}

Save-Command "14_smb_shares" {
    Get-SmbShare |
        Select-Object Name, Path, Description, ShareState
}

Save-Command "15_smb_server_config" {
    Get-SmbServerConfiguration |
        Select-Object EnableSMB1Protocol, EnableSMB2Protocol, EncryptData, RejectUnencryptedAccess
}

# 8. Audit policy
Save-Command "16_audit_policy" {
    auditpol /get /category:*
}

# 9. Startup commands and scheduled tasks
Save-Command "17_startup_commands" {
    Get-CimInstance Win32_StartupCommand |
        Select-Object Name, Command, Location, User
}

Save-Command "18_scheduled_tasks" {
    Get-ScheduledTask |
        Where-Object {$_.State -ne "Disabled"} |
        Select-Object TaskName, TaskPath, State
}

# 10. Event logs
Save-Events "19_event_logon_failure_4625" @{LogName='Security'; Id=4625} 50
Save-Events "20_event_privileged_logon_4672" @{LogName='Security'; Id=4672} 50
Save-Events "21_event_user_created_4720" @{LogName='Security'; Id=4720} 50
Save-Events "22_event_user_deleted_4726" @{LogName='Security'; Id=4726} 50
Save-Events "23_event_group_member_added_4728_4732" @{LogName='Security'; Id=4728,4732} 50
Save-Events "24_event_service_created_7045" @{LogName='System'; Id=7045} 50
Save-Events "25_event_audit_log_cleared_1102" @{LogName='Security'; Id=1102} 20
Save-Events "26_event_powershell_scriptblock_4104" @{LogName='Microsoft-Windows-PowerShell/Operational'; Id=4104} 50

# 11. Authentication and lock settings
Save-Command "27_password_policy" {
    net accounts
}

Save-Command "28_current_user_groups" {
    whoami /groups
}

Save-Command "29_screen_lock_settings" {
    reg query "HKCU\Control Panel\Desktop" /v ScreenSaveActive
    reg query "HKCU\Control Panel\Desktop" /v ScreenSaverIsSecure
    reg query "HKCU\Control Panel\Desktop" /v ScreenSaveTimeOut
}

Save-Command "30_power_settings" {
    powercfg /query SCHEME_CURRENT
}

# 12. Installed applications and application control
Save-Command "31_installed_applications" {
    $paths = @(
        "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*",
        "HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*",
        "HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*"
    )

    $items = foreach ($path in $paths) {
        Get-ItemProperty -Path $path -ErrorAction SilentlyContinue |
            Where-Object { $_.DisplayName } |
            Select-Object DisplayName, DisplayVersion, Publisher, InstallDate, InstallLocation
    }

    $items | Sort-Object DisplayName | Format-Table -AutoSize
}

Save-Command "32_store_apps" {
    Get-AppxPackage -ErrorAction SilentlyContinue |
        Select-Object Name, PackageFullName, Publisher, InstallLocation |
        Sort-Object Name
}

Save-Command "33_winget_upgrade_available" {
    if ($RunOnlineChecks -eq $true) {
        if (Get-Command winget -ErrorAction SilentlyContinue) {
            winget upgrade --accept-source-agreements
        }
        else {
            "winget is not available on this computer."
        }
    }
    else {
        "Skipped. Set `$RunOnlineChecks = `$true at the top of this script to run winget upgrade check."
        "Note: winget upgrade may access the Internet."
    }
}

Save-Command "34_applocker_policy" {
    if (Get-Command Get-AppLockerPolicy -ErrorAction SilentlyContinue) {
        Get-AppLockerPolicy -Effective -Xml
    }
    else {
        "Get-AppLockerPolicy is not available on this Windows edition."
    }
}

Save-Command "35_device_guard_status" {
    Get-CimInstance -Namespace root\Microsoft\Windows\DeviceGuard -ClassName Win32_DeviceGuard -ErrorAction SilentlyContinue |
        Select-Object SecurityServicesConfigured,
                      SecurityServicesRunning,
                      VirtualizationBasedSecurityStatus,
                      CodeIntegrityPolicyEnforcementStatus,
                      UserModeCodeIntegrityPolicyEnforcementStatus
}

Save-Command "36_code_integrity_active_policies" {
    $activePath = Join-Path $env:windir "System32\CodeIntegrity\CiPolicies\Active"
    if (Test-Path $activePath) {
        Get-ChildItem $activePath -ErrorAction SilentlyContinue |
            Select-Object Name, FullName, Length, LastWriteTime
    }
    else {
        "No active Code Integrity policy folder found: $activePath"
    }
}

Stop-Transcript

$ZipPath = "$OutputDir.zip"
Compress-Archive -Path "$OutputDir\*" -DestinationPath $ZipPath -Force

Write-Host ''
Write-Host "Windows security check v3 completed."
Write-Host ("Output folder: " + $OutputDir)
Write-Host ("ZIP file: " + $ZipPath)
Write-Host ''
Write-Host "If you want to check application updates with winget, set RunOnlineChecks to true in the script and run it again."
(4)STEP3:スクリプトを実行する

・PowerShellで次のコマンドを実行します。

powershell -NoProfile -ExecutionPolicy Bypass -File "$env:USERPROFILE\Desktop\windows_security_check.ps1"

実行すると、デスクトップに次のようなフォルダが作成されます。
windows_security_check_2026XXX

(5)STEP4:結果を確認する

作成されたフォルダの中には、次のようなテキストファイルが保存されます。
01_computer_info.txt
04_hotfix.txt
05_local_users.txt
06_administrators_group.txt
08_listening_ports.txt
09_firewall_profiles.txt
11_defender_status.txt
12_bitlocker_status.txt
19_event_logon_failure_4625.txt
24_event_service_created_7045.txt
これらのログを確認することで、Windows端末の状態を把握できます。

(6)STEP5:AIに分析させる

ZIPファイル、または必要なテキストファイルをChatGPTやClaudeに渡し、「ログをもとにセキュリティ上の問題がないか確認して」くらいでもチェックしてくれると思います。
ファイルのアップロード制限があるなら、コマンドプロンプトで、以下を実行してファイルを結合しましょう。

copy /b *.txt merged.txt

こんな感じで、かなり詳細に分析をしてくれます。

3.5 ネットワーク機器Config診断

(1)概要

・ネットワーク機器は、Webアプリのように攻撃リクエストを投げるより、Configを読む診断が中心です。
・対象機器は、ファイアウォール、ルータ、L3スイッチ、VPN装置など。
・ネットワーク機器Config診断では、ConfigファイルをAIに渡して、設定リスクを読ませるだけでも十分有効です。
・書き換えるなどのリスクもあり、必要もないのにAIエージェントでネットワーク機器に対して直接的な診断をかけるべきではない。

(2)静的診断に必要な情報

❶Config
admin>設定>バックアップ からConfigを取得(古いOSでごめんなさい。SSL-VPNをテストしたかったので)

❷コマンドの実行結果 ※想定

コマンド 内容
get system status 各種セキュリティDBの「現在の」バージョン
システムの現在時刻(System time)
BIOSのバージョン(BIOS version)
システムの部品番号(System Part-Number)
などが表示
diagnose autoupdate versions 脅威シグネチャの詳細な更新ステータス
(3)設計書を読み込ませるべきか

❶設計書が無いと、正しい指摘ができないことはある
たとえば、以下の設定

edit "wan1"
    set allowaccess ping ssh fgfm

設計書「wan1 は ISP 直結、グローバル IP」 → 即時遮断
設計書「wan1 は上位 UTM 配下の管理セグメント」 → 許容。むしろ ssh は運用要件

❶設計書は不要どころか有害の可能性
・攻撃者は設計書を読まない:逆に、設計書を先に読むと、「こう設計したのだからこうなっているはず」という確証バイアスが入る
・設計書自体が脆弱な場合がある
・LLMがその設計が正しいとして、指摘しなくなるリスクがある

❷設計書は「重み付け材料」として使う
フェーズ1: conf / コマンド結果のみで、機械的に検出
→ 設計意図を知らないまま、全部拾う
→ 過検知上等
フェーズ2: 検出結果を、設計書と突き合わせる
→ 「これは意図通り」を落とす
→ 「設計書にすら書かれていない」を昇格させる

(4)FortiGateでチェックすべき主なセキュリティ項目
No. カテゴリ 対策項目 詳細・アクション
1 管理と基盤 管理アクセスの制限 WAN側 allowaccess の無効化。プロトコル単位(ssh/https/fgfm/fabric/snmp)で棚卸し
2 Trusted Hosts 設定 管理アクセスを特定セグメント/IPに限定
3 管理者アカウント保護 強力なパスワード、MFA、デフォルト名 admin の廃止
4 管理セッション設定 admintimeout、ログイン失敗ロックアウト(閾値・時間)
5 パスワードポリシー 最小長・複雑性・有効期限。設定自存在確認
6 ファームウェア管理 最新パッチ適用、既知 CVE 対応
7 ライフサイクル管理 EoS/EoL 到達有無。修正版が提供される機種か
8 ファーム完全性 Firmware Signature: certified の確認
9 FWポリシー 最小権限の原則 「Any」の排除、必要な IP・ポートのみ許可
10 ポリシーの棚卸し 不要・未使用ルールの無効化/削除
11 ログ取得 暗黙 Deny ログ、許可ログ(logtraffic all)
12 Local-in ポリシー 本体宛通信の細粒度制御
13 UTMプロファイルの割り当て ポリシーへの適用状況(utm-status の有無)
14 シグネチャ更新 FortiGuard 自動更新設定
15 シグネチャ鮮度検証 契約状態と DB 日付を突合。契約有効でも DB が古い場合を検出
16 SSL インスペクション ディープインスペクションの検討
17 VPN SSL-VPN の強化 全ユーザーに MFA 必須化
18 接続元制限 source-address / source-interface の妥当性
19 Geo-IP 制限 接続元国制限
20 サーバ証明書 Fortinet_Factory(自己署名)を使っていないか
21 到達範囲の限定 Split Tunneling、ポータルの tunnel/web mode の要否
22 アカウント棚卸し 不要ユーザー、グループ所属の妥当性、テスト用アカウント残存
23 暗号プロトコル・暗号スイート strong-crypto、banned-cipher、ssl-min-proto-version
24 ログ ログの取得 FortiAnalyzer/Cloud/syslog への転送
25 許可ログの取得 ポリシーでの許可ログ
26 保存先の冗長性 メモリログのみになっていないか
27 運用 タイムゾーン ログ相関の前提。Asia/Tokyo
28 通知・アラート ライセンス失効、再起動、HA、設定変更の通知
29 警告の抑止確認 gui-auto-upgrade-setup-warning 等が disable でないか
30 永続化の痕跡 auto-script / automation-stitch の不審な定義
(5)実施結果

❶ChatGPT課金

優先 問題 判断
FortiOS が 7.4.3 のまま 古い。現時点の 7.4 系最新は 7.4.12。7.4.3 は複数の後続脆弱性の影響範囲に入る可能性が高いです。 ([Fortinet Document Library][1])
FortiGuard契約/定義更新が切れている AV/IPS/App Control 等が `Unauthorized` で更新不可。防御力がかなり落ちています。
wan1 に SSH / FGFM が開いている `wan1` が `allowaccess ping ssh fgfm`。インターネット側なら攻撃面が大きいです。
SSL-VPN が wan1 で全送信元に公開 `source-interface "wan1"`、`source-address "all"`、`default-portal "full-access"`。ブルートフォースやSSL-VPN脆弱性の対象になります。
guest ユーザが SSL-VPN グループに入っている `guest` が `ssl-group` に含まれています。外部公開VPNに「guest」は危険です。
SSL-VPN から LAN へ service ALL VPN利用者がLAN全体・全ポートへ到達できる設定。侵害時の横展開リスクが高いです。
LAN→WAN も service ALL、UTMプロファイルなし NATだけの出口制御に近く、IPS/AV/WebFilter等がポリシーに明示されていません。
外部ログが弱い メモリログのみ有効に見えます。再起動や侵害時に証跡が残りにくいです。

※二要素認証や管理者アクセスへの言及が欲しかった。

❷Claude課金(Opus4.8高)

■FortiGate-60E セキュリティ診断 指摘事項一覧

# 重要度 分類 指摘事項 該当箇所 / 根拠 推奨対処
1 🔴 管理アクセス WAN 側に SSH が解放されている `wan1: allowaccess ping ssh fgfm` `set allowaccess ping` へ変更
2 🔴 管理アクセス WAN 側に fgfm が解放されている(wan1/wan2 両方)。CVE-2024-23113(KEV 登録・実際に悪用)の攻撃面 `wan1`/`wan2: allowaccess ... fgfm` FortiManager 未使用なら即削除
3 🔴 パッチ管理 FortiOS 7.4.3 は CVE-2025-25250(SSL-VPN 情報漏洩)の影響範囲(7.4.0〜7.4.7) `Version: v7.4.3,build2573,240201` 7.4.8 以降へアップグレード
4 🔴 パッチ管理 SSL-VPN symlink 永続化(FG-IR-25-934、2026-02公表のパッチバイパス)に対して未保護 同上 + SSL-VPN 公開中 パッチ適用まで SSL-VPN 停止(CISA 推奨)
5 🔴 シグネチャ FortiGuard 契約が 2024-02-26 に失効。全項目 `Result: Unauthorized`(約2年4ヶ月更新なし) `diagnose autoupdate versions` 全項目 サブスクリプション更新
6 🔴 シグネチャ IPS-DB / APP-DB が **2015-12-01** のまま。Virus-DB は 2018-04-09 `get system status` 契約更新後に即時アップデート
7 🔴 UTM UTM プロファイルがどのポリシーにも未適用(`utm-status` が1件も無い)。IPS/AV が実質未稼働 `config firewall policy` 各ポリシーに AV/IPS/Webフィルタを適用
8 🟡 証明書 SSL-VPN サーバ証明書が全機共通の `Fortinet_Factory`。MITM が容易 `vpn ssl settings: servercert` 正規 CA 証明書へ差し替え
9 🟡 認証 SSL-VPN が ID/パスワードのみ。多要素認証(FortiToken 等)未設定 `user local` / `user group` 全 VPN ユーザーに MFA を必須化
10 🟡 認証 `config system password-policy` が存在しない。弱いパスワードを許容 設定ファイル全体 最小長・複雑性・有効期限を設定
11 🟡 管理者 管理者はデフォルト名 `admin` のみ、`trusthost` 未設定(接続元制限なし) `config system admin` 管理者名変更 + trusthost + 2FA
12 🟡 管理者 `config system admin-setting` が未設定(admintimeout・ロックアウト閾値がデフォルト) 設定ファイル全体 タイムアウト短縮・ロックアウト設定
13 🟡 ポリシー ポリシー1が `all → all / service ALL`、UTM なし・ログなしの全許可 `firewall policy edit 1` 宛先/サービスを最小化、`logtraffic all`
14 🟡 ポリシー ポリシー2(sslvpn-to-lan)が `dstaddr all / service ALL`。VPN 接続後に内部全体へフルアクセス `firewall policy edit 2` 必要な宛先・ポートのみに絞る
15 🟡 権限 `ssl-group` に `guest` アカウントが含まれ、full-access ポータルで内部到達可能 `user group` + `vpn ssl settings` guest を VPN グループから除外
16 🟡 ログ ログがメモリのみ。再起動で消失し、侵害調査が不可能 `config log memory setting` のみ syslog / FortiAnalyzer へ転送
17 🟢 運用 タイムゾーンが `US/Pacific`。日本運用ならログのタイムスタンプが混乱 `system global: timezone` `Asia/Tokyo` へ変更
18 🟢 運用 ファーム更新の警告表示が抑止されている `gui-auto-upgrade-setup-warning disable` `enable` へ戻す
19 🟢 暗号 `strong-crypto` が未設定(デフォルト有効だが明示推奨) `system global` `set strong-crypto enable` を明示
20 🟢 ハードウェア FortiGate-60E は EoS 到達またはその直前。7.4.8 が提供されない可能性 機種情報 Fortinet の Product Lifecycle を確認、機器更改を検討
良好 SSL-VPN で弱い暗号スイートを禁止済み `banned-cipher SHA1 SHA256 SHA384` 現状維持

❸Gemini課金(Pro拡張)

No. 項目 現在の設定・状態 リスク・問題点 推奨される対応・ベストプラクティス
1 WANインターフェースの

アクセス許可
インターネット接続側(`wan1`)のインターフェースで、`ping` および `ssh` によるアクセスが許可されています(設定ファイルより)。 【クリティカル】

インターネットにSSH(ポート22番)を直接公開しているため、総当たり攻撃(ブルートフォース)やファームウェアの脆弱性を狙った攻撃を直接受ける危険性が極めて高い状態です。
`wan1` および `wan2` の `allowaccess` 設定から `ssh` および `ping` を直ちに削除してください。

外部からの管理が必要な場合は、VPN(IPsec等)を経由して安全にアクセスするよう構成してください。
2 FortiGuard

ライセンスの失効
各種エンジンの「Contract Expiry Date(契約有効期限)」が `Mon Feb 26 2024`(2024年2月26日)となっており、アップデート結果がすべて `Unauthorized`(未承認)です 。 【高】

アンチウイルス、IPS、ウェブフィルタリングなどの最新の脅威情報(シグネチャ)が受信できておらず、最近のマルウェアやサイバー攻撃を防ぐことができません。
機器を安全に運用するために、至急FortiGuardライセンスを更新し、データベースの自動更新が正常に行われる状態に復旧させてください。
3 ファームウェアと

シグネチャの老朽化
FortiOSバージョンが `v7.4.3` のままです 。また、ウイルスDB(2018年)やIPS-DB(2015年)など、多くのデータベースが非常に古い状態です 。 【高】

古いOSには既知の脆弱性(CVE)が存在する可能性が高く、攻撃者に狙われやすくなります。また、DBが古いため防御機能が実質的に機能していません。
メーカー推奨の最新安定版ファームウェア(OS)へアップグレードを実施してください。

ライセンス適用後、すべてのデータベースを手動またはスケジュールで最新版に更新してください。
4 管理者アクセスの

送信元制限(未設定)
`admin` アカウントに対して、アクセス可能な送信元IPアドレスを制限する「Trusted Hosts(信頼されるホスト)」の設定が存在しません(設定ファイルより)。 【中〜高】

機器のログイン画面(またはSSH)に通信さえ届けば、世界中のどこからでもログイン試行が可能となり、パスワードクラックのリスクが増大します。
管理者アカウントの設定にて `trusthost` を構成し、社内の特定のIPセグメントや、VPN接続時の限られたIPアドレスからのみログインできるように厳格に制限してください。
5 デフォルトアカウント

「admin」の利用
デフォルトの管理者アカウント名である `admin` がそのまま利用されています(設定ファイルより)。 【低〜中】

攻撃者がパスワード推測攻撃(辞書攻撃など)を行う際、必ず「admin」というユーザー名を使用するため、突破される確率が高まります。
推測されにくい独自のアカウント名で新しい管理者(権限:`super_admin`)を作成し、既存の `admin` アカウントは無効化または削除することを推奨します。

❹Copiot課金(特に複雑な指示無)
指示は他と同じ

優先度 項目 現状 リスク 推奨対応
🔴 高 FortiGuardライセンス失効 2024/02に契約期限切れ。AV/IPS/AppControl等が更新停止。 新しいマルウェア・脆弱性攻撃を検知できない FortiGuardライセンス更新
🔴 高 IPS/AVシグネチャが古い IPS・AV定義が2024年2月時点で停止 未知・新規攻撃への防御力低下 FortiGuard更新
🟠 中 WAN1でSSH管理公開 wan1 allowaccess ping ssh fgfm SSHブルートフォース攻撃対象になる SSH無効化またはTrusted Hosts制限
🟠 中 SSL-VPN公開 SSLVPNがWAN1で有効、認証グループ設定あり 資格情報漏洩時の侵入リスク MFA必須化、制限強化
🟠 中 SSLVPNユーザー存在 guest、ssl-user1、testuser が存在 不要アカウント悪用リスク 利用状況確認・削除
🟠 中 SSLVPNポリシーがALL許可 sslvpn-to-lan で dstaddr all + service ALL VPN利用者が広範囲アクセス可能 必要な宛先・サービスへ限定
🟡 低 タイムゾーン不一致 US/Pacific設定 監査・障害調査でログ解析困難 Asia/Tokyoへ変更
🟡 低 自動通知無効 License、Reboot、HA Failover等の通知が無効 障害に気付きにくい メール通知有効化
🟡 低 管理者MFA不明 adminアカウント確認できるがMFA設定不明 パスワード漏洩時に危険 FortiToken等でMFA導入

❺Copiot課金(具体的な指示有)
3.5(4)の内容を入れて、その項目でチェックしてと依頼した結果。もちろん、きちんとチェックしてくれる。

No. カテゴリ 対策項目 判定 実施結果
1 管理と基盤 管理アクセスの制限 WAN1で ssh が許可されている。HTTPS管理は無効。WAN2はSSH無効。
2 Trusted Hosts設定 設定確認不可。
3 管理者アカウント保護 adminアカウントが利用中。MFA設定確認不可。
4 管理セッション設定 admintimeout、ログイン失敗ロック設定を確認できず。
5 パスワードポリシー password-policy設定を確認できず。
6 ファームウェア管理 ⚠️ FortiOS 7.4.3を使用。比較的新しいが最新版確認は別途必要。
7 ライフサイクル管理 ⚠️ FortiGate 60Eは旧世代機種。EOS/EOL確認推奨。
8 ファーム完全性 Firmware Signature: certified。
9 FWポリシー 最小権限の原則 Firewall Policyで srcaddr all dstaddr all service ALL を使用。
10 ポリシーの棚卸し ⚠️ ポリシー数は少ない(内部→WAN、SSLVPN→LAN)。不要ルールは見当たらない。
11 ログ取得 denyログ、logtraffic all 設定確認不可。
12 Local-inポリシー Local-in Policy設定は確認できない。未実装の可能性あり。
13 UTMプロファイル割り当て UTMプロファイルは存在するがポリシー適用状況不明。さらにFortiGuard失効中。
14 シグネチャ更新 FortiGuard更新失敗(Unauthorized)。
15 シグネチャ鮮度検証 AV/IPS定義が2024年2月で停止。
16 SSLインスペクション ⚠️ Deep Inspectionプロファイルは存在するが適用状況は不明。
17 VPN SSL-VPN強化 MFA強制を確認できない。FortiToken自体は登録あり。
18 接続元制限 SSLVPNはWAN1公開。source-address制限確認不可。
19 Geo-IP制限 設定確認不可。
20 サーバ証明書 SSLVPN証明書に Fortinet_Factory を利用。
21 到達範囲の限定 SSLVPN→LANポリシーが ALL 許可。到達範囲が広い。
22 アカウント棚卸し guest ssl-user1 testuser が残存。用途確認が必要。
23 暗号プロトコル・暗号スイート banned-cipher設定あり。SHA1等禁止。
24 ログ ログの取得 FortiAnalyzer/Syslog連携確認できず。
25 許可ログの取得 logtraffic設定確認不可。
26 保存先の冗長性 HDDなし。実質メモリログ中心。外部保管なし。
27 運用 タイムゾーン US/Pacific設定。日本環境として不適切。
28 通知・アラート ライセンス失効、HA、再起動等の通知設定が無効。
29 警告の抑止確認 ⚠️ gui-auto-upgrade-setup-warning disable を確認。
30 永続化の痕跡 不審な automation-stitch、auto-script は確認されず。

3.6 アプリケーション診断

(1)診断概要

・アプリケーション診断では、Webアプリ、API、認証処理、認可処理、DBアクセス、ファイルアップロード、セッション管理などを確認します。
・クラウド、OS、ネットワーク機器と比べると、アプリケーション診断はAIとの相性が高い分野です。理由は、ソースコード、HTTPリクエスト・レスポンス、ログ、設定ファイル、診断結果など、AIが読み取れるテキスト情報が多いからです。

(2)アプリケーション診断の主な方法

アプリケーション診断は、大きく3つがありますが、必要に応じて組み合わせて実施されます。

方法 読み方 意味 内容 AIとの相性
SAST(Static Application Security Testing) サスト 静的診断を自動化するツールや手法 ソースコードを静的に確認する。実行しない 高い
DAST(Dynamic Application Security Testing) ダスト 動的診断を自動化するツールや手法 動作中のWebアプリケーションにリクエストを送り、実際の応答から脆弱性を確認する 高いが制御が必要
手動診断 仕様や業務ロジックを人間が確認 仕様上の問題や権限管理、業務ロジックの不備などは、自動診断だけでは発見が難しい場合があり、診断員による手動確認も必要 AIは補助役
(3)実際の方法①:チャット画面で使う

最も手軽なのは、ChatGPTやClaudeなどのチャット画面にソースコードや診断結果を渡す方法です。

(4)実際の方法②:静的診断として、AIエージェントのGUIで使う

・CodexやClaude CodeなどのAIエージェントをGUIから使う方法があります。
・チャット画面との違いは、AIがプロジェクト全体を見ながら作業できる点です。
・なので、AIエージェントを使うと、AIが以下も実施してくれます。

・ AIがリポジトリ内を探索する
・ 関連ファイルを自分で読む
 ・必要に応じてコマンドを実行する

・私がやった方法は、VScodeからClaudeCodeを起動し、ソースファイルを指定して、以下のように指示。

・5,6分で診断が完了

(5)実際の方法③:外部から診断する

・私がやった方法は、Ubuntu上でSemgrep(セムグレップ)、ZAP、nmapなどの可能な限りの診断ツールを入れて、AIエージェント(codexとClaudeCodeで評価)で自動診断をしました。
・小規模なWebアプリなので、ツールを個別に実行するのでも結果はそれほど変わらないかもしれませんが、自動で全部やってくれるのは楽。
・結果は、モデルによる違いはあるなーという感想。Mythosだったらさらにいい結果になるんだろうと思います。

また、本格的な診断をするには、AIに、以下の仕組みが必要になりそうです。

・何を調べるか計画させる
・適切なツールを選ばせる
・結果を記録・整理させる
・検出結果を別の方法で検証させる
・次の診断へ引き継がせる
(6)静的診断か動的診断か

・書き換えたり壊したりするリスクがあるので、静的診断によるソースコード診断の方が安全ではないか、と思っています。

・あとAIによるセーフガード機能がまあまあ効いてくるので、プロンプトの指示も(攻撃と思われないように)工夫が必要だし、申請が必要だったり、外部からの診断は制限される気がする。※政府などが公式にMythosを使う場合は、どうなんでしょう。これらの申請がスキップされるのかもしれません(わかりません)。
・以下、結果の比較です。

項目 動的診断(ブラックボックス) 静的診断(ソースコード解析)
検出件数 Critical 2 / High 3 / Medium 4 / Low 2 (計10件) Critical 5 / High 6 / Medium 6 / Low 4 (計21件)
SQLインジェクション 確認済み(1箇所、差分ベースで推測) 確認済み(6箇所以上、行番号付きで特定)
認証バイパス(IDOR) 確認済み(idパラメータ変更で発覚) 同様に検出、かつCookieのvisited改ざんだけでログイン済み扱いになるという根本原因まで特定
パストラバーサル 確認済み(`/etc/hostname`読取で存在確認のみ) 確認済み、該当ページの該当行(19-21など)を特定、原因(readfileへの直接埋め込み)まで明示
OSコマンドインジェクション 認識はあり。ただ、「成立を確認できず(HTTP 500)」と保留 確定。2箇所を行番号付きで特定し、system()への直接埋め込みという原因まで断定
任意ファイルアップロード(RCE) 未検出 新規発見。検証コードがコメントアウトされている箇所を特定、RCEに直結すると指摘
任意ファイル削除 未検出 発見。某ページで認証チェックなしの削除処理を特定
パスワード保管 「ソルトなしMD5と推定」(ハッシュから推測) 平文保存と断定
DB認証情報の漏洩 未検出 発見。DBパスワードがハードコードされている箇所を特定
CSRF 未検出 発見。しかも攻撃実証用のPHPファイルまで同梱されていることを発見
バックアップ/スワップファイル残存 未検出 発見。.swpファイルや.sqlファイルの公開領域への混入を指摘

4.AIによる情報漏えい対策

4.1基本方針

・AIをセキュリティ診断に使う場合、最も注意すべき点の一つが情報漏えいです。
・診断では、ソースコード、設定ファイル、ログ、IPアドレス、ホスト名、ユーザ名、認証情報、脆弱性情報など、外部に出すべきではない情報を扱います。これらをそのままAIに入力すると、機密情報や個人情報を外部サービスに送信してしまう可能性があります。
・そのため、AIを使う場合は、次の3つを基本方針とします。

1. AIに渡す前に、機密情報を削る・伏せる
2. 個人向けではなく、企業向け・組織管理されたAIサービスを使う
3. 高い機密性が必要な場合は、ISMAP登録サービスやBedrockなど、管理されたクラウド基盤を使う

4.2 AIに渡す前に機密情報を取り除く

AIにログやソースコードを渡す前に、機密情報を削除・マスクします。

種類 対応
認証情報 パスワード、APIキー、トークン、秘密鍵 原則削除
個人情報 氏名、メールアドレス、電話番号、住所 マスク
内部情報 社内IP、ホスト名、ドメイン名 必要に応じて置換
設定情報 DB接続文字列、S3バケット名、VPN設定 マスク
脆弱性情報 未修正の重大脆弱性、攻撃手順 共有範囲を限定

たとえば、AIに渡す前に次のように置き換えます。

192.168.10.25        → <INTERNAL_IP>
db-prod.example.local → <DB_HOST>
AKIAxxxxxxxxxxxx      → <AWS_ACCESS_KEY>
password=xxxxx        → password=<REDACTED>

5.運用上の検討ポイント

5.1 AI診断の責任と位置づけ

No. 論点 詳細 判断の分岐
1-1 最終責任の所在 AI の見落とし・誤検知で被害が出たとき、誰が責を負うか 診断実施者(人間)が全責任 / ツールベンダー / 顧客の受入
1-2 成果物の位置づけ 「AI 診断報告書」は診断結果か、下書きか 正式成果物 / 人間レビュー前提の一次出力 / 内部作業メモ
1-3 契約・約款上の扱い 顧客との診断契約に「AI 使用」を書けるか、書く義務があるか 明示・同意取得 / 手法の一部として非開示

5.2 AI診断の情報管理

No. 論点 詳細 判断の分岐
2-1 入力可否の基準 Config はそもそも機密か
・どこまでが機密情報かの分岐点
顧客資産 / NDA 対象 / 個人情報の有無
2-2 匿名化の限界 ・IP・ホスト名・シリアルを抜いて、診断が成立するか
・匿名化しても残る情報
抜くと診断精度が落ちる項目がある
2-3 AIに情報を投入する行為の是非 ビジネス版であればいいか。機密情報を抜けば学習しないに設定してビジネス版以外でもいいか くわえて、リージョンを国内に限定すべきか
2-4 顧客同意 顧客資産を組織外 AI に入れる同意を、どう取るか 契約に入れるか

5.3 プラットフォーム選択とコスト

No. 論点 詳細
3-1 モデル選択
3-2 実行基盤 クラウド API / VPC 内(Bedrock 等) / オンプレ推論 / ローカル LLM
3-3 コスト ソースコードの量や実行回数によって大きくコストが変わる