From 9bf72f8e193c2e74240a8705bbe2a72b62a61a28 Mon Sep 17 00:00:00 2001 From: poprhythm Date: Sun, 16 Aug 2026 14:24:29 +0000 Subject: [PATCH] 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. --- falco/docker-compose.yaml | 2 ++ falco/rules/git-hook-tamper.yaml | 29 ++++++++++++++++++++++++ falco/rules/unexpected-child-of-git.yaml | 28 +++++++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 falco/rules/git-hook-tamper.yaml create mode 100644 falco/rules/unexpected-child-of-git.yaml diff --git a/falco/docker-compose.yaml b/falco/docker-compose.yaml index a8fdac5..18db208 100644 --- a/falco/docker-compose.yaml +++ b/falco/docker-compose.yaml @@ -32,3 +32,5 @@ services: - ./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/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 diff --git a/falco/rules/git-hook-tamper.yaml b/falco/rules/git-hook-tamper.yaml new file mode 100644 index 0000000..96e349b --- /dev/null +++ b/falco/rules/git-hook-tamper.yaml @@ -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] diff --git a/falco/rules/unexpected-child-of-git.yaml b/falco/rules/unexpected-child-of-git.yaml new file mode 100644 index 0000000..ae7ac63 --- /dev/null +++ b/falco/rules/unexpected-child-of-git.yaml @@ -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]