Privilege escalation gets all the attention. It's the dramatic beat in every write-up — the moment the shell prompt flips from $ to # and the attacker owns the box. But in my experience, escalation is rarely the point. It's the ticket. What the attacker does with that ticket in the next ninety seconds tells you far more about their intent, and it's usually the thing that leaves the evidence you'll actually use later.
So let me pick the one action I find most instructive to reason about: installing a persistence mechanism. Specifically, a malicious systemd service on Linux. It's unglamorous, it's common, and — this is the part I want to sit with — it's a control the defender can win, if they understand what they're really watching.
What the attacker gains
The honest answer is time. Everything else follows from that.
An exploit is fragile. It depends on a vulnerable version, a reachable service, a particular condition holding true. Patch the service and the door closes. This is exactly what I saw in this week's lab work chaining CVE-2025-32433 — the exploit is a beautiful thing until the target gets updated, and then it's a museum piece. An attacker who has done any real work to get to root is not going to leave their continued access hostage to a CVE that could be remediated on Tuesday.
Persistence decouples access from the vulnerability. A systemd service that calls back on a schedule survives reboots, survives the patch, and survives the analyst who thinks closing the original hole ended the incident. That last one matters more than people admit. I have watched remediation efforts declare victory on the entry vector while the persistence quietly sat one directory over, waiting. The attacker's goal isn't a shell today; it's a shell next month, on their terms, after everyone has stopped looking.
Systemd in particular is an attractive home because it's legitimate infrastructure. A rogue .service unit dropped into /etc/systemd/system/ with an innocuous name blends into a directory full of things administrators are conditioned to trust. Enable it with systemctl enable, and the OS itself becomes the thing that maintains the attacker's foothold. That's the uncomfortable elegance of it — you're not fighting malware anymore, you're fighting the service manager doing its job.
What it leaves behind
Here's my core claim, and I'll defend it: persistence is loud if you know where to listen, and the attacker's need for reliability is what makes it loud.
Reliability requires artifacts. A callback that has to survive a reboot must be registered somewhere durable. That durability is the tell. You cannot have persistence that is both reboot-surviving and evidence-free, because the mechanism that survives the reboot is, by definition, written down somewhere the system reads on boot.
For a malicious systemd service, that "somewhere" is a short list:
- A new or modified unit file, typically under
/etc/systemd/system/or/usr/lib/systemd/system/, with a creation or modification timestamp that rarely matches any change window you can account for. - The payload itself — an executable or script, often parked in a world-writable path like
/tmp,/var/tmp, or/dev/shm, or masquerading in/usr/local/bin. - Journald entries showing the unit being enabled and started, which is the service manager narrating the attacker's actions in its own logs.
- The behavioral signature at runtime: a process spawned by systemd (PID 1 lineage) that promptly opens an outbound socket to a host that has no business being contacted from that server.
None of these is subtle once you've decided to look. The problem is almost never that the evidence is absent. The problem is that nobody correlated the file with the process with the connection.
How a defender detects and investigates
If I could give a defender one piece of advice here, it would be this: stop watching for "a bad file" and start watching for "a change to how this host schedules and runs code." That reframe is what makes the detection durable against an attacker who has read the same hardening guides you have.
Concretely, in order of what I'd reach for first:
File integrity monitoring on the systemd unit directories is table stakes, but on its own it only tells you a file appeared. Pair it with auditd rules that watch those same directories and record execve calls, so you catch not just the unit file being written but the payload actually running. FIM tells you the trap was set; auditd tells you it sprang.
Then correlate on lineage and behavior. A process whose parent traces back to systemd, launched from/tmp, opening an outbound connection, is a specific and huntable pattern. I care much more about that causal chain — scheduler spawns unusual binary, binary calls home — than about any single indicator in isolation. It's the combination that turns a maybe into a finding without waiting on reverse engineering.
For the investigation itself, the questions I'd want answered are the boring, useful ones. When was the unit file created, and by which subject’s session? Correlate that timestamp back to the authentication and process records around it — the same logon-session pivot I'd use for account-creation cases applies here. Has the service fired more than once? Journald and execve records give you every invocation, which bounds how long the persistence has actually been live and therefore how far back your scope has to reach. And critically: does the entry vector's remediation actually touch this? If not, you haven't closed the incident. You've closed a door in a house with an open window.
The takeaway
Privilege escalation is the headline, but persistence is where the investigation is usually won or lost. The attacker installs it because they need reliability, and that same need for reliability forces them to write something durable to disk and register it with the system — which is precisely the evidence a prepared defender is watching for. The mechanism that keeps them in is the mechanism that gives them away.
Watch the scheduler, not just the file. Correlate the artifact to the execution to the connection. And never let anyone declare an incident closed on the strength of a patch alone.
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.