phpMyAdmin SQL注入漏洞(CVE-2016-5703)分析

本文原发于腾讯安全应急响应中心(TSRC),查看原文

0x00 影响版本

  • Version 4.6.x(< 4.6.3)
  • Version 4.4.x(< 4.4.15.7)

0x01 漏洞描述

phpMyAdmin 是一个 web 端通用 MySQL 管理工具,上述版本在 central_columns.lib.php 文件里的 db 参数存在 SQL 注入漏洞,攻击者利用此漏洞可以获取数据库中敏感信息,甚至可以执行任意命令。

0x02 测试环境

Windows 7 (x64) + PHP 5.5.12 + Apache/2.4.9 + phpMyAdmin 4.6.2

0x03 漏洞详情

从官方的补丁 ef6c66dca1b0cb0a1a482477938cfc859d2baee3 来看,其对 libraries\central_columns.lib.php 中某几个 function 中的 $db 参数进行了转义,由此我们可以初步判定注入点就出现在这几个函数的 $db 参数处:

补丁对 $db 参数做了转义

我们全局搜索一下引入了 central_columns.lib.php 的文件:

全局搜索引入 central_columns.lib.php 的文件

总共四个文件包含了 central_columns.lib.php,其中三个文件为库函数文件,因此最直接与用户交互的文件还是 db_central_columns.php

我们来到 db_central_columns.php,搜索一下打补丁的几个函数:

  • PMA_deleteColumnsFromList 出现在大约 89 行
  • PMA_getColumnsList 出现在大约 135 行
  • PMA_getCentralColumnsCount 出现在大约 94 行
  • PMA_getCentralColumnsListRaw 出现在大约 49 行

我们应该尽量选择不需要满足过多 if 条件语句、以及位置尽量靠前的不危险函数分析,跟进 PMA_getCentralColumnsCount 函数:

跟进 PMA_getCentralColumnsCount

我们能在函数 91 行之前打印出任意字符串,而在 if 语句之后无法打印出字符串,我们看到函数 93~95 行出现了 if 语句判断,因此我们跟进 if 语句 if(empty($cfgCentralColumns)),其中 $cfgCentralColumns 是从 PMA_centralColumnsGetParams 获取到的,继续跟进 PMA_centralColumnsGetParams 函数 —— 该函数同样在 central_columns.lib.php 文件里,大约 17 行:

跟进 PMA_centralColumnsGetParams

我们在 25 行之后打印一下 $cfgRelation 变量:

打印 $cfgRelation 变量

根据接下来的 if 语句,我们需要使得 $cfgRelation['centralcolumnswork'] 不为 false,才能使程序完整执行下去,那么 $cfgRelation['centralcolumnswork'] 是个什么变量呢?

跟进函数 PMA_getRelationsParam(在 libraries\relation.lib.php 大约 61 行):

跟进 PMA_getRelationsParam

继续跟进函数 PMA_checkRelationsParam(在 libraries\relation.lib.php 大约 451 行):

跟进 PMA_checkRelationsParam

我们可以看到,我们需要的变量在这个 foreach 语句中被定义成了 false。我们继续向下跟进,从大约 563 行起,出现了如下语句:

563 行起的语句

根据官方文档 http://docs.phpmyadmin.net/zh_CN/latest/config.html,我们可以知道 PMA_checkRelationsParam 函数的作用就是检查用户是否自定义了配置文件,只有用户自定义了配置文件,我们需要的 $cfgRelation['centralcolumnswork'] 才能为 True。

那么,如何自定义配置文件呢?

我们知道,phpMyAdmin 在没有自定义配置文件时会默认加载 libraries\config.default.php 中的配置;要自定义配置文件,我们只需要在 phpMyAdmin 根目录将 config.sample.inc.php 文件 copy 为 config.inc.php,并将 41~44 / 47~68 行取消注释,43 以及 44 行改为 MySQL 用户(需要与攻击时 phpMyAdmin 的登录用户一致):

自定义配置文件 config.inc.php

然后创建一个名为 phpmyadmin 的数据库,选中该数据库然后点击导航栏”操作”,根据页面错误提示即可自动创建 phpMyAdmin 自身的数据库。

接下来回到 central_columns.lib.php 文件的 PMA_centralColumnsGetParams 函数中,我们在与之前同样的位置打印一下 $cfgCentralColumns 变量,我们发现页面已经能够 dump 出数据了,说明程序已经能够向下执行,$cfgRelation['centralcolumnswork'] 变量为 True:

打印 $cfgCentralColumns 变量

接下来我们到存在漏洞的函数 PMA_getCentralColumnsCount 中打印查询语句以及结果集:

打印查询语句与结果集

我们发现打印在页面上的 SQL 语句存在很典型的注入类型,如下图所示:

典型的注入类型

最后需要明确的一个问题,central_columns 是什么?

我们知道之前我们创建的数据库 phpmyadmin 存在一个数据表 pma_central_columns,而任意一个数据表的任何字段都可以添加进入 pma_central_columns,在创建新的表或者添加字段时就能从此表中直接选取插入,所以我们能看出 central_columns 是作为储存一些关键字段,以方便添加外键时使用。

0x04 漏洞修复

  1. 使用 Utils::sqlAddSlashes 函数对 libraries\central_columns.lib.php$db 参数转义;
  2. 或者升级 phpMyAdmin Version 4.6 至 4.6.3、Version 4.4 升级至 4.4.15.7 以修复此漏洞。

0x05 漏洞总结

phpMyAdmin 本身作为数据库管理工具,登录后的注入显得相当鸡肋,最近的无需登录漏洞也是出在 2.8.3 左右版本。而从出现漏洞的文件来看,同一个文件仅仅部分函数进行了转义防护,这也可以看出开发人员在修复漏洞时”指哪修哪”,而最近以色列安全研究人员 @e3amn2l 提交的近 20 个漏洞中也出现了相似的未转义引起的漏洞,更加印证了这一点。

因此我认为安全从业人员在接收到安全漏洞时,应该首先构思最优的安全修复指南,而不是直接交给开发人员进行修复,多一个流程也可尽量避免在同一个地方重复跌倒。

0x06 参考资料

2016 年 phpMyAdmin 漏洞统计

评论Comments