是否可以绕过file_get_contents参数的附加文件后缀? [英] Can an appended file suffix to a parameter for file_get_contents be bypassed?
问题描述
考虑以下代码
<?php
// warning: this code is unsafe and for demonstrational purposes only,
// do not use in a production environment
$filename = $_GET['filename'];
$extension = 'txt';
$path = '/absolute/path';
$fullFilename = sprintf('%s/%s.%s', $path, $filename, $extension);
echo file_get_contents($fullFilename);
我们都知道(至少我希望如此),绝对路径绝对不是足够的表示要避免离开给定的路径-只需在查询字符串中插入一个或多个 ../
即可到达文件系统上的任何路径。
We all know (at least I hope so) that prepending an absolute path is by no way an adequate mean to prevent leaving the given path - one can simply insert one or more "../
"s to the query string to reach any path on the file system.
我的问题是:与给定的示例类似,也可以在 $ _ GET ['filename']
中进行操作这样也可以绕过给定扩展名后缀的方式,即回显了.txt以外的文件?我特别想到某些控制字符以与 ../ $code>相同的方式绕过前缀。
My question is: Analogously to the given example, can $_GET['filename']
also be manipulated in such a way that the given extension suffix can be bypassed as well, i.e. a file other than .txt is echoed? I'm especially thinking of certain control characters that bypass the appended file extension in the same fashion as ../
does with the prefix.
我尝试在查询字符串中添加一些控制字符(例如,用于删除的ASCII码127)或通过使用& ,
|
或>
,但都无济于事,我想知道是否存在这种可能性。
I tried adding some control characters (e.g. ASCII code 127 for delete) to the query string or concatenating two filenames by using &&
, |
or >
, but all to no avail and I wondered if there exists such a possibility at all.
(顺便说一句,我想补充一点,这个问题并不是出于开发系统的目的而提出的。这纯粹是我最近想到的一个假设问题。) / p>
(Btw, I'd like to add the note that this questions is not asked for the purpose to exploit a system. It's purely a hypothetical question that came across my mind recently.)
推荐答案
当然, nullbyte
, \ 0
(如果要在查询字符串中进行测试,则为%00
),将具有 file_get_contents()
遇到字符串时停止处理。
Sure, the nullbyte
, \0
(or %00
if you want to test in a query-string), will have file_get_contents()
stop processing the string when it hits it.
因此,如果 $ _ GET ['filename']
是 ../../../../../ etc / passwd%00
(例如 your_ page.php?filename = .. / .. / .. / .. / etc / passwd%00
), file_get_contents()
永远不会看到结尾的 .txt
(它将看到它,但不会处理它)。
So, if $_GET['filename']
is ../../../../../etc/passwd%00
(such as your_page.php?filename=../../../../etc/passwd%00
), file_get_contents()
will never see the ending .txt
(it will see it, but won't process it).
可悲的是, sprintf
在构建字符串时不会删除nullbyte。我不确定其他控制字符,但是如果有的话,我总是建议删除空字节。但是,更直观的方法是建立允许字符的白名单,并对输入内容执行 preg_match()
。
Sadly, sprintf
does not strip the nullbyte when building your string. I'm not sure about other control characters, but if anything - I would always recommend to strip the nullbyte. However, a more intuitive approach would be to build a whitelist of allowed characters and perform a preg_match()
against the input.
单单,可以使用PHP的 realpath()
放在生成的字符串上,它将确定实际访问的完整路径。
因此, / absolute / path /../../../../ etc / passwd\0.txt
传递给 realpath()
将返回 / etc / passwd
。然后,您可以对返回的值进行进一步的验证(例如,扩展名是否仍然是 .txt
还是位于指定/必需的目录中)。
Going one-up on that one, you can use PHP's realpath()
on the built string and it will determine the full path that is really being accessed.
So, /absolute/path/../../../../etc/passwd\0.txt
, passed to realpath()
will return /etc/passwd
. You can then do further validation on the returned value (such as, is the extension still .txt
or is it within a specified/required directory).
这篇关于是否可以绕过file_get_contents参数的附加文件后缀?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!