[編集者 – NGINX ModSecurity WAFモジュール(NGINX Plus向け)は、2022年4月1日付で正式に販売終了となり、2024年3月31日付でサポート終了となります。詳細については、F5ブログの「F5 NGINX ModSecurity WAF Is Transitioning to End-of-Life<.htmla>」をご覧ください。]
Apache Strutsアプリケーションライブラリの脆弱性(CVE-2017-5638)は、Equifaxの1億4,300万件のアカウントの侵害につながった、仮想パッチを適用できるエクスプロイトの一例です。この脆弱性は、#cmd=または#cmds=という文字列が、HTTPヘッダーのContent-Type、Content-Disposition、またはContent-Lengthに含まれることで識別できます。(詳細については、以下を参照してください。)
ModSecurityを使用すると、影響を受けるHTTPヘッダー内の悪意のある文字列を検索するシンプルなルールで、仮想パッチを作成できます。
SecRule REQUEST_HEADERS:Content-Type|REQUEST_HEADERS:Content-Length|REQUEST_HEADERS:Content-Disposition "@rx #cmds?=" "id:5638,auditlog,log,deny,status:403"ルールはSecRuleを使用し、3つのパラメーターを指定して定義します。
- 検索対象のリクエストヘッダー。3つの「
REQUEST_HEADERS」変数をORで結合した形式で指定します - The PERL‑compatible regular expression (PCRE), as specified by
@rx, that searches the specified request headers for strings including#cmd=or#cmds= - 実行するアクション
ModSecurityがアクティブブロッキングモードに設定されている場合、PCREに一致してルールをトリガーするトラフィックはすべて破棄されます。
eBook「ModSecurity 3.0とNGINX:クイックスタートガイド」で、NGINXとModSecurityを組み合わせて使い始める方法をご確認ください
なぜ仮想パッチが必要なのか?
多くの場合、影響を受けるコードにパッチを適用し、再テストして本番環境にデプロイするよりも、ModSecurityにルールをデプロイする方が迅速です。
Apache Strutsの脆弱性を例に考えてみましょう。Strutsはオペレーティングシステムのパッケージではなくアプリケーションライブラリであるため、企業の本番環境での更新には時間がかかる場合があります。Strutsを新しいバージョンにアップグレードする際は、Strutsに依存する各アプリケーションを最新のStrutsライブラリで再ビルドし、テストする必要があります。大規模な組織では、それぞれ異なるバージョンのStrutsアプリケーションライブラリを使用するアプリケーションが数百に及ぶこともあり、すべてのアプリケーションを更新し終えるまで脆弱な状態が続きます。
ModSecurityのカスタムルールを適用しておけば、脆弱な状態にあるという切迫感に追われることなく、無理のないスケジュールで本番ソフトウェアに慎重にパッチを適用できます。影響を受けるすべてのソフトウェアを更新した後は、カスタムルールを廃止できます。
CVE-2017-5638のエクスプロイトの仕組み
Apache Struts CVE-2017-5638は、リモートコマンド実行(RCE)の脆弱性です。この種の脆弱性により、攻撃者は標的システム上で、たとえば「/bin/bash」や「cmd.exe」などの任意のコマンドを実行できます。これにより、攻撃者はJavaアプリケーションサーバーと同じアクセスレベルで、ファイルシステムやネットワークから機密データを検索できるようになります。たとえば、Javaアプリケーションサーバーが「root」として実行されている場合、攻撃者は標的システム上で「root」権限を取得します。
According to the 公式CVEによると、この脆弱性は、攻撃者が不正な形式の「Content-Type」、「Content-Disposition」、または「Content-Length」HTTPヘッダーを送信した場合に発生します。これらのHTTPヘッダーが想定されるいずれの値とも一致しない場合、Apache Strutsは例外をスローします。問題が発生するのは、例外処理コードが、エスケープされていない不正なヘッダーを出力しようとするためです。(ここで「エスケープされていない」とは、通常コードを出力する際に行うように、疑わしいコマンドの先頭に、その実行を防ぐ文字(エスケープ文字)が付加されていないことを意味します。)
攻撃者は、Object Graph Navigation Library(OGNL)式をContent-Typeヘッダーに挿入できます。OGNLにはシステムコマンドを実行する機能があります。エスケープされていない無効なヘッダーが出力されると、OGNL式が評価され、その式に含まれるシステムコマンドが実行されます。
通常、エクスプロイトは以下のcurlコマンドを変形したものです。
curl -H "Content-Type:%{(#_='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='ls -ltr').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}" www.example.com重要な構文はコマンドの後半にあります。文字列「#cmd=」と「#cmds=」がそれぞれ1つずつ含まれています(上記のハイライト部分)。各文字列の後には、実行するシステムコマンドが続きます。
まとめ
脆弱性のあるソフトウェアには、直ちにパッチを適用することが常に望ましい解決策です。しかし、本番環境のソフトウェアへのパッチ適用には時間がかかる場合があり、更新を急ぐとリスクが生じる可能性があります。ModSecurityで脆弱性のあるソフトウェア向けの仮想パッチを作成すれば、対応までの時間を確保できます。
仮想パッチでは、CVE-2017-5638などのセキュリティ脆弱性を悪用する可能性のあるトラフィックをブロックするために、カスタムModSecurityルールを作成します。これにより、サイトを攻撃から保護できます。その間に攻撃を受ける心配をせず、無理のないスケジュールで慎重に本番サーバーへパッチを適用できます。
ModSecurityとNGINX ModSecurity WAFの詳細については、eBook「ModSecurity 3.0 and NGINX: クイックスタートガイド」をダウンロードしてください。
リソース
- CVE-2017-5638 – CVEの公式通知
- CVE-2017-5638:Apache Strutsの脆弱性の詳細 – 脆弱性について理解するうえで役立つ概要
- Apache Strutsセキュリティ情報S2‑045 – セキュリティ脆弱性と回避策を掲載したApache Strutsのページ
- ArsTechnicaフォーラムのユーザーコメント – Apache Strutsへのパッチ適用が容易でない理由の説明
[NGINX Plus向けNGINX ModSecurity WAFモジュールは、2022年4月1日付で正式に販売終了となり、2024年3月31日付でサポート終了となります。詳細については、F5ブログの「F5 NGINX ModSecurity WAF Is Transitioning to End-of-Life<.htmla>」をご覧ください。]
著者について

関連するブログ記事
チュートリアル:NGINXを使用してアプリケーション向けにOpenTelemetryを構成する
OpenTelemetryを使用してNGINXサーバーの状態と健全性をより明確に把握することで、問題のトラブルシューティングを行い、Webアプリケーションのパフォーマンスを向上できます。
AkitaのNGINX Plus認定モジュールでAPIエンドポイントの問題を特定・修正
Akita SoftwareのAPIオブザーバビリティ向け新しいNGINX Plus Certified Moduleを活用して、APIエンドポイントの問題をより迅速に特定し、修正できます。
JavaプロジェクトをスキャフォールディングしてKubernetesネイティブアプリを構築する方法
Red HatのシニアプリンシパルデベロッパーアドボケイトであるDaniel Oh氏が、Javaプロジェクトをゼロから構築するためのひな形を作成し、Kubernetesネイティブアプリケーションとしてビルドする方法を解説します。
F5 NGINXaaS for Azureのご紹介:Microsoft Azureでネイティブに利用できるSaaS型ロードバランシング
NGINXaaS for Azureは、NGINX PlusをAzureネイティブのSaaSとして利用できるサービスです。NGINXの設定を容易にリフト&シフトできるため、クラウド導入とモダンアプリの展開を加速できます。

SELinuxでNGINXおよびNGINX Plusを使用する
Red Hat Enterprise Linux(RHEL)および関連ディストリビューションでSecurity-Enhanced Linux(SELinux)を有効にすると、デフォルト設定によりNGINXとNGINX Plusの一部の操作が制限されます。この記事では、すべての機能を利用できるようにSELinuxの設定を変更する方法について説明します。
NGINX PlusによるAWS Auto Scalingグループの負荷分散
新しいnginx-asg-sync統合ソフトウェアにより、NGINX PlusはAWS Auto Scalingグループの負荷を直接分散できるため、クラウドでの負荷分散がさらに柔軟になります