目录遍历
目录遍历(英文:Directory traversal),又名路径遍历(英文:Path traversal)是一种利用网站的安全验证缺陷或用户请求验证缺陷(如传递特定字符串至文件应用程序接口)来列出服务器目录的漏洞利用方式。
此攻击手段的目的是利用存在缺陷的应用程序来获得目标文件系统上的非授权访问权限。与利用程序漏洞的手段相比,这一手段缺乏安全性(因为程序运行逻辑正确)。
目录遍历在英文世界里又名../
攻击(Dot dot slash attack)、目录攀登(Directory climbing)及回溯(Backtracking)。其部分攻击手段也可划分为规范化攻击(Canonicalization attack)。
示例
下方是一个存在安全隐患的PHP程序示例:
<?php
$template = 'red.php';
if (isset($_COOKIE['TEMPLATE']))
$template = $_COOKIE['TEMPLATE'];
include ("/home/users/phpguru/templates/" . $template);
?>
攻击者可对此程序发送下列HTTP请求:
GET /vulnerable.php HTTP/1.0
Cookie: TEMPLATE=../../../../../../../../../etc/passwd
从而使服务器产生如下的响应:
HTTP/1.0 200 OK
Content-Type: text/html
Server: Apache
root:fi3sED95ibqR6:0:1:System Operator:/:/bin/ksh
daemon:*:1:1::/tmp:
phpguru:f8fk3j1OIf31.:182:100:Developer:/home/users/phpguru/:/bin/csh
/home/users/phpguru/templates/
后重复的../
导致include()
函数遍历Root目录,并向攻击者返回Unix密码文件/etc/passwd
。
Unix中的/etc/passwd
常用于展示应用程序存在目录遍历问题,黑客及骇客可使用此文件来破解密码。
新版Unix操作系统中,原位于passwd文件中的经散列处理后的密码被移动到了/etc/shadow
,其无法被没有特权的用户读取。但攻击者仍可使用此文件来列出系统上的用户账户。
变体
下方是已知的目录遍历攻击方式变体:
Unix上的目录遍历
常见的Unix类目录遍历攻击使用../
字符。攻击者可使用glob通配符对Sudo程序进行攻击(如chown /opt/myapp/myconfig/*
可通过sudo chown baduser /opt/myapp/myconfig/../../../etc/passwd
命令攻击)。
Windows上的目录遍历
对微软Windows及DOS进行目录遍历通常使用..\
或../
。[1]
在这类系统上,每个分区均有不同的根目录(如C盘则为C:\
),不同的盘符之间没有共同的根目录。这意味着对于大多数的目录遍历缺陷而言,其仅仅对单一的分区有效。
这种攻击手段也是此类系统上大多数安全缺陷的异派同源。[2][3]
URI编码目录遍历
此缺陷与规范化问题有关。
部分网页应用程序会检查查询字符串中的危险字符,如:
..
..\
../
这种方法能避免部分目录遍历问题。但是,查询字符串在使用前通常经过URI解码。因此,这些应用程序易受到百分号编码类的目录遍历攻击,如:
%2e%2e%2f
将解码为.
./
%2e%2e/
将解码为.
./
..%2f
将解码为.
./
%2e%2e%5c
将解码为.
.\
Unicode / UTF-8编码目录遍历
同样与规范化问题有关。
布魯斯·施奈爾与杰弗里·斯特里夫林(Jeffrey Streifling)称UTF-8是安全缺陷与攻击向量的根源。[4]
当微软为其网页服务器添加Unicode支持时,同时添加了一种编码../
的全新方式,却绕过了防止目录遍历的补丁。
多个百分号编码,如:
%c1%1c
%c0%af
可被解码为/
或\
符。
微软的网页服务器将百分号编码解码为对应的8位字符。这是Windows和DOS的正确行为,因为两者都使用基于ASCII的8位字符集的规范形式。
但是,原版UTF-8并不是规范形式,多个字符串经编码后可被译为相同的字符串。微软在未经UTF-8规范化时即进行防遍历检查,从而导致在字符串比较时忽略了(HEX)C0AF
及(HEX) 2F
均为同一字符。攻击者可使用%c0%9v
字符进行攻击。[5]
Zip/压缩文件遍历攻击
攻击者可使用归档文件(如zip格式)来进行目录遍历攻击:压缩文件中的文件可为攻击者精心制造,利用回溯法来覆盖文件系统上的文件。用于解压缩归档文件的代码应对归档中的文件进行检查,避免目录遍历。
防止目录遍历的方法
下方是防止目录遍历的几种方法:
- 在继续运行下方代码时处理与文件无关的URI请求(如钩入用户代码);
- 当用户请求访问文件/目录时,构造文件/目录(若存在)所在的的完整路径,并标准化所有字符(如
%20
转为空格); - 假设文档根目录已合格、被正常化、目录已知且字符串的长度为N。假设此目录外的任何文件都无法被读取/写入;
- 确保请求文件完整目录后的头N个字符与文档根目录完全相同;
- 若相同,则返回指定文件;
- 若不同,则返回错误,因为请求显然超出服务器提供文件范围;
- 将硬编码的预定义文件拓展名添加到目录后将无法限制对此文件拓展名的攻击。
<?php
include($_GET['file'] . '.html');
用户可使用空字符(表示字符串结束)来绕过$_GET
后的全部内容(仅限PHP语言)。
另请参阅
参考文献
- ^ Naming Files, Paths, and Namespaces. Microsoft. [2019-07-11]. (原始内容存档于2018-06-01).
File I/O functions in the Windows API convert '/' to '\' as part of converting the name to an NT-style name
- ^ Burnett, Mark. Security Holes That Run Deep. SecurityFocus. December 20, 2004 [2019-07-11]. (原始内容存档于2021-02-02).
- ^ Microsoft: Security Vulnerabilities (Directory Traversal). CVE Details. [2019-07-11]. (原始内容存档于2019-07-11).
- ^ Crypto-Gram Newsletter July 2000. [2019-07-11]. (原始内容存档于2014-08-14).
- ^ IIS cmd.exe attack strings. [2019-07-11]. (原始内容存档于2010-08-03).