> For the complete documentation index, see [llms.txt](https://gitbook-88.gitbook.io/ctf-writeup/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://gitbook-88.gitbook.io/ctf-writeup/2020/2020-zer0pts/can-you-guess-it.md).

# Can you guess it?

猜字符串游戏，了解一下几个函数的机制：

> `hash_equals ( string $known_string , string $user_string ) : bool`
>
> 比较两个字符串，无论它们是否相等，本函数的时间消耗是恒定的。
>
> 本函数可以用在需要防止时序攻击的字符串比较场景中， 例如，可以用在比较 crypt() 密码哈希值的场景。

> `random_bytes(int $length)`
>
> 生成适合于加密使用的任意长度的加密随机字节字符串，例如在生成salt、密钥或初始化向量时，一般配合bin2hex()函数使用。

> `bin2hex()`
>
> 把ASCII字符串转换为十六进制值

我们可以看一下hash\_equals()内部实现机制

```
<?php
if(!function_exists('hash_equals')) {
    function hash_equals($a, $b) {
        if(!is_string($a) || !is_string($b)) {
            return false;
        }

        $len = strlen($a);
        if($len !== strlen($b)) {
            return false;
        }

        $status = 0;
        for($i = 0; $i<$len; $i++) {
            $status |= ord($a[$i]) ^ ord($b[$i]);
        }

        return $status  === 0;
    }
}
```

基本上可以说整个流程是很安全的，所以突破口又回到了前面的文件包含。

```
<?php
include 'config.php'; // FLAG is defined in config.php

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 :)");
}

if (isset($_GET['source'])) {
    highlight_file(basename($_SERVER['PHP_SELF']));
    exit();
}
```

记录一下三个$\_SERVER的区别：

> 网址：<https://www.shawroot.cc/php/index.php/test/foo?username=root>
>
> $\_SERVER\[‘PHP\_SELF’] 得到：/php/index.php/test/foo\
> $\_SERVER\[‘SCRIPT\_NAME’] 得到：/php/index.php\
> $\_SERVER\[‘REQUEST\_URI’] 得到：/php/index.php/test/foo?username=root

漏洞点：`$_SERVER['PHP_SELF']`提交index.php/config.php时，经过basename过滤后只剩下config.php，需要绕过的只有正则，basename只能转换ASCII码内的字符，通过超过ASCII码范围的字符进行绕过。

```
/index.php/config.php/%dd?source
```
