PHP的is_numeric()函数对抗目录遍历攻击有效吗?

huangapple go评论72阅读模式
英文:

Is PHP's is_numeric() function effective against directory traversal attacks?

问题

我想知道下面的代码是否安全,而不是它是好还是坏的实践,因为我想报告它是否容易受到目录遍历攻击的攻击。我不认为这个问题是重复的!

我正在为我的一个PHP项目编写渗透测试报告,目前正在评估它对目录遍历(或路径遍历)攻击的漏洞性。

以下是涉及的代码片段:

$number = $_GET['numberByUser'] ?? null;

if (is_numeric($number) && file_exists($number)) {
    readfile($number);
}

在这段代码中,$GET['numberByUser'] 变量可以被用户操纵,但它通过内置的PHP函数**is_numeric()** 进行了净化。

在当前目录中只有全数字的文件名,每个用户都可以访问。我想知道**is_numeric()** 是否防止了“../”或“%2e%2e%2f”或任何其他可以将我移出当前目录的恶意有效负载。

我的问题是:恶意用户是否可以绕过这个过滤器?

我知道如何防止PHP中的目录遍历漏洞,但我想知道上面的代码是否可以被绕过。服务器上有以数字命名的文件/var/www/html/numbers/123

根据我的理解,is_numeric() 在理论上应该阻止目录遍历攻击,因为它确保只有数字值通过。然而,这个函数通常不用作防护目录遍历攻击的安全措施。

我尝试使用来自以下来源的多个有效负载绕过此函数:

然而,这些尝试都没有成功,使我相信**is_numeric()** 确实可以作为目录遍历攻击的有效威慑手段,即使这不是它的预期用途。

如果有更多知识或经验的人能够确认我的理解是否准确,或者是否存在我可能忽视的已知绕过技术,我将不胜感激。

英文:

I would like to know if the code below is SECURE and not that it is a good or bad practice, since I want to report if it is vulnerable to directory traversal attack. I do not think if this question is duplicated!

I am working on a penetration testing report for one of my PHP projects and am currently assessing its vulnerability to directory traversal (or path traversal) attacks.

Below is a snippet of the code in question:

$number = $_GET['numberByUser'] ?? null;

if (is_numeric($number) && file_exists($number)) {
    readfile($number);
}

In this code, the $GET['numberByUser'] variable can be manipulated by the user, but it is sanitized with the built-in PHP function is_numeric().

There are only all-numeric filenames in the current directory, which can be accessed by every user. I'd like to know if the is_numeric() protect against "../" or "%2e%2e%2f" or any other tricky payloads which can move me outside from the current directory.

My question is: can a malicious user bypass this filter?

I know how to prevent directory traversal vulnerability in PHP, but I want to know if the code above can be bypassed or not. On the server there are files with number names /var/www/html/numbers/123


From my understanding, is_numeric() should theoretically block directory traversal attacks as it ensures that only numerical values pass through. Yet, this function isn't typically used as a safeguard against such attacks.

I have attempted to bypass this function using several payloads sourced from:

However, these attempts were unsuccessful, leading me to believe that is_numeric() could indeed be a viable deterrent against directory traversal attacks, even if this isn't its intended purpose.

I would appreciate if anyone with further knowledge or experience could confirm whether my understanding is accurate or whether there exist known bypass techniques that I may be overlooking.

答案1

得分: 2

is_numeric 是一个具有简单名称但实现相对复杂的函数之一。它尝试检测各种不同类型的“数字”,包括“5”、“-5”、“5.0”甚至“0.5e-3”(表示“0.0005”的一种方式)。虽然我无法想出特定的攻击方式,但这可能不是最适合依赖的函数。

如果你实际想要的是只有数字,那么你需要的函数是名字不太容易记住的 ctype_digit

另外,你在这里所做的不是净化输入,而是验证它 - 净化通常指的是以某种方式更改值;验证是关于如果值不符合预期格式则拒绝它。净化通常更难做到正确,但在这种情况下,你可以通过简单地将其转换为整数来净化输入($number = (int)$number;) - 只需记住结果可能是0或负数。

最后,你不会经常看到is_numeric或ctype_digit在这种情况下被大量使用的原因是,验证通常需要更复杂的规则,因此会使用正则表达式等工具。例如,如果你的文件名实际上是"1.txt"、"2.txt"等,你可以使用 preg_match('/^\d+\.txt$/', $number) 进行验证。(尽管正则表达式难以正确使用!)

英文:

is_numeric is one of those functions that has a simple name, and a rather complicated implementation. It attempts to detect lots of different sorts of "numbers", including "5", "-5", "5.0", and even "0.5e-3" (a way of writing "0.0005"). While I can't think of a specific attack in this case, it's probably not the best function to rely on.

If what you want is actually only digits, the function you want is the less memorably named ctype_digit.

On a different note, what you are doing here is not sanitising the input, but validating it - sanitisation generally refers to changing the value in some way; validation is about rejecting the value if it doesn't meet the expected format. Sanitisation is generally harder to get right, but in this case, you could sanitise the input by simply casting it to an integer ($number = (int)$number;) - just remember that the result might be 0 or a negative number.

Finally, the reason you won't see lots of uses of either is_numeric or ctype_digit used in this context is that validation often needs more complex rules, and so things like regular expressions are used. For instance if your filenames were actually "1.txt", "2.txt", etc, you could validate with preg_match('/^\d+\.txt$', $number). (Although, regexes are also hard to get right!)

huangapple
  • 本文由 发表于 2023年6月2日 03:22:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/76385069.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定