某PHP CTF题目学习

题目来源于:https://twitter.com/OctagonNetworks/status/1665408800646389761

参考如下:

1686016830415.png

源码如下:

<?php
require "flag.php";

$input = $_GEt['input'];
$input = str_replace(".", "", $input);

function check_input($value) {

if (strlen($value) > "3") {
if ($value < "1" && $value > "0.99") {
if(strlen($value) <= "4") {
return 1;
}
}
}
}

if(check_input($input)) {
print("You win! Flag is: ". $flag);
} else {
print("Wrong input!");
}
?>

在下面的评论中其实已经给出了具体的答案:?input=00\.9 。

首先,先看源码。主要难点在于函数check_input中,代码要求传入的值长度为4 ,但要小于字符串"1"并且大于字符串"0.99"。

在 PHP 中,字符串比较是根据字符的 ASCII 值进行比较的。当比较字符串时,PHP 会逐个比较字符串中的字符,并根据 ASCII 值的大小确定它们的顺序。

在 ASCII 表中,数字字符的 ASCII 值是按照其对应的数值顺序排列的。因此,比较字符串 "00\9" 和 "1" 时,先比较第一个字符 "0" 和 "1",由于 "0" 的 ASCII 值为 48,而 "1" 的 ASCII 值为 49,所以 "0" 比 "1" 小。

另一方面,比较字符串 "00\9" 和 "0.99" 时,先比较第一个字符 "0" 和 "0",它们的 ASCII 值相同。然后比较下一个字符 "0" 和 ".",由于 "." 的 ASCII 值为 46,而 "0" 的 ASCII 值为 48,所以 "." 比 "0" 大。

因此,根据字符串的比较规则,"00\9" 在 ASCII 值上小于 "1",但大于 "0.99"。

但是在查询相关资料时,发现

1686019209039.png

也就是说如下代码输出是相等的:

<?php
if ("\400" === "\000") {
echo "相等" . "<br>";
}
?>

1686019288140.png

这是因为在 PHP 中,八进制转义字符的范围是 \000 到 \377(即 0 到 255 的八进制表示)。由于八进制转义字符 "\400" 导致了溢出,此时与"\000" 相等了,

同理"\401" 和 \001是相等的。