ローカルファイルインクルード(Local File Inclusion, LFI)脆弱性について
ローカルファイルインクルード(LFI)脆弱性は、Webアプリケーションがユーザーからの入力を使用してローカルファイルをインクルードする際に、不適切な入力検証により攻撃者が意図しないファイルをインクルードさせる脆弱性です。この脆弱性を利用すると、攻撃者はサーバー内の任意のファイル(例: /etc/passwd
など)を読み込んだり、場合によってはWebシェルなどの悪意のあるコードを実行させることが可能になります。
脆弱なコード例:
<?php
$page = $_GET['page'];
include($page);
?>
攻撃手法:
攻撃者は、page
パラメータに任意のファイルパスを指定して、サーバー上の任意のファイルをインクルードさせることができます。
http://example.com/vulnerable.php?page=/etc/passwd
また、ディレクトリトラバーサル(../
)を使用して、システム上の重要なファイルを読み込むことも可能です。
http://example.com/vulnerable.php?page=../../../../etc/passwd
脆弱なコード例:
from flask import Flask, request
app = Flask(__name__)
@app.route('/include')
def include_file():
page = request.args.get('page')
with open(page, 'r') as file:
content = file.read()
return content
if __name__ == '__main__':
app.run()
攻撃手法:
攻撃者は、URLパラメータに任意のファイルパスを指定して、サーバー上のファイルを読み込ませることができます。
http://localhost:5000/include?page=/etc/passwd
脆弱なコード例:
const express = require('express');
const fs = require('fs');
const app = express();
app.get('/include', (req, res) => {
const page = req.query.page;
fs.readFile(page, 'utf8', (err, data) => {
if (err) {
return res.status(500).send('Error loading file');
}
res.send(data);
});
});
app.listen(3000);
攻撃手法:
攻撃者は、任意のファイルパスを指定して、サーバー上のファイルを読み込ませることができます。
http://localhost:3000/include?page=/etc/passwd
脆弱なコード例:
<%
String page = request.getParameter("page");
RequestDispatcher dispatcher = request.getRequestDispatcher(page);
dispatcher.include(request, response);
%>
攻撃手法:
攻撃者は、任意のファイルパスを指定して、サーバー上のファイルをインクルードさせることができます。
http://example.com/vulnerable.jsp?page=../../../../WEB-INF/web.xml
../
など)が含まれていないかチェックします。PHPの例:
$page = basename($_GET['page']); // ファイル名のみに制限
$filepath = "/var/www/html/pages/" . $page;
include($filepath);
Pythonの例(Flask):
import os
from flask import Flask, request, abort
app = Flask(__name__)
@app.route('/include')
def include_file():
page = request.args.get('page')
if '..' in page or page.startswith('/'):
abort(400)
safe_path = os.path.join('/var/www/html/pages', page)
if os.path.exists(safe_path):
with open(safe_path, 'r') as file:
content = file.read()
return content
else:
abort(404)
Node.jsの例(Express):
const express = require('express');
const fs = require('fs');
const path = require('path');
const app = express();
const allowedFiles = ['about.html', 'contact.html'];
app.get('/include', (req, res) => {
const page = req.query.page;
if (!allowedFiles.includes(page)) {
return res.status(400).send('Invalid file');
}
const filepath = path.join(__dirname, 'pages', page);
fs.readFile(filepath, 'utf8', (err, data) => {
if (err) {
return res.status(404).send('File not found');
}
res.send(data);
});
});
app.listen(3000);
Javaの例(JSP):
List<String> allowedPages = Arrays.asList("home.jsp", "about.jsp", "contact.jsp");
if (allowedPages.contains(page)) {
RequestDispatcher dispatcher = request.getRequestDispatcher("/WEB-INF/pages/" + page);
dispatcher.include(request, response);
} else {
response.getWriter().write("Invalid page request.");
}
まとめ: ローカルファイルインクルード脆弱性は、サーバー上の任意のファイルを読み込ませることができる非常に危険な脆弱性です。入力のバリデーション、ホワイトリストの使用、絶対パスの検証、外部ファイルのインクルード禁止などの防止策を実装することで、この脆弱性を効果的に防ぐことができます。各言語やフレームワークに適した対策を講じることが推奨されます。