Details
| ID | SSL Labs |
|---|---|
| Provider | Qualys |
| Category | Vulnerability Management |
| From Version | 6.0.0 |
| Docker Image | demisto/python3:3.12.8.3296088 |
| Supported Modules | Agentix XSIAM |
README
Analyze a host or a URL.
Configure SSL Labs (Community Contribution) in Cortex
| Parameter | Description | Required |
|---|---|---|
| Registered Email Address | The registered email address that will be used to access SSL Labs. | False |
Commands
You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.
ssl-labs-register-email
Register for Scan API initiation and result fetching
Base Command
ssl-labs-register-email
Input
| Argument Name | Description | Required |
|---|---|---|
| firstName | Users First Name. | Required |
| lastName | Users Last Name. | Required |
| Users Email Address. Email services such as Gmail, Yahoo, or Hotmail are not allowed. | Required | |
| organization | Name of the organization using the service. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| SslLabs.Registation.message | string | Registration message response |
| SslLabs.Registation.status | string | Either success or failure |
ssl-labs-info
Check the availability of the SSL Labs servers, retrieve the engine and criteria version, and initialize the maximum number of concurrent assessments.
Base Command
ssl-labs-info
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| SslLabs.Info.criteriaVersion | string | Rating criteria version as a string (e.g., “2009f”) |
| SslLabs.Info.currentAssessments | number | The number of ongoing assessments submitted by this client. |
| SslLabs.Info.engineVersion | string | SSL Labs software version as a string (e.g., “2.2.0”) |
| SslLabs.Info.maxAssessments | number | The maximum number of concurrent assessments the client is allowed to initiate. |
| SslLabs.Info.newAssessmentCoolOff | number | The cool-off period after each new assessment, in milliseconds; you’re not allowed to submit a new assessment before the cool-off expires, otherwise you’ll get a 429. |
| SslLabs.Info.messages | string | A list of messages (strings). Messages can be public (sent to everyone) and private (sent only to the invoking client). Private messages are prefixed with “[Private]” |
ssl-labs-analyze
Invoke assessments.
Base Command
ssl-labs-analyze
Input
| Argument Name | Description | Required |
|---|---|---|
| host | Provide hostname or URL. | Required |
| publish | Set to on if assessment results needs to be published on the public results boards. Default: off. Possible values are: off, on. Default is off. | Optional |
| startNew | If on setting is enabled, a new assessment is started, even if there is a cached assessment in progress. However, if an assessment is in progress, its status is returned instead of starting a new assessment. Note: This parameter should only be used once to start a new assessment; any additional use may cause an assessment loop. Possible values are: off, on. Default is off. | Optional |
| fromCache | Delivers cached assessment reports if available. This parameter is intended for API consumers who do not wish to wait for assessment results and cannot be used simultaneously with the startNew parameter. Default: off. Possible values are: off, on. Default is off. | Optional |
| maxAge | Maximum report age in hours if retrieving from cache (fromCache parameter). | Optional |
| all | When the parameter is set to on, full information will be returned. When the parameter is set to done, full information will be returned only if the assessment is complete (status is READY or ERROR). Possible values are: off, on. Default is on. | Optional |
| ignoreMismatch | Ignores the mismatch if server certificate doesn’t match the assessment hostname and proceeds with assessments if set to on. Default: off Note: This parameter is ignored if a cached report is returned. Possible values are: off, on. Default is off. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| SslLabs.Analyze.host | string | Assessment host, which can be a hostname or an IP address |
| SslLabs.Analyze.port | number | Assessment port (e.g., 443) |
| SslLabs.Analyze.protocol | string | Protocol (e.g., HTTP) |
| SslLabs.Analyze.isPublic | boolean | true if this assessment is publicly available (listed on the SSL Labs assessment boards) |
| SslLabs.Analyze.status | string | Assessment status; possible values: DNS, ERROR, IN_PROGRESS, and READY. |
| SslLabs.Analyze.startTime | number | Assessment starting time, in milliseconds since 1970 |
| SslLabs.Analyze.testTime | number | Assessment completion time, in milliseconds since 1970 |
| SslLabs.Analyze.engineVersion | string | Assessment engine version (e.g., “2.2.0”) |
| SslLabs.Analyze.criteriaVersion | string | Grading criteria version (e.g., “2009l”) |
| SslLabs.Analyze.cacheExpiryTime | number | When will the assessment results expire from the cache (typically set only for assessment with errors; otherwise the results stay in the cache for as long as there’s sufficient room) |
| SslLabs.Analyze.certHostnames | unknown | The list of certificate hostnames collected from the certificates seen during assessment. The hostnames may not be valid. This field is available only if the server certificate doesn’t match the requested hostname. In that case, this field saves you some time as you don’t have to inspect the certificates yourself to find out what valid hostnames might be. |
| SslLabs.Analyze.endpoints | unknown | list of Endpoint objects |
| SslLabs.Analyze.certs | unknown | a list of Cert object, representing the chain certificates in the order in which they were retrieved from the server. |
Configuration parameters
email— Registered Email Address
Commands (3)
-
ssl-labs-analyzeInvoke assessments.
-
ssl-labs-infoCheck the availability of the SSL Labs servers, retrieve the engine and criteria version, and initialize the maximum number of concurrent assessments.
-
ssl-labs-register-emailRegister for Scan API initiation and result fetching.
import re import urllib3 from CommonServerPython import * # noqa: F401 # Disable insecure warnings urllib3.disable_warnings() class Client(BaseClient): def __init__(self, base_url: str, proxy: bool, verify: bool, headers: dict): """ Client to use. Overrides BaseClient. Args: base_url (str): URL to access when doing a http request. Webhook url. """ super().__init__(base_url=base_url, proxy=proxy, verify=verify, headers=headers) def register(self, first_name: str, last_name: str, email: str, org: str): """ Registers the user of the API Service. Args: first_name (str): The users first name used for registering to the API service last_name (str): The users last name used for registering to the API service email (str): The users email used for registering to the API service org (str): The organization registering to the API service """ json_data = {"firstName": first_name, "lastName": last_name, "email": email, "organization": org} res = self._http_request( method="POST", json_data=json_data, raise_on_status=True, url_suffix="/register", headers={"Content-Type": "application/json"}, ) demisto.info(f"Registration Sent. Response {res}") return res def info(self): """ Check the availability of the SSL Labs servers retrieve the engine and criteria version initialize the maximum number of concurrent assessments. Args: None """ res = self._http_request( method="GET", raise_on_status=True, url_suffix="/info", headers={"Content-Type": "application/json"} ) demisto.info(f"SSL Labs Info. Response {res}") return res def analyze( self, host: str, publish: Optional[str], start_new: Optional[str], from_cache: Optional[str], max_age: Optional[str], all_endpoints: Optional[str], ignore_mismatch: Optional[str], ): """ Initiate an assessment, or to retrieve the status of an assessment in progress or in the cache. It will return a single Host object on success. The Endpoint object embedded in the Host object will provide partial endpoint results. Args: client (Client): SSL Labs client to use. host (str): Hostname or URL to analyze. publish (str): Set to on if assessment results needs to be published on the public results boards. start_new (str): If on setting is enabled, a new assessment is started, even if there is a cached assessment in progress. However, if an assessment is in progress, its status is returned instead of starting a new assessment. Note: This parameter should only be used once to start a new assessment; any additional use may cause an assessment loop. from_cache (str): Delivers cached assessment reports if available. This parameter is intended for API consumers who do not wish to wait for assessment results and cannot be used simultaneouslywith the startNew parameter. max_age (str): Maximum report age in hours if retrieving from cache (fromCache parameter). all_endpoints (str): When the parameter is set to on, full information will be returned. When the parameter is set to done, full information will be returned only if the assessment is complete (status is READY or ERROR). ignore_mismatch (str): Ignores the mismatch if server certificate doesn't match the assessment hostname and proceeds with assessments if set to on. """ cmd = "ssl-labs-analyze" ScheduledCommand.raise_error_if_not_supported() polling_timeout = 600 interval_in_secs = 60 url_suffix = ( f"/analyze?host={host}&publish={publish}&startNew={start_new}" f"&fromCache={from_cache}&maxAge={max_age}&all={all_endpoints}" f"&ignoreMismatch={ignore_mismatch}" ) res = self._http_request(method="GET", raise_on_status=True, url_suffix=url_suffix) outputs = [] polling_args = { "host": host, "publish": publish, "start_new": start_new, "from_cache": from_cache, "max_age": max_age, "all_endpoints": all_endpoints, "ignore_mismatch": ignore_mismatch, "interval_in_seconds": interval_in_secs, "polling": True, } if res["status"] != "READY": status = res["status"] scheduled_command = ScheduledCommand( command=cmd, next_run_in_seconds=interval_in_secs, args=polling_args, timeout_in_seconds=polling_timeout ) command_results = CommandResults(scheduled_command=scheduled_command, readable_output=f"Scan Status: {status}") return command_results else: outputs.append( { "host": res.get("host"), "port": res.get("port"), "protocol": res.get("protocol"), "status": res.get("status"), "start_time": res.get("startTime"), "test_time": res.get("testTime"), } ) headers = ["host", "port", "protocol", "status", "start_time", "test_time"] return CommandResults( outputs_prefix="sslLabs.analysis", outputs=outputs, readable_output=tableToMarkdown("SSL Labs Analysis", outputs, headers, removeNull=True), raw_response=res, ) def is_valid(self, host: str): """ This regex checks for the basic components of a URL """ regex = re.compile( r"^(?:http|ftp)s?://" # http:// or https:// r"(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+" # subdomain r"(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|" # top-level domain r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})" # ...or ip r"(?::\d+)?" # optional port r"(?:/?|[/?]\S+)$", re.IGNORECASE, ) return re.match(regex, host) is not None def register_email_command(client: Client, first_name: str, last_name: str, email: str, org: str) -> CommandResults: """ SSLLabs has been available directly for all its users directly via UI and API to be consumed freely. It will remain the same with slight change with introduction to this new registration API. Now you need to register yourself with first name, last name, organization's name and organization's email. Args: client (Client): SSL Labs client to use. first_name (str): The users first name used for registering to the API service last_name (str): The users last name used for registering to the API service email (str): The users email used for registering to the API service org (str): The organization registering to the API service Returns: CommandResults/dict: A 'CommandResults' Compatible to return 'return_results()', which contains the readable_output indicating the message was sent. """ res = client.register(first_name, last_name, email, org) if res: result = {"message": res.get("message"), "status": res.get("status")} markdown = "### SSL Labs Registration\n" markdown += tableToMarkdown("Response", result) results = CommandResults( readable_output=markdown, outputs_prefix="SslLabs.Registation", outputs_key_field="name", outputs=result ) return results return CommandResults(entry_type=EntryType.ERROR, readable_output="Could not register email") def info_command(client: Client) -> CommandResults: """ This API request should be used to check the availability of the SSL Labs servers, retrieve the engine and criteria version, and initialize the maximum number of concurrent assessments. Args: client (Client): SSL Labs client to use. Returns: CommandResults/dict: A 'CommandResults' Compatible to return 'return_results()', which contains the readable_output indicating the message was sent. """ res = client.info() if res: result = { "engineVersion": res.get("engineVersion"), "criteriaVersion": res.get("criteriaVersion"), "maxAssessments": res.get("maxAssessments"), "currentAssessments": res.get("currentAssessments"), "newAssessmentCoolOff": res.get("newAssessmentCoolOff"), "messages": res.get("messages"), } markdown = "### SSL Labs Info\n" markdown += tableToMarkdown("Response", result) results = CommandResults( readable_output=markdown, outputs_prefix="SslLabs.Info", outputs_key_field="name", outputs=result ) return results return CommandResults(entry_type=EntryType.ERROR, readable_output="Could not retrieve client info") def analyze_command( client: Client, host: str, publish: Optional[str], start_new: Optional[str], from_cache: Optional[str], max_age: Optional[str], all_endpoints: Optional[str], ignore_mismatch: Optional[str], ) -> CommandResults: """ This API request is used to initiate an assessment, or to retrieve the status of an assessment in progress or in the cache. It will return a single Host object on success. The Endpoint object embedded in the Host object will provide partial endpoint results. Please note that assessments of individual endpoints can fail even when the overall assessment is successful (e.g., one server might be down). At this time, you can determine the success of an endpoint assessment by checking the statusMessage field; it should contain "Ready". Args: client (Client): SSL Labs client to use. host (str): Hostname or URL to analyze. publish (str): Set to on if assessment results needs to be published on the public results boards. start_new (str): If on setting is enabled, a new assessment is started, even if there is a cached assessment in progress. However, if an assessment is in progress, its status is returned instead of starting a new assessment. Note: This parameter should only be used once to start a new assessment; any additional use may cause an assessment loop. from_cache (str): Delivers cached assessment reports if available. This parameter is intended for API consumers who do not wish to wait for assessment results and cannot be used simultaneously with the startNew parameter. max_age (str): Maximum report age in hours if retrieving from cache (fromCache parameter). all_endpoints (str): When the parameter is set to on, full information will be returned. When the parameter is set to done, full information will be returned only if the assessment is complete (status is READY or ERROR). ignore_mismatch (str): Ignores the mismatch if server certificate doesn't match the assessment hostname and proceeds with assessments if set to on. Returns: CommandResults/dict: A 'CommandResults' Compatible to return 'return_results()', which contains the readable_output indicating the message was sent. """ is_url = client.is_valid(host) if is_url is False: raise Exception(f"Input is not a valid URL.\nhttp://example.com OR https://example.com \nInput provided {host}") res = client.analyze(host, publish, start_new, from_cache, max_age, all_endpoints, ignore_mismatch) return res def test_module(client): """ Test command, will send a request to the info endpoint. Args: client (Client): SSL Labs client to use. Return: str: 'ok' if test passed, anything else will raise an exception in main. """ res = client.info() if res: return "ok" return None """ ENTRY POINT """ def main() -> None: """ Main function, parses params and runs command functions Executes a test, analyzes hosts and urls, gets info """ params = demisto.params() args = demisto.args() command = demisto.command() email = params.get("email") base_url = "https://api.ssllabs.com/api/v4" proxy = params.get("proxy", False) verify_certificate = not params.get("insecure", False) headers = {"email": email} try: client = Client(base_url=base_url, verify=verify_certificate, proxy=proxy, headers=headers) # Runs the Register Email command. if command == "ssl-labs-register-email": first_name = args.get("firstName", "") last_name = args.get("lastName", "") email = args.get("email", "") org = args.get("organization", "") return_results(register_email_command(client, first_name, last_name, email, org)) # Runs the Info command. elif command == "ssl-labs-info": return_results(info_command(client)) # Runs the Analyze command. elif command == "ssl-labs-analyze": host = args.get("host", "") publish = args.get("publish", "") start_new = args.get("startNew", "") from_cache = args.get("fromCache", "") max_age = args.get("maxAge", "") all_endpoints = args.get("all", "") ignore_mismatch = args.get("ignoreMismatch", "") return_results(analyze_command(client, host, publish, start_new, from_cache, max_age, all_endpoints, ignore_mismatch)) elif command == "test-module": return_results(test_module(client)) else: raise NotImplementedError(f"command {command} is not implemented.") except Exception as e: demisto.error(traceback.format_exc()) return_error(f"Failed to execute {command} encountered {e}.") if __name__ in ("__main__", "__builtin__", "builtins"): main()