题目直接就给了源码
<?php
include 'config.php'; // FLAG is defined in config.php
if (preg_match('/config\.php\/*$/i', $_SERVER['PHP_SELF'])) {
//$_SERVER['PHP_SELF']返回的是当前正在执行的脚本的名字'PHP_SELF'当前执行脚本的文件名,与 document root 有关。例如,在地址为 http://example.com/foo/bar.php 的脚本中使用 $_SERVER['PHP_SELF'] 将得到 /foo/bar.php。__FILE__ 常量包含当前(例如包含)文件的完整路径和文件名。 从 PHP 4.3.0 版本开始,如果 PHP 以命令行模式运行,这个变量将包含脚本名。之前的版本该变量不可用。如果想要获得完整的url,要使用$_SERVER['REQUEST_URL']
exit("I don't know what you are thinking, but I won't let you read it :)");
}
//如果正则匹配到了url最后是config.php那么就不让访问
if (isset($_GET['source'])) {
highlight_file(basename($_SERVER['PHP_SELF']));
exit();
}
//这里加上了basename() 可能是为了跨目录读文件
$secret = bin2hex(random_bytes(64));
//string random_bytes( int $length)生成适合于加密使用的任意长度的加密随机字节字符串
// 一般配合bin2hex()函数使用
// bin2hex()把ASCII字符串转换为十六进制值
if (isset($_POST['guess'])) {
$guess = (string) $_POST['guess'];
if (hash_equals($secret, $guess)) {
//hash_equals 判断 字符串值是否相等,等效于使用===,可防止时序攻击,即不管一不一样花费的时候都是一样的
$message = 'Congratulations! The flag is: ' . FLAG;
} else {
$message = 'Wrong.';
}
//这里有一个随机数guess,如果能把随机数猜出来,就可以直接输出flag
}
?>
随机数那边破解不出来
但是在上面找到了了突破口basename() 函数
basename
则可以返回路径中的文件名部分
如果传入/index.php/config.php/
,则$_SERVER['PHP_SELF']
返回/index.php/config.php/
,basename($_SERVER['PHP_SELF'])
返回config.php
即/index.php/config.php/
运行的是index.php
,但是basename()
获取到的是config.php
正常我们可以/index.php/config.php?source
读取,但是因为存在正则/config\.php\/*$/i
来限制URL结尾出现config.php
,返回空
%0d之类的来污染绕过
然后正则表达式找的url结尾找不到config.php,通过basename函数读取到的也是config.php里面的内容