HN 日本語サマリー

← 一覧へ戻る
セキュリティ

OPNsense RCEの追求:私の最初のCVEsの裏話

Chasing the OPNsense RCE: The Story Behind My First CVEs (hackerask.com)

12 pointsby HackerAsk0 コメント

要約

この記事では、OPNsenseファイアウォールで発見された5つの脆弱性、特にCVSSスコア9.9の重大なリモートコード実行(RCE)の裏話が語られています。著者は、OPNsenseの深いセキュリティ研究を通じて、自身の最初のCVEs(共通脆弱性識別子)を獲得した経験を詳細に解説しています。

全文翻訳

OPNsense RCEの追求:私の最初のCVEsの裏話 (CVE-2026-57155) 目次 OPNsense RCEの追求:私の最初のCVEsの裏話 (CVE-2026-57155) すべてのセキュリティ研究者は、自身の最初のCVEを覚えていると思います。私にとって、そのマイルストーンは単一の低影響のバグとして訪れたわけではありませんでした。代わりに、Hacking Cultでの指定されたセキュリティ研究週間の間に、OPNsenseへの深い調査は5つの承認された脆弱性をもたらしました。このマイルストーンは、CVSSスコア9.9の重大なリモートコード実行の欠陥(CVE-2026-57155)によって締めくくられました。 人気のオープンソースFreeBSDベースのファイアウォールおよびルーティングプラットフォームとして、OPNsenseは企業およびホームネットワークのエッジに位置しています。OPNsenseの主張は、高価な商用ファイアウォールのすべての機能とそれ以上のものを無料で提供することで、デジタルセキュリティをすべての人にアクセス可能にすることです。 当社ではペネトレーションテスターとして、セキュリティ研究と専門能力開発に時間を費やす機会が定期的にあります。オープンソースソフトウェアに大きく依存しているため、この時間を利用してペネトレーションテストを実施し、エコシステムの改善に貢献することにしました。コミュニティアンケートでOPNsenseがターゲットとして提案され、完璧な組み合わせでした! 5日間で、8つの脆弱性を特定することができました。責任ある開示の観点から、この記述ではすでにパッチが適用されている5つにのみ焦点を当てます。残りの3つのうち、1つは重複と特定され、他の2つは執筆時点ではメンテナによってまだ積極的にレビューされています。 | 脆弱性 | CVE/GHSA | 重大度 | |---|---|---| | GeoIPエイリアスインポーターにおける任意のファイル書き込みを介したRCE | CVE-2026-57155 GHSA-wjqq-rfmm-v5h3 | Critical (9.9) | | MVC safe-deleteにおけるXPathインジェクション | CVE-2026-58395 GHSA-98h6-479q-9q3w | Medium (4.3) | | サービス: NTP GPSにおけるStored XSS | CVE-2026-58392 GHSA-h793-67jm-j4m5 | Medium (5.4) | | 証明書の説明を介したStored XSS | CVE-2026-58394 GHSA-8pgr-x852-qx4j | Medium (5.2) | | ファイアウォールルール/NATグリッドにおけるStored XSS | CVE-2026-58391 GHSA-2xrm-p255-p43h | Medium (5.4) | OPNsenseチームの迅速かつプロフェッショナルな対応のおかげで、開示された5つの脆弱性はすべて正常に修正されました。 この記事では、この研究週間の背景にあるストーリー、4つの中程度のバグの概要、そして最後に、CVE-2026-57155を発見し、連鎖させて完全なRCEを達成した方法の深い技術分析について説明します。 コードの中の一週間 研究は、仮想マシン上にOPNsenseインスタンスをセットアップすることから始まりました。OPNsenseコアのソースコードをダウンロードし、すぐに深く潜り始めました。私の主な目標は、アプリケーションの攻撃対象領域をマッピングし、ルーティングロジックとWebインターフェースを強化するPhalconベースのModel-View-Controller(MVC)フレームワークをトレースすることでした。 これを達成するために、私の方法論の主要な柱の1つは手動の汚染分析でした。私は、大規模なPHPコードベース全体で潜在的なシンクを探索するために、カスタム正規表現を使用してripgrepを広範囲に利用しました。ファイルシステム操作、シェル実行、無害化されていない出力などの危険な関数をgrepすることで、ユーザー提供の入力が適切な検証なしにこれらのシンクに到達するかどうかを遡って手動でトレースすることができました。 OPNsenseでシンクをトレースすることは、Phalconフレームワークのために課題を提示しました。ルーティングとパラメータバインディングの多くは、内部で動的に処理されるため、単純なgrepでは常に全体像を把握できません。ripgrepの発見を、フロントエンドコントローラをバックエンドAPIエンドポイントにマッピングする実際のXML設定ファイルと相互参照する必要がよくありました。 さらに、Burp Suiteを使用して動的プロキシを行い、フロントエンドとPhalconバックエンド間のAPIコールを傍受および分析しました。また、証明書の記述、エイリアス名、グリッドパラメータなどのさまざまな入力フィールドをXSSポリグロットペイロードで積極的にファジングしました。ポリグロットは、この種のブラックボックステストに非常に効率的です。なぜなら、単一のペイロードが複数のコンテキストから同時に抜け出すように作成されるためです(例:HTML属性、JavaScript文字列、標準HTMLタグを一度にエスケープする)。 4つの中程度の脆弱性 私が発見した重大なRCEの詳細を説明する前に、OPNsenseの監査で発見した他の中程度の脆弱性について少し説明します。これらはいずれも、それ自体でrootシェルを取得することはできませんが、それぞれの脆弱性は、同じ種類の誤り(サニタイズなしに入力を信頼する)が同じコードベースの異なる場所でどのように現れるかについて教えてくれます。 MVC Safe-DeleteにおけるXPathインジェクション OPNsenseのMVCベースのモジュールにあるすべての「削除」ボタンは、最終的に同じ汎用的なsafe-deleteルーチンを呼び出します。これは数十のエンドポイントで共有されています。したがって、URLからの削除トークンが、プレーンな文字列補間を使用してXPathクエリに直接ドロップされることを発見したとき、それは1つのエンドポイントに影響を与えただけでなく、21のエンドポイントに影響を与えました! ')or(' のような単純なペイロードは、次のようになります。 ``` 1 $xpath = "//text()[contains(.,'{$token}')]"; ``` config.xml内のすべてのテキストノードに一致するクエリに変換されます。一致すると、APIはHTTP 500エラーメッセージをスローし、一致したノジュールのモジュール、説明、およびUUIDが含まれます。 いくつかの権限のうち1つを持つユーザーは、safe-deleteエンドポイントを、本来見せるべきではなかったモジュールの読み取りオラクルとして使用できます。データは変更されず、削除も行われませんが、エラーメッセージを通じて設定が漏洩します。 3つのStored XSS 残りの3つの発見はすべてStored XSSであり、私が単一のペイロードよりも興味深いと感じるのは、それらを結びつけるパターンです。すべての場合において、エスケープが間違った場所で行われていました。 ファイアウォールルールとNATグリッドでは、カテゴリ名とエイリアスの説明が title="..." 属性内に入りますが、バックエンドは htmlspecialchars() を ENT_NOQUOTES でのみ実行します。これは <、>、& をブロックしますが、既存の <span> に onanimationstart のようなイベントハンドラ属性を注入してJavaScriptをゼロユーザーインタラクションで実行するために必要な二重引用符(")はブロックしません。 NTP GPSページはもっと努力しています。エスケーパーを呼び出しますが、初期化コマンドのbase64エンコード形式に対してのみです。値が <textarea> 内のページにデコードされる頃には、エスケープは存在しない文字列に対してすでに消費されているため、タグを早めに閉じるだけのペイロードは、ページがレンダリングされた瞬間に実行されます: ``` 1 </textarea><script>alert(1337);</script> ``` もう1つのケースは、管理ページのSSL証明書ドロップダウンです。config.xmlから証明書の記述を直接読み取り、エスケープなしで <option> タグに値を出力します。そのため、単純な <script>alert(1337);</script> ペイロードがそのまま機能します。 3つの異なる間違い、3つの異なるコードパス。しかし、教訓は、リモートコード実行を解除したのと同じものです。検証とエスケープは、シンクのできるだけ近くで行うべきです。なぜなら、その間の余分なステップはすべて、保護が静かに外れる機会だからです。 RCEの追求 脆弱なコードの理解 OPNsenseには、組み込みのGeoIPエイリアスインポーターが付属しています。国IPデータベースURLを指定すると、定期的にそのデータベースをrootとしてダウンロードおよび展開し、国XのすべてのIPアドレスのようなファイアウォールエイリアスを作成できます。このインポーターは src/opnsense/scripts/filter/lib/alias/geoip.py にあり、ダウンロードされたデータベースが指示するファイル名を盲目的に書き込みます。 2つの関数が展開を処理します: process_zip() と process_gzip()。どちらも同じ欠陥を共有しています。アーカイブには、geoname_id を country_iso_code にマッピングする「locations」CSVと、同じ geoname_id をネットワーク値にマッピングする「blocks」CSVが含まれています。インポーターは、geoname_id で両方を結合し、次に国ごとに1つの出力ファイルを書き込みます。 ``` 1 2 3 4 5 6 7 8 9 # src/opnsense/scripts/filter/lib/alias/geoip.py _target_dir = '/usr/local/share/GeoIP/alias' # line 46 ... country_code = country_codes[parts[1]] # line 88 - from the locations CSV if country_code not in output_handles: output_handles[country_code] = open( '%s/%s-%s' % (cls._target_dir, country_code, proto), 'w') # line 90-91 - country_code WRITE SINK ... output_handles[country_code].wr ```