OverTheWire Natas Walkthrough: Levels 0 to 34 (Beginner-Friendly Web Security Guide)
OverTheWire Natas Walkthrough: Levels 0 to 34 (Beginner-Friendly Web Security Guide)
Natas is OverTheWire's web-security wargame. There's no SSH here — just a browser, your DevTools, and curl. Each level is a small website with a flaw, and your job is to exploit it to recover the next level's password. It's the perfect way to learn how real web vulnerabilities work in a safe, legal sandbox.
This guide walks you through all 34 levels, explaining the idea behind each one before showing the fix.
Passwords are reused across the game, so this guide focuses on the method, not the passwords.
<pass>means "the password you currently hold."
URL pattern: http://natasX.natas.labs.overthewire.org
Login: username natasX, password <pass> (natas0's password is natas0).
Tools you'll use: browser DevTools (F12), View Source (Ctrl+U), and curl.
Natas 0 — View Source
The very first lesson: never trust that "hidden" page content is actually hidden. The password sits in a plain HTML comment.
Takeaway: Anything sent to the browser — comments, hidden fields, scripts — is fully visible to the user.
Natas 1 — Right-Click Blocked
This level disables right-click with JavaScript to "protect" the source. But blocking the menu doesn't block the source — keyboard shortcuts and DevTools still work.
Takeaway: Client-side restrictions are cosmetic. They never provide real security.
Natas 2 — A Hidden Directory
The page looks empty, but the source loads a 1×1 pixel image from a /files/ folder. If that folder allows directory listing, you can browse everything in it.
Takeaway: Leftover files and open directories leak data. Disable directory listing.
Natas 3 — robots.txt
The source comment jokes that "not even Google" will find it — a direct hint toward robots.txt, the file that tells search engines what to skip. People often hide "secret" folders there, which ironically advertises them.
Takeaway: robots.txt hides things from crawlers, not from attackers.
Natas 4 — Referer Header
The page says it only allows visitors coming "from natas5." It checks the Referer header — which the client controls and can fake.
Takeaway: Headers are user-supplied. Never use them for access control.
Natas 5 — Cookie Tampering
You're told you're "not logged in." A cookie named loggedin is set to 0. Since cookies live in your browser, you can simply change it to 1.
Takeaway: Cookies are editable by the user. Authentication state must be verified server-side.
Natas 6 — Include File Leak
The form asks for a secret it compares server-side. That secret is stored in an include file you can read directly in the browser.
Takeaway: Files inside the web root can be requested directly — keep secrets out of it.
Natas 7 — Local File Inclusion (LFI)
Links use index.php?page=home. The page value is fed straight into a file include with no validation, so you can point it at any file on the server.
Takeaway: Never pass user input directly to file functions. Whitelist allowed pages.
Natas 8 — Reverse the Encoding
The source reveals how the secret is stored: bin2hex(strrev(base64_encode(secret))). Encoding isn't encryption — if you know the steps, you just run them backwards.
Submit the decoded result in the form.
Takeaway: Encoding (hex, base64) hides nothing. It's reversible by design.
Natas 9 — Command Injection
Your search term is dropped straight into a shell grep command. By adding a ; you can run a second command of your choice.
Takeaway: Building shell commands from user input lets attackers run their own commands.
Natas 10 — Filtered Command Injection
Same flaw, but now ; | & are blocked. You can't add a new command — so instead, abuse the existing grep by giving it extra files to search.
grep now matches everything (.*) inside the password file and prints it.
Takeaway: Blacklists leak. The safe fix is to avoid shells entirely or escape input properly.
Natas 11 — XOR-Encrypted Cookie
Your settings cookie is JSON that's been XOR-encrypted with a secret key and base64-encoded. Because you already know the original JSON, XORing it against the cookie reveals the key — then you can forge any cookie you like.
Takeaway: XOR with a fixed key is trivially broken when part of the plaintext is known.
Natas 12 — Unrestricted File Upload
The upload form pretends you can only send a .jpg, but the extension is set in a hidden field you control. Upload a PHP script and the server will happily execute it.
Intercept the upload, change the filename to .php, then open the uploaded file in your browser.
Takeaway: Validate uploads on the server, and never let the user choose the saved extension.
Natas 13 — Bypassing the Image Check
This time the server checks that your file is a real image using its magic bytes. Just prepend a valid JPEG header to your PHP shell — it passes the check but still runs as code.
Upload it, rename to .php, open it.
Takeaway: File-type checks based on content can be spoofed. Store uploads outside the web root.
Natas 14 — SQL Injection (Login Bypass)
The login query inserts your input directly into SQL. By closing the quote and adding OR "1"="1, the condition is always true, so the login succeeds.
Takeaway: Always use parameterised queries — never glue user input into SQL.
Natas 15 — Blind SQL Injection
Here the page only tells you whether a user exists — no data is returned. You exploit this by guessing the password one character at a time and watching for "user exists."
Loop through each character and position with a script until the full password is built.
Takeaway: Even a yes/no response leaks data, one bit at a time.
Natas 16 — Filtered Command Injection (Advanced)
Input is wrapped in quotes and several symbols are filtered, but $( ) command substitution still works. You run an inner command whose output changes the search result — letting you confirm each character.
If the first character is a, the inner grep returns the password, so the outer search for "doom…" finds nothing. Wrong guess → "doom" still appears. Script it character by character.
Takeaway: Even tightly filtered shells often leave one injection path open.
Natas 17 — Time-Based Blind SQL Injection
Now there's no visible feedback at all. The trick: make the database pause with SLEEP() when your guess is correct, and time the response.
A slow reply = correct guess. Automate the timing checks.
Takeaway: Response time is a side channel — it leaks data even with no output.
Natas 18 — Session ID Brute Force
Admins get a session ID somewhere between 1 and 640. Since the range is tiny, you can simply try every value until one is recognised as admin.
Takeaway: Session IDs must be long and random — never small sequential numbers.
Natas 19 — Semi-Predictable Sessions
This time IDs aren't plain numbers — they're the hex encoding of "<number>-<username>". Once you spot the pattern, you brute-force <n>-admin instead.
Takeaway: "Encoded" is not "random." Predictable patterns are still brute-forceable.
Natas 20 — Session Injection via Newline
The app saves your profile into a session file as key value lines. By sneaking a newline into your name, you write an extra line: admin 1.
Takeaway: Sanitise input before writing it to structured storage — newline injection is real.
Natas 21 — Shared Session Across Sites
A sister site on another port shares natas21's session and blindly copies any POST field into it. Send admin=1 there, grab the session cookie, then reuse it on the main site.
Takeaway: Sites that share sessions inherit each other's weaknesses.
Natas 22 — Forced Redirect
The page redirects you away before the secret renders — but the secret is still in the response body. Add ?revelio=1 and tell curl not to follow the redirect.
Takeaway: A redirect doesn't erase content already sent. Stop processing before output.
Natas 23 — PHP Loose Comparison
The check wants the input to both contain "iloveyou" and be "greater than 10." In PHP, a string that starts with a number is read as that number in comparisons — so one clever value passes both tests.
Takeaway: PHP's loose == and numeric string casting cause surprising bypasses.
Natas 24 — strcmp Bypass
The password check uses strcmp(). In older PHP, comparing a string to an array returns NULL, which loosely equals 0 — i.e. "they match."
Takeaway: Type confusion breaks comparisons. Validate input types first.
Natas 25 — LFI + Log Poisoning
The lang parameter includes files; ../ is filtered but bypassable. The trick: write PHP into a value the server logs (your User-Agent), then include that log file so your code runs.
Takeaway: Anything the server logs can become executable code if logs are includable.
Natas 26 — PHP Object Injection
A drawing cookie is passed straight into unserialize(). You craft a malicious Logger object whose "log file" is a .php path in the web root and whose content is a shell — then visit it.
Takeaway: Never unserialize() untrusted input — it can create arbitrary objects.
Natas 27 — SQL Truncation
Usernames have a fixed length in the database. By registering natas28 followed by spaces (and a trailing char), MySQL trims it back to natas28, colliding with the real account and handing you its stored password.
Takeaway: Silent string truncation lets attackers impersonate existing users.
Natas 28 — ECB Block Reordering
The search box encrypts your query into a base64 token using ECB mode, where identical input blocks produce identical output blocks. By controlling input and rearranging 16-byte blocks, you splice in your own SQL.
Takeaway: ECB mode leaks structure. Use authenticated encryption (e.g. AES-GCM).
Natas 29 — Perl open() Injection
The file parameter reaches Perl's two-argument open, which treats a trailing | as "run this as a command." The word "natas" is filtered, so you split it to slip past.
Takeaway: Perl's 2-arg open is dangerous with user input — use the 3-arg form.
Natas 30 — Perl DBI Array Injection
Sending parameters as arrays confuses Perl's database quoting, reopening classic SQL injection on the login.
Takeaway: Unexpected input shapes (arrays vs strings) break naive sanitisation.
Natas 31 — Perl CGI + ARGV
Combining a multipart upload with Perl's special ARGV handling lets you make open read any file you name.
Takeaway: Framework "magic" features (like ARGV) can become file-read primitives.
Natas 32 — Perl Command Execution
The same ARGV technique is escalated from reading files to executing a helper binary that prints the next password.
Takeaway: A file-read bug often becomes code execution with a little creativity.
Natas 33 — Upload + Phar/Hash Check
The uploader validates a file's size and hash before running a job. Bypass that check — for example via phar deserialization or by matching the expected hash — to get your payload executed.
Takeaway: Validation logic itself can be the vulnerability if it's bypassable.
Natas 34 — The End
🎉 All 34 levels done. You've now seen the core of how web apps get broken — and, just as importantly, how to defend them.
What You Practised
| Category | Levels |
|---|---|
| Source, files & robots.txt | 0–3 |
| Headers & cookies | 4, 5, 11 |
| LFI & encoding | 7, 8, 25 |
| Command injection | 9, 10, 16, 29, 32 |
| File-upload shells | 12, 13, 33 |
| SQL injection | 14–17, 27, 28, 30, 31 |
| Sessions & object injection | 18–21, 26 |
| PHP logic flaws | 6, 22, 23, 24 |
Defender's Cheat Sheet
The flaws above map to a handful of golden rules:
- Never trust the client — headers, cookies, hidden fields, and form values are all editable.
- Parameterise every query — keep user input out of SQL and shell commands.
- Validate uploads server-side and store them outside the web root.
- Use long, random session IDs and never expose internal logic in them.
- Avoid
unserialize()on untrusted data and prefer modern, authenticated crypto.
For educational use only. OverTheWire wargames are built for safe, legal, hands-on learning — never test these techniques on systems you don't own or have explicit permission to test.
Tags
Keep Reading