falco: add rules for git hook tampering and unexpected pack-service children

Written after the 2026-08-10/11 gitea internal-API log-poisoning attack
that planted a malicious uploadpack.packObjectsHook backdoor. Catches
both the planting (unexpected exec from a hooks/ path) and the firing
(git-upload-pack/git-receive-pack spawning anything but its own
pack-objects binary), independent of how the hook config got written.
This commit is contained in:
2026-08-16 14:24:29 +00:00
parent 6a52b6195a
commit 9bf72f8e19
3 changed files with 59 additions and 0 deletions
+2
View File
@@ -32,3 +32,5 @@ services:
- ./rules/miner-detect.yaml:/etc/falco/rules.d/miner-detect.yaml:ro - ./rules/miner-detect.yaml:/etc/falco/rules.d/miner-detect.yaml:ro
- ./rules/miner-pool-ports.yaml:/etc/falco/rules.d/miner-pool-ports.yaml:ro - ./rules/miner-pool-ports.yaml:/etc/falco/rules.d/miner-pool-ports.yaml:ro
- ./rules/tune-noise.yaml:/etc/falco/rules.d/tune-noise.yaml:ro - ./rules/tune-noise.yaml:/etc/falco/rules.d/tune-noise.yaml:ro
- ./rules/git-hook-tamper.yaml:/etc/falco/rules.d/git-hook-tamper.yaml:ro
- ./rules/unexpected-child-of-git.yaml:/etc/falco/rules.d/unexpected-child-of-git.yaml:ro
+29
View File
@@ -0,0 +1,29 @@
# Custom rule: catch execution of any git hook file gitea didn't put there.
# Added after the 2026-08-10/11 gitea internal-API log-poisoning attack, where
# an attacker used /api/internal/manager/add-logger to write a malicious
# uploadpack.packObjectsHook entry into the global .gitconfig, pointed at a
# planted hooks/pre-applypatch.sample file under an unrelated repo. Gitea only
# ever manages four hook names per repo (post-receive, pre-receive, update,
# proc-receive), each delegating to a same-named script under hooks/*.d/gitea -
# anything else executing from a hooks/ path is not something Gitea put there.
- list: gitea_managed_hook_names
items: [post-receive, pre-receive, update, proc-receive, gitea]
- rule: Unexpected git hook execution
desc: >
A process executed from a path under a git repository's hooks/ directory
whose name isn't one of Gitea's own managed hook scripts. Catches planted
hooks used for persistence/RCE (e.g. a malicious uploadpack.packObjectsHook
or receive hook), independent of how the file got written.
condition: >
spawned_process
and container.name = "gitea"
and proc.exepath contains "/hooks/"
and not proc.name in (gitea_managed_hook_names)
output: >
Unexpected git hook executed
(user=%user.name command=%proc.cmdline exepath=%proc.exepath
parent=%proc.pname container=%container.name pid=%proc.pid)
priority: CRITICAL
tags: [git, persistence, mitre_persistence]
+28
View File
@@ -0,0 +1,28 @@
# Custom rule: catch git-upload-pack/git-receive-pack forking anything other
# than git's own pack-objects binary. Added after the 2026-08-10/11 gitea
# log-poisoning attack, which planted a malicious `uploadpack.packObjectsHook`
# global git config entry - a documented git RCE primitive where upload-pack
# forks an attacker-chosen executable instead of git-pack-objects on every
# fetch/clone. This is the moment the backdoor actually fires, independent of
# how the hook config got planted, so it's a strong last-line catch even if
# git-hook-tamper.yaml's file-write detection is bypassed some other way.
- list: git_pack_children
items: [git-pack-objects, git, git-remote-https, git-remote-http]
- rule: Unexpected child process of git pack service
desc: >
git-upload-pack or git-receive-pack spawned a process that isn't git's own
pack-objects binary. Normal fetch/push never does this - it's the exact
behavior of an abused uploadpack.packObjectsHook / pre-receive-style RCE.
condition: >
spawned_process
and container.name = "gitea"
and proc.pname in (git-upload-pack, git-receive-pack)
and not proc.name in (git_pack_children)
output: >
git pack service spawned unexpected child process
(user=%user.name command=%proc.cmdline parent=%proc.pname
container=%container.name pid=%proc.pid)
priority: CRITICAL
tags: [git, execution, mitre_execution]