本文目录导读:

路径遍历漏洞(Path Traversal)相对容易被代码审计发现,尤其是在人工审计中,其风险点通常较为直观,但它的“易发现”程度取决于几个关键因素。
在静态代码中,如果代码逻辑直接、清晰,那么漏洞非常明显;但如果逻辑复杂、使用编码或间接调用,则可能被隐藏或遗漏。
下面详细分析其“易发现”程度及原因:
为什么路径遍历漏洞相对“容易”发现?
-
核心模式固定且明显:漏洞的根本原因是用户可控的输入被用于文件路径的拼接,且没有进行充分的过滤或验证,审计人员可以重点搜索以下高危函数/操作:
- 文件读取/包含:
open()、file_get_contents()、include()、require()、readfile()等。 - 文件写入/删除:
fwrite()、file_put_contents()、unlink()、rename()、move_uploaded_file()等。 - 目录操作:
opendir()、scandir()、glob()、DirectoryIterator等。 - 下载功能:如
download.php?file=xxx。
- 文件读取/包含:
-
输入源清晰:审计人员会重点关注接收用户输入的变量,如
$_GET、$_POST、$_REQUEST、$_FILES、$_COOKIE、请求头(如Referer、User-Agent被用作路径时)等,只要发现用户输入直接或间接地流向了上述文件操作函数,就存在潜在风险。 -
手工审查十分有效:精明的代码审计人员会沿着数据流(数据从哪里来,到哪里去)进行跟踪,寻找路径拼接处,如果发现类似
$path = $base_dir . '/' . $_GET['file'];的代码,且没有对$_GET['file']做任何检查,可以直接判定为高危漏洞。
什么情况下会“不易”发现或容易被忽略?
虽然模式固定,但现代应用开发中存在许多“伪装”手段,使得漏洞更隐蔽。
-
不完整的过滤与净化:
- 黑名单过滤:只过滤了 或 ,但攻击者可以使用 ( 和 的简单组合可能绕过)、URL编码(
%2e%2e%2f)、双编码(%252e%252e%252f,如果后端有解码操作)、Unicode编码(如..%c0%af,在特殊解码下可视为 )等。 - 未考虑操作系统差异:Windows下使用 作为路径分隔符,Linux下使用 ,过滤了 但没过滤 ,在Windows服务器上可能被利用。
- 过滤了 但允许 :攻击者使用 就能绕过。
- 只过滤了绝对路径:认为限制路径必须以
/var/www/开头就安全,但用户输入../../../etc/passwd拼接后可能成为/var/www/../../../etc/passwd,最终指向/etc/passwd。
- 黑名单过滤:只过滤了 或 ,但攻击者可以使用 ( 和 的简单组合可能绕过)、URL编码(
-
复杂的拼接与间接传参:
- 多次赋值:
$userFile = $_GET['file'];->$processedFile = sanitize($userFile);->$finalPath = $base . $processedFile;。sanitize()函数本身有缺陷,审计可能遗漏。 - 通过数据库或文件配置:用户输入先被存入数据库,然后另一个文件操作从数据库中读取该值进行路径拼接,这种间接的数据流增加了追踪难度。
- 使用配置或常量:如
define('UPLOAD_DIR', '/uploads/');后,程序使用$path = UPLOAD_DIR . $userInput;,常量看似安全,但$userInput仍可能是../../etc/passwd。
- 多次赋值:
-
动态语言特性(PHP、Python等):
- 变量函数:
$func = 'file_get_contents'; $result = $func($userInput);,静态分析工具可能难以跟踪这种动态调用的目标函数。 - 回调函数:
array_map('file_get_contents', $userInputArray);。 - 反序列化漏洞联动:攻击者通过反序列化漏洞注入一个包含路径遍历的恶意对象,这使得漏洞触发点隐藏在反序列化链中,常规审计难以发现。
- 变量函数:
-
代码量巨大与逻辑分散:
- 在一个大型项目中,文件操作可能分散在几十个甚至上百个文件中,审计人员可能需要手动审查所有调用了文件操作函数的文件,如果输入源(某个接口)与操作点不在同一个文件或模块中,就容易漏掉。
- 使用了框架(如 Spring、Laravel、Django)的路径处理或资源加载功能,框架可能提供了看似“安全”的抽象层,但如果开发者没有正确使用(如直接使用
new File(uri)而非借助资源管理器),仍然可能出问题。
工具辅助:自动化的“快”与人工审计的“准”
-
静态分析工具(SAST):
- 优点:能快速扫描整个代码库,标记出所有用户输入流向文件操作函数的路径,效率极高,SonarQube、Checkmarx、Fortify、CodeQL 等。
- 缺点:易产生大量误报(False Positive),很多工具无法准确判断开发者是否做了有效的过滤(如正则匹配、白名单验证),会报告理论上存在风险但实际上被安全处理过的代码。可能漏掉(False Negative)上面提到的复杂间接传参或编码绕过情况。
- 工具是发现初步线索的利器,但不能完全依赖。
-
人工代码审计:
- 优点:能理解上下文、业务逻辑、绕过技巧,判断工具报告的是否真实可利用,善于发现工具难以处理的复杂场景、逻辑缺陷和隐蔽的绕过方式。
- 缺点:耗时、成本高,对审计人员经验要求高。
- 人工审计是最终判断和确认漏洞是否存在的关键。
总结与建议
路径遍历漏洞的“易发现”程度:
- 对经验丰富的审计人员(结合工具):非常容易,通常能快速定位并确认。
- 对自动化工具:容易发现基础样本,但难以完全判定且存在误报和漏报。
- 对无经验的审计人员或不充分的审计:容易被忽视,尤其是面对复杂过滤和间接传参时。
- 对开发者友好(反方):非常不容易,很多开发者认为自己加了过滤(如
str_replace('../', '', $path))就安全了,但实际上这种“过滤”脆弱不堪。
最佳实践(如何让它更“难”被发现——即如何有效防御):
- 使用白名单:最安全的做法是使用固定的、允许的路径值列表(如
switch($action){case 'profile': $file = 'profile.html';...}),用户输入只是一个索引,而非路径。 - 验证和规范路径:
- 使用标准库函数(如 Python 的
os.path.realpath()、Java 的File.getCanonicalPath())将路径解析为绝对路径。 - 然后检查这个绝对路径是否以允许的基目录开头(
$canonicalPath.startsWith('/var/www/uploads/')),这是最可靠的防御。
- 使用标准库函数(如 Python 的
- 从根源避免:如果可能,不要直接让用户输入影响文件系统路径,使用从数据库中查询文件ID、文件名然后映射到服务器路径的方式。
- 最小化权限:运行Web应用的进程使用最低权限账户,即使发生路径遍历,能访问的文件也极其有限。
路径遍历漏洞是代码审计中的高频发现点,对专业审计人员来说相对容易发现,但对自动化工具和浅层面的审计来说也可能被绕过。理解其核心模式、过滤的脆弱性以及间接调用是发现和防范该漏洞的关键。