概述 (Overview)
当Web应用程序允许用户下载文件时,如果后端代码直接将用户请求的文件名或路径参数拼接到文件路径中,而没有进行充分的安全验证和过滤(特别是对目录遍历字符如 ../),就可能导致任意文件下载漏洞。攻击者可以利用此漏洞下载服务器上预期之外的敏感文件,如配置文件、源代码、日志文件、密码文件等。
利用条件 (Conditions)
- Web应用程序提供文件下载功能。
- 存在读取文件的函数被调用 (
file_get_contents,readfile)。 - 读取文件的路径或文件名参数由用户控制。
- 后端代码未对用户提供的路径/文件名进行严格校验,或校验逻辑存在缺陷(可被绕过)。
- 应用程序将读取到的文件内容输出到响应中。
漏洞发现 (Discovery)
- 专用搜索引擎 Hacking:
- 使用 Google Dorks 或类似语法搜索可能存在漏洞的URL模式。
- 示例:
inurl:"readfile.php?file=",inurl:"download.php?path="
- 从URL链接判断:
- 观察URL中是否包含明显用于文件下载的路径或文件名。
- 示例:
download.php?path=report.pdf,getFile.jsp?filename=logo.png
- 从参数名判断:
- 寻找URL参数或POST请求参数中暗示文件路径或名称的关键字。
- 常见参数名:
file=,filename=,filepath=,File=,InputFile=path=,Path=,RealPath=url=,URL=,urls=src=,image=readfile=,down=Data=,menu=,Lang=,dis=,pg=(有时也可能被滥用)
漏洞验证 (Verification)
- 识别目标URL中控制下载文件的参数(如
file,path)。 - 尝试将参数值替换为目录遍历序列 (
../或..\,根据服务器操作系统选择) 加上已知存在的文件名,尝试向上级目录跳转并读取文件。 - 示例:
- 原始URL:
http://example.com/download.php?file=user_guide.pdf - 尝试读取
/etc/passwd(Linux):http://example.com/download.php?file=../../../../../../etc/passwd - 尝试读取
C:\Windows\win.ini(Windows):http://example.com/download.php?file=..\..\..\..\..\Windows\win.ini
- 原始URL:
- 如果服务器返回了目标文件的内容(即使是在浏览器中显示而非直接下载),则确认存在漏洞。可能需要对
../进行URL编码 (%2e%2e%2f) 或其他编码绕过。
漏洞利用 (Exploitation)
一般思路 (General Approach)
- 下载敏感配置文件:
- Web服务器配置 (Apache
httpd.conf, Nginxnginx.conf, Tomcatserver.xml) - SSH配置 (
/etc/ssh/sshd_config,~/.ssh/known_hosts,~/.ssh/id_rsa) - 数据库配置 (MySQL
my.cnf,web.xml中的连接字符串) - FTP配置
- 中间件配置 (WebLogic
config.xml) - 应用特定配置 (
config.php,.env)
- Web服务器配置 (Apache
- 下载日志文件:
- Web服务器访问/错误日志 (
/var/log/apache2/access.log,/var/log/nginx/error.log) - 应用日志 (
app.log) - 数据库日志
- 从中可能发现后台管理路径、其他漏洞信息、用户名等。
- Web服务器访问/错误日志 (
- 下载源代码:
- 获取Web应用程序的源代码进行白盒审计,寻找其他漏洞(SQL注入、命令执行、文件上传等)。
- 下载系统文件:
/etc/passwd,/etc/shadow(Linux, shadow通常需要高权限)/etc/hosts/root/.bash_history,~/.bash_history(用户命令历史)C:\Windows\win.ini,C:\boot.ini(Windows)
权限场景 (Permission Scenarios)
Root 权限 (Root Privilege)
- 利用
mlocate.db: 如果能下载/var/lib/mlocate/mlocate.db(通常需要较高权限),可以在本地使用locate -d mlocate.db <keyword>搜索服务器上几乎所有文件的路径,极大方便后续下载。 - 可以直接尝试读取如
/etc/shadow等高权限文件。
非 Root 权限 (Non-Root Privilege)
- 受限读取: 只能读取Web进程用户有权限访问的文件。
- 目录猜测: 需要更多地依赖
../目录遍历和猜测常见的目录结构 (如/home/user/.ssh/,/var/www/html/,C:\Users\user\Documents\)。 - 重点关注:
- 当前用户家目录下的配置文件 (
.bash_history,.profile,.ssh/)。 - Web目录下的源代码和配置文件。
- 临时文件目录 (
/tmp/,C:\Windows\Temp\)。 - 日志文件(如果权限允许)。
- 当前用户家目录下的配置文件 (
特定环境示例 (Specific Environment Example - Java/Oracle)
- 下载Web应用配置文件: 尝试下载
WEB-INF/web.xml和可能的框架配置文件,如WEB-INF/classes/applicationContext.xml(Spring)。这些文件可能包含数据库连接信息、其他配置路径等。 - 下载Class文件: 下载
WEB-INF/classes/目录下的.class文件。 - 反编译: 使用反编译工具(如 JD-GUI)查看
.class文件源代码。 - 寻找上传点: 在反编译的代码中搜索
upload,FileUpload,MultipartFile等关键字,寻找文件上传接口或逻辑。 - 构造利用: 如果找到上传接口,可以在本地构造HTML表单或使用工具(如 curl, Postman)调用该接口尝试上传WebShell。
防御策略 (Defense Strategies)
- 过滤和净化路径:
- 严格过滤用户输入的路径/文件名参数中的
.、/、\等目录遍历和路径分隔符。特别是要过滤掉../和..\序列。 - 对用户输入进行规范化处理后再使用。
- 严格过滤用户输入的路径/文件名参数中的
- 白名单或固定路径:
- 最佳实践: 不要将用户输入直接拼接到文件路径。应该将允许下载的文件名或ID存储在数据库或配置文件中,用户请求时只传递ID或安全的名称,后端根据ID查找真实路径。
- 如果必须使用用户输入的文件名,应将其限制在预定义的安全目录内,并校验最终路径是否仍在该安全目录下。
- 使用硬编码或配置化的文件下载根目录。
- 权限控制:
- Web应用程序运行用户应使用最低权限。
- 确保Web目录外的敏感文件没有被Web用户读取的权限。
- PHP
open_basedir配置:- 在
php.ini或虚拟主机配置中设置open_basedir,将PHP脚本的文件访问限制在指定的目录树内,可以有效防止跨目录读取文件。 - 示例:
open_basedir = /var/www/html/:/tmp/
- 在
- 对下载接口进行身份验证和授权: 确保只有授权用户才能访问下载功能,并根据用户角色限制可下载的文件范围。