QintelQSentry

QSentry queries help measure the likelihood that a user is masking their identity using publicly or privately available proxy or VPN services. The returns also flag any known fraud associations. QSentry aggregates data from Qintel’s proprietary Deep and DarkWeb research, as well as from commercially available anonymization services.

Data Enrichment & Threat Intelligence · Qintel

Details

IDQintelQSentry
ProviderQintel
CategoryData Enrichment & Threat Intelligence
From Version6.0.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix XSIAM

README

QSentry queries help measure the likelihood that a user is masking their identity using publicly or privately available proxy or VPN services. The returns also flag any known fraud associations. QSentry aggregates data from Qintel’s proprietary Deep and DarkWeb research, as well as from commercially available anonymization services.
This integration was integrated and tested with version 4.0 of Qintel QSentry

Configure QintelQSentry in Cortex

Parameter Required
QSentry API URL (optional) False
Qintel Token True
Trust any certificate (not secure) False
Use system proxy settings 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.

ip


Queries Qintel for IP reputation data

Base Command

ip

Input

Argument Name Description Required
ip List of IPs. Required

Context Output

Path Type Description
DBotScore.Indicator String The indicator that was tested
DBotScore.Type String The indicator type
DBotScore.Vendor String The vendor used to calculate the score
DBotScore.Score Number The actual score
IP.Address string IP address
IP.ASN string The autonomous system name for the IP address
IP.ASOwner string The autonomous system name for the IP address
IP.Malicious.Vendor string The vendor reporting the IP address as malicious
IP.Malicious.Description string A description explaining why the IP address was reported as malicious
Qintel.IP.Address boolean IP address
Qintel.IP.Tags string Proxy tags
Qintel.IP.Description string IP description
Qintel.IP.LastObserved string Last observed time

Command Example

!ip ip=192.168.35.100

Context Example

{
    "DBotScore": {
        "Indicator": "192.168.35.100",
        "Score": 2,
        "Type": "ip",
        "Vendor": "Qintel"
    },
    "IP": {
        "ASN": 65000,
        "ASOwner": "Some Service Provider",
        "Address": "192.168.35.100",
        "Malicious": {
            "Description": "Indicator is associated with a criminal proxy/vpn",
            "Vendor": "Qintel"
        },
        "Tags": [
            "Proxy",
            "Vpn"
        ]
    },
    "Qintel": {
        "IP": {
            "Address": "192.168.35.100",
            "Description": [
                "this ip address has been associated with a vpn network that offers paid access to users. it is advertised in online underground spaces.",
                "This ip address has been associated with a proxy network that offers paid access to users and is advertised within the online underground. it is commonly utilized by criminal actors to conduct compromised credential checking and the proxy network is hosted on a botnet infrastructure. ip address is likely an infected machine."
            ],
            "LastObserved": "2021-08-31 11:00:00",
            "Tags": [
                "Proxy",
                "Vpn"
            ]
        }
    }
}

Human Readable Output

Qintel results for IP: 192.168.35.100

ASN AS Owner Tags Description Last Observed
65000 Some Service Provider
Proxy,
Vpn
This ip address has been associated with a vpn network that offers paid access to users. it is advertised in online underground spaces.,
This ip address has been associated with a proxy network that offers paid access to users and is advertised within the online underground. it is commonly utilized by criminal actors to conduct compromised credential checking and the proxy network is hosted on a botnet infrastructure. ip address is likely an infected machine.
2021-08-31 11:00:00

Configuration parameters

  • remote — QSentry API URL (optional)
  • token — Qintel Token (required)
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings
  • integrationReliability — Source Reliability
  • feedExpirationPolicy
  • feedExpirationInterval

Commands (1)

  • ip

    Queries Qintel for IP reputation data.

import demistomock as demisto
from CommonServerPython import *  # noqa # pylint: disable=unused-wildcard-import

""" IMPORTS """

import traceback
from datetime import datetime
from typing import Any

import urllib3
from dateutil.parser import parse as parse_dt
from pytz import utc as pyutc

# Disable insecure warnings
urllib3.disable_warnings()

""" CONSTANTS """
DATE_FORMAT = "%Y-%m-%d %I:%M:%S"
VERSION = "v1.0.0"
USER_AGENT = f"Qintel-CortexXSOAR/{VERSION}"
VENDOR = "Qintel"

QSENTRY_REMOTE = "https://api.qsentry.qintel.com"


IP_HR_FIELDS = {
    "ASN": "IP.asn",
    "AS Owner": "IP.as_owner",
    "Tags": "Qintel.Tags",
    "Description": "Qintel.Description",
    "Last Observed": "Qintel.LastObserved",
}


DBOT_TYPE_MAP = {"ip": DBotScoreType.IP, "email": DBotScoreType.EMAIL}


class Client(BaseClient):
    """Client class to interact with Qintel APIs"""

    def __init__(self, base_url, verify=True, proxy=False, **kwargs):
        super().__init__(base_url, verify=verify, proxy=proxy)

        self._headers = {"User-Agent": USER_AGENT, "x-api-key": kwargs.get("token")}

    def search(self, params: dict) -> dict[str, Any]:
        return self._http_request(method="GET", params=params, backoff_factor=0.5, retries=5)

    def ping(self) -> dict[str, Any]:
        return self._http_request(
            method="GET",
        )


def test_module(client) -> str:
    search_params = {"q": "1.1.1.1"}

    try:
        client.search(search_params)
    except Exception as e:
        return f"Test failed: {e}"

    return "ok"


def _make_timestamp(ts):
    if not ts:
        return None

    if isinstance(ts, int):
        return datetime.utcfromtimestamp(ts)

    if isinstance(ts, str):
        return parse_dt(ts).replace(tzinfo=pyutc)
    return None


def _make_dbot_score(itype, i, data):
    dbot_itype = DBOT_TYPE_MAP[itype]
    mal_desc = None

    score = Common.DBotScore.NONE
    tags = demisto.get(data, "Qintel.Tags")
    if tags:
        score = Common.DBotScore.SUSPICIOUS

    if tags and "Criminal" in tags:
        mal_desc = "Indicator is associated with a criminal proxy/vpn"
        score = Common.DBotScore.BAD

    return Common.DBotScore(
        indicator=i,
        indicator_type=dbot_itype,
        integration_name=VENDOR,
        score=score,
        malicious_description=mal_desc,
        reliability=demisto.params().get("integrationReliability"),
    )


def _process_ip_record(ip, data, return_data):
    return_data["IP"]["ip"] = ip
    return_data["Qintel"]["Address"] = ip

    return_data["IP"]["asn"] = data.get("asn")

    as_owner = data.get("asn_name")
    if as_owner:
        asn_owner = as_owner.title()
        return_data["IP"]["as_owner"] = asn_owner

    tags = data.get("tags")
    if tags:
        tags = [t.capitalize() for t in tags]

    return_data["IP"]["tags"] = tags
    return_data["Qintel"]["Tags"] = tags

    desc = data.get("descriptions")
    if desc:
        desc = [d.capitalize() for d in desc]

    return_data["Qintel"]["Description"] = desc

    last = data.get("last_seen")
    if last:
        last = _make_timestamp(last).strftime(DATE_FORMAT)

    return_data["Qintel"]["LastObserved"] = last


def _process_ip_data(data, ip):
    return_data: dict = {"IP": {}, "Qintel": {}}

    _process_ip_record(ip, data, return_data)

    return_data["IP"]["dbot_score"] = _make_dbot_score("ip", ip, return_data)

    return return_data


def ip_command(client, args):
    ips = args.get("ip", "")
    ips = argToList(ips)
    command_results = []

    for ip in ips:
        response = client.search({"q": ip})

        if response:
            data = _process_ip_data(response, ip)

            ip_return = Common.IP(**data["IP"])

            hr_data = {}
            for k, v in IP_HR_FIELDS.items():
                hr_data[k] = demisto.get(data, v)

            header = f"Qintel results for IP: {ip}"
            hr = tableToMarkdown(header, hr_data, headers=list(hr_data.keys()))

            command_results.append(
                CommandResults(
                    outputs_prefix="Qintel.IP",
                    outputs_key_field="Address",
                    outputs=data["Qintel"],
                    indicator=ip_return,
                    readable_output=hr,
                )
            )

        else:
            # human readable output
            header = f"Qintel vulnerability results for: {ip}"
            hr = tableToMarkdown(header, {})

            command_results.append(CommandResults(readable_output=hr))

    return command_results


def main() -> None:
    params = demisto.params()

    client_args = {"token": params.get("token")}

    remote = params.get("remote", QSENTRY_REMOTE)

    proxy = params.get("proxy", False)
    verify_ssl = not params.get("insecure", False)

    command = demisto.command()

    demisto.debug(f"Command being called is {command}")

    try:
        client = Client(remote, verify_ssl, proxy, **client_args)

        args = demisto.args()

        if command == "test-module":
            demisto.results(test_module(client))

        elif command == "ip":
            return_results(ip_command(client, args))

    # Log exceptions
    except Exception as e:
        demisto.error(traceback.format_exc())
        return_error(f"Failed to execute {command} command.\nError:\n{e!s}")


if __name__ in ("__main__", "__builtin__", "builtins"):
    main()