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 獲得位置

...
/tmp/systemd-private-f5c7e8a0d62449b8b0efb31878c2771e-apache2.service-rhS5Q4/tmp /tmp rw,relatime shared:273 master:1 - ext4 /dev/mapper/ubuntu--vg-ubuntu--lv rw
490 405 253:0 /var/tmp/systemd-private-f5c7e8a0d62449b8b0efb31878c2771e-apache2.service-rQZ1EI/tmp /var/tmp rw,relatime shared:274 master:1 - ext4 /dev/mapper/ubuntu--vg-ubuntu--lv rw
...
/proc/self/mountinfo

不過 zipping 這題之所以會寫到 /tmp 而不是 privatetmp 是因為透過 mariadb 寫檔,因此只有當兩個 process 都是用 root 跑時,一個能寫檔一個能 LFI 才需要這樣搞。

p.s.  docker container boot_id 和 host 一樣,也許能利用?