iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 6
2
Security

CTF 的三十道陰影系列 第 6

Day6: [Web] Path Traversal

Path Traversal (CWE-22)

根據 CWE-22 的定義:

The software uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the software does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.

Path traveral 主要出現在需要透過 路徑 來存取檔案的功能中,最明顯的 payload 就是出現大量的 ../,透過相對路徑去讀取檔案 (CWE-23),但偶爾業會有直接透過絕對路徑存取的例子 (CWE-36)

但不只是 web 服務,其他檔案分享服務,像是:FTP、SMB 等 service 也經常被發現存在 path traversal 的問題,今天特別放在 web 的分類是因為 path traversal 可以說是被早期 web server 的機制給發揚光大 (?) 了

Web 是基於 HyperText Transfer Protocol (HTTP) 所發展的服務,在最早還沒有動態網頁的時代,網頁要呈現的內容是會先寫在一個靜態的 .html 檔,由 web server 接收到 HTTP request 之後,parse uri 之後得知要存取哪一個頁面,就把該頁面的 .html 的內容讀取到 web server 內,最後包裝成 HTTP response 回傳給使用者

  • 一直到今天這種模式還是有被使用,近年來又流行透過 pelican 或 hexo 等 framework 將 markdown 之類的筆記轉化成 html 頁面後,搭配免費的網頁空間製作個人網站
  • 舉例來說:https://ddaa.tw 就是用 pelican 生成靜態網頁後,放到 github page 上而成

這種 file based 的網頁開發模式在處理靜態網頁一般來說不會出現 path traversal 的問題,原因有兩點:

  • web developer 在設定檔的規定好 root directory 之後,從 url 轉化為 resource 的實體路徑就交給 web server 負責
  • 靜態網頁基本上整個網頁都是允許被使用者存取,不像動態網頁要根據是否登入之類的來呈現不同的網頁內容

靜態網頁的功能滿足不了逐漸成長的 Internet,因此後來出現了根據用戶狀態來呈現不同內容的動態網頁,但早期的動態網頁,依然是基於 file based 的機制來設計,因此經常會出現這樣的設計:

  • menu 會存在像是:http://example.com/show.php?page=peoplehttp://example.com/show.php?page=product 的 url
  • 同目錄底下存在 people.html, product.html 的靜態頁面
  • show.php 只要透過參數 page 就可以去存取不同的網頁內容

但如果 show.php 沒有去檢查檢查 resource 的路徑, 直接透過 file_get_content() 之類的功能讀取檔案內容並呈現給使用者,就會發生 path traversal 的問題了

  • 因 path traversal 導致可以讓 show.php 載入任意頁面的問題,又稱為 Local File Inclusion (LFI)

雖然現今的 web 開發主流已經逐漸變成 route based 的 design pattern,已經比較少直接將 uri 對應實體的檔案路徑,但只要是有需要自行處理存取檔案的功能都要小心是不是會發生 path traversal 的問題

0x05: Codegate 2015 CTF quals – Web 200 Owlur

由於單純 Path Traversal 實在太簡單了 = =,想不到什麼比較經典的 web 題目,因此就拿 LFI 的題目充數......

這題類似上面舉的例子,典型的 php + path traversal (LFI) 的問題,網站上可以透過 index.php?page=$action 開啟另外兩個頁面:viewupload

由於 php 的網頁會被 php-fpm 之類的程序執行之後才得到結果,因此沒辦法直接取得 php 的原始碼,但在大多數的情況,基於 php 的 LFI 都可以透過 php 特有的 wrapper 來讀取任意檔案,因此我們也可以用以下的 payload 取得 index.php 和其他兩個頁面的 source

  • http://website/index.php?page=php://filter/convert.base64-encode/resource=index
    • 將頁面內容 base encode 之後再呈現出來,這樣就不會被當成 php code 執行
  • 取得 source 之後可以得知 LFI 是寫法為 include(null_filter($var).".php");,因為後面會補上 .php,因此我們的 payload 才不用寫完整的檔案名稱

取得 source 之後也會得知在 LFI 之前 index.php 有對 page 的內容進行過濾,因此沒辦法直接透過 ../ 跳脫出網頁目錄,也沒辦法根據 http 或 ftp 等外部協定進行 RFI (Remote File Includion)

在 index.php 能做的事情受限了,但別忘了我們還可以透過 upload.php 上傳檔案,從 source 我們可以知道上傳只限制了檔案大小,不限制檔案類型,但最後都會被 rename 成 $random_str.jpg,由於 LFI 的部分會補上 .php 的後綴,這表示我們沒辦法直接把上傳檔案的內容用 LFI 執行,否則就可以直接達成 RCE 了

但 php wrapper 能做的事情遠不只讀 source code,還可以透過 phar://zip:// 之類的協定對檔案進行解壓縮之後,執行裡面的 php 指令

因此我們可以把我們想執行的 php code 包裝成 phar 透過 upload.php 上傳,最後透過以下 payload 來達成 RCE:


上一篇
Day5: [Reverse] 淺談 reverse engineering
下一篇
Day7: [Crypto] Encode? Encrypt? Hash?
系列文
CTF 的三十道陰影31

尚未有邦友留言

立即登入留言