Lab 03 — Bandit 5 to 10: finding things you cannot see
0 / 5 steps
The goal
The first six levels were about opening files you already knew the name of. These five are the opposite problem: the file is somewhere in a haystack and all you have is a description of it. By the end you will be able to search a filesystem by size, owner and type, and pull one line out of a file with a million of them.
No passwords here either. OverTheWire ask content creators not to publish game credentials, and their passwords rotate regardless. You get the reasoning and the commands; the answers are yours to find. Bandit is free and community-run — start at overthewire.org.
Where this picks up. You should be logged in as bandit5, which means you have finished Lab 02. Same host, same port 2220, same notes file open beside you.
Steps
01Search by what a file is, not what it is called
This level hides the file somewhere beneath inhere and describes it three ways: human-readable, exactly 1033 bytes, and not executable. You are not given a name, because the name is not the point.
$ find inhere -type f -size 1033c ! -executable
then read whatever single path comes back $ cat inhere/maybehere07/.file2
Each word is a filter, and they stack. -type f means a regular file, not a directory. -size 1033c is exactly 1033 bytes — the c matters enormously, because a bare -size 1033 means 1033 512-byte blocks, which is a completely different question. ! negates the test that follows it.
Notice what find is doing that ls cannot. It walks the whole tree beneath the path you gave it, so subdirectories are searched without you asking. From here on, “I do not know where it is” stops being an obstacle.
02Search the whole machine by ownership
Now the file is somewhere on the server — anywhere — and the description is that it is owned by user bandit7, owned by group bandit6, and 33 bytes. Read that pairing twice. The user and the group are different numbers, and transposing them is the most common way to fail this level.
$ find / -type f -user bandit7 -group bandit6 -size 33c 2>/dev/null
What 2>/dev/null is for. Searching from / as an unprivileged user means find will hit hundreds of directories it is not allowed to read, and complain about every one. Those complaints go to standard error, stream number 2. Redirecting stream 2 into /dev/null throws them away and leaves only the result you wanted on screen.
This is your first real encounter with the three streams — stdin (0), stdout (1) and stderr (2) — and they are the foundation of everything in the next three steps. The reason errors get their own stream is exactly this: so you can discard the noise without discarding the answer.
Ownership as a search key is not a puzzle-game trick. On a compromised host, “which files does this service account own that it should not” is a real question, and this is how you ask it.
03One line out of a million
A file called data.txt, and the thing you want sits next to the word millionth. This is the simplest command in the whole lab and the one you will type most often for the rest of your career.
$ grep millionth data.txt
grep prints the lines that match. That is all it does, and it is enough. Three flags turn it from useful into indispensable: -i ignores case, -r searches a whole directory tree, and -v inverts the match so you see everything that does not contain the pattern. That last one is how you strip known-good noise out of a log.
04The line that appears exactly once
Same filename, harder question: every line in it is repeated except one. Find the one. There is no pattern to grep for, so you need two commands and a pipe.
$ sort data.txt | uniq -u
Why the sort is not optional. This is the single most valuable thing in this lab. uniq only ever compares a line to the one directly above it — it has no memory beyond that. Run uniq -u data.txt on its own and you get nonsense, because identical lines scattered through the file never end up adjacent. Sorting first is what puts the duplicates next to each other so uniq can see them.
And the pipe. | takes the standard output of the command on the left and makes it the standard input of the command on the right. Nothing is written to disk. This is the idea Unix is built on: small tools that read a stream and write a stream, chained into something none of them could do alone. Once that clicks, -u is a footnote — it just means “only the lines that were never repeated”, where -d would mean the opposite and -c would count them.
05Text hiding inside a binary
The last one in this run: data.txt again, but this time it is mostly not text. What you want is one of the few readable runs in it, and it has several = characters in front of it.
$ strings data.txt | grep ===
run strings data.txt on its own first to see what it pulls out
strings walks a file byte by byte and prints any run of printable characters long enough to look deliberate — four or more by default, adjustable with -n. Everything else it discards. That is why you can point it at a binary and get back URLs, error messages, file paths and the occasional hard-coded password.
This is genuine malware-triage technique, not a game mechanic. Running strings over an unknown executable is frequently the first thing an analyst does, because authors leave a surprising amount of plain text lying around in compiled code. You have just done, in one line, what that job starts with.
On the grep ===: you are filtering the readable output down to the run with the equals signs. Three is enough to be distinctive without assuming exactly how many there are.
You can now find a file by its properties rather than its name, search a whole filesystem without drowning in permission errors, and chain small tools together to pull one line out of noise. That is most of what day-to-day Linux work actually consists of.
Before you leave — prove it
Without looking: one, what is the difference between -size 33c and -size 33? Two, why does uniq need sort in front of it? Three, what does 2>/dev/null throw away, and what does it deliberately keep?
If the second one gives you any hesitation, go back to step 04. It is the idea that carries furthest.
What you learned
- find -type -size -user -group — describing a file you cannot name
- The c suffix on -size — bytes, not 512-byte blocks
- 2>/dev/null — discarding stderr while keeping stdout
- grep, and -i -r -v — matching, and inverting the match to remove noise
- sort | uniq -u — and why uniq is blind without the sort
- strings — readable text pulled out of binary, the first move in triage
NextBandit 10 to 15: encodings, and your first SSH key→
Go deeper
- OverTheWire Bandit — free, community-run, and worth a donation if you get value from it
- Lab 02 if you skipped ahead, and Lab 01 for nmap
- Command references for when you want the flags in one place
Original walkthrough. The wargame belongs to the OverTheWire community; this page reproduces none of their level text and none of their passwords, in line with their rules for content creators. If a command here no longer does what the page says, tell me and I will fix it.