Пример #1
0
def command_builder(scan_id, agentConfig, target):
    outFiles = utils.get_data_dir(scan_id) + f"/nmap.{scan_id}"
    command = [
        "nmap", "--privileged", "-oA", outFiles, "--servicedb",
        "./tmp/natlas-services"
    ]

    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))

    command.append(target)
    return command
Пример #2
0
def get_vnc_screenshots(target, scan_id, proctimeout):
    if "DISPLAY" not in os.environ:
        return False

    data_dir = utils.get_data_dir(scan_id)
    outFile = f"{data_dir}/vncsnapshot.{scan_id}.jpg"

    logger.info("Attempting to take VNC screenshot for %s" % target)

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

    return False
Пример #3
0
def get_web_screenshots(target, scan_id, services, proctimeout):
    data_dir = utils.get_data_dir(scan_id)
    outFiles = f"{data_dir}/aquatone.{scan_id}"
    inputstring = ""
    for service in services:
        inputstring += service + "://" + target + "\n"

    if inputstring:
        inputstring = inputstring[:
                                  -1]  # trim trailing newline because otherwise chrome spits garbage into localhost for some reason

    logger.info("Attempting to take %s screenshot(s) for %s" %
                (', '.join(services).upper(), target))

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

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

    return False
Пример #4
0
def get_web_screenshots(target, scan_id, xml_data, proctimeout):
    data_dir = utils.get_data_dir(scan_id)
    outFiles = f"{data_dir}/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:
        out, err = 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
Пример #5
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)
    data_dir = utils.get_data_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("TIMEOUT: Nmap against %s (%s)" % (target, scan_id))
        return result

    logger.info("Nmap %s (%s) complete" % (target, scan_id))

    for ext in 'nmap', 'gnmap', 'xml':
        path = f"{data_dir}/nmap.{scan_id}.{ext}"
        try:
            result.add_item(ext + "_data", open(path).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 shutil.which(
            "vncsnapshot") is not None:
        if "5900/tcp" in result.result['nmap_data']:
            if screenshots.get_vnc_screenshots(
                    target, scan_id,
                    agentConfig["vncScreenshotTimeout"]) is True:

                screenshotPath = f"{data_dir}/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("VNC screenshot acquired for %s" %
                                result.result['ip'])

    # submit result

    return result
Пример #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)
    data_dir = utils.get_data_dir(scan_id)

    result = ScanResult(target_data, config)

    try:
        process = 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("TIMEOUT: Nmap against %s (%s)" % (target, scan_id))
        return result

    logger.info("Nmap %s (%s) complete" % (target, scan_id))

    for ext in 'nmap', 'gnmap', 'xml':
        path = f"{data_dir}/nmap.{scan_id}.{ext}"
        try:
            result.add_item(ext + "_data", open(path).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:
        targetServices = []
        if "80/tcp" in result.result['nmap_data']:
            targetServices.append("http")
        if "443/tcp" in result.result['nmap_data']:
            targetServices.append("https")
        if len(targetServices) > 0:
            screenshots.get_web_screenshots(
                target, scan_id, targetServices,
                agentConfig["webScreenshotTimeout"])

        serviceMapping = {"http": 80, "https": 443}
        for service in targetServices:
            screenshotPath = f"{data_dir}/aquatone.{scan_id}/screenshots/{service}__{target.replace('.','_')}.png"
            # "data/aquatone." + scan_id + "/screenshots/" + service + "__" + target.replace('.', '_') + ".png"

            if not os.path.isfile(screenshotPath):
                continue

            result.add_screenshot({
                "host":
                target,
                "port":
                serviceMapping[service],
                "service":
                service.upper(),
                "data":
                str(base64.b64encode(open(screenshotPath, 'rb').read()))[2:-1]
            })
            logger.info("%s screenshot acquired for %s" %
                        (service.upper(), target))

    if agentConfig["vncScreenshots"] and shutil.which(
            "vncsnapshot") is not None:
        if "5900/tcp" in result.result['nmap_data']:
            if screenshots.get_vnc_screenshots(
                    target, scan_id,
                    agentConfig["vncScreenshotTimeout"]) is True:

                screenshotPath = f"{data_dir}/vncsnapshot.{scan_id}.jpg"
                if os.path.isfile(screenshotPath):
                    result.add_screenshot({
                        "host":
                        target,
                        "port":
                        5900,
                        "service":
                        "VNC",
                        "data":
                        str(base64.b64encode(
                            open(screenshotPath, 'rb').read()))[2:-1]
                    })
                    logger.info("VNC screenshot acquired for %s" %
                                result.result['ip'])

    # submit result

    return result