Example #1
0
def get_vnc_screenshots(target, scan_id, proctimeout):

    scan_dir = utils.get_scan_dir(scan_id)
    output_file = os.path.join(scan_dir, f"vncsnapshot.{scan_id}.jpg")

    logger.info(f"Attempting to take VNC screenshot for {target}")

    vncsnapshot_args = [
        "xvfb-run",
        "vncsnapshot",
        "-quality",
        "50",
        target,
        output_file,
    ]

    process = subprocess.Popen(vncsnapshot_args,
                               stdout=subprocess.DEVNULL,
                               stderr=subprocess.DEVNULL)  # nosec
    try:
        process.communicate(timeout=proctimeout)
    except subprocess.TimeoutExpired:
        logger.warning(f"TIMEOUT: Killing vncsnapshot against {target}")
        process.kill()

    if not is_valid_image(output_file):
        return {}

    logger.info(f"VNC screenshot acquired for {target} on port 5900")
    return {
        "host": target,
        "port": 5900,
        "service": "VNC",
        "data": base64_file(output_file),
    }
Example #2
0
def get_web_screenshots(target, scan_id, proctimeout):
    scan_dir = utils.get_scan_dir(scan_id)
    xml_file = os.path.join(scan_dir, f"nmap.{scan_id}.xml")
    output_dir = os.path.join(scan_dir, f"aquatone.{scan_id}")
    logger.info(f"Attempting to take screenshots for {target}")

    aquatoneArgs = [
        "aquatone", "-nmap", "-scan-timeout", "2500", "-out", output_dir
    ]
    with open(xml_file, "r") as f:
        process = subprocess.Popen(aquatoneArgs,
                                   stdin=f,
                                   stdout=subprocess.DEVNULL)  # nosec

    try:
        process.communicate(timeout=proctimeout)
        if process.returncode == 0:
            time.sleep(
                0.5
            )  # a small sleep to make sure all file handles are closed so that the agent can read them
    except subprocess.TimeoutExpired:
        logger.warning(f"TIMEOUT: Killing aquatone against {target}")
        process.kill()

    return parse_aquatone_session(output_dir)
Example #3
0
def get_vnc_screenshots(target, scan_id, proctimeout):

    scan_dir = utils.get_scan_dir(scan_id)
    outFile = os.path.join(scan_dir, f"vncsnapshot.{scan_id}.jpg")

    logger.info(f"Attempting to take VNC screenshot for {target}")

    process = subprocess.Popen(
        ["xvfb-run", "vncsnapshot", "-quality", "50", target, outFile],
        stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL,
    )  # nosec
    try:
        process.communicate(timeout=proctimeout)
        if process.returncode == 0:
            return True
    except Exception:
        try:
            logger.warning(f"TIMEOUT: Killing vncsnapshot against {target}")
            process.kill()
            return False
        except Exception:
            pass

    return False
Example #4
0
def command_builder(scan_id, agentConfig, target):
    outFiles = os.path.join(utils.get_scan_dir(scan_id), f"nmap.{scan_id}")
    servicepath = utils.get_services_path()
    command = [
        "nmap", "--privileged", "-oA", outFiles, "--servicedb", servicepath
    ]

    commandDict = {
        "versionDetection": "-sV",
        "osDetection": "-O",
        "osScanLimit": "--osscan-limit",
        "noPing": "-Pn",
        "onlyOpens": "--open",
        "udpScan": "-sUS",
        "enableScripts": "--script={scripts}",
        "scriptTimeout": "--script-timeout={scriptTimeout}",
        "hostTimeout": "--host-timeout={hostTimeout}",
    }

    for k, v in agentConfig.items():
        if agentConfig[k] and k in commandDict:
            command.append(commandDict[k].format(**agentConfig))
    if ipaddress.ip_network(target).version == 6:
        command.append("-6")
    command.append(target)
    return command
Example #5
0
def get_web_screenshots(target, scan_id, xml_data, proctimeout):
    scan_dir = utils.get_scan_dir(scan_id)
    outFiles = os.path.join(scan_dir, f"aquatone.{scan_id}")
    output = []
    logger.info(f"Attempting to take screenshots for {target}")

    p1 = subprocess.Popen(["echo", xml_data], stdout=subprocess.PIPE)  # nosec
    aquatoneArgs = [
        "aquatone", "-nmap", "-scan-timeout", "2500", "-out", outFiles
    ]
    process = subprocess.Popen(aquatoneArgs,
                               stdin=p1.stdout,
                               stdout=subprocess.DEVNULL)  # nosec
    p1.stdout.close()

    try:
        process.communicate(timeout=proctimeout)
        if process.returncode == 0:
            time.sleep(
                0.5
            )  # a small sleep to make sure all file handles are closed so that the agent can read them
    except subprocess.TimeoutExpired:
        logger.warning(f"TIMEOUT: Killing aquatone against {target}")
        process.kill()

    session_path = os.path.join(outFiles, "aquatone_session.json")
    if not os.path.isfile(session_path):
        return output

    with open(session_path) as f:
        session = json.load(f)

    if session["stats"]["screenshotSuccessful"] > 0:
        logger.info(
            f"{target} - Success: {session['stats']['screenshotSuccessful']}, Fail: {session['stats']['screenshotFailed']}"
        )

        for k, page in session["pages"].items():
            fqScreenshotPath = os.path.join(outFiles, page["screenshotPath"])
            if page["hasScreenshot"] and os.path.isfile(fqScreenshotPath):
                urlp = urlparse(page["url"])
                if not urlp.port and urlp.scheme == "http":
                    port = 80
                elif not urlp.port and urlp.scheme == "https":
                    port = 443
                else:
                    port = urlp.port
                logger.info(
                    f"{urlp.scheme.upper()} screenshot acquired for {page['hostname']} on port {port}"
                )
                output.append({
                    "host": page["hostname"],
                    "port": port,
                    "service": urlp.scheme.upper(),
                    "data": base64_image(fqScreenshotPath),
                })
    return output
Example #6
0
def scan(target_data, config):

    if not utils.validate_target(target_data["target"], config):
        return False

    target = target_data["target"]
    scan_id = target_data["scan_id"]

    agentConfig = target_data["agent_config"]

    command = command_builder(scan_id, agentConfig, target)
    scan_dir = utils.get_scan_dir(scan_id)

    result = ScanResult(target_data, config)

    try:
        subprocess.run(
            command,
            stdout=subprocess.PIPE,
            stderr=subprocess.DEVNULL,
            timeout=int(agentConfig["scanTimeout"]),
        )  # nosec
    except subprocess.TimeoutExpired:
        result.add_item("timed_out", True)
        logger.warning(f"TIMEOUT: Nmap against {target} ({scan_id})")
        return result

    logger.info(f"Nmap {target} ({scan_id}) complete")

    for ext in "nmap", "gnmap", "xml":
        path = os.path.join(scan_dir, f"nmap.{scan_id}.{ext}")
        try:
            with open(path, "r") as f:
                result.add_item(ext + "_data", f.read())
        except Exception:
            logger.warning(f"Couldn't read {path}")
            return False

    try:
        nmap_report = NmapParser.parse(result.result["xml_data"])
    except NmapParserException:
        logger.warning(f"Couldn't parse nmap.{scan_id}.xml")
        return False

    if nmap_report.hosts_total < 1:
        logger.warning(f"No hosts found in nmap.{scan_id}.xml")
        return False
    elif nmap_report.hosts_total > 1:
        logger.warning(f"Too many hosts found in nmap.{scan_id}.xml")
        return False
    elif nmap_report.hosts_down == 1:
        # host is down
        result.is_up(False)
        return result
    elif nmap_report.hosts_up == 1 and len(nmap_report.hosts) == 0:
        # host is up but no reportable ports were found
        result.is_up(True)
        result.add_item("port_count", 0)
        return result
    else:
        # host is up and reportable ports were found
        result.is_up(nmap_report.hosts[0].is_up())
        result.add_item("port_count", len(nmap_report.hosts[0].get_ports()))

    if agentConfig["webScreenshots"] and shutil.which("aquatone") is not None:
        screens = screenshots.get_web_screenshots(
            target,
            scan_id,
            result.result["xml_data"],
            agentConfig["webScreenshotTimeout"],
        )
        for item in screens:
            result.add_screenshot(item)

    if (agentConfig["vncScreenshots"]
            and "5900/tcp" in result.result["nmap_data"]
            and screenshots.get_vnc_screenshots(
                target, scan_id, agentConfig["vncScreenshotTimeout"])):

        screenshotPath = os.path.join(scan_dir, f"vncsnapshot.{scan_id}.jpg")
        if os.path.isfile(screenshotPath):
            result.add_screenshot({
                "host":
                target,
                "port":
                5900,
                "service":
                "VNC",
                "data":
                screenshots.base64_image(screenshotPath),
            })
            logger.info(f"VNC screenshot acquired for {result.result['ip']}")

    # submit result

    return result
Example #7
0
def scan(target_data, config):

    if not utils.validate_target(target_data["target"], config):
        return False
    target = target_data["target"]
    scan_id = target_data["scan_id"]

    agentConfig = target_data["agent_config"]

    command = command_builder(scan_id, agentConfig, target)
    scan_dir = utils.get_scan_dir(scan_id)

    result = ScanResult(target_data, config)

    try:
        subprocess.run(
            command,
            stdout=subprocess.PIPE,
            stderr=subprocess.DEVNULL,
            timeout=int(agentConfig["scanTimeout"]),
        )  # nosec
    except subprocess.TimeoutExpired:
        add_breadcrumb(level="warn", message="Nmap scan timed out")
        result.add_item("timed_out", True)
        logger.warning(f"TIMEOUT: Nmap against {target} ({scan_id})")
        return result
    logger.info(f"Nmap {target} ({scan_id}) complete")

    for ext in "nmap", "gnmap", "xml":
        path = os.path.join(scan_dir, f"nmap.{scan_id}.{ext}")
        try:
            with open(path, "r") as f:
                result.add_item(ext + "_data", f.read())
        except Exception:
            logger.warning(f"Couldn't read {path}")
            return False
    try:
        nmap_report = NmapParser.parse(result.result["xml_data"])
    except NmapParserException:
        logger.warning(f"Couldn't parse nmap.{scan_id}.xml")
        return False
    if nmap_report.hosts_total < 1:
        logger.warning(f"No hosts found in nmap.{scan_id}.xml")
        return False
    elif nmap_report.hosts_total > 1:
        logger.warning(f"Too many hosts found in nmap.{scan_id}.xml")
        return False
    elif nmap_report.hosts_down == 1:
        # host is down
        result.is_up(False)
        return result
    elif nmap_report.hosts_up == 1 and len(nmap_report.hosts) == 0:
        # host is up but no reportable ports were found
        result.is_up(True)
        result.add_item("port_count", 0)
        return result
    else:
        # host is up and reportable ports were found
        result.is_up(nmap_report.hosts[0].is_up())
        result.add_item("port_count", len(nmap_report.hosts[0].get_ports()))
    if agentConfig["webScreenshots"]:
        screens = screenshots.get_web_screenshots(
            target, scan_id, agentConfig["webScreenshotTimeout"])
        for item in screens:
            result.add_screenshot(item)
    if agentConfig["vncScreenshots"] and "5900/tcp" in result.result[
            "nmap_data"]:
        vnc_screenshot = screenshots.get_vnc_screenshots(
            target, scan_id, agentConfig["vncScreenshotTimeout"])
        if vnc_screenshot:
            result.add_screenshot(vnc_screenshot)
    # submit result

    return result