はじめに
FortiGate の SSL-VPN に設置されたシンボリックリンクによる永続化は、ファームウェアを更新しても痕跡が残り続けるという性質を持っています。CVE-2025-68686 が CISA KEV に追加されたことで、パッチ適用だけでなく過去の痕跡の確認まで求められる状況になりました。
ところが、この確認は簡単ではありません。FortiOS の通常の管理 CLI からファイルシステムを直接参照する手段は限られており、シンボリックリンクの有無を機器内部から確認する方法が見つけにくいためです。脆弱性を報告した ITRESIT が公開している検査スクリプトは、この確認を外部から行うためのものです。MIT ライセンスで公開されており、発見者本人が作成しています。
- 検査ツールが判定できる項目と、判定できない条件
- Python の実行環境を用意してツールを導入する手順
- 単体および複数台に対する検査の実行方法とオプションの使い分け
- 判定結果ごとの解釈と、その後に取るべき対応
- 検査を実施する前に確認しておきたい注意事項
先に結論を述べます。このツールが判定するのは、修正の適用状況と、シンボリックリンク経由でファイルを取得できるかどうかの 2 点です。いずれも外部からの HTTP 応答に基づく判定であるため、陰性の結果が出ても「過去に侵害を受けていない」ことの証明にはなりません。 特に、すでにファームウェアを更新済みの機器では過去の侵害を検出できない点は、検査の順序を決めるうえで押さえておきたい前提です。
なお、CVE-2025-68686 の内容や影響を受けるバージョンについては、関連記事『CVE-2025-68686 が KEV 追加』で扱っています。
検査ツールでわかること・わからないこと
手順に入る前に、このツールで何が判定できて何が判定できないかを整理します。結果の解釈を誤ると、対応の要否そのものを見誤ることになるためです。
ツールが判定する 2 つの項目
ツールが確認するのは次の 2 点です。
| 項目 | 内容 |
|---|---|
| 修正の適用状況 | 対象機器がシンボリックリンクへの対策を含むバージョンで動作しているか |
| 侵害の兆候 | 悪性のシンボリックリンク経由でファイルを取得できる状態にあるか |
後者はオプションで有効化する形になっており、設定ファイルの取得可否を実際に試行して判定します。あわせて、CVE-2025-68686 のダブルスラッシュ手法によるパッチ回避を試すオプションも用意されています。これにより、2025 年 4 月の対策を適用済みの機器が、回避手法によって依然として読み出し可能な状態にないかまで確認できます。 具体的なオプションの指定方法は、後述の実行手順で扱います。
この確認が実務上どの程度必要かは、公開されている調査データが参考になります。
参考: Bypassing the FortiGate Symlink Patch: The Double Slash Technique(Labs at ITRES)
“from 3503 randomly selected FortiGate units, 144 were still compromised”
(無作為に抽出した 3,503 台の FortiGate のうち、144 台が依然として侵害された状態でした)
https://labs.itresit.es/2026/02/11/fortigate-symlink-persistence-method-patch-bypass-cve-2025-68686/
この調査は、Fortinet がアドバイザリを公開してから約 1 か月後の時点で実施されたものです。割合にすると 4.11% にあたります。同じ調査では、3,503 台のうち 787 台がシンボリックリンクの整合性チェックを含む最新ファームウェアで動作していたことも報告されています。なお、調査対象は FortiGate の台数であり、SSL-VPN ポータルの公開台数ではない点に留意が必要です。
外部からの検査で判定できない条件
ここが本ツールを使ううえで最も重要な部分です。 以下の条件に該当する機器では、検査を実行しても侵害の有無を判定できません。
- SSL-VPN ポータルが外部に公開されていない機器
-
検査は SSL-VPN ポータルへの HTTP リクエストに基づくため、到達できない機器は検査対象になりません。送信元 IP を制限している構成も同様です
- すでにファームウェアを更新済みの機器
-
7.6.2、7.4.7、7.2.11、7.0.17、6.4.16 以降へのアップグレードでは、悪性のシンボリックリンクが削除されます。更新後に検査しても、過去に侵害を受けていたかどうかは分かりません
- AV/IPS エンジンによってリンクが削除済みの機器
-
2025 年 4 月の対策では、シグネチャによる検出と自動削除も行われました。エンジンのライセンスが有効だった機器では、すでに痕跡が消えている可能性があります
- 前段に WAF やロードバランサーを配置している構成
-
応答を返す主体が FortiGate 以外になる場合、判定結果が実態を反映しないことがあります
この 2 番目の条件は、作業の順序に直接影響します。 アップグレードを先に実施してから検査しても得られる情報は限られるため、痕跡の確認を重視するのであれば、検査を先に行う判断もありえます。ただし脆弱性を残したまま検査を待つことになるため、対象機器の公開状況とリスク許容度を踏まえた判断が必要です。
そしてもう 1 点、原理的な限界があります。このツールが見ているのは「現時点でファイルを取得できるか」であり、「過去に設定を窃取されたか」ではありません。 シンボリックリンクが削除された後の機器で陰性の結果が出ても、それ以前に設定ファイルが読み出されていた可能性は残ります。判断に迷う場合は、設定情報が漏えいした前提で資格情報を扱う方が安全側に倒せます。
実行環境の準備
検査ツールは Python で書かれた単一のスクリプトです。対象機器側での作業は不要で、検査を実行する端末側の準備のみで動作します。
必要なもの
準備するものは 3 点です。
| 項目 | 内容 |
|---|---|
| Python 3 の実行環境 | 仮想環境(venv)を利用する手順が公開されています |
| ネットワーク経路 | 対象機器の SSL-VPN ポータルへ HTTP で到達できること |
| リポジトリの取得手段 | git、または GitHub からの ZIP ダウンロード |
対象機器のポータルに到達できることが前提となるため、検査を実行する端末の設置場所は結果に影響します。 送信元 IP を制限している構成では、許可された経路から実行しないと正しく判定できません。この点は判定できない条件のひとつとして、前のセクションでも触れたとおりです。

仮想環境の作成と依存パッケージの導入
リポジトリの取得から依存パッケージの導入までは、次の流れになります。
git clone https://github.com/I3IT/Fortigate.Symlink.Persistence.Checker.git
cd Fortigate.Symlink.Persistence.Checker
python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt3 行目以降は公開されている手順そのままです。1 行目と 2 行目は、リポジトリを取得してディレクトリへ移動するための一般的な操作として補っています。
仮想環境を作成しているのは、依存パッケージをシステム全体の Python 環境に入れないためです。検査が終わったあとは、deactivateで仮想環境を抜け、ディレクトリごと削除すれば環境が残りません。一時的な用途で使うツールとしては扱いやすい構成といえます。
検査の実行手順
対象の指定方法は 3 種類あり、いずれか 1 つを選ぶ形になっています。同時には指定できません。
python3 check_fix.py -h引数の一覧はこのコマンドで確認できます。
単体の機器を検査する
1 台だけを対象にする場合は-tで IP アドレスとポート番号を指定します。
python3 check_fix.py -t 192.0.2.1:10443ポート番号は SSL-VPN ポータルが待ち受けているポートを指定します。公開されている実行例では 10443 が使われていますが、実際の値は機器の設定によって異なります。管理 GUI と同じ 443 で運用している構成もあるため、事前に設定を確認しておくことをおすすめします。
複数台をまとめて検査する
複数台を対象にする場合は-iでリストファイルを指定します。ファイルにはIP:ポートの形式で 1 行に 1 台ずつ記載します。
python3 check_fix.py -i targets.txttargets.txtの記載例です。
192.0.2.1:10443
198.51.100.1:443
203.0.113.1:10443拠点ごとに FortiGate を配置している環境では、この方法でまとめて確認できます。ただし、対象は自組織が管理する機器に限定してください。 注意事項は後述します。
なお、Shodan から取得した JSON ファイルを読み込ませる-jオプションも用意されています。これは調査目的で不特定多数の機器を対象にするためのものであり、本記事では扱いません。
--check と --try-bypass の使い分け
判定の深さは 2 つのオプションで変わります。
| オプション | 動作 |
|---|---|
| 指定なし | 修正の適用状況を確認 |
--check | sys_global.conf.gzに対する侵害チェックを実行 |
--try-bypass | ダブルスラッシュ手法によるパッチ回避を試行 |
sys_global.conf.gzは FortiGate の設定ファイルにあたります。--checkは、このファイルをシンボリックリンク経由で取得できる状態かどうかを実際に試すものです。
参考: Fortigate Symlink Persistence Method Checker(GitHub)
“try bypassing the patch using double slash technique”
(ダブルスラッシュ手法を用いてパッチの回避を試行します)
https://github.com/I3IT/Fortigate.Symlink.Persistence.Checker
--try-bypassが本記事の文脈で重要なオプションです。 2025 年 4 月の対策を適用済みの機器では、通常のパスによるアクセスは遮断されます。しかし CVE-2025-68686 が未修正であれば、スラッシュを重ねたパスで検査が回避される可能性が残ります。この状態を確認するのがこのオプションです。
両方を組み合わせて指定することもできます。
python3 check_fix.py -t 192.0.2.1:10443 --check --try-bypass過去の侵害痕跡と、回避手法による読み出しの可否をあわせて確認したい場合は、この形が基本になります。
結果の読み方と次のアクション
検査結果は、修正の適用状況と読み出しの可否という 2 つの軸で解釈します。この 2 軸の組み合わせによって、次に取るべき対応が変わります。
判定結果ごとの解釈
考えられる組み合わせと、その解釈は次のとおりです。
| 修正の適用状況 | 読み出しの可否 | 解釈と対応 |
|---|---|---|
| 未適用 | 取得できた | シンボリックリンクが残存し、読み出し可能な状態。侵害を受けたものとして対応する |
| 未適用 | 取得できなかった | リンクが存在しないか、すでに削除済み。脆弱性自体は未修正のためアップグレードが必要 |
| 適用済み | 取得できなかった | 現時点で読み出しは遮断されている。ただし過去の侵害の有無は判定できない |
| 適用済み | 取得できた | 想定と異なる結果。検査経路や前段機器の影響を疑い、条件を変えて再確認する |
2 行目の解釈には注意が必要です。 取得できなかったという結果は、侵害を受けていないことを意味しません。AV/IPS エンジンによってリンクがすでに削除されている場合も、同じ結果になります。前のセクションで整理した判定できない条件を踏まえたうえで読む必要があります。
対象機器に到達できず、タイムアウトや接続エラーとなる場合もあります。この場合はツールの問題ではなく、ポート番号の指定、経路、送信元 IP の制限のいずれかを疑うことになります。SSL-VPN の待ち受けポートを設定で確認し、許可された経路から再実行してください。
侵害が検出された場合に取るべき対応
読み出しが可能な状態だった場合、設定ファイルはすでに窃取されているものとして扱う考え方が推奨されています。
参考: Analysis of Threat Actor Activity(Fortinet PSIRT Blog)
“Treat all configuration as potentially compromised and follow the recommended steps below to recover”
(すべての設定が侵害された可能性があるものとして扱い、以下の復旧手順に従ってください)
https://www.fortinet.com/blog/psirt-blogs/analysis-of-threat-actor-activity
着手の順序として、ログと設定バックアップの保全を最初に行うことをおすすめします。 アップグレードや初期化を先に実施すると、調査に使える情報が失われます。あわせて、管理者と VPN ユーザーの資格情報、RADIUS シークレット、IPsec の事前共有鍵、証明書の扱いを検討することになります。復旧手順の詳細は、Fortinet Community が公開している手順とあわせてハブ記事で整理していますので、そちらを参照してください。
復旧後は修正済みバージョンへの更新が必要です。7.2 以下のブランチには修正版が提供されていないため、上位ブランチへの移行を伴います。移行時のアップグレードパスと所要時間の見積もりについては、関連記事『FortiGate アップグレードパスの確認方法』を参照してください。
検査を実施する際の注意事項
このツールは対象機器に対して実際に HTTP リクエストを送信します。読み取りのみの動作ではありますが、実施前に確認しておきたい点がいくつかあります。
対象は自組織が管理する機器に限定する
検査の対象は、自組織が管理権限を持つ機器に限定してください。 管理権限のない機器に対する検査は、国内では不正アクセス行為の禁止等に関する法律などに関わる可能性があります。個別の判断は事情によって異なるため、判断に迷う場合は法務部門への確認をおすすめします。
社内の機器であっても、所管部署が異なる場合は事前に承認を得ておく方が安全です。特に複数拠点を対象にする場合、リストファイルへの記載内容が管理範囲に収まっているかを実行前に確認してください。
実行前に確認しておきたいこと
実務上、あらかじめ関係者と共有しておきたい項目は次のとおりです。
- アクセスログへの記録
-
検査を実行した端末の IP アドレスは、対象機器のログに記録されます。あとから不審なアクセスとして扱われないよう、実施日時と実行元を記録に残しておくことをおすすめします
- 監視アラートの発生
-
SIEM や SOC で監視している環境では、検査のリクエストがアラートとして検知される可能性があります。事前に監視担当へ連絡しておくと、無用な調査を避けられます
- 変更管理上の扱い
-
設定を変更する操作ではありませんが、本番機器への外部からのアクセスにあたります。社内の作業申請ルールに沿った扱いが必要かを確認してください
- 利用者への影響
-
通常の HTTP リクエストであるため影響は限定的と考えられますが、SSL-VPN の利用が少ない時間帯を選ぶ方が無難です
取得されたファイルの扱いにも注意が必要です。 侵害チェックは設定ファイルの取得を試みるものであり、取得に成功した場合、その内容には機微な情報が含まれます。検査後の削除まで含めて手順に組み込んでおくことをおすすめします。
まとめ
FortiGate のシンボリックリンクによる永続化は、ファームウェアを更新しても痕跡が残る性質を持つため、外部からの検査が確認手段のひとつになります。ITRESIT が公開している検査ツールは、修正の適用状況と読み出しの可否を判定できますが、判定できない条件が複数あります。結果を正しく解釈するには、この限界を理解しておくことが欠かせません。
- 判定できるのは修正適用状況と読み出し可否の 2 点
- 判定は外部からの HTTP 応答に基づくため範囲に限界がある
- アップグレード済みの機器では過去の侵害を検出できない
- 陰性の結果は過去の設定漏えいを否定するものではない
- 検査の対象は自組織が管理する機器に限定する
- 侵害が確認された場合は設定を窃取された前提で復旧する
- 実行前にログ記録とアラート発生の可能性を関係者と共有する
以上、最後までお読みいただきありがとうございました。

