The Image Upload That Must Not Break Production
You have low-privilege credentials to a .NET procurement portal used by 2,000 suppliers. The client allows exploitation during a four-hour window but forbids denial-of-service and any change to production data. The profile-photo upload enforces a 5 MB limit and a client-side extension allowlist; the server returns JSON and stores files under /uploads/.jpg. A separate /api/import endpoint accepts multipart ZIP archives and invokes ImageMagick 6.9.11-60. You also notice /api/export?template=invoice reflecting a 'format' parameter into a PDF renderer. Both endpoints require a valid session. The portal sits behind a WAF that blocks obvious traversal strings. The change freeze begins in six hours, and the client wants proof of impact, not a shell. You have Burp Suite and a canary account. Tests that create files must be cleaned up, and any crash would page the on-call team.
1. Which endpoint do you test first for proof of impact, and what safe validation steps do you take?
Read the worked answer
Test /api/export first, because it is a read-only rendering path and less likely to crash the service. Send a canary string in the format parameter and observe whether it is reflected literally, HTML-encoded, or evaluated. Use a benign arithmetic expression plus a unique DNS canary; do not send a full template payload that could loop or allocate heavily. If the renderer evaluates, escalate one step at a time and capture the exact response. Only then move to /api/import. For ImageMagick, do not throw a known weaponized SVG at production. Reproduce locally first: run the same ImageMagick version in a disposable container against a minimal file that references a harmless local file. If that works locally, replay the smallest payload against the canary upload and confirm with an out-of-band DNS callback, not a shell. This order respects the no-DoS constraint: export is observational, and import is validated locally before a single live request.
2. You get a 500 from ImageMagick with a stack trace. How do you determine whether it is exploitable or just malformed input, without crashing the service?
Read the worked answer
A 500 proves only that the input reached a parser. Separate parser error from code execution. (1) Reproduce with the same version and policy.xml in a local container; if the local process also 500s without a callback, it is a robustness bug, not RCE. (2) Read the stack trace for the delegate name (svg, msl, ephemeral) and compare it to ImageMagick's policy, which often disables those coders. (3) Send one request with an out-of-band DNS or HTTP canary in the payload; a callback proves the parser followed an external reference. (4) Check the version against the vendor's patch level; 6.9.11-60 is old, but the distribution may have backported fixes. Do not fuzz or send fork bombs. If local reproduction is not possible within the window, report it as a suspected parser vulnerability with the 500 and stack trace, not as confirmed RCE. That distinction matters for the client's risk decision.
3. What evidence do you capture for the report to prove impact while respecting the no-change constraint?
Read the worked answer
Capture the full HTTP request and response for each test, including timestamp, source IP, redacted session identifier, and the canary value. For the export path, save the rendered output and show the evaluated expression in the PDF. For the upload path, save the exact multipart body hash, the returned UUID, and the local reproduction log with the same ImageMagick version. Record the DNS callback timestamp and the authoritative server log if available. If you created a file, record its path, hash, and deletion command with the response, and add a cleanup attestation. Do not include actual sensitive file contents; use a harmless file such as /etc/hostname or a canary string. Finally, state what you did not do: no writes to production data, no shell, and no persistence. The client or QSA should be able to replay your steps from the evidence alone.