TL;DR

The application exposes a URL fetcher that attempts to force http URLs, and an upload endpoint that superficially checks MIME and filename. Using file:// and php:// style paths we bypassed the http check (file:///http/../...) to read local files and source code. We discovered an upload endpoint that only checks the filename contains .png/.jpg/.jpeg and that mime_content_type() begins with image/. By embedding PHP inside a PNG and naming the file shell.png.php we uploaded a webshell. The fetcher can read files via file:///http/../..., so we triggered the uploaded shell through the fetcher to achieve remote code execution even though system and common exec functions were disabled.

Initial view

Visiting the challenge page shows a single input asking for an image URL to fetch.

Screenshot: Fetched image UI.

image.png

A normal request like:

GET /?url=http://google.com

works and returns fetched HTML.

image.png

Local file read via file:// and bypassing http check

I tried fetching local files using file:///etc/passwd and received the file contents.

Payload:

?url=file:///etc/passwd

image.png

To bypass the server-side check that insists on 'http' being present in the URL, I used:

?url=file:///http/../etc/passwd

stripos($url, 'http') === false is used by the app as a guard; the crafted path contains the literal sequence http while still resolving to the local file due to file:///http/../etc/passwd/etc/passwd. This returned /etc/passwd contents.

image.png

Using the same technique I retrieved application files: