Step 100. Bandit 21~25 — The cron Exploitation Mindset
Level 2 — Introduction to Security and Attack Skill Basics | Difficulty ★★★☆☆ | Estimated time: 3 hours
Prerequisites: you’ve finished setuid and the "whose privileges does it run with?" mindset from Step 99. You have the Bandit 20→21 password.
- What you need: an SSH connection environment, your password record, and a local Linux/WSL setup for experiments.
- ⚠️ All exercises in this chapter are for your own lab and legal platforms only. Applying them to unauthorized systems is a crime.
- About the legal practice ground: OverTheWire Bandit is an official attack-practice platform. Techniques for slipping into cron are especially about persistence — on someone else’s system that amounts to installing a backdoor, so experiment only on the practice ground and your own lab.
Servers have jobs that run without anyone typing. Cleaning logs every minute, backing up every hour, generating reports every night — automated jobs run by a scheduler called cron. Let’s lay the hacker’s question on top. Automated jobs usually run with high privileges. But what if such a job reads or executes a file I can change? Then I can borrow those privileges. If setuid was "a program’s mask," cron exploitation is "slipping into the schedule." What you learn today is a mindset before it’s a technique — the eye that looks first at what runs automatically.
1. Learning Objectives
By the end of this chapter, you will be able to:
- Read
/etc/cron.d/and interpret "who runs what, with whose privileges, when" - Read the shell scripts cron executes and trace their input/output paths
- Pre-compute filenames generated by
md5sumby hand - Explain and reproduce the slip-in condition: "high privileges execute something from a place I can plant"
- Explain that privilege is not a point but a line (from execution to result delivery)
2. Background Knowledge — Today’s Tools and Concepts
Today’s Tools at a Glance
| Category | Details |
|---|---|
| Language/environment | Linux shell (Bandit server + local WSL), reading shell scripts |
| Today’s commands | ls /etc/cron.d/, cat, md5sum, cut, heredoc (<<'EOF'), chmod +x |
| Concepts needed | cron schedule structure, shell script basics, hashing, privilege chains, persistence |
| Today’s artifact | Bandit 21→26 password chain + a one-page cron exploitation checklist |
2-1. Dissecting cron — Commands Typed by a Clock
Linux’s cron is the system’s alarm clock: "run this command at a set time." Its configuration lives as files in folders like /etc/cron.d/, and each line is one scheduled job.
* * * * * bandit22 /usr/bin/some_script.sh
└ min hr day mon dow └ with whose privileges └ what
The five fields are the schedule (* * * * * means "every minute"), then comes the owner of the executing privileges, and last, the thing to be executed. The key to reading is the middle field — "whose privileges does this job run with?" Exactly the question you gained in Step 99.
2-2. Reading Shell Scripts — Only Three Pieces of Syntax Needed
What cron executes is mostly shell scripts — text files with commands written in order. Today you need just three pieces of syntax.
#!/bin/bash # declares that bash runs this file
myname=$(whoami) # store a command's result in a variable
echo "text $myname" > /tmp/x # output to a file instead of the screen (overwrite)
$(...) means "run the command inside the parentheses and substitute its result." It’s not programming — just the commands you type in the terminal written down in a file, so don’t be intimidated.
2-3. Naming Files with a Hash — Enter md5sum
md5sum computes a data’s hash (a fixed-length fingerprint-like value). The same input always yields the same hash. If a script "names a file using the MD5 value of the username," we can do the same calculation by hand and learn that filename in advance. It’s not a cipher — it’s an address book.
2-4. The Three Conditions for Slipping In
Today’s core formula. Cron exploitation works when these three come together.
- There’s an automated job running with high privileges
- That job executes or reads a file in a location I can write to
- The result is delivered to a place I can read
Break any one of the three and the attack fails. Defense, in the end, is the work of breaking one of these three — the attack map and the defense checklist are the same picture.
3. Follow Along
3-1. Level 21 → 22 — Peeking at Someone Else’s Schedule
Input (on the server, Screen example)
ls /etc/cron.d/
cat /etc/cron.d/cronjob_bandit22
A line appears saying that some script runs every minute with bandit22’s privileges. Read that script.
Input (Screen example)
cat /usr/bin/cronjob_bandit22.sh
How to read it: following the script, it’s copying the password into some file. That file’s path is this level’s answer. A three-stage trace — "schedule (cron config) → executable (script) → result (output file)." An attacker’s reconnaissance flows in this order.
3-2. Reading cron.d on Your Own Computer
Let’s do the same reading on your own computer (measured 2026-09-09, WSL, Ubuntu 24.04):
ls /etc/cron.d/
cat /etc/cron.d/e2scrub_all
Output (measured 2026-09-09):
e2scrub_all
30 3 * * 0 root test -e /run/systemd/system || SERVICE_MODE=1 /usr/lib/x86_64-linux-gnu/e2fsprogs/e2scrub_all_cron
10 3 * * * root test -e /run/systemd/system || SERVICE_MODE=1 /sbin/e2scrub_all -A -r
How to read it: the first line schedules "every Sunday at 3:30 AM," the second "every day at 3:10 AM," running a disk-checking tool with root privileges. The root in the middle is the privileges field — automated jobs like this quietly live on your computer too.
3-3. Level 22 → 23 — Finding and Reading the Result
Read the path you identified in 3-1 (on the server, Screen example).
cat /tmp/t7O6lds9S0RqQj9aGh5PYeFZqZl2V6xW # check the actual path by reading the script
How to read it: since cron refreshes that file every minute, if it’s empty or stale, wait a minute and look again. An automated job’s output is "a quietly updating bulletin board." This is the section where you learn cron’s clock speed — the answer is delivered in one-minute units.
3-4. Level 23 → 24 — Computing the Filename by Hand
Here’s the core part of this script (on the server, Screen example).
myname=$(whoami)
mytarget=$(echo I am user $myname | md5sum | cut -d ' ' -f 1)
# ... copies the password to /tmp/$mytarget
Instead of waiting for cron, we compute it in advance. This calculation is completely identical on your own computer, not just the server (measured 2026-09-09, WSL):
echo "I am user bandit23" | md5sum | cut -d ' ' -f 1
Output (measured 2026-09-09):
8ca319486bfbbc3663ea0fbe81326349
How to read it: this 32-digit hexadecimal is the filename the script creates when running as bandit23. Just read /tmp/8ca319486bfbbc3663ea0fbe81326349. cut -d ' ' -f 1 means "cut on spaces and take the first piece" — it strips the - that trails md5sum’s output.
Why: "read the program’s rules, then turn those rules to your advantage" — the essence of the hacker mindset. Most attacks aren’t destruction but the reuse of rules. Note that changing even a single character completely changes the hash — "I am user bandit24" gives ee4ee1703b083edac9f8183e4ae70293 (measured 2026-09-09). Spaces and letter case all change the hash.
3-5. Level 24 → 25 — Slipping Myself into the Schedule
Finally, the counterattack. This cron "executes and then deletes every script placed in /var/spool/bandit24/."
Input (on the server, Screen example)
mkdir /tmp/mystage
cat > /var/spool/bandit24/myjob.sh <<'EOF'
#!/bin/bash
cat /etc/bandit_pass/bandit24 > /tmp/mystage/password
EOF
chmod +x /var/spool/bandit24/myjob.sh
Wait 1~2 minutes and /tmp/mystage/password appears — containing the password read with bandit24’s privileges.
How to read it: cron, with bandit24’s privileges, executed on my behalf a script I wrote. <<'EOF' is an input technique (heredoc) for writing multiple lines to a file at once, and chmod +x grants execute permission — both are essential.
We safely simulated this structure on our own computer — a script planted in a spool folder being executed (measured 2026-09-09, WSL):
mkdir -p /tmp/spool /tmp/mystage
cat > /tmp/spool/myjob.sh <<'EOF'
#!/bin/bash
echo "simulated_secret_password" > /tmp/mystage/password
EOF
chmod +x /tmp/spool/myjob.sh
/tmp/spool/myjob.sh # playing cron's role by hand
cat /tmp/mystage/password
Output (measured 2026-09-09):
simulated_secret_password
The whole chain was reproduced: the script executed from where it was planted, delivering its result to a different folder.
3-6. Make a Prediction — Why Put It in /tmp?
In 3-5, why did we set the output path to /tmp/mystage instead of our home folder?
- (a) Habit
- (b) Because bandit24, which cron runs as, must also be able to write there
- (c) To hide it
Check for yourself (measured 2026-09-09, WSL):
ls -ld /tmp
drwxrwxrwt 10 root root 4096 Sep 9 14:32 /tmp
drwxrwxrwt — a public folder anyone can read and write. The answer is (b). bandit24 can’t write to my home folder, so the result would never be created there.
Why it matters: not just "execute permission" but "the delivery path of the result" must also have matching privileges for the chain to complete. Privilege is not a point — it’s a line: every segment from start to finish must connect.
3-7. Level 25 → 26 — A Restricted Environment’s Component Is the Escape Hatch
The last one is an unusual problem. bandit26’s login shell is not a normal shell.
Input (on the server, Screen example)
grep bandit26 /etc/passwd
The last field is something other than /bin/bash — that’s this account’s restricted shell. If that program internally uses more (a tool that shows long text page by page), more appears only when the content is longer than the terminal window. Shrink your terminal window very small and connect, and you get trapped in the more state; pressing v there opens an editor (vim). From vim there’s a path to read files with :e /etc/bandit_pass/bandit26.
How to read it: the lesson is — don’t hunt for a locked door; look at the components the door is made of. A component of the restricted environment (more) turned out to be the escape hatch. It’s fine if you can’t solve this one — just take the mindset with you. If you get stuck in vim, the escape spell is Esc then :q! + Enter.
4. Missions & Exercises
Mission — The Bandit 21→26 Chain and a cron Exploitation Checklist
- Complete the chain through bandit25 and record each level in write-up format
- Read your own computer’s
/etc/cron.d/and interpret each job’s "what, with whose privileges" in a table - Reproduce the md5sum calculation from 3-4 and the spool experiment from 3-5 locally
- Write a one-page cron exploitation checklist in your wiki — items to include: ① check the schedule (/etc/cron.d/ and "whose privileges") ② analyze the executable (the script’s input/output paths) ③ the three slip-in conditions ④ privileges on the result delivery path ⑤ waiting one cron cycle
Exercises
Exercise 1. Interpret each part (five fields, user, command) of the cron config line * * * * * bandit22 /usr/bin/x.sh.
Exercise 2. Why is cut needed in echo "I am user bandit23" | md5sum | cut -d ' ' -f 1?
Exercise 3. State the three conditions for slipping into cron, and pair each one with a defense that breaks it.
Exercise 4. Explain, connecting it to the sentence "privilege is a line," why the result path in 3-6 had to be /tmp.
5. Model Answers & Completion Criteria
Mission Model Answer
The skeleton of the chain (on-server commands are a Screen example):
cat /etc/cron.d/cronjob_bandit22 # L21→22: identify the script path
cat /usr/bin/cronjob_bandit22.sh # → identify the result path, then cat it
echo "I am user bandit23" | md5sum | cut -d ' ' -f 1 # L23→24: pre-compute the filename
# L24→25: plant a script in /var/spool/bandit24/ with a heredoc and wait 1~2 minutes
How to verify: ① does the one-page checklist contain all five items? ② does your own cron.d table include an interpretation of the "privileges field" (as in the section 3-2 measurement)? ③ in the local reproduction, did the heredoc-written script execute and produce the result file? ④ did you clean up the scripts and folders used in the experiment?
Exercise Answers
Answer 1. The five asterisks mean "minute hour day month weekday" all match every time — a schedule of running every minute; bandit22 is the owner of the privileges this job runs with; and the path at the end is what runs every minute. The key to reading is the privileges field in the middle.
Answer 2. Because md5sum‘s output appends a filename (a - since the input is a pipe) after the hash. To extract only the hash from 8ca3...6349 -, you need "cut on spaces and take the first piece" (see the measured output form from 2026-09-09).
Answer 3. Conditions: ① an automated job with high privileges ② an executable in a location I can write to ③ a delivery path I can read. Defenses: ① minimize job privileges (only what’s strictly needed) ② restrict write permissions on scripts and spool folders to the owner only ③ deliver results to a privileged location, not a public folder. Break any one and the chain snaps.
Answer 4. The execution happens with bandit24’s privileges, but the act of creating the result file also happens with bandit24’s privileges. bandit24 can’t write to my home folder, so the line breaks at that segment. /tmp is writable by everyone (drwxrwxrwt, measured 2026-09-09), so the line connects to the end. An attack chain completes only when privileges connect across every segment.
Completion Criteria Checklist
- [ ] I can read
/etc/cron.d/and interpret "who runs what, with whose privileges, when" - [ ] I can read a shell script’s input/output paths
- [ ] I can pre-compute a hash-generated filename by hand
- [ ] I can write a multi-line script to a file with a heredoc (
<<'EOF') - [ ] I can explain the three slip-in conditions and pair them with defenses
- [ ] I can explain, with the /tmp permissions example, that privilege is a line, not a point
- [ ] Mission: I completed the chain and the one-page cron exploitation checklist
6. Common Pitfalls & Fixes
Wall 1. My script disappeared but there’s no result
Symptom: cron seems to have run it (the file in the spool was deleted), but no result file exists.
Cause: a typo in a path inside the script, missing execute permission (chmod +x), the result folder not created, or using relative paths (cron’s working directory isn’t what you expect).
Fix: make all paths absolute paths, create the result folder with mkdir beforehand, and check the script’s first line #!/bin/bash. And don’t forget to wait 1~2 minutes — cron’s clock ticks in minutes.
Wall 2. I computed the md5sum but no such file exists
Symptom: you calculated the filename, but it’s not in /tmp.
Cause: you typed the formula even one character differently (including spaces and letter case), or cron hasn’t run yet.
Fix: compare the echo part of the original script character by character. We confirmed in the section 3-4 measurement (bandit23 vs bandit24) that a one-character difference changes the hash completely. And wait a minute and check again.
Wall 3. I can’t find the cron config file
Symptom: /etc/cron.d/ shows only filenames different from the guide.
Cause: the server configuration can change slightly over time.
Fix: look for a name containing the next level’s number in the full ls /etc/cron.d/ listing. If you still can’t see it, re-check the hints on the official level page.
Wall 4. Pressing v in more does nothing
Symptom: the Level 25 trick doesn’t work.
Cause: you’re not in the more state — the window is big enough that the text fits on one screen, or your keypresses aren’t reaching the pager program.
Fix: shrink your terminal window’s height to 2~3 lines, drastically, and reconnect. more appears only when the text overflows the window.
Wall 5. The file I wrote with a heredoc is empty
Symptom: you typed cat > file <<'EOF' but the content didn’t go in.
Cause: the closing EOF wasn’t at the very start of its line (no leading spaces allowed), or the unquoted <<EOF mixed in variable-substitution rules.
Fix: the closing EOF must sit alone at the start of its line. For today’s purpose (writing a script verbatim), the quoted form 'EOF' is the safe choice (follow the measured procedure in section 3-5 exactly).
7. Summary
Today’s Concepts
| Concept | One-line explanation |
|---|---|
| cron | the system’s alarm clock that runs commands at set times |
/etc/cron.d/ |
the system-wide schedule folder — each line is one job |
| Shell script | a text file of commands in order — starts with #!/bin/bash |
| md5sum | fixed-length hash calculation — same input, always same value |
| Privilege chain | the line of privileges running from execution to result delivery |
| Persistence | a technique planted into automation to maintain access — a backdoor outside the practice ground |
Today’s Commands
| Command | What it does |
|---|---|
ls /etc/cron.d/ |
list the schedules |
cat /etc/cron.d/file |
read a job’s contents |
echo "..." | md5sum | cut -d ' ' -f 1 |
extract only the hash |
cat > file <<'EOF' |
write multiple lines to a file at once (heredoc) |
chmod +x file |
grant execute permission |
ls -ld /tmp |
see a folder’s own permissions |
An Instinct More Important Than Commands
Engrave today’s tracing order into your body — schedule → executable → result. And build the habit of checking "who can write to this?" with ls -l before reading any script you find. A writable script + a high-privilege cron is already an open door. Combine Level 20’s "I wait and the other side connects" with today’s "an automated job executes my file" and you’ll see it — a large share of attacks is loading my thing onto a legitimate flow. Once you bundle it into this structure, even new techniques start reading as "ah, another case of loading something onto the flow." Step 100 — the hundredth door. A journey that began with finding files has arrived, before you knew it, at the level of "reading the system’s flows and loading yourself onto them."
Once every box is checked, Step 100 is complete. Click the checkbox in the sidebar to save your progress.