PHP File Access in Windows

2 minute read

起源

這篇文章是打了 MMA CTF 2nd 2016 後,詢問學長產出的一篇心得文。

這場 CTF 為期 48 小時,題目也是眾多(而且主辦方是日本,一堆 ruby source code),不過第二天我什麼題目都解不出來,頗令人挫折,看來這條路沒這麼好走啊XD

唉呀呀離題了,這篇文章會探討 PHP 在 Windows 下存取檔案的一些奇怪行為,讓你分不出 Windows 的 bug 跟 feature。

首先來看一下 MMA CTF 2nd 2016 的這一題

Rotten Uploader - 150

Find the secret file.

http://rup.chal.ctf.westerns.tokyo/

Hint1 (2016/09/04 16:31)

  - The files/directories on the DOCUMENT_ROOT are below four.

      - download.php
      - file_list.php
      - index.php
      - uploads(directory)
  - The number of files in the DOCUMENT_ROOT/uploads is 5. The directory have "index.html".
  - You don't need scan tools.

首先進入頁面可以看到很明顯的 LFI (Local file inclusion) 漏洞:

http://rup.chal.ctf.westerns.tokyo/download.php?f=../index.php
http://rup.chal.ctf.westerns.tokyo/download.php?f=../download.php

但是要拿 file_list.php 這個檔案卻失敗,仔細看了一下 download.php ,原來被加了防護:

<?php
  header("Content-Type: application/octet-stream");
  if(stripos($_GET['f'],  'file_list') !== FALSE) die();
    readfile('uploads/' . $_GET['f']); // safe_dir is enabled. 
?>

直覺告訴我,打開 file_list ,flag 就不遠矣!

然後我就卡在這裡,直到比賽結束……

Solution 1: WinAPI feature

主要參考自 onsec whitepaper 02,假設你要讀取 1.php 這個檔案,使用 phpfile_get_content($url)$url 等於下列任何一個值都會成功讀取:

1.php
1.phP
1.ph>
1.ph<

前面兩個是因為檔案系統不分大小寫的關係,後面兩個就非常詭異了,可以上網找 onsec whitepaper 02 自己看一下,這裡引用第五頁的話:

character > gets replaced with ?, character < transforms to *

當然這個 ?就是任意單一字元,*是任意長度字元,跟 bash 的 wildcard 字元相同。

雖然它用了不分大小寫的檢查 stripos ,讓我們無法用換成大寫的方法繞過,但可以用 wildcard 躲過他的判斷,payload 如下:

# 它會被取代成 ?
http://rup.chal.ctf.westerns.tokyo/download.php?f=../file_lis>.php
# 這樣也可,它會被取代成 *
http://rup.chal.ctf.westerns.tokyo/download.php?f=../file<.php

Reference: Fluxion’ write-up

Solution2: 8.3 Filename

8.3 filename 是早期 DOS 檔案名稱的習慣,8 的意思是在 . 前面有八個字元,.後面的副檔名為三個字元。

重點是,為了向前兼容,現在的 Windows 系統仍然會支援這種格式,至於他是怎麼解讀呢?這就是可以下手的點了,參考 wiki 的這一節

Example: TextFile.Mine.txt becomes TEXTFI~1.TXT (or TEXTFI~2.TXT, should TEXTFI~1.TXT already exist). ver +1.2.text becomes VER_12~1.TEX. .bashrc.swp becomes BASHRC~1.SWP

所以file_list.php 會變成 file_l~1.php,那麼 Payload 就是 download.php?f=../file_l~1.php

Reference: Tomislav Zubcic’s blog

我感覺 Windows 的 8.3 filename 肯定會造成很多漏洞……

後記

一般遇到這種很明顯要繞過某個判斷式的題目,首先可以嘗試繞過函數,例如型態判別寫的不對,可以送 array 或是 boolean 讓它判斷出錯;再來就是研究函數漏洞,有些函數解析會有問題,例如 AIS3 2016 pre-exam web3;沒招了就往檔案系統下手,Windows 果然很多洞(bug)….阿不,是特色(feature)!

註:文章開頭問的學長是 217 的 Shik 大大喔~