Cron Ran curl at Three in the Morning
Cron ran curl at three in the morning
This lab runs in a VM
A single Ubuntu 24.04 VM already has Falco running with the modern eBPF driver. Syscall instrumentation is a kernel feature, so it is simply impossible in a lab Pod. It takes 2–3 minutes to come up (because Falco is being installed).
Goal
Write a rule that catches the incident in the title yourself. You split the list and the macro, leave the alerts in a JSON file, actually plant a scheduled job, and confirm in the file that the rule catches it. Then you create one more normal job that matches the same rule, remove only that one as an exception, and confirm again that the bad one is still caught.
Why it matters
Log-based detection has a structural limit. A log contains only what the program decided to write. Syscalls are different — whether you create a process or open a file, you have to go through the kernel, and you cannot deceive the kernel.
But if you look at all the syscalls, there are too many alerts. So the real work of runtime detection is not "what to catch" but "what may be left out." If one rule also catches normal backup jobs, within days nobody looks at the alerts. If you then fix the rule by broadening it, the real incident drops out along with them. The habit of keeping exceptions narrow and writing down the reason decides the lifespan of a detection system.
Steps
- Save Falco's version, driver, and service state to
/root/falco/01-engine.txt. - Write a rule in
/etc/falco/rules.d/labhub-cron.yamlwith onelist, onemacro, and onerule. The output must include%user.nameand%proc.cmdline. - In
/etc/falco/config.d/labhub-output.yaml, turn on JSON output and file output (/var/log/falco/events.json) and restart the service. - Create
/etc/cron.d/telemetryso that it makes a request outside every minute. - Wait at least a minute and save one caught alert line to
/root/falco/05-alert.json. - Create
/etc/cron.d/backup-syncto add one more normal job that matches the same rule, remove only that one through the rule'sexceptions, and restart the service. - After emptying
events.json, wait until the scheduled job has run once, and confirm in/root/falco/07-verify.txtthat the normal job is not caught and the bad one is. - Write the basis for the rule in
/root/falco/08-report.mdin four sections,## 무엇을 잡는가,## 왜 예외를 두었나,## auditd 와 무엇이 다른가, and## 다음에 넓힐 곳(in order: what it catches, why an exception was made, how it differs from auditd, and where to widen next).
Notes
- Validate the rule with
falco --validate /etc/falco/falco_rules.yaml --validate <내 파일>(the placeholder is your rule file). You must also give the default rules file — macros such asspawned_processare defined there. - cron starts a shell and that shell calls the command, so the parent is the shell. To look at ancestors, write something like
proc.aname[2]. - The service name is
falco, but the actual unit differs depending on the driver. Check withsystemctl show -p Id --value falcoand look at the journal under that name. - The scheduled jobs run every minute. The waiting is divided into steps, so do not rush the grading.
- Common mistake: melting the exception into the end of
conditionasand not …. Six months later nobody knows the reason for that fragment. - Common mistake: making the exception too broad so that the whole rule goes quiet. Step 7 catches that.
Which driver is running what
Save the version number from falco --version, which driver (unit name) it runs with, and the service state to /root/falco/01-engine.txt.
systemctl show -p Id --value falco tells you the actual unit name. falco is an alias of that unit. If you do not know the driver, you cannot find out "why it is not catching."
Write one rule
Write one list, one macro, and one rule in /etc/falco/rules.d/labhub-cron.yaml. It must catch an outbound request tool being executed under a scheduled job, %user.name and %proc.cmdline must be in output, and priority must be WARNING or higher.
list and macro can refer only to things defined before themselves, so write in the order list → macro → rule. cron starts a shell, so you have to look at the ancestor, not the parent. When you finish, check with --validate together with the default rules file.
Leave alerts in a file
In /etc/falco/config.d/labhub-output.yaml, turn on json_output: true and file output (/var/log/falco/events.json) and restart the service. Do not edit falco.yaml wholesale.
Files under config.d are added on top of the default configuration. After restarting, if you look at the journal, it prints one line per configuration file it read — that is the evidence that "it really took effect."
Plant the incident
Create /etc/cron.d/telemetry so that it makes a request outside with curl every minute. Because it is in /etc/cron.d format, there is a user field for the command to run as after the schedule.
Every minute is * * * * *. The request does not actually need to succeed — the fact that the process was executed is caught by the syscall.
See in the file whether it was caught
Wait until the scheduled job has run once, then pick one alert line for your rule from /var/log/falco/events.json and save it to /root/falco/05-alert.json.
jq -c 'select(.rule == "<규칙 이름>")' /var/log/falco/events.json | tail -1 gives one line (the placeholder is your rule name). The file also has Falco's internal alerts mixed in, so filter by rule name.
Remove one normal case narrowly
Create /etc/cron.d/backup-sync to add one more normal job that matches the same rule, remove only that one through the rule's exceptions, and restart the service. Do not attach and not … to the end of condition.
exceptions is written with name, fields, comps, and values. If you write the event fields to look at in fields, the comparison methods in comps, and the bundles of values in values, the engine appends them after the condition as and not (…). If you make the values broad, step 7 catches it.
Run both again
After emptying /var/log/falco/events.json, wait until the scheduled job has run once (at most 1 minute), confirm that telemetry is caught and backup-sync is not, and write it in two or more lines to /root/falco/07-verify.txt.
An exception takes effect only after the service rereads the rules (you restarted it in the earlier step). If old alerts remain, your judgment gets muddied, so empty the file and look only at what you newly received. If the exception is too broad, even what should be caught goes quiet.
Leave the basis for the rule
Write four sections, ## 무엇을 잡는가, ## 왜 예외를 두었나, ## auditd 와 무엇이 다른가, and ## 다음에 넓힐 곳 (in order: what it catches, why an exception was made, how it differs from auditd, and where to widen next), in /root/falco/08-report.md. The three words exceptions, priority, and events.json must appear in the body.
What the next person looking at this rule most wants to delete first is the exception. If the reason it was put there is not written down, they really will delete it. Also summarize what overlaps with and what differs from the kernel audit in the earlier module.