在本节中,我们将解释什么是目录遍历,描述如何进行路径遍历攻击和规避常见障碍,并说明如何防止路径遍历漏洞。
目录遍历(也称为文件路径遍历)是一种网络安全漏洞,允许攻击者读取运行应用程序的服务器上的任意文件。这可能包括应用程序代码和数据、后端系统的凭据以及敏感的操作系统文件。在某些情况下,攻击者可能能够写入服务器上的任意文件,允许他们修改应用程序数据或行为,并最终完全控制服务器。
考虑一个显示待售商品图像的购物应用程序。图像通过一些 HTML 加载,如下所示:
<img src="/loadImage?filename=218.png">
loadImage
URL 接受一个参数并返回指定文件 的filename
内容。图像文件本身存储在磁盘中的位置/var/www/images/
。要返回图像,应用程序将请求的文件名附加到此基本目录并使用文件系统 API 来读取文件的内容。在上述情况下,应用程序从以下文件路径读取:
/var/www/images/218.png
该应用程序没有针对目录遍历攻击实施任何防御措施,因此攻击者可以请求以下 URL 从服务器的文件系统中检索任意文件:
https://insecure-website.com/loadImage?filename=../../../etc/passwd
这会导致应用程序从以下文件路径读取:
/var/www/images/../../../etc/passwd
该序列../
在文件路径中有效,意味着在目录结构中上一级。三个连续的../
序列从/var/www/images/
文件系统的根目录开始,所以实际读取的文件是:
/etc/passwd
在基于 Unix 的操作系统上,这是一个标准文件,其中包含在服务器上注册的用户的详细信息。
在 Windows 上,../
和..\
都是有效的目录遍历序列,检索标准操作系统文件的等效攻击是:
https://insecure-website.com/loadImage?filename=..\..\..\windows\win.ini
实例1
打开网站看到界面
随便点击,抓包,放过,头部出现这个
filename之后改变路径,../../../etc/passwd,就success了。
常见障碍分析
障碍1
许多将用户输入放置到文件路径中的应用程序实现了某种针对路径遍历攻击的防御,并且这些通常可以被规避。
如果应用程序从用户提供的文件名中剥离或阻止目录遍历序列,则可以使用多种技术绕过防御。
您也许可以使用来自文件系统根目录的绝对路径,例如filename=/etc/passwd
直接引用文件,而无需使用任何遍历序列。
实例2
过程一样,试了../../../etc/passwd,看不到效果,直接试了etc/passwd,出来了。
障碍2
您也许可以使用嵌套遍历序列,例如....//或者
....\/
,当内部序列被剥离时,它将恢复为简单的遍历序列。
实例3
前面的方法都用了一遍,然后使用前面4点点和两个斜杠杠,成功了
障碍3
在某些情况下,例如在 URL 路径或请求filename
参数中multipart/form-data
,Web 服务器可能会在将您的输入传递给应用程序之前剥离任何目录遍历序列。您有时可以通过 URL 编码,甚至双重 URL 编码,绕过这种清理,这些../
字符分别产生%2e%2e%2f
或%252e%252e%252f
。各种非标准编码,例如..%c0%af或者
..%
ef%bc%8f
,也可以解决问题。 生僻词:multipart
多部分
案例4
..%252f..%252f..%252fetc/passwd
可以成功过程不做,比较简单,这个完成之后做ctf的题强化。
障碍4
如果应用程序要求用户提供的文件名必须以预期的基本文件夹开头,例如/var/www/images
,则可以包括所需的基本文件夹,然后是合适的遍历序列。例如:
filename=/var/www/images/../../../etc/passwd
案例不做了,简单,ctf系列再做案例。
障碍5
如果应用程序要求用户提供的文件名必须以预期的文件扩展名结尾,例如.png
,则可以使用空字节有效地终止所需扩展名之前的文件路径。例如:
filename=../../../etc/passwd%00.png
如何防止
防止文件路径遍历漏洞的最有效方法是完全避免将用户提供的输入传递给文件系统 API。可以重写许多执行此操作的应用程序功能,以更安全的方式提供相同的行为。
如果认为将用户提供的输入传递给文件系统 API 是不可避免的,则应结合使用两层防御来防止攻击:
- 应用程序应在处理用户输入之前对其进行验证。理想情况下,验证应与允许值的白名单进行比较。如果所需功能无法做到这一点,则验证应验证输入是否仅包含允许的内容,例如纯字母数字字符。
- 验证提供的输入后,应用程序应将输入附加到基本目录并使用平台文件系统 API 来规范化路径。它应该验证规范化路径是否以预期的基本目录开头。
下面是一些简单的 Java 代码示例,用于根据用户输入验证文件的规范路径:
File file = new File(BASE_DIRECTORY, userInput); if (file.getCanonicalPath().startsWith(BASE_DIRECTORY)) { // process file }
getCanonicalPath()方法是Path类的一部分。此函数返回给定文件对象的规范路径名。如果文件对象的路径名是Canonical,则它仅返回当前文件对象的路径。规范路径始终是绝对且唯一的,该函数会删除路径中的“。”和“ ..”(如果存在)。
file.getCanonicalPath()
参数:该函数不接受任何参数。
返回值:如果给定File对象的规范路径,则该函数返回String值。
异常:此方法引发以下异常:
- 安全异常 如果无法访问所需的属性值。
- I /O异常如果发生I /O异常。
startsWith()方法用来判断当前字符串是否是以另外一个给定的子字符串“开头”的,根据判断结果返回 true 或 false。
参数:str.startsWith(searchString [, position]);
searchString
要搜索的子字符串。
position
在 str 中搜索 searchString 的开始位置,默认值为 0,也就是真正的字符串开头处。
示例:
var str = "To be, or not to be, that is the question.";
alert(str.startsWith("To be")); // true
alert(str.startsWith("not to be")); // false
alert(str.startsWith("not to be", 10)); // true
白名单的话直接放弃,还没学java,以后有时间学习java,毕竟主流,可能转开发,哈哈哈。