コンテンツにスキップ

Path Traversal

パストラバーサル (Path Traversal)

概要

パストラバーサルの脆弱性は、Webアプリケーションによるユーザー入力の処理が不適切な場合に発生し、攻撃者が意図されたディレクトリ構造の外部に移動して、権限のないファイルやディレクトリにアクセスすることを可能にします。この脆弱性を悪用するには、入力を操作して、ファイルシステムをトラバースできる ../ のようなシーケンスを含めます。

パストラバーサルの脆弱性の影響は、脆弱性が悪用されるコンテキストに応じて、機密情報の漏洩から任意のコード実行まで多岐にわたります。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.io.BufferedReader;
import java.io.FileReader;

@SpringBootApplication
public class PathTraversalExample {

    public static void main(String[] args) {
  SpringApplication.run(PathTraversalExample.class, args);
    }
}

@RestController
class FileController {

    @PostMapping("/processFile")
    public String processFile(@RequestBody String userInput) {
  try {
      // Vulnerable path traversal without proper input validation
      String filePath = "/var/www/data/" + userInput;

      // Process the file content (vulnerable code)
      return processFileContent(filePath);
  } catch (Exception e) {
      return "Error processing file content: " + e.getMessage();
  }
    }

    private String processFileContent(String filePath) throws Exception {
  // Read the file content
  BufferedReader br = new BufferedReader(new FileReader(filePath));
  StringBuilder content = new StringBuilder();
  String line;
  while ((line = br.readLine()) != null) {
      content.append(line).append("\n");
  }
  br.close();
  return "Processed file content:\n" + content.toString();
    }
}
const express = require('express');
const bodyParser = require('body-parser');
const fs = require('fs');

const app = express();
const port = 3000;

app.use(bodyParser.text());

app.post('/processFile', (req, res) => {
    try {
  // Vulnerable path traversal without proper input validation
  const filePath = '/var/www/data/' + req.body;

  // Process the file content (vulnerable code)
  const content = processFileContent(filePath);
  res.send(content);
    } catch (error) {
  res.status(500).send('Error processing file content: ' + error.message);
    }
});

function processFileContent(filePath) {
    // Read the file content
    const content = fs.readFileSync(filePath, 'utf-8');
    return 'Processed file content:\n' + content;
}

app.listen(port, () => {
    console.log(`Server listening at http://localhost:${port}`);
});
<?php
// Save this file as index.php and run it using: php -S localhost:8000

// Get user input from the POST request
$userInput = $_POST['userInput'];

// Vulnerable path traversal without proper input validation
$filePath = '/var/www/data/' . $userInput;

// Process the file content (vulnerable code)
echo processFileContent($filePath);

function processFileContent($filePath) {
    try {
  // Read the file content
  $content = file_get_contents($filePath);
  return 'Processed file content:' . PHP_EOL . $content;
    } catch (Exception $e) {
  return 'Error processing file content: ' . $e->getMessage();
    }
}
?>

推奨事項

パストラバーサルのリスクを軽減するには、以下の推奨事項を検討してください。

  • 直接の連結の回避: ファイルシステムのパスを構築する際に、ユーザー入力を直接連結することは避けてください。
  • ユーザー入力のサニタイズ: ファイルシステムのパス構築に使用する前にユーザー入力をサニタイズし、../ のような文字列シーケンスは削除し、パスを正規化する必要があります。
  • 堅牢なパスパーサーの使用: 確立された安全なパス解析パッケージを使用してください。一部のパッケージは本質的にパストラバーサルに対して脆弱である可能性があります。
  • パスの包含チェック: 指定された入力を検証した後、ベースディレクトリに入力を追加し、プラットフォームのファイルシステムAPIを使用してパスを正規化(カノニカライズ)します。正規化されたパスがベースディレクトリ内に含まれていることを確認してください。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.io.BufferedReader;
import java.io.FileReader;

@SpringBootApplication
public class MitigatedPathTraversalExample {

    public static void main(String[] args) {
  SpringApplication.run(MitigatedPathTraversalExample.class, args);
    }
}

@RestController
class MitigatedFileController {

    @PostMapping("/processFile")
    public String processFile(@RequestBody String userInput) {
  try {
      // Mitigated: Validate user input to prevent path traversal
      if (!isValidInput(userInput)) {
    return "Invalid file path.";
      }

      // Safe file inclusion with proper input validation
      String filePath = "/var/www/data/" + userInput;

      // Process the file content
      return processFileContent(filePath);
  } catch (Exception e) {
      return "Error processing file content: " + e.getMessage();
  }
    }

    private boolean isValidInput(String userInput) {
  // Mitigated: Implement proper input validation (e.g., regex)
  // In a real-world scenario, use a more robust validation mechanism.
  return userInput.matches("[a-zA-Z0-9_-]+\\.pdf");
    }

    private String processFileContent(String filePath) throws Exception {
  // Read the file content
  BufferedReader br = new BufferedReader(new FileReader(filePath));
  StringBuilder content = new StringBuilder();
  String line;
  while ((line = br.readLine()) != null) {
      content.append(line).append("\n");
  }
  br.close();
  return "Processed file content:\n" + content.toString();
    }
}
const express = require('express');
const bodyParser = require('body-parser');
const fs = require('fs');

const app = express();
const port = 3000;

app.use(bodyParser.text());

app.post('/processFile', (req, res) => {
    try {
  // Mitigated: Validate user input to prevent path traversal
  if (!isValidInput(req.body)) {
      res.status(400).send('Invalid file path.');
      return;
  }

  // Safe file inclusion with proper input validation
  const filePath = '/var/www/data/' + req.body;

  // Process the file content
  const content = processFileContent(filePath);
  res.send(content);
    } catch (error) {
  res.status(500).send('Error processing file content: ' + error.message);
    }
});

function isValidInput(userInput) {
    // Mitigated: Implement proper input validation (e.g., regex)
    // In a real-world scenario, use a more robust validation mechanism.
    return userInput.match(/^[a-zA-Z0-9_-]+\.pdf$/);
}

function processFileContent(filePath) {
    // Read the file content
    const content = fs.readFileSync(filePath, 'utf-8');
    return 'Processed file content:\n' + content;
}

app.listen(port, () => {
    console.log(`Server listening at http://localhost:${port}`);
});
<?php
// Save this file as index.php and run it using: php -S localhost:8000

// Mitigated: Validate user input to prevent path traversal
$userInput = $_POST['userInput'];
if (!isValidInput($userInput)) {
    http_response_code(400);
    echo 'Invalid file path.';
    exit;
}

// Safe file inclusion with proper input validation
$filePath = '/var/www/data/' . $userInput;

// Process the file content
echo processFileContent($filePath);

function isValidInput($userInput) {
    // Mitigated: Implement proper input validation (e.g., regex)
    // In a real-world scenario, use a more robust validation mechanism.
    return preg_match('/^[a-zA-Z0-9_-]+\.pdf$/', $userInput);
}

function processFileContent($filePath) {
    try {
  // Read the file content
  $content = file_get_contents($filePath);
  return 'Processed file content:' . PHP_EOL . $content;
    } catch (Exception $e) {
  return 'Error processing file content: ' . $e->getMessage();
    }
}
?>

リンク

標準

  • CWE_TOP_25:
    • CWE_22
  • GDPR:
    • ART_25
    • ART_32
  • PCI_STANDARDS:
    • REQ_6_4
    • REQ_6_5
  • SOC2_CONTROLS:
    • CC_2_1
    • CC_4_1
    • CC_7_1
    • CC_7_2
    • CC_7_4
    • CC_7_5
  • HIPAA_CONTROLS:
    • SECURITY212
    • SECURITY213
    • SECURITY255