QintelQWatch
Qintel's QWatch system contains credentials obtained from dump sites, hacker collaboratives, and command and control infrastructures of eCrime- and APT-related malware. With this integration, users can fetch exposure alerts as incidents and discover exposed credentials associated with their organization.
Data Enrichment & Threat Intelligence · Qintel
Details
| ID | QintelQWatch |
|---|---|
| Provider | Qintel |
| Category | Data Enrichment & Threat Intelligence |
| From Version | 6.0.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Supported Modules | Agentix XSIAM |
README
Qintel’s QWatch system contains credentials obtained from dump sites, hacker collaboratives, and command and control infrastructures of eCrime- and APT-related malware. With this integration, users can fetch exposure alerts as incidents and discover exposed credentials associated with their organization.
This integration was integrated and tested with version 1.1.6 of QWatch
Configure QintelQWatch in Cortex
| Parameter | Required |
|---|---|
| QWatch API URL (optional) | False |
| Qintel Credentials | True |
| Password | True |
| Trust any certificate (not secure) | False |
| Use system proxy settings | False |
| Fetch incidents | False |
| Fetch plaintext passwords | False |
| Limit number of records per fetch | False |
| First fetch time | False |
| Incidents Fetch Interval | False |
| Default Incident Severity | True |
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.
qintel-qwatch-exposures
Search QWatch for exposed credentials
Base Command
qintel-qwatch-exposures
Input
| Argument Name | Description | Required |
|---|---|---|
| Email to search. | Optional | |
| domain | Domain to search. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Qintel.QWatch.Exposures | String | QWatch Exposure Records |
Command Example
!qintel-qwatch-exposures email=test@example.local
Context Example
{
"Qintel": {
"QWatch": {
"Exposures": [
{
"email": "test@example.local",
"firstseen": "2020-03-25 09:38:40",
"lastseen": "2021-02-05 04:35:33",
"loaded": "2021-02-05 04:35:33",
"password": "SuperSecretPassword",
"source": "combo-BigComboList"
},
{
"email": "test@example.local",
"firstseen": "2020-03-25 09:38:40",
"lastseen": "2021-02-05 04:35:33",
"loaded": "2020-08-10 02:10:11",
"password": "SuperSecretPassword",
"source": "dump-example.local"
},
{
"email": "test@example.local",
"firstseen": "2020-03-25 09:38:40",
"lastseen": "2021-02-05 04:35:33",
"loaded": "2020-03-25 09:38:40",
"password": "SuperSecretPassword",
"source": "malware-evilbot_March_22_2020"
}
]
}
}
}
Human Readable Output
Qintel QWatch exposures for: test@example.local
Password Source Loaded First Seen Last Seen test@example.local SuperSecretPassword combo-BigComboList 2021-02-05 04:35:33 2020-03-25 09:38:40 2021-02-05 04:35:33 test@example.local SuperSecretPassword dump-example.local 2020-08-10 02:10:11 2020-03-25 09:38:40 2021-02-05 04:35:33 test@example.local SuperSecretPassword malware-evilbot_March_22_2020 2020-03-25 09:38:40 2020-03-25 09:38:40 2021-02-05 04:35:33
Configuration parameters
remote— QWatch API URL (optional)credentials— Qintel Credentials (required)insecure— Trust any certificate (not secure)proxy— Use system proxy settingsisFetch— Fetch incidentsfetch_passwords— Fetch plaintext passwordsmax_fetch— Limit number of records per fetchfirst_fetch— First fetch timeincidentFetchInterval— Incidents Fetch Intervalfetch_severity— Default Incident Severity (required)incidentType— Incident type
Commands (1)
-
qintel-qwatch-exposuresSearch QWatch for exposed credentials.
"""Qintel QWatch Integration for Cortex XSOAR - Unit Tests file""" import json MOCK_URL = "https://this-is-only-a-test.local" MOCK_CLIENT_ID = "client-id" MOCK_CLIENT_SECRET = "client-secret" def util_load_json(path): with open(path, encoding="utf-8") as f: return json.loads(f.read()) def test_make_timestamp(): from datetime import datetime from QintelQWatch import _make_timestamp res = _make_timestamp(None) assert res is None res = _make_timestamp(1626211855) assert isinstance(res, datetime) assert res.isoformat() == "2021-07-13T21:30:55" res = _make_timestamp("2021-07-13T21:30:55") assert isinstance(res, datetime) assert int(res.timestamp()) == 1626211855 def test_test_module(mocker): """Tests test-module command function with valid response. Checks the output of the command function with the expected output. """ from QintelQWatch import Client, test_module client = Client(base_url=MOCK_URL, verify=False, client_id=MOCK_CLIENT_ID, client_secret=MOCK_CLIENT_SECRET) mock_response = util_load_json("test_data/test_module.json") mocker.patch.object(Client, "_http_request", return_value=mock_response) response = test_module(client) assert response == "ok" def test_fetch_incidents_command(mocker): """Tests fetch-incidents command function with valid response. Checks the output of the command function with the expected output when plaintext passwords ARE requested. """ from QintelQWatch import Client, fetch_incidents client = Client(base_url=MOCK_URL, verify=False, client_id=MOCK_CLIENT_ID, client_secret=MOCK_CLIENT_SECRET) mock_response = util_load_json("test_data/qwatch_data.json") mocker.patch.object(Client, "_http_request", return_value=mock_response) params = {"first_fetch": "90 days", "fetch_severity": "Medium", "fetch_passwords": True} response = fetch_incidents(client, params) assert len(response) == 1 rawJSON = json.loads(response[0]["rawJSON"]) assert len(rawJSON["QWatch"]["Exposures"]) == 3 record = rawJSON["QWatch"]["Exposures"][0] assert record["email"] == "test@example.local" assert record["password"] == "SuperSecretPassword" assert record["source"] == "combo-BigComboList" assert record["loaded"] == "2021-02-05 04:35:33" def test_fetch_incidents_command_no_password(mocker): """Tests fetch-incidents command function with valid response. Checks the output of the command function with the expected output when plaintext passwords are NOT requested. """ from QintelQWatch import Client, fetch_incidents client = Client(base_url=MOCK_URL, verify=False, client_id=MOCK_CLIENT_ID, client_secret=MOCK_CLIENT_SECRET) mock_response = util_load_json("test_data/qwatch_data.json") mocker.patch.object(Client, "_http_request", return_value=mock_response) params = {"first_fetch": "90 days", "fetch_severity": "Medium"} response = fetch_incidents(client, params) assert len(response) == 1 rawJSON = json.loads(response[0]["rawJSON"]) assert len(rawJSON["QWatch"]["Exposures"]) == 3 record = rawJSON["QWatch"]["Exposures"][0] assert record["email"] == "test@example.local" assert record["password"] is None assert record["source"] == "combo-BigComboList" assert record["loaded"] == "2021-02-05 04:35:33" def test_fetch_incidents_command_no_results(mocker): """Tests fetch-incidents command function with valid response. Checks the output of the command function with the expected output when no results are returned. """ from QintelQWatch import Client, fetch_incidents client = Client(base_url=MOCK_URL, verify=False, client_id=MOCK_CLIENT_ID, client_secret=MOCK_CLIENT_SECRET) mock_response = util_load_json("test_data/qwatch_data_empty.json") mocker.patch.object(Client, "_http_request", return_value=mock_response) params = {"first_fetch": "90 days", "fetch_severity": "Medium"} response = fetch_incidents(client, params) assert len(response) == 0 def test_search_exposures(mocker): """Tests qintel-qwatch-exposures command function with valid response. Checks the output of the command function with the expected output """ from QintelQWatch import Client, search_exposures client = Client(base_url=MOCK_URL, verify=False, client_id=MOCK_CLIENT_ID, client_secret=MOCK_CLIENT_SECRET) mock_response = util_load_json("test_data/qwatch_data.json") mocker.patch.object(Client, "_http_request", return_value=mock_response) args = { "email": "test@example.local", } params = {"fetch_passwords": True} response = search_exposures(client, args, params) assert len(response) == 1 outputs = response[0].outputs hr = response[0].readable_output prefix = response[0].outputs_prefix assert prefix == "Qintel" assert "Qintel QWatch exposures for: test@example.local" in hr assert "|Email|Password|Source|Loaded|First Seen|Last Seen|" in hr assert "test@example.local | SuperSecretPassword | malware-evilbot_March_22_2020 | 2020-03-25 09:38:40 |" in hr record = outputs["QWatch"]["Exposures"][0] assert record["email"] == "test@example.local" assert record["password"] == "SuperSecretPassword" assert record["source"] == "combo-BigComboList" assert record["loaded"] == "2021-02-05 04:35:33"