[程式碼審計基礎 15]phpmcs_v9.6 rce

upstream_yu發表於2023-02-23

PHP:5.4.5

設定除錯:https://blog.csdn.net/m0_46641521/article/details/120107786

版本:phpcms_v9.6.0_UTF8

0x01:路由分析

前一篇一樣的路由,但是對輸入的關鍵字都有了防護;

0x02:漏洞分析

01 慢慢除錯

目前是代審的基礎,就沒有太注重邏輯,就直接給了漏洞利用點在哪;

是在phpcms/modules/member/index.php的register模組,也就是上一篇用來觸發連線那裡;

PHPstorm開啟除錯,這裡點選提交註冊,burp抓包一下;

image-20230222202712585

image-20230222203215049

然後在偵錯程式能夠看到除錯資訊:

image-20230222202857980

然後向後慢慢走:

image-20230222203404443

這裡是配置資訊,不用管;

主要是下面這個isset($_POST['dosubmit']地方;

顯然是進行了提交的,所以這裡能夠進入:

image-20230222203650556

這個驗證碼是沒得的,在註冊的時候也沒看見驗證碼;

然後注意這個$userinfo['modelid'] = isset($_POST['modelid']) ? intval($_POST['modelid']) : 10;;現在先不管這個是什麼,知道這個是可以透過我們控制的就好;

然後下面能夠看見一個ip(),跟進看看:

image-20230222203907345

ip()最後進行了一個正則匹配,只有數字匹配上了才能夠返回一個ip,否則就是空;

然後回到原來的register:一直走,直到走到這裡:

image-20230222205520756

然後跟進看看:

image-20230222205803808

一般來說,model是和資料庫有關的;

在這裡:

db是連線的資料庫物件;
$this->db_pre是資料庫的字首,字首是:v9_
要查的表是v9_model_field這個表;

為什麼是檢視v9_model_field這個表呢?跟進load_modle除錯一下:這裡指定了路徑

image-20230222210852760

再跟進,就是返回的這個:

image-20230222210644975

開啟資料庫,看看資料庫v9_model_field表中有什麼:

image-20230222210104847

由於是才重灌CMS的,沒有對這個表有什麼修改,所以這裡是什麼樣,原始資料就是什麼樣子;

接著除錯往下走:

image-20230222211318880

這裡給member_input物件加了一個attachement屬性,先不管是什麼;

接著F8往下走:

image-20230222211558440

array_map('new_html_special_chars',$_POST['info']);
# 讓$_POST['info']執行new_html_special_chars()函式

image-20230222211748962

大概是想起一個編碼的作用,不用管;

然後注意到箭頭指向的地方,是取值$_POST['info'];,也就是說,這也是可控的;

接下來F7步入:

image-20230222212334440

又走到了member_input這個地方;

02 整理輸入-1

現在已知的是:

$_POST['info']可控,並且在member_input->get()會將其呼叫

所以現在重點關注get()能夠做什麼,這裡是預先知道有洞的,不是現審的;這是還在學基礎;

現在就要看,輸入的可控的東西經歷了哪些東西;

F7步入trim_script($data)函式

image-20230222213546093

轉義js程式碼的,用來防禦XSS;替換了<>javascript

回到原先的地方再F8;

image-20230222214217449

之後就是對此做操作;

F8走幾步:

image-20230222214451397

已知:
$modelid 是可控的;

$data已經是可控的了:
	foreach之後,field和value就是可控的了
	$field = birthday
	$value = 2023-02-03

safe_replace():
	進行了過濾,例如:%20,%2527,%27,',",*,'',<,>,{,}等字元

$func = $this->fields[$field]['formtype'];
	這裡的$this->fields是不可控的,它是在建構函式中已經定義了;
	但是$field是可控的;

於是$func被從$this->fields[$field]['formtype'];中取出來的值賦值為datetime

然後再檢測這個類中有沒有datetime這個方法,有就執行;並且執行的引數也是可控的;

這裡能執行的方法只有這個類中的方法:

image-20230222215415233

但是同樣要求這個方法存在於$this->fields中;

因為$func同樣是從$this->fields中取出來的;

所以需要知道$this->fields是怎麼來的;

然後重新除錯,為了知道$this->fields是怎麼來的:

image-20230222220251308

然後步入:

image-20230222220049233

資料是存在資料庫的

快取從資料庫中取出來,存在記憶體,存在redis中;

這個地方是快取資料之類的,看的意義不大,由於資料都是存在資料庫中,所以進入資料庫中檢視modelid=10的;

image-20230222220723531

所以會把這個birthday取出來,然後這裡又有formtype=datetime

由於modelid也是可控的,所以可以透過控制modelid來控制fields的資料;假如將modelid改成3,那麼會將modelid=3的所有取出來;

這裡重新除錯一下,將modelid修改成3:

image-20230222221406576

可以看到,相較於前兩幅圖中的modelid=10,fields[1]這裡的fields[23]多了很多東西;

隨後可以透過$_POST['info']來控制選擇什麼;

不過實際上,也需要看$this中的方法有哪些;所以目標就縮小到了原來那幾個函式中,即:

image-20230222215415233

將函式都看一下之後,定位到editor函式中;

1 $this->textarea()

作用:剝離HTML標籤

2 box

作用:裁剪元素組成字串

3 images

作用:傳圖片,返回字串

剩下的就沒意思了

4 editor

注意到了$this->attachment->download,然後檢視download函式:

image-20230222222804608

editor是一個附件下載的函式;

03 整理輸入-2

所以考慮能不能向伺服器中下載(寫入)PHP檔案;

所以現在修改modelid等引數,發包

image-20230222224345128

讓其進入download函式:

image-20230222224838284

new_stripslashes函式是一個去掉反斜線的函式;

然後這裡是一個正則,如果匹配不上,就沒了;顯然目前是匹配不上的;

然後進一個網站匹配匹配:https://regex101.com/

image-20230222225559504

匹配正則之後,透過一個foreach然後在裡面的fillurl拼接出一個url,應該叫透過fillurl判斷傳入的引數是一個什麼協議,然後根據什麼協議返回什麼連結;

最後將返回的url填充到$remotefileurls陣列中,並透過array_unique函式去重;

然後接著跟:

image-20230223091812841

看到之類有一個getname函式,跟進去看看或者點進去都行:

image-20230223091452227

這裡對名字進行了一個拼接,返回了日期隨機數.字尾樣式的檔名;

在171行有$upload_func = $this->upload_func;,這裡將$upload_func賦值為了copy();因為原來的定義也是這樣

image-20230223092716346

現在找找copy()函式作用:

https://www.php.net/manual/zh/function.copy

image-20230223092627555

並且它支援url連結;

同時,可以在除錯資訊中看到filenewfile兩個路徑;

copy函式一執行就會被上傳上去,所以現在去看看上傳的檔案:

但是會傳入http://www.baidu.com/1.png失敗了,原因是

image-20230223093305778

既然是not found,那麼考慮一下found的;

嘗試一下其他的:http://www.taobao.com/1.png

image-20230223093508777

然後上傳了過來:

image-20230223093550270

看看請求的網頁:

image-20230223104332571

所以,只要不是not found就行,哪怕是頁面不存在

檔案上傳成功了,接著再跟一跟後續函式:

在上傳檔案成功的if判斷操作中,有一個add函式,進入add函式檢視資訊:

image-20230223093901736

發現這裡是將檔案資訊傳入資料庫的一個操作,先記下來;

隨後F8走幾步,就完結了;

所以最後得到結論:

  1. 修改modelid和info[content]可以指定執行editor()函式
  2. editor()中的download(),跟進download()發現使用了copy賦值檔案
  3. 由於copy()支援從url中下載檔案,且url可控,但是需要滿足正則匹配,在滿足的情況下,能夠下載任意滿足正則匹配的檔案
  4. 最後,新檔名是隨機的,檔案資訊會被存入資料庫

0x03 輸入流轉

01 上傳PHP檔案

目前是能夠上傳一個檔案了,於是考慮上傳一個php檔案

現在整理一遍輸入:

info[content] = url
url可控,並且會解析且過正則
	正則:(href|src)=([\"|']?)([^ \"'>]+\.(gif|jpg|jpeg|bmp|png))\2
	正則保證了字尾是圖片型別
伺服器對傳入的url進行請求

希望伺服器下載一個php字尾的檔案

但是注意到這個正則,它相當於只進行了字尾的識別。

那麼考慮能不能在透過正則之後,透過處理,將字尾去掉,保留前面的一部分;

所以現在就比較關注傳入的url在哪裡進行的拼接;

editor中直接呼叫了download並且傳入了content,但是並沒有進行什麼處理,於是跟進download

download()前部分都是進行的賦值和正則(只檢測了字尾,所以這個也能過:<a href=http://www.taobao.com/1.php/1.png>),唯一的操作就是去掉反斜線;

然後注意到到了fillurl()函式;

跟進除錯一下,或者直接看也行:

$surl是傳入的地址,ctrl f一下,發現,就截圖部分進行了裁剪和擷取,其它的都是整段拼接,所以看截圖部分;

image-20230223103409698

然後看到這裡:

$pos = strpos($surl,'#');
if($pos>0) $surl = substr($surl,0,$pos);
# 返回#第一次出現的位置,並且將$surl擷取到#出現之前
# 所以考慮<a href=http://url#1.png>

所以試試:http://www.taobao.com/1.php#1.png

顯然是滿足png的字尾,然後這裡進入這個拼接就行,不需要執行後面的copy;現在的目的是為了拼出來php字尾,拼出來了之後在指定一下伺服器,自然是可以的;

image-20230223104714868

然後這裡拼接出來了php字尾;

現在請求一下其他地方的檔案,就本地的吧,都一樣了;

image-20230223105657091

能夠看到這裡是能夠請求的;

現在在這裡寫一個<?php phpinfo();?>1.php中,在請求一下;

image-20230223110018030

現在有返回了,能拉進去;

現在就只需要解決最後的問題了,就是不知道這個檔案路徑的;

02 路徑報錯

之前有提到一件事,就是說是已知漏洞的;

index.php後有一個資料庫插入資訊的操作,這裡的資訊插入是在檔案上傳之後插入的,並且插入資訊,是插入的使用者模型的資訊;

image-20230223114108777

由於已經改info[birthday]成了info[content],所以這裡跟進:

burp中發包,需要將usernameemail改成資料庫中沒有的,不然$status過不了判斷:

image-20230223115317759

執行的SQL語句成為了

INSERT INTO `phpcmsv9`.`v9_member_detail`(`content`,`userid`) VALUES ('&lt;a href=http://127.0.0.1:81/uploadfile/2023/0223/20230223114555862.php&gt;','2')

但是顯然member模型是沒有content欄位的,所以之類會報錯;

於是burp中就能夠看到報錯的資料:

image-20230223115002893

最後獲取到了檔名;

因為這裡是先進行了檔案的上傳,再進行的資料庫插入操作,所以能夠訪問對應的檔案;

image-20230223115121870

最後訪問對應檔案;發現檔案能夠上傳;

所以可以上傳其它的馬,這裡只是上傳了phpinfo,沒做其它的事情;

0x04 總結

註冊模組,改modelid,進下載

最後還是試了很多次,那時候不知道usernaememail會影響$status

image-20230223120137542

任重道遠

相關文章