HackBlue

Labs / Web and API security

File upload validation

Nine uploads hit a profile picture endpoint: two real photos and seven files that should never be stored as sent. Turn on checks until every one is handled.

  • Interactive lab
  • Intermediate
  • 5 steps
  • 0 of 5 solved

Goal

The profile picture endpoint accepts anything today and saves it in the public folder under the name the client sent. A test suite of nine uploads is ready: two real photos and seven files that should never be stored as they are.

Turn checks on and off and watch what the server would store. Nothing is uploaded or executed; each row is a description of a file and the decision the server makes about it.

Server checks, in order

Upload test suite7 wrong
FileClaimedFirst bytesSizeServer
avatar.pngA real photoimage/png89 50 4e 47 0d 0a 1a 0a182 kBaccepted
Stored as an image.
Holiday Photo.JPGA real photoimage/jpegff d8 ff e0 00 10 4a 462.3 MBaccepted
Stored as an image.
shell.phpContains server-side scriptimage/png3c 3f 70 68 70 20 2f 2f1 kBdangerous
Stored in the web root with its own name, where the server may run it as PHP.
avatar.php.pngContains server-side scriptimage/png3c 3f 70 68 70 20 2f 2f1 kBdangerous
Stored in the web root with its own name, where the server may run it as PHP.
badge.jpgContains script text hidden in a JPEG comment segmentimage/jpegff d8 ff fe 00 2c 3c 3f48 kBdangerous
Stored in the web root with its own name, where the server may run it as PHP.
logo.svgContains an inline <script> elementimage/svg+xml3c 73 76 67 20 78 6d 6c3 kBdangerous
Served with a type the browser can sniff as a page, so the script runs on your origin.
../../static/js/app.pngContains a path that climbs out of the upload folderimage/png89 50 4e 47 0d 0a 1a 0a40 kBdangerous
Stored at the client’s path, overwriting /static/js/app.png.
scan.pngContains a 96 MB file meant to exhaust disk and decoder memoryimage/png89 50 4e 47 0d 0a 1a 0a96 MBdangerous
Stored a 96 MB file; repeated uploads fill the disk and stall the thumbnailer.
profile.pngContains an HTML page saved with a .png nameimage/png3c 21 64 6f 63 74 79 702 kBdangerous
Served with a type the browser can sniff as a page, so the script runs on your origin.

Steps

  1. 01Turn on the checks that keep both real photos working and leave none of the seven bad uploads stored in a dangerous way.

    Do this in the workbench above. This step completes itself when the condition is met.

  2. 02Why does “Accept if the Content-Type header says image/*” stop nothing here?

  3. 03Which upload passes the extension and first-byte checks but still carries script? Give its filename.

  4. 04Why is SVG left off the allowlist for profile pictures?

  5. 05What does storing under a random name outside the web root prevent?