CVE-2018-12613 PhpMyadmin后台文件包含分析
2018年6月19日,phpmyadmin在最新版本修复了一个严重级别的漏洞.
描述:
一个攻击者可以在服务器上包含(查看和潜在执行)文件的漏洞被发现。
该漏洞来自一部分代码,其中页面在phpMyAdmin中被重定向和加载,以及对白名单页面进行不正确的测试。
攻击者必须经过身份验证,但在这些情况下除外:
- $ cfg ['AllowArbitraryServer'] = true:攻击者可以指定他/她已经控制的任何主机,并在phpMyAdmin上执行任意代码
- $ cfg ['ServerDefault'] = 0:这会绕过登录并在没有任何身份验证的情况下运行易受攻击的代码
受影响版本:
phpMyAdmin 4.8.0和4.8.1受到影响。
一. 漏洞分析
1 2 3 4 5 6 7 8 9 10 11 12 | //index.php //line 55-63 if (! empty($_REQUEST['target']) && is_string($_REQUEST['target']) && ! preg_match('/^index/', $_REQUEST['target']) && ! in_array($_REQUEST['target'], $target_blacklist) && Core::checkPageValidity($_REQUEST['target']) ) { include $_REQUEST['target']; exit; } |
if区间一共有五个判断:
是否存在target参数
target参数是否为字符串
值不能以index开头
值不能出现在$target_blacklist内
Core类的checkPageValidity方法判断
如果通过判断则包含参数所指定的文件。
前几个判断可以忽略,重要的是后面两个判断,先看第一个
1 2 3 4 5 6 | //index.php //line 50-52 $target_blacklist = array ( 'import.php', 'export.php' ); |
$target_blacklist中的数组为import.php 和 export.php,只要target的值不是这两个就可以
我们看下一个判断
首先找到Core类的checkPageValidity函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | //443-478 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; } $_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; } return false; } |
checkPageValidity函数里又是五个判断:
$whitelist为空则引用静态声明的$goto_whitelist
如果$page没有被定义过或者$page不为字符串则return false
$page存在$whitelist中的某个值则返回true
$_page存在$whitelist中的某个值则返回true
经过urldecode函数解码后的$_page存在$whitelist中的某个值则返回true
我们来逐行分析:
首先index.php调用checkPageValidity参数时并没有传第二个参数所以会进入此参数的第一个if区间,我们来看一下$goto_whilelist
1 2 3 4 5 6 7 8 9 10 11 | public static $goto_whitelist = array( 'db_datadict.php', 'db_sql.php', 'db_events.php', 'db_export.php', 'db_importdocsql.php', 'db_multi_table_query.php', 'db_structure.php', ...... 'user_password.php', ); |
$goto_whilelist定义了些可以被包含的文件名(省略了一部分)
第二个if直接跳过我们来看第三个if区间,如果$page如果等于$goto_whilelist的某个值则return真。
phpmyadmin的开发团队考虑的很全面,想到了会存在target的值后面再跟参数的情况,于是有了第三个判断:
1 2 3 4 5 6 7 8 | $_page = mb_substr( $page, 0, mb_strpos($page . '?', '?') ); if (in_array($_page, $whitelist)) { return true; } |
$_page为 以?分割然后取出前面的字符串再判断值是否存在与$goto_whilelist某个数组中。
这个判断的作用是,如果target值带有参数的情况下,phpmyadmin也能正确的包含文件。
也正是因为phpmyadmin团队考虑的太全面了,才会出现此漏洞......
1 2 3 4 5 6 7 8 9 10 11 | $_page = urldecode($page); $_page = mb_substr( $_page, 0, mb_strpos($_page . '?', '?') ); if (in_array($_page, $whitelist)) { return true; } |
后面又将$page参数用urlencode解码再进行以?分割取出前面的值做判断。
那么传入target=db_sql.php%253f/../../test.txt
txt内容为<?php phpinfo();?>
//%253f是?号的二此url编码
urlcode将$page解码后是db_sql.php?/../../test.php 再以?分割取出来前面的字符串为index.php,$whitelist中有index.php所以会进入最后一个if区间return true
1 2 3 4 5 6 7 8 9 10 11 | //我们回到最初的起点 if (! empty($_REQUEST['target']) && is_string($_REQUEST['target']) && ! preg_match('/^index/', $_REQUEST['target']) && ! in_array($_REQUEST['target'], $target_blacklist) && Core::checkPageValidity($_REQUEST['target']) ) { include $_REQUEST['target']; exit; } |
前面5个if都符合后会包含$_REQUEST['target'],target值会被解析成db_sql.php%3f/../../test.txt,因为php会前面db_sql.php%3f当成目录,所以要多加一个../来跨出目录
目前有三种getshell的方法,第一个是上传sql文件,然后包含mysql的sql文件,第二个是开启general_log来完成getshell
不过这两种思路都有些繁琐,最简单的思路是p牛在知识星球中发出的(安利一波p牛的小蜜圈,真的能学到很多骚操作)
下面复现下第三种思路:
首先在sql中select ‘要执行的代码’
然后包含phpsession文件:
要包含session的文件名可以在cookie中的phpmyadmin参数找到。
文章来源:https://blog.csdn.net/qq_33020901/article/details/80829269 (他似乎也是转载的)
布施恩德可便相知重
微信扫一扫打赏
支付宝扫一扫打赏