目錄

前言

通常只要網頁需要跟使用者進行互動,都會提供檔案上傳的功能,但這也會出現問題,我們可以利用檔案上傳漏洞來存取伺服器系統或者執行惡意code,通常檔案上傳漏洞可以被分成三個種類

第一種,利用這個漏洞我們可以上傳檔案,並且用網頁應用服務來執行該檔案,舉例來說,如果我們可以上傳一個php腳本進網頁伺服器而該網頁伺服器可以執行php的內容,那我們便可以透過瀏覽器或curl來存取並執行這個腳本

在檔案引用漏洞的文章中,我們也提及了這類型的漏洞可以執行除了php之外的框架或伺服器程式語言

再來第二種,我們必須組合檔案上傳機制跟其他漏洞才有機會攻擊成功,例如搭配目錄遍歷手法,像是如果目標網頁應用服務存在目錄遍歷漏洞時,我們可以找到檔案上傳請求的相對位置,嘗試覆寫”authorized_keys”這類系統層級的檔案

更甚者,我們可以組合檔案上傳機制搭配XML外部元件(XML External Entity, XXE)或者跨網頁腳本(Cross Site Scripting, XSS)攻擊,舉例來說,當目標允許上傳一組SVG格式檔案的頭貼到帳號時,我們就可以嵌入一組XXE攻擊來顯示檔案系統裡的內容,或甚至執行任意的惡意code

而最後第三種,仰賴於使用者的互動,舉例來說,當我們在找工作時,投遞履歷的網頁系統都會有上傳檔案的表單,這時就可以嘗試上傳一份惡意的履歷,這份履歷可以是由.docx檔案寫成,但裡面包含著惡意的巨集

但由於這個類型需要受害者存取我們上傳的檔案,而後續還需要遠端操控,其複雜度較高,所以在檔案上傳漏洞中,前兩個漏洞討論的熱度比較高

利用可執行檔案

這個方法取決於網頁應用服務的架構,如果目標有使用內容管理系統(Content Management System, CMS),意思是後端有架設資料庫,這種情況時代表我們可以上傳自己的頭貼,或者建立部落格文章以及有包含下載檔案的頁面

如果我們的目標是公司網頁,通常就會發現存在可以上傳履歷的頁面,或者需要私人諮詢時的聯絡資訊表單,舉例來說,如果我們的目標是一家律師事務所的網站,就可能出現一個上傳案件的頁面

有時候,上傳檔案的機制可能不會很明顯,所以我們事前在頁面枚舉搜集資訊時不能跳過,否則有可能忽略了一個攻擊面向

在實驗中,我們要假裝誤用了檔案上傳機制,來執行惡意code以及獲得逆向shell,我們用”Mountain Desserts”網頁應用服務來呈現,找到這台機器裡頁面有上傳的地方

該實驗機器是由XAMPP建立起來的,並且是在Windows系統環境之下,我們先來建立一個文字檔,看看上傳文字檔案而不是圖片檔時會發生什麼事

而我們嘗試上傳這個測試用的檔案到應用服務的表單裡

上圖顯示我們成功上傳的回應,代表這個這個系統的上傳機制並沒有限制只能某些圖片檔案格式,接著,我們可以嘗試上傳simple-backdoor.php網頁shell

真意外!文字檔ok但是封鎖掉我們上傳的php檔案了,代表目標的網頁應用服務應該是把附檔名是php的都列入黑名單,由於我們並不知道實際過濾器所有的規則,這種時候我們就只能夠在錯誤中嘗試了

把我們手邊所有的工具都拿來嘗試找出一個方法來繞過,而在實驗過程中,我們發現一組方法可以繞過,就是把原先常見的php附檔名格式改成更少見的型態,例如”.phps”或者”.php7”

這個方法可以繞過簡易的過濾器規則,如果過濾器只檢查檔案格式是”.php”或”.phtml”的話就可以成功,而”.phps”或者”.php7”替代格式雖然是用在舊版的php框架裡,或者某些特定使用情形的環境下,但近代的PHP架構還是支援這些格式

另一種比較直觀的想法是,直接把附檔名的字元變更成大寫,如果目標網站的後端工程師非常懶的話,他們有可能就只是比對字串來做成黑名單,並且預設使用者只會上傳小寫的”.php”格式檔案

如果真有這種事,我們就可以更新一下檔案格式變成大寫來繞過,在我們的環境下實驗第二種方法,更新simple-backdoor.php附檔名,從”.php”弄成”.pHP”,再重新上傳一次

如此小小的改動卻成功繞過了,在滲透測試時,有時候天馬行空的想法不要馬上排除,有可能成功的路徑就藏在這些意想不到之中,畢竟打CTF時也常常在通靈嘛

而成功繞過並且上傳後,我們就可以利用RFI的方法來引用並執行code裡的內容,在腳本裡我們要它顯示上傳到的地方,其輸出的結果表示它被放到一個叫做”uploads”的目錄底下

如此我們可以確定的確有一個叫做”uploads”的檔案目錄存在,接著我們用curl存取網站,呼叫我們上傳的腳本,在cmd的參數底下使用”dir”索引出全部的檔案

上述顯示我們的dir指定輸出結果,代表我們可以在目標系統內執行任意的指令

儘管這種繞過的方法很基礎,但通常都很有效,而我們也可以來啟動上傳的逆向shell,一樣把Netcat監聽打開,我們實驗監聽port 4444接收目標網頁系統回傳的資訊

前面提到目標系統環境是Windows,所以我們可以嘗試單行式PowerShell(PowerShell one-liner)來執行逆向shell,由於這種型態的逆向shell會包含數個特殊字元在裡頭,我們就必須將這些字串編碼成base64的格式

通常可以直接用PowerShell或者線上的轉換器[1]來編碼,而我們嘗試使用Kali裡的PowerShell來編碼我們的單行逆向shell

首先,我們建一個變數$Text,這個變數用來儲存單行逆向shell為一組字串,接著我們用convert這個方法搭配Unicode的特性,在Encoding這個class裡頭把$Text變數的內容給編碼起來

在上述的單行逆向shell中我們最後讓編碼成base64格式的資料儲存進$EncodedText這個變數裡,而我們就能夠用curl來呼叫simple-backdoor.pHP來執行這段code

在PowerShell裡,我們可以使用”-enc”這個參數來額外新增base64編碼的字串進去指令中,同時搭配URL編碼把一些空格處理掉

送出我們的逆向shell後,可以在我們剛才監聽的頁面裡收到回傳的資訊

上面的結果就是回傳的資訊,看來是成功的,太讚了!

以上就是我們可以誤用PHP頁面裡的檔案上傳機制,透過我們的Kali來執行上傳上去的網頁shell,但如果目標網頁伺服器後端使用的是ASP的話,我們一樣可以用上面的流程來執行code,而不用另外寫一個ASP的網頁shell

幸運的是,Kali Linux裡面已經包含許多種網頁shell應付各式各樣的框架及語言了,如我們之前提到的都儲存在”/usr/share/webshells/”這個目錄底下

上述就是該目錄底下已經存在的語言或框架,有興趣的讀者可以去看看,由於通常我們要接觸目標時才會知道該伺服器使用的語言,而不一定每次都可以同一套打天下,所以了解各式各樣的技術對於讀者來說是必要的功課

尤其當您遇到更新的架構時,需要在網路上找是否有人寫新的shell,或者要製造自己的工具時,詳細理解背後的實作原理才能夠在當下測試時做出反應

雖說目前的框架都很類似,但我們也會有需要識別不同種類或後端語言的情況,才有辦法找出上傳我們的網頁shell,以及將shell放在目可以存取到的目錄位置,如此我們才能在系統裡執行指令

另外要注意的是,有時目標網頁應用服務的後端會建立黑名單來過濾上傳的資料格式,而此時我們必須找出可以繞過的方法,又或者我們可以走另一條路

有些網頁應用服務在我們上傳檔案後,其實還有重新命名檔案名字或變更檔案的功能,我們可以利用這點,在上傳完一組看似沒問題的檔案後,例如.txt格式檔案,再把檔名改回原本我們想要的副檔名格式

利用非執行檔案

上一節我們認知到如果網頁伺服器的檔案上傳有嚴重的缺陷,就能夠讓攻擊者執行他們想要做的事情,而帶來嚴重的後果,甚至,即便上傳的檔案不能夠執行,也有辦法造成破壞

有時我們就是會遇到上傳機制沒有限制任何檔案格式,但還是無法利用的情形發生,例如在Google雲端我們可以上傳任何型態的檔案,但沒辦法利用檔案取得存取系統的效果

在這種情況下,我們必須依賴其他種的漏洞,像是目錄遍歷來誤用檔案上傳功能,我們一樣在”Mountain Desserts”來實驗

我們一樣建置一個可以上傳的網頁應用服務,而目標系統我們建立在Linux系統上,這次我們沒有Admin連結或者index.php在URL裡,首先遇到這種情況時應該用curl來確認admin.php跟index.php檔案是否還存在

我們檢查時發現這幾個頁面檔案都不在目標伺服器裡,所以我們可以認為,這個網頁伺服器不是用PHP來建構的,我們一樣上傳文字檔案,不過我們換成在Burp Suite上送出請求

成功上傳後網頁一樣顯示出資訊,通常我們在測試檔案上傳表單時,我們會需要上傳個兩次以上,來看看每次給的結果如何,如果伺服器回應說檔案已存在,我們就有辦法透過暴力破解的方法得到伺服器裡的資訊

而如果伺服器回應給我們的是錯誤資訊,就有辦法從不同檔案的錯誤資訊中拼湊出有價值的情報,例如後端伺服器使用的程式語言或架構等等

在Burp Suite裡我們用POST請求送出,通常HTML的上傳機制是吃這個型態,在歷史記錄中我們一樣送到Repeater裡運作

上圖我們接收到跟網頁一樣的資訊,但沒有任何新的或有價值的資訊,接著我們可以來確認網頁伺服器允不允許我們使用相對路徑,利用目錄遍歷指定網頁根目錄之外的地方上傳我們的檔案

利用”filename”這個參數來指定成”../../../../../../../test.txt”檔案上傳,再送出一次來測試看看回應

回應給我們的是”../”相對路徑字串都有成功吃進去,但不幸的是,我們不知道檔案上傳的確切位置,有可能網頁應用服務只是回應了我們的檔名,但其實內部伺服器已經把相對路徑字串給清洗掉了

但目前我們也沒有其他種攻擊路徑可以考慮,就只能先假設我們設置的相對路徑有成功被使用進去了,如果我們真的猜對了,就可以嘗試盲覆寫這過檔案了,之後就可以讓我們存取系統

要特別注意的是,如果讀者在現實中進行滲透測試,盲覆寫有可能造成檔案的損毀,或者目標系統重大斷線損失,所以我們需要先了解目標網頁伺服器的帳號以及權限資訊,才不會做出錯誤的判斷

通常網頁應用服務會使用像是Apache、Nginx或其他種網頁伺服器來架設,而這些服務會執行特定的使用者,例如在Linux內就是”www-data”這個目錄

而Windows傳統上是架設IIS網頁伺服器來執行網路服務帳號,通常這個服務都是用無密碼且低權限的帳號作為使用者,而在IIS 7.5版本之後,微軟開發了一個IIS應用程式集區身分識別(IIS Application Pool Identities)[3]的擴充彌補這個缺失

它會在Windows裡的應用程式集區裡建立多個虛擬帳號,以用來執行網頁應用服務,每個集區裡有自己的集區身份,是為了更精確的區分不同應用服務需要的權限而分割出來

但基於這點,由於管理員或開發人員經常用root或者管理角色權限來部署網頁,只為了避開權限的問題,而完全不用任何權限分割的架構

導致如果我們想要驗證我們是否可以使用root或管理員權限進行上傳漏洞,我們可以在建構shell時使用跟目標網頁伺服器背後一樣的程式語言,所以我們來嘗試看看,是否可以利用root權限來覆寫在家目錄底下的”authorized_keys”檔案

如果這把key裡面的公私鑰都被我們控制住,我們就可以用root權限透過SSH來連線進系統存取了,我們先用SSH金鑰配對ssh-keygen來產生一組,同時這把公私鑰對我們命名為”authorized_keys”

此時這把”authorized_keys”檔案包含我們知道的公鑰,接著我們利用相對路徑”../../../../../../../root/.ssh/authorized_keys”上傳到目標伺服器裡,我們把Burp攔截打開,在上傳頁面一樣選擇”authorized_keys”

而在Burp裡我們把上傳的欄位調整成上面的相對路徑,調整完後再送出

上圖就是我們變更了上傳欄位的請求,把我們自製的”authorized_keys”檔案放進去,如果成功複寫了目標伺服器裡的root使用者公私鑰對,我們就可以拿自己知道的私鑰透過SSH連線進去

由於root使用者通常沒有鎖著SSH連線權限,通常都預設只有真正的使用者才會知道密碼,就算在新的機器上也只是建立新的fingerprint

另一個原因是我們在滲透測試時通常不知道系統裡還有什麼使用者,只有在使用root成功連線進去後看”/etc/passwd”時才會知道,這也是唯一的辦法

在實驗過程當中我們還發現目標系統同時也開啟了一個port 2222的SSH伺服器,我們一樣用方才放進去的authorized_keys檔案來嘗試連線,透過”-i”這個參數,我們可以指定我們自製的私鑰以及”-p”指定port

如果讀者在之前有連線到其他種服務的話,就必須記得把known_hosts檔案給清空掉,由於該檔案會儲存以前的SSH連線紀錄

至此我們就可以利用先前自製的公私鑰對覆寫”authorized_keys”檔案,在透過SSH成功連線進去取得root使用者權限,所以讀者如果遇到沒辦法上傳檔案後執行的情形下

就必須花點心思考慮其他種攻擊路徑來利用了,事前了解各種網頁應用服務框架及語言是非常重要的,尤其目前還是有許多的技術以及擴充功能被開發出來

Reference

[1] HAZOTA Europe Kft, “BASE64 Decode and Encode,” https://www.base64encode.org/, 2010-2025.

[2] OffSec, “Common Web Application Attacks: File Upload Vulnerabilities,” The Penetration Testing with Kali Linux (PEN-200).

[3] Thomas Deml, “IIS應用程式集區身分識別,” https://learn.microsoft.com/zh-tw/iis/manage/configuring-security/application-pool-identities, Microsoft Ignite, 2024/07/11.

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *