June 16, 2026
OverTheWire Bandit Walkthrough — Level 18 → 19 | 30-Day Cybersecurity Learning Journey (Day 18)
Bypassing a hostile .bashrc by passing a remote command directly to SSH and why understanding shell startup files matters when something is…
William | Cybersecurity & SOC Analyst
5 min read
Bypassing a hostile .bashrc by passing a remote command directly to SSH and why understanding shell startup files matters when something is actively working against you.
Introduction
Day 18. Bandit Level 18 to Level 19. Every previous level assumed that logging in successfully meant you had a working shell to operate in. This one breaks that assumption deliberately. The password is sitting in a file called readme in the home directory, exactly like Day 1. But this time, the moment you log in interactively, the connection closes immediately. Someone has modified .bashrc to log you out the instant your session starts.
This level teaches something that goes beyond any single command. It teaches that SSH does not require an interactive shell to function. SSH can execute a single remote command and return its output without ever triggering the shell startup files that would normally run. Understanding the difference between an interactive login and a non-interactive command execution is what solves this level.
By the end of this article you will understand why .bashrc runs on login, how a hostile modification to it can be used to kick out a user and how to work around it without ever needing to fix or even see the file causing the problem.
Level Objective
The password for the next level is stored in a file readme in the homedirectory. Unfortunately, someone has modified .bashrc to log you out when you log in with SSH. The level requires reading the readme file without triggering the interactive shell that immediately disconnects.
Approach
A standard interactive login would normally look like this:
ssh bandit18@bandit.labs.overthewire.org -p 2220ssh bandit18@bandit.labs.overthewire.org -p 2220But the level description warns this will fail. The moment an interactive bash shell starts, .bashrc runs as part of the shell initialization process, and the modified version of that file ends the session before any commands can be typed.
The workaround is to give SSH a command to run directly as part of the connection itself. When SSH is given a command argument, it connects, authenticates, runs that exact command non-interactively and returns the output, all without spawning the interactive login shell that triggers .bashrc. I structured the connection this way, appending cat readme directly after the connection details:
ssh bandit18@bandit.labs.overthewire.org -p 2220 cat readmessh bandit18@bandit.labs.overthewire.org -p 2220 cat readmeThe connection proceeded normally. The Bandit ASCII art banner displayed and the password prompt appeared exactly as it would for a standard login.
Connecting to bandit18 with a remote command attached to bypass the hostile .bashrc.
After entering the password, SSH executed cat readme remotely and began streaming the output back to the terminal instead of dropping into an interactive shell. The connection closed automatically once the command finished running, which is expected behaviour for a non-interactive SSH command.
Commands Used
# Standard interactive login — this triggers the hostile .bashrc and gets logged out immediately
ssh bandit18@bandit.labs.overthewire.org -p 2220
# Workaround: attach a remote command directly to the SSH connection
ssh bandit18@bandit.labs.overthewire.org -p 2220 cat readme# Standard interactive login — this triggers the hostile .bashrc and gets logged out immediately
ssh bandit18@bandit.labs.overthewire.org -p 2220
# Workaround: attach a remote command directly to the SSH connection
ssh bandit18@bandit.labs.overthewire.org -p 2220 cat readmeCommand Breakdown
ssh bandit18@bandit.labs.overthewire.org -p 2220 cat readme Everything after the port flag is treated by SSH as a remote command to execute on the server rather than a request for an interactive shell. SSH connects, authenticates, runs cat readme in a non-interactive context and streams the output back before closing the connection.
Non-interactive vs interactive shells An interactive login shell is what starts when you SSH in normally and land at a prompt. It reads startup files like .bashrc as part of initializing that interactive environment. A non-interactive command execution, where SSH is given a specific command to run, does not need to fully initialize an interactive shell environment in the same way, which is why it can avoid triggering a .bashrc modification designed to act on login.
cat readme The actual command being executed remotely. It reads the readme file in the home directory exactly the same way it would if typed manually inside an interactive session. The difference is entirely in how the command gets executed, not what it does.
Lesson Learned
The main technical takeaway is that SSH offers more than one way to interact with a remote system. Most people only ever use it to open an interactive shell. But SSH was designed from the start to also support running a single specific command remotely without ever needing an interactive session. That capability is exactly what bypasses a .bashrc configured to act against an interactive login.
What stood out about this level is that nothing about the actual file system or password retrieval changed from Day 1. The lesson is entirely about the delivery mechanism. The same readme file, the same cat command, executed through a different invocation of SSH that avoids the trap entirely.
This is also a useful reminder that shell startup files are powerful and can be weaponised. .bashrc, .bash_profile and .profile all execute automatically under certain login conditions. A modification to any of them can silently alter or sabotage a user's session before they ever see a prompt.
ssh user@host command— run a single command remotely without an interactive shellssh user@host -p PORT command— same as above with a custom port specifiedcat ~/.bashrc— inspect bash startup file content for unexpected modificationsssh user@host bash --noprofile --norc— start a shell while skipping startup file executionscp— transfer files without needing an interactive shell at all
🔴 SOC Analyst Insight
Modified shell startup files are a known persistence and sabotage technique on compromised Linux systems. An attacker with access to a user account can append malicious commands to .bashrc, .bash_profile or .profile so that every future login silently executes their payload, exfiltrates data or, in a denial-of-service scenario, simply locks the legitimate user out. Recognising that a user cannot get a stable interactive session is itself a signal worth investigating.
# Read a user's shell startup files without triggering them by executing cat remotely
ssh -i recovery.key admin@compromised-host "cat /home/victim/.bashrc"# Read a user's shell startup files without triggering them by executing cat remotely
ssh -i recovery.key admin@compromised-host "cat /home/victim/.bashrc"The command above demonstrates the exact same principle from this level applied defensively. Running a remote command directly through SSH allows an incident responder to inspect a potentially sabotaged startup file without ever triggering its execution, which would happen automatically in a normal interactive login. That is a critical distinction during a live incident where triggering a malicious script accidentally could escalate the situation further.
Key Takeaway
SSH is not limited to opening an interactive shell. It can execute a single remote command non-interactively, and that capability is precisely what makes it possible to retrieve information from a system even when something is actively working to prevent a normal login session. Understanding the distinction between interactive and non-interactive execution is a small piece of knowledge with an outsized payoff: it turns a hostile, sabotaged login into a non-issue with one alternate command structure.
30-Day Cybersecurity Learning Journey — Progress
🟢 Open Day — Setup & Series Introduction | OverTheWire Bandit
✅ Day 0. — Bandit Level 0 | First Login
✅ Day 1. — Bandit Level 1 → 2 | Special Characters
✅ Day 2. — Bandit Level 2 → 3 | Spaces in Filenames
✅ Day 3. — Bandit Level 3 → 4 | Hidden Files
✅ Day 4. — Bandit Level 4 → 5 | File Types
✅ Day 5. — Bandit Level 5 → 6 | find with Properties
✅ Day 6. — Bandit Level 6 → 7 | find across Filesystem
✅ Day 7. — Bandit Level 7 → 8 | grep
✅ Day 8. — Bandit Level 8 → 9 | sort and uniq
✅ Day 9. — Bandit Level 9 → 10 | strings and grep
✅ Day 10. — Bandit Level 10 → 11 | base64
✅ Day 11. — Bandit Level 11 → 12 | ROT13 and tr
✅ Day 12. — Bandit Level 12 → 13 | hexdump and compression
✅ Day 13. — Bandit Level 13 → 14 | SSH keys
✅ Day 14. — Bandit Level 14 → 15 | Netcat
✅ Day 15. — Bandit Level 15 → 16 | SSL and OpenSSL
✅ Day 16. — Bandit Level 16 → 17 | Port Scanning
✅ Day 17. — Bandit Level 17 → 18 | diff
✅ Day 18. — Bandit Level 18 → 19 | SSH command execution ← today
⬜ Day 19. — Bandit Level 19 → 20 | coming next🟢 Open Day — Setup & Series Introduction | OverTheWire Bandit
✅ Day 0. — Bandit Level 0 | First Login
✅ Day 1. — Bandit Level 1 → 2 | Special Characters
✅ Day 2. — Bandit Level 2 → 3 | Spaces in Filenames
✅ Day 3. — Bandit Level 3 → 4 | Hidden Files
✅ Day 4. — Bandit Level 4 → 5 | File Types
✅ Day 5. — Bandit Level 5 → 6 | find with Properties
✅ Day 6. — Bandit Level 6 → 7 | find across Filesystem
✅ Day 7. — Bandit Level 7 → 8 | grep
✅ Day 8. — Bandit Level 8 → 9 | sort and uniq
✅ Day 9. — Bandit Level 9 → 10 | strings and grep
✅ Day 10. — Bandit Level 10 → 11 | base64
✅ Day 11. — Bandit Level 11 → 12 | ROT13 and tr
✅ Day 12. — Bandit Level 12 → 13 | hexdump and compression
✅ Day 13. — Bandit Level 13 → 14 | SSH keys
✅ Day 14. — Bandit Level 14 → 15 | Netcat
✅ Day 15. — Bandit Level 15 → 16 | SSL and OpenSSL
✅ Day 16. — Bandit Level 16 → 17 | Port Scanning
✅ Day 17. — Bandit Level 17 → 18 | diff
✅ Day 18. — Bandit Level 18 → 19 | SSH command execution ← today
⬜ Day 19. — Bandit Level 19 → 20 | coming nextFollow along with the series as I document each level, command and lesson learned.
A locked door is not a wall. SSH always has another way in if you know where to look.