servicectl PrivateTmp 小記
在打 HTB 靶機 Zipping ,題目本身是 mariadb 寫檔後 LFI, mariadb 預設值可以讀寫任何地方,於是我一開始寫到 /tmp
下,但是一直無法 LFI 成功
後來寫到 /var/lib/mysql
後才成功 LFI,在拿到 root 後回去看,發現我確實有成功寫檔到 /tmp
,並且我用跑 apache2 的 user 直接用 php
執行檔案也成功,但是透過 apache2 跑卻會找不到,怪哉,怪哉
在查了好一陣子終於看到這篇 php-fpm temporary file path problem (Sytemd PrivateTmp pit) ,原來是 systemd 可以設置 PrivateTmp 讓每個 process 有獨立的 /tmp
,讀 source 可知實際位置會是 /tmp/systemd-private-{SD_ID128_TO_STRING(boot_id)}-{id}-XXXXXX
像是 /tmp/systemd-private-f5c7e8a0d62449b8b0efb31878c2771e-apache2.service-rhS5Q4
其中 boot_id
是任何人都可讀的 $ cat /proc/sys/kernel/random/boot_id
,開機會隨機產生, id
可預測,最後面的隨機字串 XXXXXX
則是透過呼叫 mkdtemp
產生。
透過這個方法產生的 /tmp
對於其他 process 看到的權限是 drwx------ 3 root root
,基本上是跑 systemd
的 user,所以在 zipping 這題是繞不過去。查了一下看到這篇 Access files in system tmp directory, when using PrivateTmp ,設計上也是不給共用,能繞就是 0-day 了。
但如果是其他場景下呢?不安全的 container 可能直接用 root 跑,並且對於 read-only filesystem 來說, /tmp
通常也能寫入,雖然 XXXXXX
太大,看 source 不確定能不能預測,但是使用 privateTmp 的 process 可以直接讀 /proc/self/mountinfo
獲得位置
不過 zipping 這題之所以會寫到 /tmp
而不是 privatetmp 是因為透過 mariadb
寫檔,因此只有當兩個 process 都是用 root 跑時,一個能寫檔一個能 LFI 才需要這樣搞。
p.s. docker container boot_id
和 host 一樣,也許能利用?