PassiveTotal v2
Analyze and understand threat infrastructure from a variety of sources-passive DNS, active DNS, WHOIS, SSL certificates and more-without devoting resources to time-intensive manual threat research and analysis.
Data Enrichment & Threat Intelligence · PassiveTotal
Details
| ID | PassiveTotal v2 |
|---|---|
| Provider | Microsoft |
| Category | Data Enrichment & Threat Intelligence |
| From Version | 5.0.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Supported Modules | Agentix XSIAM |
README
Analyze and understand threat infrastructure from a variety of sources-passive DNS, active DNS, WHOIS, SSL certificates and more-without devoting resources to time-intensive manual threat research and analysis.
This integration was integrated and tested with enterprise version of PassiveTotal v2.
Configure PassiveTotal v2 in Cortex
| Parameter | Description | Required |
|---|---|---|
| url | API URL | True |
| username | Username | True |
| secret | API Secret | True |
| insecure | Trust any certificate (not secure) | False |
| proxy | Use system proxy settings | False |
| request_timeout | HTTP(S) Request Timeout (in seconds) | 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.
pt-whois-search
Gets WHOIS information records based on field matching queries.
Base Command
pt-whois-search
Input
| Argument Name | Description | Required |
|---|---|---|
| query | Query value to use in your request. | Required |
| field | WHOIS field to execute the search on: domain, email, name, organization, address, phone, nameserver. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| Domain.Name | String | The domain name, for example: ‘google.com’. |
| Domain.WHOIS.CreationDate | Date | The date that the domain was created. |
| Domain.WHOIS.UpdatedDate | Date | The date that the domain was last updated. |
| Domain.WHOIS.ExpirationDate | Date | The expiration date of the domain. |
| Domain.WHOIS.NameServers | String | Name servers of the domain. |
| Domain.Organization | String | The organization of the domain. |
| Domain.Admin.Email | String | The email address of the domain administrator. |
| Domain.Admin.Name | String | The name of the domain administrator. |
| Domain.Admin.Phone | String | The phone number of the domain administrator. |
| Domain.Admin.Country | String | The country of the domain administrator. |
| Domain.Registrant.Email | String | The email address of the registrant. |
| Domain.Registrant.Name | String | The name of the registrant. |
| Domain.Registrant.Phone | String | The phone number for receiving abuse reports. |
| Domain.Registrant.Country | String | The country of the registrant. |
| Domain.WHOIS.Admin.Email | String | The email address of the domain administrator. |
| Domain.WHOIS.Admin.Name | String | The name of the domain administrator. |
| Domain.WHOIS.Admin.Phone | String | The phone number of the domain administrator. |
| Domain.WHOIS.Admin.Country | String | The country of the domain administrator. |
| Domain.WHOIS.Registrar.Name | String | The name of the registrar, for example: ‘GoDaddy’. |
| Domain.WHOIS.Registrant.Email | String | The email address of the registrant. |
| Domain.WHOIS.Registrant.Name | String | The name of the registrant. |
| Domain.WHOIS.Registrant.Phone | String | The phone number for receiving abuse reports. |
| Domain.WHOIS.Registrant.Country | String | The country of the registrant. |
| PassiveTotal.WHOIS.domain | String | The domain name, for example: ‘google.com’. |
| PassiveTotal.WHOIS.registrar | String | The name of the registrar of the domain |
| PassiveTotal.WHOIS.whoisServer | String | WHOIS server name where the details of domain registrations belong |
| PassiveTotal.WHOIS.registered | Date | The date that the domain was registered. |
| PassiveTotal.WHOIS.expiresAt | Date | The expiration date of the domain. |
| PassiveTotal.WHOIS.registryUpdatedAt | Date | The date when registry was last updated. |
| PassiveTotal.WHOIS.lastLoadedAt | Date | Last loaded date of WHOIS database. |
| PassiveTotal.WHOIS.nameServers | String | Name servers of the domain. |
| PassiveTotal.WHOIS.organization | String | The organization of the domain. |
| PassiveTotal.WHOIS.name | String | Name of the domain. |
| PassiveTotal.WHOIS.telephone | String | Telephone number fetched from whois details of the domain. |
| PassiveTotal.WHOIS.contactEmail | String | Contact Email address of the domain owner |
| PassiveTotal.WHOIS.registrantEmail | String | The name of the domain registrant. |
| PassiveTotal.WHOIS.registrantFax | String | The fax number of the domain registrant. |
| PassiveTotal.WHOIS.registrantName | String | The name of the domain registrant. |
| PassiveTotal.WHOIS.registrantOrganization | String | The organizations of the domain registrant. |
| PassiveTotal.WHOIS.registrantStreet | String | The street of the domain registrant. |
| PassiveTotal.WHOIS.registrantCity | String | The city of the domain registrant. |
| PassiveTotal.WHOIS.registrantState | String | The state of the domain registrant. |
| PassiveTotal.WHOIS.registrantPostalCode | String | The postal code of the domain registrant. |
| PassiveTotal.WHOIS.registrantCountry | String | The country of the domain registrant. |
| PassiveTotal.WHOIS.registrantTelephone | String | The telephone number of the domain registrant. |
| PassiveTotal.WHOIS.adminEmail | String | The email address of the domain administrator. |
| PassiveTotal.WHOIS.adminFax | String | The fax number of the domain administrator. |
| PassiveTotal.WHOIS.adminName | String | The name of the domain administrator. |
| PassiveTotal.WHOIS.adminOrganization | String | The organizations of the domain administrator. |
| PassiveTotal.WHOIS.adminStreet | String | The street of the domain administrator. |
| PassiveTotal.WHOIS.adminCity | String | The city of the domain administrator. |
| PassiveTotal.WHOIS.adminState | String | The state of the domain administrator. |
| PassiveTotal.WHOIS.adminPostalCode | String | The postal code of the domain administrator. |
| PassiveTotal.WHOIS.adminCountry | String | The country of the domain administrator. |
| PassiveTotal.WHOIS.adminTelephone | String | The telephone number of the domain administrator. |
| PassiveTotal.WHOIS.billingEmail | String | The email address of the domain billing. |
| PassiveTotal.WHOIS.billingFax | String | The fax number of the domain billing. |
| PassiveTotal.WHOIS.billingName | String | The name of the domain billing. |
| PassiveTotal.WHOIS.billingOrganization | String | The organizations of the domain billing. |
| PassiveTotal.WHOIS.billingStreet | String | The street of the domain billing. |
| PassiveTotal.WHOIS.billingCity | String | The city of the domain billing. |
| PassiveTotal.WHOIS.billingState | String | The state of the domain billing. |
| PassiveTotal.WHOIS.billingPostalCode | String | The postal code of the domain billing. |
| PassiveTotal.WHOIS.billingCountry | String | The country of the domain billing. |
| PassiveTotal.WHOIS.billingTelephone | String | The telephone number of the domain billing. |
| PassiveTotal.WHOIS.techEmail | String | The email address of the domain tech. |
| PassiveTotal.WHOIS.techFax | String | The fax number of the domain tech. |
| PassiveTotal.WHOIS.techName | String | The name of the domain tech. |
| PassiveTotal.WHOIS.techOrganization | String | The organizations of domain tech. |
| PassiveTotal.WHOIS.techStreet | String | The street of the domain tech. |
| PassiveTotal.WHOIS.techCity | String | The city of the domain tech. |
| PassiveTotal.WHOIS.techState | String | The state of the domain tech. |
| PassiveTotal.WHOIS.techPostalCode | String | The postal code of the domain tech. |
| PassiveTotal.WHOIS.techCountry | String | The country of the domain tech. |
| PassiveTotal.WHOIS.techTelephone | String | The telephone number of the domain tech. |
Command Example
!pt-whois-search field=domain query=riskiq.com
Context Example
{
"DBotScore": [
{
"Indicator": "riskiq.com",
"Score": 0,
"Type": "domain",
"Vendor": "PassiveTotal"
}
],
"Domain": [
{
"Admin": {
"Country": "us",
"Email": "domains@riskiq.com",
"Name": "Risk IQ",
"Phone": "18884154447"
},
"CreationDate": "2006-01-11T16:00:00.000-0800",
"ExpirationDate": "2017-01-11T16:00:00.000-0800",
"Name": "riskiq.com",
"NameServers": [
"luke.ns.cloudflare.com",
"serena.ns.cloudflare.com"
],
"Organization": "RiskIQ, Inc.",
"Registrant": {
"Country": "us",
"Email": "domains@riskiq.com",
"Name": "Risk IQ",
"Phone": "18884154447"
},
"Registrar": {
"AbuseEmail": null,
"AbusePhone": null,
"Name": "GODADDY.COM, LLC"
},
"UpdatedDate": "2014-12-08T16:00:00.000-0800",
"WHOIS": {
"Admin": {
"Country": "us",
"Email": "domains@riskiq.com",
"Name": "Risk IQ",
"Phone": "18884154447"
},
"CreationDate": "2006-01-11T16:00:00.000-0800",
"ExpirationDate": "2017-01-11T16:00:00.000-0800",
"NameServers": [
"luke.ns.cloudflare.com",
"serena.ns.cloudflare.com"
],
"Registrant": {
"Country": "us",
"Email": "domains@riskiq.com",
"Name": "Risk IQ",
"Phone": "18884154447"
},
"Registrar": {
"AbuseEmail": null,
"AbusePhone": null,
"Name": "GODADDY.COM, LLC"
},
"UpdatedDate": "2014-12-08T16:00:00.000-0800"
}
}
],
"PassiveTotal": {
"WHOIS": {
"adminCity": "san francisco",
"adminCountry": "us",
"adminEmail": "domains@riskiq.com",
"adminName": "Risk IQ",
"adminOrganization": "RiskIQ, Inc.",
"adminPostalCode": "94111",
"adminState": "california",
"adminStreet": "22 Battery Street\n10th Floor",
"adminTelephone": "18884154447",
"contactEmail": "domains@riskiq.com",
"domain": "riskiq.com",
"expiresAt": "2017-01-11T16:00:00.000-0800",
"lastLoadedAt": "2016-09-27T09:40:31.180-0700",
"name": "Risk IQ",
"nameServers": [
"luke.ns.cloudflare.com",
"serena.ns.cloudflare.com"
],
"organization": "RiskIQ, Inc.",
"registered": "2006-01-11T16:00:00.000-0800",
"registrantCity": "san francisco",
"registrantCountry": "us",
"registrantEmail": "domains@riskiq.com",
"registrantName": "Risk IQ",
"registrantOrganization": "RiskIQ, Inc.",
"registrantPostalCode": "94111",
"registrantState": "california",
"registrantStreet": "22 Battery Street\n10th Floor",
"registrantTelephone": "18884154447",
"registrar": "GODADDY.COM, LLC",
"registryUpdatedAt": "2014-12-08T16:00:00.000-0800",
"techCity": "san francisco",
"techCountry": "us",
"techEmail": "domains@riskiq.com",
"techName": "Risk IQ",
"techOrganization": "RiskIQ, Inc.",
"techPostalCode": "94111",
"techState": "california",
"techStreet": "22 Battery Street\n10th Floor",
"techTelephone": "18884154447",
"telephone": "18884154447",
"whoisServer": "whois.godaddy.com"
}
}
}
Human Readable Output
Total Retrieved Record(s): 2
Associated Domains
Domain WHOIS Server Registrar Contact Email Name Servers Registrant Admin Tech Creation Date (GMT) Expire Date (GMT) Updated Date (GMT) Last Scanned (GMT) riskiq.com whois.godaddy.com GODADDY.COM, LLC domains@riskiq.com luke.ns.cloudflare.com, serena.ns.cloudflare.com City: san francisco,
Country: us,
Email: domains@riskiq.com,
Name: Risk IQ,
Organization: RiskIQ, Inc.,
PostalCode: 94111,
State: california,
Street: 22 Battery Street
10th Floor,
Telephone: 18884154447City: san francisco,
Country: us,
Email: domains@riskiq.com,
Name: Risk IQ,
Organization: RiskIQ, Inc.,
PostalCode: 94111,
State: california,
Street: 22 Battery Street
10th Floor,
Telephone: 18884154447City: san francisco,
Country: us,
Email: domains@riskiq.com,
Name: Risk IQ,
Organization: RiskIQ, Inc.,
PostalCode: 94111,
State: california,
Street: 22 Battery Street
10th Floor,
Telephone: 188841544472006-01-11T16:00:00.000-0800 2017-01-11T16:00:00.000-0800 2014-12-08T16:00:00.000-0800 2016-09-27T09:40:31.180-0700
pt-get-components
Retrieves the host attribute components for a domain or IP address. Maximum 2000 records are fetched.
Base Command
pt-get-components
Input
| Argument Name | Description | Required |
|---|---|---|
| query | Domain or IP address you want to search components for. | Required |
| start | Filter for records whose last seen is after this datetime. It accepts “yyyy-mm-dd hh:mm:ss” or “yyyy-mm-dd” format. | Optional |
| end | Filter for records whose first seen is before this datetime. It accepts “yyyy-mm-dd hh:mm:ss” or “yyyy-mm-dd” format. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Domain.Name | String | The domain name, for example: “google.com”. |
| 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 | The IP Address of the component. |
| PassiveTotal.Component.firstSeen | Date | The date and time when the component was first observed. |
| PassiveTotal.Component.lastSeen | Date | The date and time when the component was most recently observed. |
| PassiveTotal.Component.version | String | The current version of component. |
| PassiveTotal.Component.category | String | The category under which the component falls. |
| PassiveTotal.Component.label | String | The value of the component. |
| PassiveTotal.Component.hostname | String | The hostname of the component. |
| PassiveTotal.Component.address | String | The IP address of the component. |
Command Example
!pt-get-components query=www.furth.com.ar
Context Example
{
"DBotScore": {
"Indicator": "www.furth.com.ar",
"Score": 0,
"Type": "domain",
"Vendor": "PassiveTotal"
},
"Domain": {
"Name": "www.furth.com.ar"
},
"PassiveTotal": {
"Component": [
{
"category": "Framework",
"firstSeen": "2020-05-29 10:57:44",
"hostname": "www.furth.com.ar",
"label": "PHP",
"lastSeen": "2020-05-29 10:57:44"
},
{
"category": "Server",
"firstSeen": "2020-05-29 10:57:44",
"hostname": "www.furth.com.ar",
"label": "Apache",
"lastSeen": "2020-05-29 10:57:44"
},
{
"category": "Server Module",
"firstSeen": "2016-01-11 23:45:15",
"hostname": "www.furth.com.ar",
"label": "mod_bwlimited",
"lastSeen": "2017-10-24 15:53:52",
"version": "1.4"
},
{
"category": "Server Module",
"firstSeen": "2016-01-11 23:45:15",
"hostname": "www.furth.com.ar",
"label": "OpenSSL",
"lastSeen": "2017-10-24 15:53:52",
"version": "1.0.1e-fips"
},
{
"category": "Server",
"firstSeen": "2016-01-11 23:45:15",
"hostname": "www.furth.com.ar",
"label": "Apache",
"lastSeen": "2017-10-24 15:53:52",
"version": "2.2.29"
},
{
"category": "Operating System",
"firstSeen": "2016-01-11 23:45:15",
"hostname": "www.furth.com.ar",
"label": "Unix",
"lastSeen": "2017-10-24 15:53:52"
},
{
"category": "Server Module",
"firstSeen": "2016-01-11 23:45:15",
"hostname": "www.furth.com.ar",
"label": "mod_ssl",
"lastSeen": "2017-10-24 15:53:52",
"version": "2.2.29"
}
]
}
}
Human Readable Output
Total Retrieved Record(s): 7
COMPONENTS
Hostname First (GMT) Last (GMT) Category Value Version www.furth.com.ar 2020-05-29 10:57:44 2020-05-29 10:57:44 Framework PHP www.furth.com.ar 2020-05-29 10:57:44 2020-05-29 10:57:44 Server Apache www.furth.com.ar 2016-01-11 23:45:15 2017-10-24 15:53:52 Server Module mod_bwlimited 1.4 www.furth.com.ar 2016-01-11 23:45:15 2017-10-24 15:53:52 Server Module OpenSSL 1.0.1e-fips www.furth.com.ar 2016-01-11 23:45:15 2017-10-24 15:53:52 Server Apache 2.2.29 www.furth.com.ar 2016-01-11 23:45:15 2017-10-24 15:53:52 Operating System Unix www.furth.com.ar 2016-01-11 23:45:15 2017-10-24 15:53:52 Server Module mod_ssl 2.2.29
pt-get-trackers
Retrieves the host attribute trackers for a domain or IP address. Maximum 2000 records are fetched.
Base Command
pt-get-trackers
Input
| Argument Name | Description | Required |
|---|---|---|
| query | Domain or IP address you want to search trackers for. | Required |
| start | Filter for records whose last seen is after this datetime. It accepts “yyyy-mm-dd hh:mm:ss” or “yyyy-mm-dd” format. | Optional |
| end | Filter for records whose first seen is before this datetime. It accepts “yyyy-mm-dd hh:mm:ss” or “yyyy-mm-dd” format. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Domain.Name | String | The domain name, for example: “google.com”. |
| 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 | The IP Address of the component. |
| PassiveTotal.Tracker.firstSeen | Date | The date and time when the tracker was first observed. |
| PassiveTotal.Tracker.lastSeen | Date | The date and time when the tracker was most recently observed. |
| PassiveTotal.Tracker.attributeValue | String | The value of the tracker. |
| PassiveTotal.Tracker.attributeType | String | The type under which the tracker falls. |
| PassiveTotal.Tracker.hostname | String | The hostname of the tracker. |
| PassiveTotal.Tracker.address | String | The IP address of the tracker. |
Command Example
!pt-get-trackers query=filmesonlinegratis.net
Context Example
{
"DBotScore": [
{
"Indicator": "filmesonlinegratis.net",
"Score": 0,
"Type": "domain",
"Vendor": "PassiveTotal"
},
{
"Indicator": "www.filmesonlinegratis.net",
"Score": 0,
"Type": "domain",
"Vendor": "PassiveTotal"
}
],
"Domain": [
{
"Name": "filmesonlinegratis.net"
},
{
"Name": "www.filmesonlinegratis.net"
}
],
"PassiveTotal": {
"Tracker": [
{
"attributeType": "GoogleAnalyticsTrackingId",
"attributeValue": "ua-70630818-3",
"firstSeen": "2016-10-14 10:16:38",
"hostname": "filmesonlinegratis.net",
"lastSeen": "2020-06-14 19:43:28"
},
{
"attributeType": "GoogleAnalyticsAccountNumber",
"attributeValue": "ua-70630818",
"firstSeen": "2016-10-14 10:16:38",
"hostname": "filmesonlinegratis.net",
"lastSeen": "2020-06-14 19:43:28"
},
{
"attributeType": "GoogleAnalyticsAccountNumber",
"attributeValue": "ua-11598035",
"firstSeen": "2012-03-07 05:53:50",
"hostname": "www.filmesonlinegratis.net",
"lastSeen": "2016-10-13 15:38:35"
},
{
"attributeType": "GoogleAnalyticsTrackingId",
"attributeValue": "ua-11598035-1",
"firstSeen": "2012-03-07 05:53:50",
"hostname": "www.filmesonlinegratis.net",
"lastSeen": "2016-10-13 15:38:35"
},
{
"attributeType": "GoogleAnalyticsTrackingId",
"attributeValue": "ua-11598035-1",
"firstSeen": "2014-02-11 01:30:40",
"hostname": "filmesonlinegratis.net",
"lastSeen": "2016-09-13 03:54:34"
},
{
"attributeType": "GoogleAnalyticsAccountNumber",
"attributeValue": "ua-11598035",
"firstSeen": "2014-02-11 01:30:40",
"hostname": "filmesonlinegratis.net",
"lastSeen": "2016-09-13 03:54:34"
},
{
"attributeType": "TumblrId",
"attributeValue": "25.media",
"firstSeen": "2016-07-02 00:46:33",
"hostname": "www.filmesonlinegratis.net",
"lastSeen": "2016-09-02 11:09:30"
},
{
"attributeType": "FacebookId",
"attributeValue": "filmesog",
"firstSeen": "2012-11-27 06:06:44",
"hostname": "www.filmesonlinegratis.net",
"lastSeen": "2015-09-26 05:52:23"
},
{
"attributeType": "FacebookId",
"attributeValue": "filmesog",
"firstSeen": "2014-02-11 01:30:40",
"hostname": "filmesonlinegratis.net",
"lastSeen": "2015-09-24 05:12:39"
},
{
"attributeType": "WhosAmungUsId",
"attributeValue": "6cdg",
"firstSeen": "2012-03-07 05:53:50",
"hostname": "www.filmesonlinegratis.net",
"lastSeen": "2012-03-07 16:00:45"
}
]
}
}
Human Readable Output
Total Retrieved Record(s): 10
TRACKERS
Hostname First (GMT) Last (GMT) Type Value filmesonlinegratis.net 2016-10-14 10:16:38 2020-06-14 19:43:28 GoogleAnalyticsTrackingId ua-70630818-3 filmesonlinegratis.net 2016-10-14 10:16:38 2020-06-14 19:43:28 GoogleAnalyticsAccountNumber ua-70630818 www.filmesonlinegratis.net 2012-03-07 05:53:50 2016-10-13 15:38:35 GoogleAnalyticsAccountNumber ua-11598035 www.filmesonlinegratis.net 2012-03-07 05:53:50 2016-10-13 15:38:35 GoogleAnalyticsTrackingId ua-11598035-1 filmesonlinegratis.net 2014-02-11 01:30:40 2016-09-13 03:54:34 GoogleAnalyticsTrackingId ua-11598035-1 filmesonlinegratis.net 2014-02-11 01:30:40 2016-09-13 03:54:34 GoogleAnalyticsAccountNumber ua-11598035 www.filmesonlinegratis.net 2016-07-02 00:46:33 2016-09-02 11:09:30 TumblrId 25.media www.filmesonlinegratis.net 2012-11-27 06:06:44 2015-09-26 05:52:23 FacebookId filmesog filmesonlinegratis.net 2014-02-11 01:30:40 2015-09-24 05:12:39 FacebookId filmesog www.filmesonlinegratis.net 2012-03-07 05:53:50 2012-03-07 16:00:45 WhosAmungUsId 6cdg
pt-get-pdns-details
Retrieves the passive DNS results from active account sources.
Base Command
pt-get-pdns-details
Input
| Argument Name | Description | Required |
|---|---|---|
| query | The domain or IP being queried. | Required |
| start | Filter for records whose last seen is after this datetime. It accepts “yyyy-mm-dd hh:mm:ss” or “yyyy-mm-dd” format. | Optional |
| end | Filter for records whose first seen is before this datetime. It accepts “yyyy-mm-dd hh:mm:ss” or “yyyy-mm-dd” format. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PassiveTotal.PDNS.resolve | String | The host or ip address that indicates resolve in Passive DNS record. |
| PassiveTotal.PDNS.resolveType | String | The type of the resolve. I.e domain, ip, host, etc. |
| PassiveTotal.PDNS.value | String | The value of the Passive DNS record. |
| PassiveTotal.PDNS.source | String | Source of the passive DNS records. |
| PassiveTotal.PDNS.firstSeen | String | First seen timestamp of the passive DNS record. |
| PassiveTotal.PDNS.lastSeen | String | Last seen timestamp of the passive DNS record. |
| PassiveTotal.PDNS.collected | String | The date when a passive DNS record is collected. |
| PassiveTotal.PDNS.recordType | String | The type of the passive DNS record. I.e CNAME, SOA, A, etc |
| PassiveTotal.PDNS.recordHash | String | The hash value of the passive DNS record. |
| Domain.Name | String | The domain name, for example: ‘google.com’. |
| IP.Address | String | The IP Address of the component. |
| 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. |
Command Example
!pt-get-pdns-details query=www.furth.com.ar
Context Example
{
"DBotScore": [
{
"Indicator": "furth.com.ar",
"Score": 0,
"Type": "domain",
"Vendor": "PassiveTotal"
},
{
"Indicator": "77.81.241.5",
"Score": 0,
"Type": "ip",
"Vendor": "PassiveTotal"
},
{
"Indicator": "184.75.255.33",
"Score": 0,
"Type": "ip",
"Vendor": "PassiveTotal"
}
],
"Domain": {
"Name": "furth.com.ar"
},
"IP": [
{
"Address": "77.81.241.5"
},
{
"Address": "184.75.255.33"
}
],
"PassiveTotal": {
"PDNS": [
{
"collected": "2020-06-17 12:26:33",
"firstSeen": "2010-12-15 09:10:10",
"lastSeen": "2020-06-17 05:26:33",
"recordHash": "abf781b2484ea79d521cffb0745b71319d4db1158f71bb019b41077f8e55b035",
"recordType": "CNAME",
"resolve": "furth.com.ar",
"resolveType": "domain",
"source": [
"riskiq",
"pingly"
],
"value": "www.furth.com.ar"
},
{
"collected": "2020-06-17 12:26:33",
"firstSeen": "2020-05-29 03:57:44",
"lastSeen": "2020-06-17 05:26:33",
"recordHash": "d7183564ca617e173fc26aeff66a38bb5c1b9089e56819851183860b9a37ccca",
"recordType": "A",
"resolve": "77.81.241.5",
"resolveType": "ip",
"source": [
"riskiq",
"pingly"
],
"value": "www.furth.com.ar"
},
{
"collected": "2020-06-17 12:26:33",
"firstSeen": "2016-01-11 15:45:15",
"lastSeen": "2017-10-24 08:53:52",
"recordHash": "345780dcde96f0c28e3b93ec53bd33067f26075f30c2d4e49fafe0d2396194ca",
"recordType": "A",
"resolve": "184.75.255.33",
"resolveType": "ip",
"source": [
"riskiq"
],
"value": "www.furth.com.ar"
},
{
"collected": "2020-06-17 12:26:33",
"firstSeen": "2020-06-17 05:26:33",
"lastSeen": "2020-06-17 05:26:33",
"recordHash": "63deb7c38cbea98f631777fd3ba89de0c270178bd37eb6a270ee7e37b3cd92e5",
"recordType": "SOA",
"resolve": "webmaster@furth.com.ar",
"resolveType": "email",
"source": [
"pingly"
],
"value": "www.furth.com.ar"
},
{
"collected": "2020-06-17 12:26:33",
"firstSeen": "2020-06-17 05:26:33",
"lastSeen": "2020-06-17 05:26:33",
"recordHash": "24fa99da36eecc22b8970a33f8adf0f150598391319df4fc02128d677999e886",
"recordType": "MX",
"resolve": "furth.com.ar",
"resolveType": "domain",
"source": [
"pingly"
],
"value": "www.furth.com.ar"
}
]
}
}
Human Readable Output
Total Retrieved Record(s): 5
PDNS detail(s)
Resolve Resolve Type Record Type Collected (GMT) First (GMT) Last (GMT) Source Record Hash furth.com.ar domain CNAME 2020-06-17 12:26:33 2010-12-15 09:10:10 2020-06-17 05:26:33 riskiq, pingly abf781b2484ea79d521cffb0745b71319d4db1158f71bb019b41077f8e55b035 77.81.241.5 ip A 2020-06-17 12:26:33 2020-05-29 03:57:44 2020-06-17 05:26:33 riskiq, pingly d7183564ca617e173fc26aeff66a38bb5c1b9089e56819851183860b9a37ccca 184.75.255.33 ip A 2020-06-17 12:26:33 2016-01-11 15:45:15 2017-10-24 08:53:52 riskiq 345780dcde96f0c28e3b93ec53bd33067f26075f30c2d4e49fafe0d2396194ca webmaster@furth.com.ar SOA 2020-06-17 12:26:33 2020-06-17 05:26:33 2020-06-17 05:26:33 pingly 63deb7c38cbea98f631777fd3ba89de0c270178bd37eb6a270ee7e37b3cd92e5 furth.com.ar domain MX 2020-06-17 12:26:33 2020-06-17 05:26:33 2020-06-17 05:26:33 pingly 24fa99da36eecc22b8970a33f8adf0f150598391319df4fc02128d677999e886
pt-ssl-cert-search
Retrieves SSL certificates for a given field value.
Base Command
pt-ssl-cert-search
Input
| Argument Name | Description | Required |
|---|---|---|
| field | Field by which to search. Allowed values: issuerSurname, subjectOrganizationName, issuerCountry, issuerOrganizationUnitName, fingerprint, subjectOrganizationUnitName, serialNumber, subjectEmailAddress, subjectCountry, issuerGivenName, subjectCommonName, issuerCommonName, issuerStateOrProvinceName, issuerProvince, subjectStateOrProvinceName, sha1, subjectStreetAddress, subjectSerialNumber, issuerOrganizationName, subjectSurname, subjectLocalityName, issuerStreetAddress, issuerLocalityName, subjectGivenName, subjectProvince, issuerSerialNumber, issuerEmailAddress |
Required |
| query | Field value for which to search. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| PassiveTotal.SSL.firstSeen | Number | Epoch timestamp when SSL certificate identified by the system. |
| PassiveTotal.SSL.lastSeen | Number | The last seen epoch timestamp of the SSL certificates. |
| PassiveTotal.SSL.fingerprint | String | A fingerprint detail from the SSL certificates. |
| PassiveTotal.SSL.sslVersion | Number | A version of the certificate. |
| PassiveTotal.SSL.expirationDate | String | The expiry date of the certificate. |
| PassiveTotal.SSL.issueDate | String | Issue date of the certificate. |
| PassiveTotal.SSL.sha1 | String | Sha1 of the certificate. |
| PassiveTotal.SSL.serialNumber | String | A serial number of the certificate. |
| PassiveTotal.SSL.issuerCountry | String | The country name of the certificate issuer. |
| PassiveTotal.SSL.issuerStateOrProvinceName | String | The state or province name of the certificate issuer. |
| PassiveTotal.SSL.issuerCommonName | String | The common name of the issuer. |
| PassiveTotal.SSL.issuerEmailAddress | String | A contact email address of the certificate issuer. |
| PassiveTotal.SSL.issuerProvince | String | A province of the certificate issuer. |
| PassiveTotal.SSL.issuerOrganizationUnitName | String | An organization unit name of the certificate issuer. |
| PassiveTotal.SSL.issuerSurname | String | The surname of the certificate issuer. |
| PassiveTotal.SSL.issuerStreetAddress | String | Street address of the certificate issuer. |
| PassiveTotal.SSL.issuerLocalityName | String | The locality of the certificate issuer. |
| PassiveTotal.SSL.issuerSerialNumber | String | The serial number of the certificate issuer. |
| PassiveTotal.SSL.issuerOrganizationName | String | An organization name of the certificate issuer. |
| PassiveTotal.SSL.issuerGivenName | String | A given name of the certificate issuer. |
| PassiveTotal.SSL.subjectCommonName | String | The common name of the subject. |
| PassiveTotal.SSL.subjectOrganizationName | String | An organization name of the subject of the certificate. |
| PassiveTotal.SSL.subjectOrganizationUnitName | String | An organization unit name of the subject of the certificate. |
| PassiveTotal.SSL.subjectGivenName | String | The given name of the subject of the certificate. |
| PassiveTotal.SSL.subjectSurname | String | The surname of the subject of the certificate. |
| PassiveTotal.SSL.subjectLocalityName | String | The locality of the subject. |
| PassiveTotal.SSL.subjectEmailAddress | String | A contact email address of the subject. |
| PassiveTotal.SSL.subjectProvince | String | The province of the subject. |
| PassiveTotal.SSL.subjectStateOrProvinceName | String | The state or province name of the subject. |
| PassiveTotal.SSL.subjectSerialNumber | String | A serial number of the subject. |
| PassiveTotal.SSL.subjectStreetAddress | String | The street address of the subject. |
| PassiveTotal.SSL.subjectCountry | String | The country name of the subject from the certificate. |
| PassiveTotal.SSL.subjectAlternativeNames | String | Alternative names of the subject from the certificate details. |
Command Example
!pt-ssl-cert-search field=serialNumber query=61135c80f8ed28d2
Context Example
{
"PassiveTotal": {
"SSL": [
{
"expirationDate": "Apr 09 13:15:00 2019 GMT",
"fingerprint": "88:48:e8:68:b1:90:d0:fd:cb:6f:39:c3:7b:53:82:c8:7e:09:76:b0",
"firstSeen": 1547559631314,
"issueDate": "Jan 15 13:15:00 2019 GMT",
"issuerCommonName": "Google Internet Authority G3",
"issuerCountry": "US",
"issuerOrganizationName": "Google Trust Services",
"lastSeen": 1547607634446,
"serialNumber": "6995036355238373586",
"sha1": "8848e868b190d0fdcb6f39c37b5382c87e0976b0",
"sslVersion": "3",
"subjectAlternativeNames": [
"www.google.com"
],
"subjectCommonName": "www.google.com",
"subjectCountry": "US",
"subjectLocalityName": "Mountain View",
"subjectOrganizationName": "Google LLC",
"subjectProvince": "California",
"subjectStateOrProvinceName": "California"
},
{
"expirationDate": "Apr 09 13:15:00 2019 GMT",
"fingerprint": "99:5b:00:5f:44:be:53:bf:3e:59:21:90:1d:79:a9:8e:54:af:d3:29",
"firstSeen": 1548455641692,
"issueDate": "Jan 15 13:15:00 2019 GMT",
"issuerCommonName": "Google Internet Authority G3",
"issuerCountry": "US",
"issuerOrganizationName": "Google Trust Services",
"lastSeen": 1549571983939,
"serialNumber": "6995036355238373586",
"sha1": "995b005f44be53bf3e5921901d79a98e54afd329",
"sslVersion": "3",
"subjectAlternativeNames": [
"www.google.com"
],
"subjectCommonName": "www.google.com",
"subjectCountry": "US",
"subjectLocalityName": "Mountain View",
"subjectOrganizationName": "Google LLC",
"subjectProvince": "California",
"subjectStateOrProvinceName": "California"
}
]
}
}
Human Readable Output
Total Retrieved Record(s): 2
SSL certificate(s)
Sha1 Serial Number Issued (GMT) Expires (GMT) SSL Version First (GMT) Last (GMT) Issuer Common Name Subject Common Name Subject Alternative Names Issuer Organization Name Subject Organization Name Subject Locality Name Subject State/Province Name Issuer Country Subject Country 8848e868b190d0fdcb6f39c37b5382c87e0976b0 6995036355238373586 Jan 15 13:15:00 2019 GMT Apr 09 13:15:00 2019 GMT 3 2019-01-15 13:40:31 2019-01-16 03:00:34 Google Internet Authority G3 www.google.com www.google.com Google Trust Services Google LLC Mountain View California US US 995b005f44be53bf3e5921901d79a98e54afd329 6995036355238373586 Jan 15 13:15:00 2019 GMT Apr 09 13:15:00 2019 GMT 3 2019-01-25 22:34:01 2019-02-07 20:39:43 Google Internet Authority G3 www.google.com www.google.com Google Trust Services Google LLC Mountain View California US US
pt-get-host-pairs
Retrieves the host attribute pairs related to a domain or IP address. Maximum 2000 records are fetched.
Base Command
pt-get-host-pairs
Input
| Argument Name | Description | Required |
|---|---|---|
| query | Domain or IP address you want to search host-pairs for. | Required |
| direction | The direction of searching pair records for a given domain. Valid values: children, parents. | Required |
| start | Filter for records whose last seen is after this datetime. It accepts “yyyy-mm-dd hh:mm:ss” or “yyyy-mm-dd” format. | Optional |
| end | Filter for records whose first seen is before this datetime. It accepts “yyyy-mm-dd hh:mm:ss” or “yyyy-mm-dd” format. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PassiveTotal.HostPair.firstSeen | Date | The date and time when the host pair was first observed. |
| PassiveTotal.HostPair.lastSeen | Date | The date and time when the host pair was most recently observed. |
| PassiveTotal.HostPair.cause | String | The cause of relation between parent and child. |
| PassiveTotal.HostPair.parent | String | The hostname of the parent of the host pair. |
| PassiveTotal.HostPair.child | String | The hostname of the child of the host pair. |
Command Example
!pt-get-host-pairs direction=children query=ns1.furth.com.ar
Context Example
{
"PassiveTotal": {
"HostPair": [
{
"cause": "redirect",
"child": "furth.com.ar",
"firstSeen": "2020-05-29 07:05:22",
"lastSeen": "2020-06-10 11:53:23",
"parent": "ns1.furth.com.ar"
},
{
"cause": "parentPage",
"child": "ns1.furth.com.ar",
"firstSeen": "2020-05-02 06:47:23",
"lastSeen": "2020-06-08 03:08:38",
"parent": "ns1.furth.com.ar"
}
]
}
}
Human Readable Output
Total Retrieved Record(s): 2
HOST PAIRS
Parent Hostname Child Hostname First (GMT) Last (GMT) Cause ns1.furth.com.ar furth.com.ar 2020-05-29 07:05:22 2020-06-10 11:53:23 redirect ns1.furth.com.ar ns1.furth.com.ar 2020-05-02 06:47:23 2020-06-08 03:08:38 parentPage
domain
Provides data enrichment for domains.
Notice: Submitting indicators using this command might make the indicator data publicly available. See the vendor’s documentation for more details.
Base Command
domain
Input
| Argument Name | Description | Required |
|---|---|---|
| domain | The domain to enrich. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Domain.Name | String | The domain name, for example: ‘google.com’. |
| Domain.WHOIS.CreationDate | Date | The date that the domain was created. |
| Domain.WHOIS.UpdatedDate | Date | The date that the domain was last updated. |
| Domain.WHOIS.ExpirationDate | Date | The expiration date of the domain. |
| Domain.WHOIS.NameServers | String | Name servers of the domain. |
| Domain.Organization | String | The organization of the domain. |
| Domain.Admin.Email | String | The email address of the domain administrator. |
| Domain.Admin.Name | String | The name of the domain administrator. |
| Domain.Admin.Phone | String | The phone number of the domain administrator. |
| Domain.Admin.Country | String | The country of the domain administrator. |
| Domain.Registrant.Email | String | The email address of the registrant. |
| Domain.Registrant.Name | String | The name of the registrant. |
| Domain.Registrant.Phone | String | The phone number for receiving abuse reports. |
| Domain.Registrant.Country | String | The country of the registrant. |
| Domain.WHOIS.Admin.Email | String | The email address of the domain administrator. |
| Domain.WHOIS.Admin.Name | String | The name of the domain administrator. |
| Domain.WHOIS.Admin.Phone | String | The phone number of the domain administrator. |
| Domain.WHOIS.Admin.Country | String | The country of the domain administrator. |
| Domain.WHOIS.Registrar.Name | String | The name of the registrar, for example: ‘GoDaddy’. |
| Domain.WHOIS.Registrant.Email | String | The email address of the registrant. |
| Domain.WHOIS.Registrant.Name | String | The name of the registrant. |
| Domain.WHOIS.Registrant.Phone | String | The phone number for receiving abuse reports. |
| Domain.WHOIS.Registrant.Country | String | The country of the registrant. |
| PassiveTotal.Domain.domain | String | The domain name, for example: ‘google.com’. |
| PassiveTotal.Domain.registrar | String | The name of the registrar of the domain |
| PassiveTotal.Domain.whoisServer | String | WHOIS server name where the details of domain registrations belong |
| PassiveTotal.Domain.registered | Date | The date that the domain was registered. |
| PassiveTotal.Domain.expiresAt | Date | The expiration date of the domain. |
| PassiveTotal.Domain.registryUpdatedAt | Date | The date when registry was last updated. |
| PassiveTotal.Domain.lastLoadedAt | Date | Last loaded date of WHOIS database. |
| PassiveTotal.Domain.nameServers | String | Name servers of the domain. |
| PassiveTotal.Domain.organization | String | The organization of the domain. |
| PassiveTotal.Domain.name | String | Name of the domain. |
| PassiveTotal.Domain.telephone | String | Telephone number fetched from whois details of the domain. |
| PassiveTotal.Domain.contactEmail | String | Contact Email address of the domain owner |
| PassiveTotal.Domain.registrantEmail | String | The name of the domain registrant. |
| PassiveTotal.Domain.registrantFax | String | The fax number of the domain registrant. |
| PassiveTotal.Domain.registrantName | String | The name of the domain registrant. |
| PassiveTotal.Domain.registrantOrganization | String | The organizations of the domain registrant. |
| PassiveTotal.Domain.registrantStreet | String | The street of the domain registrant. |
| PassiveTotal.Domain.registrantCity | String | The city of the domain registrant. |
| PassiveTotal.Domain.registrantState | String | The state of the domain registrant. |
| PassiveTotal.Domain.registrantPostalCode | String | The postal code of the domain registrant. |
| PassiveTotal.Domain.registrantCountry | String | The country of the domain registrant. |
| PassiveTotal.Domain.registrantTelephone | String | The telephone number of the domain registrant. |
| PassiveTotal.Domain.adminEmail | String | The email address of the domain administrator. |
| PassiveTotal.Domain.adminFax | String | The fax number of the domain administrator. |
| PassiveTotal.Domain.adminName | String | The name of the domain administrator. |
| PassiveTotal.Domain.adminOrganization | String | The organizations of the domain administrator. |
| PassiveTotal.Domain.adminStreet | String | The street of the domain administrator. |
| PassiveTotal.Domain.adminCity | String | The city of the domain administrator. |
| PassiveTotal.Domain.adminState | String | The state of the domain administrator. |
| PassiveTotal.Domain.adminPostalCode | String | The postal code of the domain administrator. |
| PassiveTotal.Domain.adminCountry | String | The country of the domain administrator. |
| PassiveTotal.Domain.adminTelephone | String | The telephone number of the domain administrator. |
| PassiveTotal.Domain.billingEmail | String | The email address of the domain billing. |
| PassiveTotal.Domain.billingFax | String | The fax number of the domain billing. |
| PassiveTotal.Domain.billingName | String | The name of the domain billing. |
| PassiveTotal.Domain.billingOrganization | String | The organizations of the domain billing. |
| PassiveTotal.Domain.billingStreet | String | The street of the domain billing. |
| PassiveTotal.Domain.billingCity | String | The city of the domain billing. |
| PassiveTotal.Domain.billingState | String | The state of the domain billing. |
| PassiveTotal.Domain.billingPostalCode | String | The postal code of the domain billing. |
| PassiveTotal.Domain.billingCountry | String | The country of the domain billing. |
| PassiveTotal.Domain.billingTelephone | String | The telephone number of the domain billing. |
| PassiveTotal.Domain.techEmail | String | The email address of the domain tech. |
| PassiveTotal.Domain.techFax | String | The fax number of the domain tech. |
| PassiveTotal.Domain.techName | String | The name of the domain tech. |
| PassiveTotal.Domain.techOrganization | String | The organizations of domain tech. |
| PassiveTotal.Domain.techStreet | String | The street of the domain tech. |
| PassiveTotal.Domain.techCity | String | The city of the domain tech. |
| PassiveTotal.Domain.techState | String | The state of the domain tech. |
| PassiveTotal.Domain.techPostalCode | String | The postal code of the domain tech. |
| PassiveTotal.Domain.techCountry | String | The country of the domain tech. |
| PassiveTotal.Domain.techTelephone | String | The telephone number of the domain tech. |
| 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 DBot score. |
| PassiveTotal.Domain.score | Number | Reputation score of the indicator. |
| PassiveTotal.Domain.classification | String | Reputation classification of the indicator. (Can be GOOD, SUSPICIOUS, MALICIOUS, or UNKNOWN) |
| PassiveTotal.Domain.rules.name | String | Name of the rule that informed the reputation score of the indicator. |
| PassiveTotal.Domain.rules.description | String | Description of the rule. |
| PassiveTotal.Domain.rules.severity | Number | Severity of the rule. |
| PassiveTotal.Domain.rules.link | String | Link to the rule. |
Command Example
!domain domain=riskiq.com
Context Example
{
"DBotScore": [
{
"Indicator": "riskiq.com",
"Score": 0,
"Type": "domain",
"Vendor": "PassiveTotal"
}
],
"Domain": [
{
"Admin": {
"Country": "us",
"Email": "domains@riskiq.com",
"Name": "Risk IQ",
"Phone": "18884154447"
},
"CreationDate": "2006-01-11T16:00:00.000-0800",
"ExpirationDate": "2017-01-11T16:00:00.000-0800",
"Name": "riskiq.com",
"NameServers": [
"luke.ns.cloudflare.com",
"serena.ns.cloudflare.com"
],
"Organization": "RiskIQ, Inc.",
"Registrant": {
"Country": "us",
"Email": "domains@riskiq.com",
"Name": "Risk IQ",
"Phone": "18884154447"
},
"Registrar": {
"AbuseEmail": null,
"AbusePhone": null,
"Name": "GODADDY.COM, LLC"
},
"UpdatedDate": "2014-12-08T16:00:00.000-0800",
"WHOIS": {
"Admin": {
"Country": "us",
"Email": "domains@riskiq.com",
"Name": "Risk IQ",
"Phone": "18884154447"
},
"CreationDate": "2006-01-11T16:00:00.000-0800",
"ExpirationDate": "2017-01-11T16:00:00.000-0800",
"NameServers": [
"luke.ns.cloudflare.com",
"serena.ns.cloudflare.com"
],
"Registrant": {
"Country": "us",
"Email": "domains@riskiq.com",
"Name": "Risk IQ",
"Phone": "18884154447"
},
"Registrar": {
"AbuseEmail": null,
"AbusePhone": null,
"Name": "GODADDY.COM, LLC"
},
"UpdatedDate": "2014-12-08T16:00:00.000-0800"
}
}
],
"PassiveTotal": {
"Domain": {
"adminCity": "san francisco",
"adminCountry": "us",
"adminEmail": "domains@riskiq.com",
"adminName": "Risk IQ",
"adminOrganization": "RiskIQ, Inc.",
"adminPostalCode": "94111",
"adminState": "california",
"adminStreet": "22 Battery Street\n10th Floor",
"adminTelephone": "18884154447",
"contactEmail": "domains@riskiq.com",
"domain": "riskiq.com",
"expiresAt": "2017-01-11T16:00:00.000-0800",
"lastLoadedAt": "2016-09-27T09:40:31.180-0700",
"name": "Risk IQ",
"nameServers": [
"luke.ns.cloudflare.com",
"serena.ns.cloudflare.com"
],
"organization": "RiskIQ, Inc.",
"registered": "2006-01-11T16:00:00.000-0800",
"registrantCity": "san francisco",
"registrantCountry": "us",
"registrantEmail": "domains@riskiq.com",
"registrantName": "Risk IQ",
"registrantOrganization": "RiskIQ, Inc.",
"registrantPostalCode": "94111",
"registrantState": "california",
"registrantStreet": "22 Battery Street\n10th Floor",
"registrantTelephone": "18884154447",
"registrar": "GODADDY.COM, LLC",
"registryUpdatedAt": "2014-12-08T16:00:00.000-0800",
"techCity": "san francisco",
"techCountry": "us",
"techEmail": "domains@riskiq.com",
"techName": "Risk IQ",
"techOrganization": "RiskIQ, Inc.",
"techPostalCode": "94111",
"techState": "california",
"techStreet": "22 Battery Street\n10th Floor",
"techTelephone": "18884154447",
"telephone": "18884154447",
"whoisServer": "whois.godaddy.com",
"score": 3,
"classification": "UNKNOWN",
"rules": [
{
"name": "Open ports observed",
"description": "The number of open ports may indicate maliciousness",
"severity": 3
}
]
}
}
}
Human Readable Output
Domain(s)
|Domain|WHOIS Server|Registrar|Contact Email|Name Servers|Registrant|Admin|Tech|Creation Date (GMT)|Expire Date (GMT)|Updated Date (GMT)|Last Scanned (GMT)|
|—|—|—|—|—|—|—|—|—|—|—|—|
| riskiq.com | whois.godaddy.com | GODADDY.COM, LLC | domains@riskiq.com | luke.ns.cloudflare.com, serena.ns.cloudflare.com | City: san francisco,
Country: us,
Email: domains@riskiq.com,
Name: Risk IQ,
Organization: RiskIQ, Inc.,
PostalCode: 94111,
State: california,
Street: 22 Battery Street
10th Floor,
Telephone: 18884154447 | City: san francisco,
Country: us,
Email: domains@riskiq.com,
Name: Risk IQ,
Organization: RiskIQ, Inc.,
PostalCode: 94111,
State: california,
Street: 22 Battery Street
10th Floor,
Telephone: 18884154447 | City: san francisco,
Country: us,
Email: domains@riskiq.com,
Name: Risk IQ,
Organization: RiskIQ, Inc.,
PostalCode: 94111,
State: california,
Street: 22 Battery Street
10th Floor,
Telephone: 18884154447 | 2006-01-11T16:00:00.000-0800 | 2017-01-11T16:00:00.000-0800 | 2014-12-08T16:00:00.000-0800 | 2016-09-27T09:40:31.180-0700 |
The reputation score for ‘riskiq.com’ is 3 and is classified as ‘UNKNOWN’.
Reputation Rules
Name Description Severity Open ports observed The number of open ports may indicate maliciousness 3
pt-get-services
Retrieves exposed services on the recently open ports for an IP address.
Base Command
pt-get-services
Input
| Argument Name | Description | Required |
|---|---|---|
| ip | IP address for which the user wants to search services for. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| PassiveTotal.Service.ip | String | IP address of the service. |
| PassiveTotal.Service.portNumber | Number | Port number on which recent services were running or current services are running. |
| PassiveTotal.Service.firstSeen | Date | The date and time when the service was started for the first time on the port. |
| PassiveTotal.Service.lastSeen | Date | The date and time when the service was most recently used on the port. |
| PassiveTotal.Service.lastScan | Date | The date and time when the system performed the last scan to check whether any service is running on the port or not. |
| PassiveTotal.Service.count | Number | The total number of times service was used on the port. |
| PassiveTotal.Service.status | String | The status of the service. |
| PassiveTotal.Service.protocol | String | The protocol used by the service. |
| PassiveTotal.Service.banners.banner | String | The description of the banner generated as a result of scanning. Can be in HTML format. |
| PassiveTotal.Service.banners.scanType | String | The type of scan when the banner was generated. |
| PassiveTotal.Service.banners.firstSeen | Date | The date and time when the scan started. |
| PassiveTotal.Service.banners.lastSeen | Date | The date and time when the scan ended. |
| PassiveTotal.Service.banners.count | Number | The total number of times the same label was generated while scanning. |
| PassiveTotal.Service.currentServices.firstSeen | Date | The date and time when the current service started. |
| PassiveTotal.Service.currentServices.lastSeen | Date | The date and time when the current service was most recently used. |
| PassiveTotal.Service.currentServices.version | String | The version of the current service. |
| PassiveTotal.Service.currentServices.category | String | The category of the current service. |
| PassiveTotal.Service.currentServices.label | String | The label of the current service. |
| PassiveTotal.Service.recentServices.firstSeen | Date | The date and time when the recent service started. |
| PassiveTotal.Service.recentServices.lastSeen | Date | The date and time when the recent service was most recently used. |
| PassiveTotal.Service.recentServices.version | String | The version of the recent service. |
| PassiveTotal.Service.recentServices.category | String | The category of the recent service. |
| PassiveTotal.Service.recentServices.label | String | The label of the recent service. |
| PassiveTotal.Service.mostRecentSslCert.firstSeen | Date | The timestamp in epoch when the most recent SSL certificate was identified by the system. |
| PassiveTotal.Service.mostRecentSslCert.lastSeen | Date | The timestamp in epoch when the most recent SSL certificate was last used. |
| PassiveTotal.Service.mostRecentSslCert.fingerprint | String | A fingerprint detail from the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.sslVersion | String | The version of the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.expirationDate | Date | The expiry date and time of the most recent SSL certificate in GMT. |
| PassiveTotal.Service.mostRecentSslCert.issueDate | Date | The date and time in GMT when the most recent SSL certificate was issued. |
| PassiveTotal.Service.mostRecentSslCert.sha1 | String | Sha1 of the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.serialNumber | String | The serial Number of the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.subjectCountry | String | The name of the Country of the subject of the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.issuerCommonName | String | The common name of the issuer of most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.issuerProvince | String | The province of the issuer of the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.subjectStateOrProvinceName | String | The state or province name of the subject of the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.subjectStreetAddress | String | The street address of the subject of the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.issuerStateOrProvinceName | String | The state or province name of the issuer of the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.subjectSurname | String | The surname of the subject of the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.issuerCountry | String | The country of the issuer of the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.subjectLocalityName | String | The subject locality name of the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.subjectAlternativeNames | String | List of alternative names of the subject of the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.issuerOrganizationUnitName | String | The name organization unit of the issuer of the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.issuerOrganizationName | String | The organization name of the issuer of the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.subjectEmailAddress | String | Email Address of the subject of the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.subjectOrganizationName | String | The organization name of the subject of the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.issuerLocalityName | String | The name of the locality of the issuer of the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.subjectCommonName | String | Common name of the subject of the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.subjectProvince | String | The province of the subject of the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.issuerGivenName | String | The given name of the issuer of the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.subjectOrganizationUnitName | String | Subject organization unit name of the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.issuerEmailAddress | String | The email address of the issuer of the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.subjectGivenName | String | Given name of the subject of the the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.subjectSerialNumber | String | The serial number of the subject of the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.issuerStreetAddress | String | The street Address of the issuer of the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.issuerSerialNumber | String | The serial number of the issuer of the most recent SSL certificate. |
| PassiveTotal.Service.mostRecentSslCert.issuerSurname | String | The surname of the issuer of the most recent SSL certificate. |
Command Example
!pt-get-services ip=1.1.1.1
Context Example
{
"PassiveTotal": {
"Service": [
{
"count": 42335,
"currentServices": [
{
"label": "Other Service"
}
],
"firstSeen": "2018-03-28 12:04:21",
"ip": "1.1.1.1",
"lastScan": "2021-03-06 02:28:14",
"lastSeen": "2021-03-04 05:11:29",
"portNumber": 53,
"protocol": "UDP",
"status": "filtered"
},
{
"banners": [
{
"banner": "<html>\r\n<head><title>301 Moved Permanently</title></head>\r\n<body>\r\n<center><h1>301 Moved Permanently</h1></center>\r\n<hr><center>cloudflare</center>\r\n</body>\r\n</html>\r\n",
"count": 3,
"firstSeen": "2021-03-05 13:56:20",
"lastSeen": "2021-03-06 00:20:32",
"scanType": "http"
}
],
"count": 1386,
"currentServices": [
{
"category": "Server",
"firstSeen": "2019-06-18 13:45:42",
"label": "CloudFlare",
"lastSeen": "2021-03-10 07:58:44"
},
{
"category": "Server",
"firstSeen": "2020-07-09 16:19:47",
"label": "cloudflare",
"lastSeen": "2021-03-10 05:59:33"
},
{
"category": "Server",
"firstSeen": "2018-07-02 11:46:37",
"label": "yunjiasu-nginx",
"lastSeen": "2021-03-09 02:26:20"
}
],
"firstSeen": "2018-04-01 00:38:56",
"ip": "1.1.1.1",
"lastScan": "2021-03-06 13:27:15",
"lastSeen": "2021-03-06 00:20:32",
"portNumber": 80,
"protocol": "TCP",
"recentServices": [
{
"category": "Server",
"firstSeen": "2020-03-18 20:37:06",
"label": "BigIP",
"lastSeen": "2021-03-05 21:31:27"
},
{
"category": "Server",
"firstSeen": "2020-06-11 11:50:49",
"label": "F5 BIG-IP load balancer httpd",
"lastSeen": "2021-03-05 21:31:27"
},
{
"category": "Server",
"firstSeen": "2020-10-27 12:39:22",
"label": "OpenResty web app server",
"lastSeen": "2021-02-27 19:59:14"
},
{
"category": "Server",
"firstSeen": "2019-02-09 11:59:43",
"label": "openresty",
"lastSeen": "2021-02-27 19:59:14"
},
{
"category": "Server",
"firstSeen": "2018-08-05 00:56:16",
"label": "Apache",
"lastSeen": "2020-11-09 07:02:20"
}
],
"status": "open"
},
{
"count": 41,
"currentServices": [
{
"label": "Other Service"
}
],
"firstSeen": "2020-02-29 04:02:09",
"ip": "1.1.1.1",
"lastScan": "2021-03-06 06:51:11",
"lastSeen": "2021-02-27 16:00:28",
"portNumber": 111,
"protocol": "UDP",
"status": "closed"
}
]
}
}
Human Readable Output
Total Retrieved Record(s) 13
Services
Port Number Protocol Status Current Service Labels First Seen Date (GMT) Last Seen Date (GMT) Last Scanned Date (GMT) 53 UDP filtered Other Service 2018-03-28 12:04:21 2021-03-04 05:11:29 2021-03-06 02:28:14 80 TCP open CloudFlare, cloudflare, yunjiasu-nginx 2018-04-01 00:38:56 2021-03-06 00:20:32 2021-03-06 13:27:15 111 UDP closed Other Service 2020-02-29 04:02:09 2021-02-27 16:00:28 2021-03-06 06:51:11
pt-get-whois
Gets WHOIS information records based on queries.
Base Command
pt-get-whois
Input
| Argument Name | Description | Required |
|---|---|---|
| query | Query value to use in the request. For example: riskiq.com, 1.1.1.1 | Required |
| history | Whether to return historical results. Valid values: true, false. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PassiveTotal.WHOIS.domain | String | The domain name. For example: ‘google.com’. |
| PassiveTotal.WHOIS.registrar | String | The name of the registrar of the domain. |
| PassiveTotal.WHOIS.whoisServer | String | WHOIS server name where the details of domain registrations belong. |
| PassiveTotal.WHOIS.registered | Date | The date that the domain was registered. |
| PassiveTotal.WHOIS.expiresAt | Date | The expiration date of the domain. |
| PassiveTotal.WHOIS.registryUpdatedAt | Date | The date when the registry was last updated. |
| PassiveTotal.WHOIS.lastLoadedAt | Date | Last loaded date of WHOIS database. |
| PassiveTotal.WHOIS.nameServers | String | Name servers of the domain. |
| PassiveTotal.WHOIS.organization | String | The organization of the domain. |
| PassiveTotal.WHOIS.name | String | Name of the domain. |
| PassiveTotal.WHOIS.telephone | String | Telephone number fetched from whois details of the domain. |
| PassiveTotal.WHOIS.contactEmail | String | Contact Email address of the domain owner. |
| PassiveTotal.WHOIS.registrantEmail | String | The name of the domain registrant. |
| PassiveTotal.WHOIS.registrantFax | String | The fax number of the domain registrant. |
| PassiveTotal.WHOIS.registrantName | String | The name of the domain registrant. |
| PassiveTotal.WHOIS.registrantOrganization | String | The organizations of the domain registrant. |
| PassiveTotal.WHOIS.registrantStreet | String | The street of the domain registrant. |
| PassiveTotal.WHOIS.registrantCity | String | The city of the domain registrant. |
| PassiveTotal.WHOIS.registrantState | String | The state of the domain registrant. |
| PassiveTotal.WHOIS.registrantPostalCode | String | The postal code of the domain registrant. |
| PassiveTotal.WHOIS.registrantCountry | String | The country of the domain registrant. |
| PassiveTotal.WHOIS.registrantTelephone | String | The telephone number of the domain registrant. |
| PassiveTotal.WHOIS.adminEmail | String | The email address of the domain administrator. |
| PassiveTotal.WHOIS.adminFax | String | The fax number of the domain administrator. |
| PassiveTotal.WHOIS.adminName | String | The name of the domain administrator. |
| PassiveTotal.WHOIS.adminOrganization | String | The organizations of the domain administrator. |
| PassiveTotal.WHOIS.adminStreet | String | The street of the domain administrator. |
| PassiveTotal.WHOIS.adminCity | String | The city of the domain administrator. |
| PassiveTotal.WHOIS.adminState | String | The state of the domain administrator. |
| PassiveTotal.WHOIS.adminPostalCode | String | The postal code of the domain administrator. |
| PassiveTotal.WHOIS.adminCountry | String | The country of the domain administrator. |
| PassiveTotal.WHOIS.adminTelephone | String | The telephone number of the domain administrator. |
| PassiveTotal.WHOIS.billingEmail | String | The email address of the domain billing. |
| PassiveTotal.WHOIS.billingFax | String | The fax number of the domain billing. |
| PassiveTotal.WHOIS.billingName | String | The name of the domain billing. |
| PassiveTotal.WHOIS.billingOrganization | String | The organizations of the domain billing. |
| PassiveTotal.WHOIS.billingStreet | String | The street of the domain billing. |
| PassiveTotal.WHOIS.billingCity | String | The city of the domain billing. |
| PassiveTotal.WHOIS.billingState | String | The state of the domain billing. |
| PassiveTotal.WHOIS.billingPostalCode | String | The postal code of the domain billing. |
| PassiveTotal.WHOIS.billingCountry | String | The country of the domain billing. |
| PassiveTotal.WHOIS.billingTelephone | String | The telephone number of the domain billing. |
| PassiveTotal.WHOIS.techEmail | String | The email address of the domain tech. |
| PassiveTotal.WHOIS.techFax | String | The fax number of the domain tech. |
| PassiveTotal.WHOIS.techName | String | The name of the domain tech. |
| PassiveTotal.WHOIS.techOrganization | String | The organizations of domain tech. |
| PassiveTotal.WHOIS.techStreet | String | The street of the domain tech. |
| PassiveTotal.WHOIS.techCity | String | The city of the domain tech. |
| PassiveTotal.WHOIS.techState | String | The state of the domain tech. |
| PassiveTotal.WHOIS.techPostalCode | String | The postal code of the domain tech. |
| PassiveTotal.WHOIS.techCountry | String | The country of the domain tech. |
| PassiveTotal.WHOIS.techTelephone | String | The telephone number of the domain tech. |
Command Example
!pt-get-whois query=riskiq.com
Context Example
{
"PassiveTotal": {
"WHOIS": {
"adminCity": "san francisco",
"adminCountry": "us",
"adminEmail": "domains@riskiq.com",
"adminName": "Risk IQ",
"adminOrganization": "RiskIQ, Inc.",
"adminPostalCode": "94111",
"adminState": "california",
"adminStreet": "22 Battery Street\n10th Floor",
"adminTelephone": "18884154447",
"contactEmail": "domains@riskiq.com",
"domain": "riskiq.com",
"expiresAt": "2017-01-11T16:00:00.000-0800",
"lastLoadedAt": "2016-09-27T09:40:31.180-0700",
"name": "Risk IQ",
"nameServers": [
"luke.ns.cloudflare.com",
"serena.ns.cloudflare.com"
],
"organization": "RiskIQ, Inc.",
"registered": "2006-01-11T16:00:00.000-0800",
"registrantCity": "san francisco",
"registrantCountry": "us",
"registrantEmail": "domains@riskiq.com",
"registrantName": "Risk IQ",
"registrantOrganization": "RiskIQ, Inc.",
"registrantPostalCode": "94111",
"registrantState": "california",
"registrantStreet": "22 Battery Street\n10th Floor",
"registrantTelephone": "18884154447",
"registrar": "GODADDY.COM, LLC",
"registryUpdatedAt": "2014-12-08T16:00:00.000-0800",
"techCity": "san francisco",
"techCountry": "us",
"techEmail": "domains@riskiq.com",
"techName": "Risk IQ",
"techOrganization": "RiskIQ, Inc.",
"techPostalCode": "94111",
"techState": "california",
"techStreet": "22 Battery Street\n10th Floor",
"techTelephone": "18884154447",
"telephone": "18884154447",
"whoisServer": "whois.godaddy.com"
}
}
}
Human Readable Output
Total Retrieved Record(s): 1
Associated Domains
Domain WHOIS Server Registrar Contact Email Name Servers Registrant Admin Tech Creation Date (GMT) Expire Date (GMT) Updated Date (GMT) Last Scanned (GMT) riskiq.com whois.godaddy.com GODADDY.COM, LLC domains@riskiq.com luke.ns.cloudflare.com, serena.ns.cloudflare.com City: san francisco,
Country: us,
Email: domains@riskiq.com,
Name: Risk IQ,
Organization: RiskIQ, Inc.,
PostalCode: 94111,
State: california,
Street: 22 Battery Street
10th Floor,
Telephone: 18884154447City: san francisco,
Country: us,
Email: domains@riskiq.com,
Name: Risk IQ,
Organization: RiskIQ, Inc.,
PostalCode: 94111,
State: california,
Street: 22 Battery Street
10th Floor,
Telephone: 18884154447City: san francisco,
Country: us,
Email: domains@riskiq.com,
Name: Risk IQ,
Organization: RiskIQ, Inc.,
PostalCode: 94111,
State: california,
Street: 22 Battery Street
10th Floor,
Telephone: 188841544472006-01-11T16:00:00.000-0800 2017-01-11T16:00:00.000-0800 2014-12-08T16:00:00.000-0800 2016-09-27T09:40:31.180-0700
pt-get-cookies
Retrieves cookies addresses or hostname information based on cookie name or domain.
Base Command
pt-get-cookies
Input
| Argument Name | Description | Required |
|---|---|---|
| search_by | Search cookies information by name or domain. Valid values: 1. get addresses by cookie domain, 2. get addresses by cookie name, 3. get hosts by cookie domain, 4. get hosts by cookie name. | Required |
| query | Name or domain of cookie the user wants to search for. | Required |
| page | Page number for paging through results. Each page contains 2000 values. Default is 0. | Optional |
| sort | Field to sort the results on. Valid values: last seen, first seen. Default is last seen. | Optional |
| order | Order to return the results in. Valid values: asc, desc. Default is desc. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PassiveTotal.Cookie.hostname | String | The hostname/IP of the machine on which the cookie was found. |
| PassiveTotal.Cookie.cookieName | String | The name of the cookie that was found on the host. |
| PassiveTotal.Cookie.cookieDomain | String | The domain from which the cookie originated from. |
| PassiveTotal.Cookie.firstSeen | Date | The date and time when the cookie was first observed. |
| PassiveTotal.Cookie.lastSeen | Date | The date and time when the cookie was most recently observed. |
Command Example
!pt-get-cookies search_by="get hosts by cookie name" query=dummyCookie
Context Example
{
"PassiveTotal": {
"Cookie": [
{
"cookieDomain": "dummy.domain",
"cookieName": "dummyCookie",
"firstSeen": "2016-11-22 03:36:07",
"hostname": "dummy.domain",
"lastSeen": "2017-07-27 21:05:10"
}
]
}
}
Human Readable Output
Total Record(s): 1
Total Retrieved Record(s): 1
Cookies
Hostname Cookie Name Cookie Domain First Seen Date (GMT) Last Seen Date (GMT) dummy.domain dummyCookie dummy.domain 2019-04-02 01:53:50 2021-01-22 07:15:13
pt-get-articles
Retrieves information related to articles for a specific indicator.
Base Command
pt-get-articles
Input
| Argument Name | Description | Required |
|---|---|---|
| query | Indicator value to search for in articles. For example: riskiq.com, 1.1.1.1 | Required |
| type | Type of the indicator. For example: domain, ip, url | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PassiveTotal.Article.guid | String | The global unique ID of the article. |
| PassiveTotal.Article.title | String | The title of the article. |
| PassiveTotal.Article.summary | String | The summary of the article. |
| PassiveTotal.Article.type | String | The type of an article. |
| PassiveTotal.Article.publishedDate | Date | The date and time on which the article was published. |
| PassiveTotal.Article.link | String | The link of the article for getting more details. |
| PassiveTotal.Article.categories | Unknown | An array of categories of the article. |
| PassiveTotal.Article.tags | Unknown | An array of tags for the article. |
| PassiveTotal.Article.indicators.type | String | The type of the indicator. |
| PassiveTotal.Article.indicators.count | Number | Total number of indicators of a particular type. |
| PassiveTotal.Article.indicators.values | Unknown | An array of values related to indicators. |
| PassiveTotal.Article.indicators.source | String | The source of the indicator. |
Command Example
!pt-get-articles query=dummy.com
Context Example
{
"PassiveTotal": {
"Article": {
"categories": [
"Categories 1",
"Categories 2"
],
"guid": "12e123b1",
"indicators": [
{
"count": 1,
"source": "public",
"type": "domain",
"values": [
"dummy.com"
]
}
],
"link": "https://community.riskiq.com/article/12e123b1",
"publishedDate": "Mon Aug 29 20:00:00 VET 2016",
"summary": "Did you know that you can get all kinds of free stuff, just by giving out your personal information? The internet is full of these fake reward scams which RiskIQ's sytems surface every hour of the day.",
"tags": [
"fake rewards",
"playstation",
"scam"
],
"title": "Free PlayStations on the Internet are Probably an Online Scam",
"type": "public"
}
}
}
Human Readable Output
Total Retrieved Record(s): 1
Article(s)
GUID Title Summary Type Tags Categories Article Link Published Date (GMT) 12e123b1 Free PlayStations on the Internet are Probably an Online Scam Did you know that you can get all kinds of free stuff, just by giving out your personal information? The internet is full of these fake reward scams which RiskIQ’s sytems surface every hour of the day. public fake rewards, playstation, scam Categories 1, Categories 2 https://community.riskiq.com/article/12e123b1 Mon Aug 29 20:00:00 VET 2016
pt-get-data-card
Retrieves a summary data card associated with the given query.
Base Command
pt-get-data-card
Input
| Argument Name | Description | Required |
|---|---|---|
| query | The domain, host or IP address to be queried. For example: riskiq.com, 1.1.1.1. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| PassiveTotal.DataCard.type | String | Type of the indicator. |
| PassiveTotal.DataCard.name | String | Name of the indicator. |
| PassiveTotal.DataCard.link | String | Link to the indicator. |
| PassiveTotal.DataCard.netblock | String | Netblock associated with the indicator. |
| PassiveTotal.DataCard.os | String | Operating system associated with the indicator. |
| PassiveTotal.DataCard.organization | String | The organization of the indicator. |
| PassiveTotal.DataCard.asn | String | Autonomous system number assigned to the indicator. |
| PassiveTotal.DataCard.hosting_provider | String | Host provider of the indicator. |
| PassiveTotal.DataCard.data_summary.resolutions.count | Number | Number of resolutions attached to the indicator. |
| PassiveTotal.DataCard.data_summary.resolutions.link | String | Link of the resolutions attached to the indicator. |
| PassiveTotal.DataCard.data_summary.services.count | Number | Number of service records for the indicator. |
| PassiveTotal.DataCard.data_summary.services.link | String | Link to the service records of the indicator. |
| PassiveTotal.DataCard.data_summary.certificates.count | Number | Number of certificates for the given indicator. |
| PassiveTotal.DataCard.data_summary.certificates.link | String | Link to the certificates associated with the indicator. |
| PassiveTotal.DataCard.data_summary.hashes.count | Number | Number of hashes associated with the indicator. |
| PassiveTotal.DataCard.data_summary.hashes.link | String | Link to the hashes associated with the indicator. |
| PassiveTotal.DataCard.data_summary.projects.count | Number | Number of projects containing the indicator. |
| PassiveTotal.DataCard.data_summary.projects.link | String | Number of projects containing the indicator. |
| PassiveTotal.DataCard.data_summary.articles.count | Number | Number of articles referencing the indicator. |
| PassiveTotal.DataCard.data_summary.articles.link | String | Link to the articles referencing the indicator. |
| PassiveTotal.DataCard.data_summary.trackers.count | Number | Number of trackers associated with the indicator. |
| PassiveTotal.DataCard.data_summary.trackers.link | String | Link to the trackers associated with the indicator. |
| PassiveTotal.DataCard.data_summary.components.count | Number | Number of components associated with the indicator. |
| PassiveTotal.DataCard.data_summary.components.link | String | Link to the components associated with the indicator. |
| PassiveTotal.DataCard.data_summary.host_pairs.count | Number | Number of host pairs associated with the indicator. |
| PassiveTotal.DataCard.data_summary.host_pairs.link | String | Link to the host pairs associated with the indicator. |
| PassiveTotal.DataCard.data_summary.reverse_dns.count | Number | Number of DNS records for the indicator. |
| PassiveTotal.DataCard.data_summary.reverse_dns.link | String | Link to the DNS records of the indicator. |
| PassiveTotal.DataCard.data_summary.cookies.count | Number | Number of available cookie records for the indicator. |
| PassiveTotal.DataCard.data_summary.cookies.link | String | Link to the cookie records for the indicator. |
Command Example
!pt-get-data-card query="1.1.1.1"
Context Example
{
"PassiveTotal": {
"DataCard": {
"asn": "AS13335 - CLOUDFLARENET",
"data_summary": {
"articles": {
"count": 0,
"link": "https://community.pt.com/research/1.1.1.1"
},
"certificates": {
"count": 3742,
"link": "https://community.pt.com/search/1.1.1.1/domaincertificates"
},
"components": {
"count": 914,
"link": "https://community.pt.com/search/1.1.1.1/components"
},
"cookies": {
"count": 23346,
"link": "https://community.pt.com/search/1.1.1.1/cookies"
},
"hashes": {
"count": 1000,
"link": "https://community.pt.com/search/1.1.1.1/hashes"
},
"host_pairs": {
"count": 6987,
"link": "https://community.pt.com/search/1.1.1.1/hostpairs"
},
"projects": {
"count": 4,
"link": "https://community.pt.com/search/1.1.1.1/projects"
},
"resolutions": {
"count": 1997,
"link": "https://community.pt.com/search/1.1.1.1/resolutions"
},
"reverse_dns": {
"count": 5,
"link": "https://community.pt.com/search/1.1.1.1/dns"
},
"services": {
"count": 3,
"link": "https://community.pt.com/search/1.1.1.1/services"
},
"trackers": {
"count": 3983,
"link": "https://community.pt.com/search/1.1.1.1/trackers"
}
},
"hosting_provider": "Cloudflare",
"link": "https://community.pt.com/search/1.1.1.1",
"name": "1.1.1.1",
"netblock": "1.1.1.0/24",
"organization": "Cloudflare, Inc.",
"os": "CentOS",
"type": "IP Address"
}
}
}
Human Readable Output
Data Card Summary
Name Type Netblock Autonomous System Number Host Provider Operating System Data Card Summary 1.1.1.1 IP Address 1.1.1.0/24 AS13335 - CLOUDFLARENET Cloudflare CentOS Resolutions: 1997, Services: 3, Certificates: 3742, Hashes: 1000, Projects: 4, Articles: 0, Trackers: 3983, Components: 914, Host Pairs: 6987, Reverse Dns: 5, Cookies: 23346
pt-get-reputation
Gets reputation for a given domain, host or IP.
Base Command
pt-get-reputation
Input
| Argument Name | Description | Required |
|---|---|---|
| query | The domain, host or IP address to be queried. For example: riskiq.com, 1.1.1.1. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| PassiveTotal.Reputation.query | String | The value of the indicator. |
| PassiveTotal.Reputation.score | Number | Reputation score of the indicator. |
| PassiveTotal.Reputation.classification | String | Reputation classification of the indicator. (Can be GOOD, SUSPICIOUS, MALICIOUS, or UNKNOWN) |
| PassiveTotal.Reputation.rules.name | String | Name of the rule that informed the reputation score of the indicator. |
| PassiveTotal.Reputation.rules.description | String | Description of the rule. |
| PassiveTotal.Reputation.rules.severity | Number | Severity of the rule. |
| PassiveTotal.Reputation.rules.link | String | Link to the rule. |
Command Example
!pt-get-reputation query="amazon.hksupd.com"
Context Example
{
"PassiveTotal": {
"Reputation": {
"classification": "MALICIOUS",
"query": "amazon.hksupd.com",
"rules": [
{
"description": "Vermilion Strike: Linux and Windows Re-implementation of Cobalt Strike",
"link": "https://community.pt.com/article/d0bf5d18",
"name": "RiskIQ Intel Article",
"severity": 5
}
],
"score": 100
}
}
}
Human Readable Output
The reputation score for ‘amazon.hksupd.com’ is 100 and is classified as ‘MALICIOUS’.
Reputation Rules
Name Description Severity RiskIQ Intel Article Vermilion Strike: Linux and Windows Re-implementation of Cobalt Strike 5
ip
Checks the reputation of an IP address.
Base Command
ip
Input
| Argument Name | Description | Required |
|---|---|---|
| ip | The IP address to check. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PassiveTotal.IP.query | String | The value of the indicator. |
| PassiveTotal.IP.score | Number | Reputation score of the indicator. |
| PassiveTotal.IP.classification | String | Reputation classification of the indicator. (Can be GOOD, SUSPICIOUS, MALICIOUS, or UNKNOWN) |
| PassiveTotal.IP.rules.name | String | Name of the rule that informed the reputation score of the indicator. |
| PassiveTotal.IP.rules.description | String | Description of the rule. |
| PassiveTotal.IP.rules.severity | Number | Severity of the rule. |
| PassiveTotal.IP.rules.link | String | Link to the rule. |
| DBotScore.Indicator | String | The indicator that was tested. |
| DBotScore.Score | Number | The actual score. |
| DBotScore.Type | String | The indicator type. |
| DBotScore.Vendor | String | The vendor used to calculate the score. |
| IP.Address | String | The IP Address. |
Command Example
!ip ip=8.8.8.8
Context Example
{
"DBotScore": {
"Indicator": "8.8.8.8",
"Score": 0,
"Type": "ip",
"Vendor": "PassiveTotal v2"
},
"IP": {
"Address": "8.8.8.8"
},
"PassiveTotal": {
"IP": {
"classification": "UNKNOWN",
"query": "8.8.8.8",
"rules": [
{
"description": "The number of open ports may indicate maliciousness",
"name": "Open ports observed",
"severity": 3
}
],
"score": 3
}
}
}
Human Readable Output
The reputation score for ‘8.8.8.8’ is 3 and is classified as ‘UNKNOWN’.
Reputation Rules
Name Description Severity Open ports observed The number of open ports may indicate maliciousness 3
pt-list-intel-profiles
Retrieves the list of all profiles.
Base Command
pt-list-intel-profiles
Input
| Argument Name | Description | Required |
|---|---|---|
| id | Specify the ID of the profile to retrieve the specific profile. Note: If ‘id’ argument is provided, all other arguments will be neglected. |
Optional |
| query | Filter the result based on title or aliases. . | Optional |
| type | Filter the results based on the profile type. Possible values: actor, tool, backdoor. |
Optional |
| indicator_value | Specify the indicator value to retrieve the profiles containing the given indicator. Note: To retrieve the list of indicators, execute the “pt-list-intel-profile-indicators” command. When both indicator_value and query are provided, higher priority will be given to indicator_value. |
Optional |
| source | Filter the result based on the indicator source. Possible values: osint, riskiq. Note: Requires ‘indicator_value’ argument. |
Optional |
| category | Filter the result based on the indicator category. Possible values: host, network. Note: Requires ‘indicator_value’ argument. |
Optional |
| page_size | Maximum number of results to return per page. Note: The minimum value supported is 1 and maximum value supported is 1000. Default is 50. |
Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PassiveTotal.IntelProfile.id | String | ID of the intel profile. |
| PassiveTotal.IntelProfile.title | String | Title of the intel profile. |
| PassiveTotal.IntelProfile.link | String | Link to the intel profile. |
| PassiveTotal.IntelProfile.osintIndicatorsCount | Number | Count of the open source intelligence indicators referencing the intel profile. |
| PassiveTotal.IntelProfile.riskIqIndicatorsCount | Number | Count of the riskiq indicators referencing the intel profile. |
| PassiveTotal.IntelProfile.indicators | String | Link to the indicators referencing the intel profile. |
| PassiveTotal.IntelProfile.aliases | String | Aliases of the intel profile. |
| PassiveTotal.IntelProfile.tags.label | String | Labels associated with the intel profile. |
| PassiveTotal.IntelProfile.tags.countryCode | String | Country code of the tags associated with the intel profile. |
Command Example
!pt-list-intel-profiles id="apt33"
Context Example
{
"PassiveTotal": {
"IntelProfile": {
"aliases": [
"Elfin",
"Magnallium",
"Refined Kitten",
"Holmium",
"Cobalt Trinity"
],
"id": "apt33",
"indicators": "https://api.pt.net/pt/v2/intel-profiles/apt33/indicators",
"link": "https://community.pt.com/intel-profiles/apt33",
"osintIndicatorsCount": 410,
"riskIqIndicatorsCount": 122,
"tags": [
{
"label": "Espionage"
},
{
"label": "Sabotage"
},
{
"label": "Windows"
},
{
"label": "Aviation"
},
{
"label": "Defense"
},
{
"label": "Oil & Gas"
},
{
"countryCode": "ir",
"label": "State Sponsored: Iran"
},
{
"countryCode": "sa",
"label": "Target: Saudi Arabia"
},
{
"countryCode": "us",
"label": "Target: USA"
},
{
"countryCode": "kr",
"label": "Target: South Korea"
},
{
"countryCode": "il",
"label": "Target: Israel"
}
],
"title": "APT33"
}
}
}
Human Readable Output
Profile(s)
ID Title Aliases Public Indicators RiskIQ Indicators apt33 APT33 Elfin, Magnallium, Refined Kitten, Holmium, Cobalt Trinity 410 122
pt-list-intel-profile-indicators
Retrieves the indicators for the given profile.
Base Command
pt-list-intel-profile-indicators
Input
| Argument Name | Description | Required |
|---|---|---|
| id | Specify the ID of the profile to retrieve indicators for the specific profile. Note: To retrieve the list of profile IDs, execute the “pt-list-intel-profile” command. |
Required |
| type | Filter the results based on the indicator type. Possible values: certificate_sha1, domain, email, hash_md5, hash_sha256, ip, pdb_path, soa_email, url, whois_email. |
Optional |
| indicator_value | Specify the indicator value to retrieve the specific indicator. | Optional |
| source | Filter the result based on the indicator source. Possible values: osint, riskiq. |
Optional |
| category | Filter the result based on the indicator category. Possible values: host, network. |
Optional |
| page_number | Page number for paging through results. Note: The minimum value supported is 0 and maximum value supported is int32. Default is 0. |
Optional |
| page_size | Maximum number of results to return per page. Note: The minimum value supported is 1 and maximum value supported is int32. Default is 50. |
Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PassiveTotal.IntelProfile.id | String | Profile ID containing the indicator. |
| PassiveTotal.IntelProfile.indicator.id | String | ID of the indicator. |
| PassiveTotal.IntelProfile.indicator.type | String | Type of the indicator. |
| PassiveTotal.IntelProfile.indicator.value | String | Value of the indicator. |
| PassiveTotal.IntelProfile.indicator.category | String | Category of the indicator. |
| PassiveTotal.IntelProfile.indicator.firstSeen | String | Date & time the record was first seen. |
| PassiveTotal.IntelProfile.indicator.lastSeen | String | Date & time the record was most recently observed. |
| PassiveTotal.IntelProfile.indicator.osint | String | Whether the indicator was published in open source intelligence articles. |
| PassiveTotal.IntelProfile.indicator.osintUrl | String | Link to the osint source of the indicator. |
| PassiveTotal.IntelProfile.indicator.articleGuids | String | List of RiskIQ OSINT article GUIDs associated with the indicator. |
Command Example
!pt-list-intel-profile-indicators id="apt33" page_size=1
Context Example
{
"PassiveTotal": {
"IntelProfile": {
"id": "apt33",
"indicator": [
{
"articleGuids": [
"633605c6"
],
"category": "host",
"firstSeen": "2017-03-06T00:00:00.000+00:00",
"id": "apt33:00c417425a73db5a315d23fac8cb353f",
"osint": true,
"type": "hash_md5",
"value": "00c417425a73db5a315d23fac8cb353f",
"lastSeen": "2017-03-06T00:00:00.000+00:00"
}
]
}
}
}
Human Readable Output
Total Retrieved Indicator(s) 532
Indicator(s)
ID Artifact Value Type First Seen (GMT) Last Seen (GMT) Source apt33:00c417425a73db5a315d23fac8cb353f 00c417425a73db5a315d23fac8cb353f hash_md5 2017-03-06T00:00:00.000+00:00 2017-03-06T00:00:00.000+00:00 OSINT
pt-list-my-attack-surface-insights
Retrieves the attack surface insight information of the individual’s account.
Base Command
pt-list-my-attack-surface-insights
Input
| Argument Name | Description | Required |
|---|---|---|
| priority | Filter the results based on the priority level specified. Possible values: high, medium, low. |
Required |
| page_size | Maximum number of results to return per page. Note: The minimum value supported is 1 and maximum value supported is 1000. Default is 50. |
Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PassiveTotal.Summary.Insight.name | String | The command name. |
| PassiveTotal.Summary.Insight.activeInsightCount | Number | Total number of active insights. |
| PassiveTotal.Summary.Insight.totalInsightCount | Number | Total number of insights. |
| PassiveTotal.Summary.Insight.totalObservations | Number | Total number of observations. |
| PassiveTotal.Insight.priorityLevel | String | Priority level of insights. |
| PassiveTotal.Insight.insight.name | String | Name of the insight. |
| PassiveTotal.Insight.insight.description | String | Description of the insight. |
| PassiveTotal.Insight.insight.observationCount | Number | Number of observations for the given insight. |
| PassiveTotal.Insight.insight.link | String | Link to the insight. |
| PassiveTotal.Insight.insight.insightId | String | ID of the third party insight. |
| PassiveTotal.Insight.insight.segmentBy | String | Segment by of the insight. |
Command Example
!pt-list-my-attack-surface-insights priority="low"
Context Example
{
"PassiveTotal": {
"Insight": {
"insight": [
{
"description": "##### Description \nThe following SSL certificates are SHA-1 certificates and are no longer recognized by web browsers due to possible hash collision.\n\n##### Remediation\nOrganizations should replace these certificates with new SSL certificate that use SHA-256.",
"insightId": "40466",
"link": "https://api.pt.net/pt/v2/attack-surface/insight/40466?page=0&size=25&groupBy=RISK_CATEGORY&segmentBy=savedfilter_metric_29630",
"name": "ASI: SHA-1 Certificates",
"observationCount": 0,
"segmentBy": "savedfilter_metric_29630"
},
{
"description": "##### Description \nDeprecated versions of Nginx web server that are no longer supported. Running end of life or deprecated hardware or software can open organizations up to potential risks and vulnerabilities as these systems are no longer supported via regular updates and security patches\n\n##### Remediation\nOrganizations should consider upgrading to supported versions of Nginx to ensure security patches are available.\n",
"insightId": "40466",
"link": "https://api.pt.net/pt/v2/attack-surface/insight/40466?page=0&size=25&groupBy=RISK_CATEGORY&segmentBy=savedfilter_metric_29643",
"name": "ASI: Deprecated Tech - Nginx",
"observationCount": 146,
"segmentBy": "savedfilter_metric_29643"
}
],
"priorityLevel": "low"
},
"Summary": {
"Insight": {
"activeInsightCount": 6,
"name": "pt-list-my-attack-surface-insights",
"totalInsightCount": 11,
"totalObservations": 165
}
}
}
}
Human Readable Output
Low Severity Insights
6 Active of 11 Insights - 165 Observations
Name Description Observations Insight ID Segment By ASI: Deprecated Tech - Nginx ##### Description
Deprecated versions of Nginx web server that are no longer supported. Running end of life or deprecated hardware or software can open organizations up to potential risks and vulnerabilities as these systems are no longer supported via regular updates and security patches
##### Remediation
Organizations should consider upgrading to supported versions of Nginx to ensure security patches are available.146 40466 savedfilter_metric_29643 ASI: SSL Certificates Expiring in 30 Days ##### Description
The following SSL Certificates expire within the next 30 days. Expired certificates can lead to critical business functions being unavailable to customers or employees. Expired certificates could prevent customers from accessing your website and negatively impact an organization’s brand.
##### Remediation
Organizations should review these certificates and ensure appropriate policies and procedures are in place to keep SSL certificates up to date.13 40466 savedfilter_metric_29632
pt-list-my-attack-surfaces
Retrieves the attack surface information of the individual’s account.
Base Command
pt-list-my-attack-surfaces
Input
| Argument Name | Description | Required |
|---|---|---|
| page_size | Maximum number of results to return per page. Note: The minimum value supported is 1 and maximum value supported is 1000. Default is 50. |
Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PassiveTotal.AttackSurface.id | Number | ID of the attack surface. |
| PassiveTotal.AttackSurface.name | String | Name of the attack surface. |
| PassiveTotal.AttackSurface.priority.high.observationCount | Number | Total observations of high priority attack surface. |
| PassiveTotal.AttackSurface.priority.high.link | String | Link to the high priority attack surface. |
| PassiveTotal.AttackSurface.priority.medium.observationCount | Number | Total observations of medium priority attack surface. |
| PassiveTotal.AttackSurface.priority.medium.link | String | Link to the medium priority attack surface. |
| PassiveTotal.AttackSurface.priority.low.observationCount | Number | Total observations of low priority attack surface. |
| PassiveTotal.AttackSurface.priority.low.link | String | Link to the low priority attack surface. |
Command Example
#### Context Example
```json
{
"PassiveTotal": {
"AttackSurface": {
"id": 88256,
"name": "RiskIQ, Inc.",
"priority": {
"high": {
"link": "https://api.pt.net/pt/v2/attack-surface/priority/high",
"observationCount": 13
},
"low": {
"link": "https://api.pt.net/pt/v2/attack-surface/priority/low",
"observationCount": 165
},
"medium": {
"link": "https://api.pt.net/pt/v2/attack-surface/priority/medium",
"observationCount": 4
}
}
}
}
}
Human Readable Output
Attack Surface(s)
ID Name High Severity Medium Severity Low Severity 88256 RiskIQ, Inc. 13 observations 4 observations 165 observations
pt-list-third-party-attack-surface
Retrieves the attack surface observations by severity level for the given third-party account.
Base Command
pt-list-third-party-attack-surface
Input
| Argument Name | Description | Required |
|---|---|---|
| id | Specify the vendor ID to retrieve the attack surface third party information. | Optional |
| page_number | Page number for paging through results. Note: The minimum value supported is 0 and maximum value supported is int32. Default is 0. |
Optional |
| page_size | Maximum number of results to return per page. Note: The minimum value supported is 1 and maximum value supported is int32. Default is 50. |
Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PassiveTotal.ThirdParty.id | Number | ID of the vendor. |
| PassiveTotal.ThirdParty.name | String | Name of the vendor. |
| PassiveTotal.ThirdParty.priority.high.observationCount | Number | Total observations of high priority attack surface. |
| PassiveTotal.ThirdParty.priority.high.link | String | Link to the high priority attack surface. |
| PassiveTotal.ThirdParty.priority.medium.observationCount | Number | Total observations of medium priority attack surface. |
| PassiveTotal.ThirdParty.priority.medium.link | String | Link to the medium priority attack surface. |
| PassiveTotal.ThirdParty.priority.low.observationCount | Number | Total observations of low priority attack surface. |
| PassiveTotal.ThirdParty.priority.low.link | String | Link to the low priority attack surface. |
| PassiveTotal.Summary.ThirdPartyASI.name | String | The command name. |
| PassiveTotal.Summary.ThirdPartyASI.totalCount | Number | Total number of attack surfaces. |
| PassiveTotal.Summary.ThirdPartyASI.totalPages | Number | Number of pages. |
| PassiveTotal.Summary.ThirdPartyASI.nextPage | String | Link to the next page. |
Command Example
#### Context Example
```json
{
"PassiveTotal": {
"Summary": {
"ThirdPartyASI": {
"name": "pt-list-third-party-attack-surface",
"totalCount": 2,
"totalPages": 1
}
},
"ThirdParty": [
{
"id": 45998,
"name": "Mitsubishi Corporation",
"priority": {
"high": {
"link": "https://api.pt.net/pt/v2/attack-surface/third-party/45998/priority/high",
"observationCount": 3
},
"low": {
"link": "https://api.pt.net/pt/v2/attack-surface/third-party/45998/priority/low",
"observationCount": 92
},
"medium": {
"link": "https://api.pt.net/pt/v2/attack-surface/third-party/45998/priority/medium",
"observationCount": 35
}
}
},
{
"id": 371662,
"name": "Aeroflot-Russian Airlines",
"priority": {
"high": {
"link": "https://api.pt.net/pt/v2/attack-surface/third-party/371662/priority/high",
"observationCount": 7
},
"low": {
"link": "https://api.pt.net/pt/v2/attack-surface/third-party/371662/priority/low",
"observationCount": 16
},
"medium": {
"link": "https://api.pt.net/pt/v2/attack-surface/third-party/371662/priority/medium",
"observationCount": 8
}
}
}
]
}
}
Human Readable Output
Attack Surface(s)
ID Name High Severity Medium Severity Low Severity 45998 Mitsubishi Corporation 3 observations 35 observations 92 observations 371662 Aeroflot-Russian Airlines 7 observations 8 observations 16 observations
pt-list-third-party-attack-surface-insights
Retrieves the attack surface insight information of the given third-party account.
Base Command
pt-list-third-party-attack-surface-insights
Input
| Argument Name | Description | Required |
|---|---|---|
| id | Specify the vendor ID to retrieve the third-party insights information. Note: To retrieve the list of vendor IDs, execute the “pt-list-third-party-attack-surface” command. |
Required |
| priority | Filter the results based on the priority level specified. Possible values: high, medium, low. |
Required |
| page_size | Maximum number of results to return per page. Note: The minimum value supported is 1 and maximum value supported is 1000. Default is 50. |
Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PassiveTotal.Summary.ThirdPartyInsight.activeInsightCount | Number | Total number of active third party insights. |
| PassiveTotal.Summary.ThirdPartyInsight.totalInsightCount | Number | Total number of third party insights. |
| PassiveTotal.Summary.ThirdPartyInsight.totalObservations | Number | Total number of third party observations. |
| PassiveTotal.ThirdParty.id | Number | Vendor ID associated with the third party insights. |
| PassiveTotal.ThirdParty.priorityLevel | String | Priority level of third party insights. |
| PassiveTotal.ThirdParty.Insight.insight.name | String | Name of the third party insight. |
| PassiveTotal.ThirdParty.Insight.insight.description | String | Description of the third party insight. |
| PassiveTotal.ThirdParty.Insight.insight.observationCount | Number | Number of observations for the given third party insight. |
| PassiveTotal.ThirdParty.Insight.insight.link | String | Link to the third party insight. |
| PassiveTotal.ThirdParty.Insight.insight.insightId | String | ID of the third party insight. |
| PassiveTotal.ThirdParty.Insight.insight.segmentBy | String | Segment by of the third party insight. |
| PassiveTotal.Summary.ThirdPartyInsight.name | String | The command name. |
Command Example
!pt-list-third-party-attack-surface-insights id="45998" priority="low"
Context Example
{
"PassiveTotal": {
"Summary": {
"ThirdPartyInsight": {
"activeInsightCount": 9,
"name": "pt-list-third-party-attack-surface-insights",
"totalInsightCount": 11,
"totalObservations": 92
}
},
"ThirdParty": {
"Insight": {
"insight": [
{
"description": "Root page assets with any CVSS/CVSS v3 score. ",
"insightId": "40466",
"link": "https://api.pt.net/pt/v2/attack-surface/third-party/45998/insight/40466?page=0&size=25&groupBy=RISK_CATEGORY&segmentBy=savedfilter_metric_15881",
"name": "Affected CVSS Page",
"observationCount": 0,
"segmentBy": "savedfilter_metric_15881"
},
{
"description": "##### Description \nDeprecated versions of Apache server that are no longer supported. Running end of life or deprecated software can open organizations up to potential risks and vulnerabilities as these systems are no longer supported via regular updates and security patches.\n\n##### Remediation\nOrganizations should consider upgrading to supported versions of Apache to ensure security patches are available.",
"insightId": "40466",
"link": "https://api.pt.net/pt/v2/attack-surface/third-party/45998/insight/40466?page=0&size=25&groupBy=RISK_CATEGORY&segmentBy=savedfilter_metric_29644",
"name": "ASI: Deprecated Tech - Apache",
"observationCount": 2,
"segmentBy": "savedfilter_metric_29644"
}
]
},
"id": 45998,
"priorityLevel": "low"
}
}
}
Human Readable Output
Low Severity Insights
9 Active of 11 Insights - 92 Observations
Name Description Observations Insight ID Segment By ASI: Deprecated Tech - Apache ##### Description
Deprecated versions of Apache server that are no longer supported. Running end of life or deprecated software can open organizations up to potential risks and vulnerabilities as these systems are no longer supported via regular updates and security patches.
##### Remediation
Organizations should consider upgrading to supported versions of Apache to ensure security patches are available.2 40466 savedfilter_metric_29644 Affected CVSS Page Root page assets with any CVSS/CVSS v3 score. 0 40466 savedfilter_metric_15881
pt-list-my-attack-surface-assets
Retrieves the attack surface asset information of the individual’s account.
Base Command
pt-list-my-attack-surface-assets
Input
| Argument Name | Description | Required |
|---|---|---|
| id | Specify the insight ID to retrieve the assets. Note: To retrieve the list of insight IDs, execute the “pt-list-my-attack-surface-insights” command. |
Required |
| segment_by | Specify the segment_by to retrieve the assets. Note: To retrieve the list of segment by, execute the “pt-list-my-attack-surface-insights” command. |
Required |
| page_number | Page number for paging through results. Note: The minimum value supported is 0 and maximum value supported is int32. Default is 0. |
Optional |
| page_size | Maximum number of results to return per page. Note: The minimum value supported is 1 and maximum value supported is int32. Default is 50. |
Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PassiveTotal.Summary.Asset.totalCount | Number | Total number of available assets. |
| PassiveTotal.Summary.Asset.totalPages | Number | Number of pages. |
| PassiveTotal.Summary.Asset.nextPage | String | Link to the next page. |
| PassiveTotal.Asset.insightId | String | Insight ID for which assets are retrieved. |
| PassiveTotal.Asset.segmentBy | String | Segment by for which assets are retrieved. |
| PassiveTotal.Asset.asset.type | String | Type of the asset. |
| PassiveTotal.Asset.asset.name | String | Name of the asset. |
| PassiveTotal.Asset.asset.firstSeen | Date | Date & time the record was first seen. |
| PassiveTotal.Asset.asset.lastSeen | Date | Date & time the record was most recently observed. |
| PassiveTotal.Summary.Asset.name | String | The command name. |
Command Example
!pt-list-my-attack-surface-assets id="40466" segment_by="savedfilter_metric_29634"
Context Example
{
"PassiveTotal": {
"Asset": {
"asset": [
{
"firstSeen": "2016-05-25 20:07:40",
"lastSeen": "2021-09-19 09:50:32",
"name": "financialtradie.com",
"type": "DOMAIN"
}
],
"insightId": "40466",
"segmentBy": "savedfilter_metric_29634"
},
"Summary": {
"Asset": {
"name": "pt-list-my-attack-surface-assets",
"totalCount": 1,
"totalPages": 1
}
}
}
}
Human Readable Output
Asset(s)
Name Type First Seen (GMT) Last Seen (GMT) financialtradie.com DOMAIN 2016-05-25 20:07:40 2021-09-19 09:50:32
pt-list-my-attack-surface-vulnerable-components
Retrieves the attack surface vulnerable component information of the individual’s account.
Base Command
pt-list-my-attack-surface-vulnerable-components
Input
| Argument Name | Description | Required |
|---|---|---|
| page_number | Page number for paging through results. Note: The minimum value supported is 0 and maximum value supported is int32. Default is 0. |
Optional |
| page_size | Maximum number of results to return per page. Note: The minimum value supported is 1 and maximum value supported is int32. Default is 50. |
Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PassiveTotal.Summary.VulnerableComponent.name | String | The command name. |
| PassiveTotal.Summary.VulnerableComponent.totalCount | Number | Total number of available vulnerable components. |
| PassiveTotal.Summary.VulnerableComponent.totalPages | Number | Number of pages. |
| PassiveTotal.Summary.VulnerableComponent.nextPage | String | Link to the next page. |
| PassiveTotal.VulnerableComponent.name | String | Name of the vulnerable component. |
| PassiveTotal.VulnerableComponent.type | String | Type of the vulnerable component. |
| PassiveTotal.VulnerableComponent.severity | String | Severity of the vulnerable component. |
| PassiveTotal.VulnerableComponent.count | Number | Number of assets affected. |
Command Example
!pt-list-my-attack-surface-vulnerable-components page_size=2
Context Example
{
"PassiveTotal": {
"Summary": {
"VulnerableComponent": {
"name": "pt-list-my-attack-surface-vulnerable-components",
"nextPage": "https://api.pt.net/pt/v2/attack-surface/vuln-intel/components?page=1&size=2",
"totalCount": 24,
"totalPages": 12
}
},
"VulnerableComponent": [
{
"count": 129,
"name": "nginx 1.14.0",
"severity": "HIGH",
"type": "Server"
},
{
"count": 13,
"name": "nginx 1.16.1",
"severity": "HIGH",
"type": "Server"
}
]
}
}
Human Readable Output
Vulnerable Component(s)
Name Type Severity Asset Count nginx 1.14.0 Server HIGH 129 nginx 1.16.1 Server HIGH 13
pt-list-my-attack-surface-vulnerabilities
Retrieves the attack surface vulnerability information of the individual’s account.
Base Command
pt-list-my-attack-surface-vulnerabilities
Input
| Argument Name | Description | Required |
|---|---|---|
| page_number | Page number for paging through results. Note: The minimum value supported is 0 and maximum value supported is int32. Default is 0. |
Optional |
| page_size | Maximum number of results to return per page. Note: The minimum value supported is 1 and maximum value supported is int32. Default is 50. |
Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PassiveTotal.Vulnerability.cveId | String | ID of the CVE. |
| PassiveTotal.Vulnerability.cwes.cweId | String | CWE ID associated with the CVE. |
| PassiveTotal.Vulnerability.priorityScore | Number | Priority score of the CVE. |
| PassiveTotal.Vulnerability.observationCount | Number | Number of observations of CVE. |
| PassiveTotal.Vulnerability.cveLink | String | Link to the CVE. |
| PassiveTotal.Summary.Vulnerability.name | String | The command name. |
| PassiveTotal.Summary.Vulnerability.totalCount | Number | Total number of vulnerabilities. |
| PassiveTotal.Summary.Vulnerability.totalPages | Number | Number of pages. |
| PassiveTotal.Summary.Vulnerability.nextPage | String | Link to the next page. |
Command Example
!pt-list-my-attack-surface-vulnerabilities page_size=2
Context Example
{
"PassiveTotal": {
"Summary": {
"Vulnerability": {
"name": "pt-list-my-attack-surface-vulnerabilities",
"nextPage": "https://api.pt.net/pt/v2/attack-surface/vuln-intel/cves?page=1&size=2",
"totalCount": 413,
"totalPages": 207
}
},
"Vulnerability": [
{
"cveId": "CVE-2021-23017",
"cveLink": "https://api.pt.net/pt/v2/vuln-intel/CVE-2021-23017",
"cwes": [
{
"cweId": "CWE-193"
}
],
"observationCount": 149,
"priorityScore": 98
},
{
"cveId": "CVE-2019-20372",
"cveLink": "https://api.pt.net/pt/v2/vuln-intel/CVE-2019-20372",
"cwes": [
{
"cweId": "CWE-444"
}
],
"observationCount": 145,
"priorityScore": 53
}
]
}
}
Human Readable Output
Vulnerabilities
CVE ID CWE ID RiskIQ Priority Score Asset Count CVE-2021-23017 CWE-193 98.0 149 CVE-2019-20372 CWE-444 53.0 145
pt-list-my-attack-surface-observations
Retrieves the attack surface vulnerability observation information of the individual’s account.
Base Command
pt-list-my-attack-surface-observations
Input
| Argument Name | Description | Required |
|---|---|---|
| cve_id | Specify the CVE ID to retrieve observations of that CVE. Note: To retrieve the list of CVE IDs, execute the “pt-list-my-attack-surface-vulnerabilities” command. |
Required |
| page_number | Page number for paging through results. Note: The minimum value supported is 0 and maximum value supported is int32. Default is 0. |
Optional |
| page_size | Maximum number of results to return per page. Note: The minimum value supported is 1 and maximum value supported is int32. Default is 50. |
Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PassiveTotal.Observation.asset.type | String | Type of the asset. |
| PassiveTotal.Observation.asset.name | String | Name of the asset. |
| PassiveTotal.Observation.asset.firstSeen | Date | Date & time the record was first seen. |
| PassiveTotal.Observation.asset.lastSeen | Date | Date & time the record was most recently observed. |
| PassiveTotal.Observation.cveId | String | ID of the CVE. |
| PassiveTotal.Observation.cwe.cweId | String | CWE ID associated with the CVE. |
| PassiveTotal.Summary.Observation.name | String | The command name. |
| PassiveTotal.Summary.Observation.totalCount | Number | Total number of vulnerabilities. |
| PassiveTotal.Summary.Observation.totalPages | Number | Number of pages. |
| PassiveTotal.Summary.Observation.nextPage | String | Link to the next page. |
Command Example
!pt-list-my-attack-surface-observations cve_id="CVE-2021-23017" page_size=2
Context Example
{
"PassiveTotal": {
"Observation": {
"asset": [
{
"firstSeen": "2018-05-11 20:40:17",
"lastSeen": "2021-09-19 14:46:48",
"name": "riskiq.app",
"type": "HOST"
},
{
"firstSeen": "2018-06-30 00:03:32",
"lastSeen": "2021-09-15 19:36:38",
"name": "www.riskiq.app",
"type": "HOST"
}
],
"cveId": "CVE-2021-23017",
"cwe": [
{
"cweId": "CWE-193"
}
]
},
"Summary": {
"Observation": {
"name": "pt-list-my-attack-surface-observations",
"nextPage": "https://api.pt.net/pt/v2/attack-surface/vuln-intel/cves/CVE-2021-23017/observations?page=1&size=2",
"totalCount": 149,
"totalPages": 75
}
}
}
}
Human Readable Output
Observation(s)
Name Type First Seen (GMT) Last Seen (GMT) riskiq.app HOST 2018-05-11 20:40:17 2021-09-19 14:46:48 www.riskiq.app HOST 2018-06-30 00:03:32 2021-09-15 19:36:38
pt-list-third-party-attack-surface-assets
Retrieves the attack surface asset information of the given third-party account.
Base Command
pt-list-third-party-attack-surface-assets
Input
| Argument Name | Description | Required |
|---|---|---|
| id | Specify the insight ID to retrieve the assets. Note: To retrieve the list of insight IDs, execute the “pt-list-third-party-attack-surface-insights” command. |
Required |
| vendor_id | Specify the vendor ID to retrieve the assets of a specific vendor. Note: To retrieve the list of vendor IDs, execute the “pt-list-third-party-attack-surface” command. |
Required |
| segment_by | Specify the segment_by to retrieve the assets. Note: To retrieve the list of segment by, execute the “pt-list-third-party-attack-surface-insights” command. |
Required |
| page_number | Page number for paging through results. Note: The minimum value supported is 0 and maximum value supported is int32. Default is 0. |
Optional |
| page_size | Maximum number of results to return per page. Note: The minimum value supported is 1 and maximum value supported is int32. Default is 50. |
Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PassiveTotal.ThirdParty.id | Number | ID of the vendor. |
| PassiveTotal.Summary.ThirdPartyInsightAsset.name | String | The command name. |
| PassiveTotal.Summary.ThirdPartyInsightAsset.totalCount | Number | Total number of available assets. |
| PassiveTotal.Summary.ThirdPartyInsightAsset.totalPages | Number | Number of pages. |
| PassiveTotal.Summary.ThirdPartyInsightAsset.nextPage | String | Link to the next page. |
| PassiveTotal.ThirdParty.InsightAsset.insightId | Number | Insight ID for which assets are retrieved. |
| PassiveTotal.ThirdParty.InsightAsset.segmentBy | String | Segment by for which assets are retrieved. |
| PassiveTotal.ThirdParty.InsightAsset.asset.type | String | Type of the asset. |
| PassiveTotal.ThirdParty.InsightAsset.asset.name | String | Name of the asset. |
| PassiveTotal.ThirdParty.InsightAsset.asset.firstSeen | Date | Date & time the record was first seen. |
| PassiveTotal.ThirdParty.InsightAsset.asset.lastSeen | Date | Date & time the record was most recently observed. |
Command Example
!pt-list-third-party-attack-surface-assets id="40464" vendor_id="45998" segment_by="savedfilter_metric_29644"
Context Example
{
"PassiveTotal": {
"Summary": {
"ThirdPartyInsightAsset": {
"name": "pt-list-third-party-attack-surface-assets",
"totalCount": 2,
"totalPages": 1
}
},
"ThirdParty": {
"InsightAsset": {
"asset": [
{
"firstSeen": "2010-06-24 07:49:19",
"lastSeen": "2021-09-21 23:02:08",
"name": "160.189.11.4",
"type": "IP_ADDRESS"
},
{
"firstSeen": "2017-12-01 09:22:21",
"lastSeen": "2021-09-21 18:23:10",
"name": "ec.soup-stock-tokyo.com",
"type": "HOST"
}
],
"insightId": "40464",
"segmentBy": "savedfilter_metric_29644"
},
"id": 45998
}
}
}
Human Readable Output
Asset(s)
Name Type First Seen (GMT) Last Seen (GMT) 160.189.11.4 IP_ADDRESS 2010-06-24 07:49:19 2021-09-21 23:02:08 ec.soup-stock-tokyo.com HOST 2017-12-01 09:22:21 2021-09-21 18:23:10
pt-list-third-party-attack-surface-vulnerable-components
Retrieves the attack surface vulnerable component information of the given third-party account.
Base Command
pt-list-third-party-attack-surface-vulnerable-components
Input
| Argument Name | Description | Required |
|---|---|---|
| id | Specify the vendor ID to retrieve the vulnerable components for a particular vendor. Note: To retrieve the list of vendor IDs, execute the “pt-list-third-party-attack-surface” command. |
Required |
| page_number | Page number for paging through results. Note: The minimum value supported is 0 and maximum value supported is int32. Default is 0. |
Optional |
| page_size | Maximum number of results to return per page. Note: The minimum value supported is 1 and maximum value supported is int32. Default is 50. |
Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PassiveTotal.ThirdParty.id | String | ID of the vendor. |
| PassiveTotal.Summary.ThirdPartyVulnerableComponent.name | String | The command name. |
| PassiveTotal.Summary.ThirdPartyVulnerableComponent.totalCount | Number | Total number of available vulnerable components. |
| PassiveTotal.Summary.ThirdPartyVulnerableComponent.totalPages | Number | Number of pages. |
| PassiveTotal.Summary.ThirdPartyVulnerableComponent.nextPage | String | Link to the next page. |
| PassiveTotal.ThirdParty.VulnerableComponent.name | String | Name of the vulnerable component. |
| PassiveTotal.ThirdParty.VulnerableComponent.type | String | Type of the vulnerable component. |
| PassiveTotal.ThirdParty.VulnerableComponent.severity | String | Severity of the vulnerable component. |
| PassiveTotal.ThirdParty.VulnerableComponent.count | Number | Number of assets affected. |
Command Example
!pt-list-third-party-attack-surface-vulnerable-components id="45998" page_size=2
Context Example
{
"PassiveTotal": {
"Summary": {
"ThirdPartyVulnerableComponent": {
"name": "pt-list-third-party-attack-surface-vulnerable-components",
"nextPage": "https://api.pt.net/pt/v2/attack-surface/vuln-intel/third-party/45998/components?page=1&size=2",
"totalCount": 45,
"totalPages": 23
}
},
"ThirdParty": {
"VulnerableComponent": [
{
"count": 14,
"name": "Microsoft-IIS 8.5",
"severity": "MEDIUM",
"type": "Server"
},
{
"count": 5,
"name": "OpenSSL 1.0.2k",
"severity": "HIGH",
"type": "Server Module"
}
],
"id": 45998
}
}
}
Human Readable Output
Vulnerable Component(s)
Name Type Severity Asset Count Microsoft-IIS 8.5 Server MEDIUM 14 OpenSSL 1.0.2k Server Module HIGH 5
pt-list-third-party-attack-surface-vulnerabilities
Retrieves the attack surface vulnerability information of the given third-party account.
Base Command
pt-list-third-party-attack-surface-vulnerabilities
Input
| Argument Name | Description | Required |
|---|---|---|
| id | Specify the vendor ID to retrieve the vulnerabilities for a particular vendor. Note: To retrieve the list of vendor IDs, execute the “pt-list-third-party-attack-surface” command. |
Required |
| page_number | Page number for paging through results. Note: The minimum value supported is 0 and maximum value supported is int32. Default is 0. |
Optional |
| page_size | Maximum number of results to return per page. Note: The minimum value supported is 1 and maximum value supported is int32. Default is 50. |
Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PassiveTotal.ThirdParty.id | Number | ID of the vendor. |
| PassiveTotal.ThirdParty.Vulnerability.cveId | String | ID of the CVE. |
| PassiveTotal.ThirdParty.Vulnerability.cwes.cweId | String | CWE ID associated with the CVE. |
| PassiveTotal.ThirdParty.Vulnerability.priorityScore | Number | Priority score of the CVE. |
| PassiveTotal.ThirdParty.Vulnerability.observationCount | Number | Number of observations of CVE. |
| PassiveTotal.ThirdParty.Vulnerability.cveLink | String | Link to the CVE. |
| PassiveTotal.Summary.ThirdPartyVulnerability.name | String | The command name. |
| PassiveTotal.Summary.ThirdPartyVulnerability.totalCount | Number | Total number of vulnerabilities. |
| PassiveTotal.Summary.ThirdPartyVulnerability.totalPages | Number | Number of pages. |
| PassiveTotal.Summary.ThirdPartyVulnerability.nextPage | String | Link to the next page. |
Command Example
!pt-list-third-party-attack-surface-vulnerabilities id="45998" page_size=2
Context Example
{
"PassiveTotal": {
"Summary": {
"ThirdPartyVulnerability": {
"name": "pt-list-third-party-attack-surface-vulnerabilities",
"nextPage": "https://api.pt.net/pt/v2/attack-surface/vuln-intel/third-party/45998/cves?page=1&size=2",
"totalCount": 548,
"totalPages": 274
}
},
"ThirdParty": {
"Vulnerability": [
{
"cveId": "CVE-2020-11022",
"cveLink": "https://api.pt.net/pt/v2/vuln-intel/CVE-2020-11022",
"cwes": [
{
"cweId": "CWE-79"
}
],
"observationCount": 19,
"priorityScore": 61
},
{
"cveId": "CVE-2020-11023",
"cveLink": "https://api.pt.net/pt/v2/vuln-intel/CVE-2020-11023",
"cwes": [
{
"cweId": "CWE-79"
}
],
"observationCount": 19,
"priorityScore": 61
}
],
"id": 45998
}
}
}
Human Readable Output
Vulnerabilities
CVE ID CWE ID RiskIQ Priority Score Asset Count CVE-2020-11022 CWE-79 61.0 19 CVE-2020-11023 CWE-79 61.0 19
pt-list-third-party-attack-surface-observations
Retrieves the attack surface vulnerability observation information of the given third-party account.
Base Command
pt-list-third-party-attack-surface-observations
Input
| Argument Name | Description | Required |
|---|---|---|
| id | Specify the vendor ID to retrieve the vulnerability observations for a particular vendor. Note: To retrieve the list of vendor IDs, execute the “pt-list-third-party-attack-surface” command. |
Required |
| cve_id | Specify the CVE ID to retrieve observations of the CVE. Note: To retrieve the list of CVE IDs, execute the “pt-list-third-party-attack-surface-vulnerabilities” command. |
Required |
| page_number | Page number for paging through results. Note: The minimum value supported is 0 and maximum value supported is int32. Default is 0. |
Optional |
| page_size | Maximum number of results to return per page. Note: The minimum value supported is 1 and maximum value supported is int32. Default is 50. |
Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PassiveTotal.ThirdParty.id | Number | ID of the vendor. |
| PassiveTotal.ThirdParty.Observation.asset.type | String | Type of the asset. |
| PassiveTotal.ThirdParty.Observation.asset.name | String | Name of the asset. |
| PassiveTotal.ThirdParty.Observation.asset.firstSeen | Date | Date & time the record was first seen. |
| PassiveTotal.ThirdParty.Observation.asset.lastSeen | Date | Date & time the record was most recently observed. |
| PassiveTotal.ThirdParty.Observation.cveId | String | ID of the CVE. |
| PassiveTotal.ThirdParty.Observation.cwe.cweId | String | CWE ID associated with the CVE. |
| PassiveTotal.Summary.ThirdPartyObservation.name | String | The command name. |
| PassiveTotal.Summary.ThirdPartyObservation.totalCount | Number | Total number of observations. |
| PassiveTotal.Summary.ThirdPartyObservation.totalPages | Number | Number of pages. |
| PassiveTotal.Summary.ThirdPartyObservation.nextPage | String | Link to the next page. |
Command Example
!pt-list-third-party-attack-surface-observations id="45998" cve_id="CVE-2020-11022" page_size=2
Context Example
{
"PassiveTotal": {
"Summary": {
"ThirdPartyObservation": {
"name": "pt-list-third-party-attack-surface-observations",
"nextPage": "https://api.pt.net/pt/v2/attack-surface/vuln-intel/third-party/45998/cves/CVE-2020-11022/observations?page=1&size=2",
"totalCount": 19,
"totalPages": 10
}
},
"ThirdParty": {
"Observation": {
"asset": [
{
"firstSeen": "2015-05-12 14:58:34",
"lastSeen": "2021-09-21 06:14:39",
"name": "blog.accesstage.com.br",
"type": "HOST"
},
{
"firstSeen": "2010-09-22 14:57:20",
"lastSeen": "2021-09-22 00:21:45",
"name": "www.accesstage.com.br",
"type": "HOST"
}
],
"cveId": "CVE-2020-11022",
"cwe": [
{
"cweId": "CWE-79"
}
]
},
"id": 45998
}
}
}
Human Readable Output
Observation(s)
Name Type First Seen (GMT) Last Seen (GMT) blog.accesstage.com.br HOST 2015-05-12 14:58:34 2021-09-21 06:14:39 www.accesstage.com.br HOST 2010-09-22 14:57:20 2021-09-22 00:21:45
Configuration parameters
url— API URL (required)credentials— Usernameusername— Usernamesecret— API Secretinsecure— Trust any certificate (not secure)proxy— Use system proxy settingsrequest_timeout— HTTP(S) Request Timeout (in seconds)integrationReliability— Source ReliabilityfeedExpirationPolicy—feedExpirationInterval—
Commands (28)
-
domainProvides data enrichment for domains.
-
ipChecks the reputation of an IP address.
-
pt-get-articlesRetrieves information related to articles for a specific indicator.
-
pt-get-componentsRetrieves the host attribute components for a domain or IP address. Maximum 2000 records are fetched.
-
pt-get-cookiesRetrieves cookies addresses or hostname information based on cookie name or domain.
-
pt-get-data-cardRetrieves a summary data card associated with the given query.
-
pt-get-host-pairsRetrieves the host attribute pairs related to a domain or IP address. Maximum 2000 records are fetched.
-
pt-get-pdns-detailsRetrieves the passive DNS results from active account sources.
-
pt-get-reputationGets reputation for a given domain, host or IP.
-
pt-get-servicesRetrieves exposed services on the recently open ports for an IP address.
-
pt-get-trackersRetrieves the host attribute trackers for a domain or IP address. Maximum 2000 records are fetched.
-
pt-get-whoisGets WHOIS information records based on queries.
-
pt-list-intel-profile-indicatorsRetrieves the indicators for the given profile.
-
pt-list-intel-profilesRetrieves the list of all profiles.
-
pt-list-my-attack-surface-assetsRetrieves the attack surface asset information of the individual's account.
-
pt-list-my-attack-surface-insightsRetrieves the attack surface insight information of the individual's account.
-
pt-list-my-attack-surface-observationsRetrieves the attack surface vulnerability observation information of the individual's account.
-
pt-list-my-attack-surface-vulnerabilitiesRetrieves the attack surface vulnerability information of the individual's account.
-
pt-list-my-attack-surface-vulnerable-componentsRetrieves the attack surface vulnerable component information of the individual's account.
-
pt-list-my-attack-surfacesRetrieves the attack surface information of the individual's account.
-
pt-list-third-party-attack-surfaceRetrieves the attack surface observations by severity level for the given third-party account.
-
pt-list-third-party-attack-surface-assetsRetrieves the attack surface asset information of the given third-party account.
-
pt-list-third-party-attack-surface-insightsRetrieves the attack surface insight information of the given third-party account.
-
pt-list-third-party-attack-surface-observationsRetrieves the attack surface vulnerability observation information of the given third-party account.
-
pt-list-third-party-attack-surface-vulnerabilitiesRetrieves the attack surface vulnerability information of the given third-party account.
-
pt-list-third-party-attack-surface-vulnerable-componentsRetrieves the attack surface vulnerable component information of the given third-party account.
-
pt-ssl-cert-searchRetrieves SSL certificates for a given field value.
-
pt-whois-searchGets WHOIS information records based on field matching queries.
from CommonServerPython import * """ IMPORTS """ import re import traceback from typing import Any from urllib import parse import urllib3 from requests import ConnectionError from requests.exceptions import InvalidSchema, MissingSchema # Disable insecure warnings urllib3.disable_warnings() """ CONSTANTS """ DATE_TIME_FORMAT = "%Y-%m-%d %H:%M:%S" DATE_FORMAT = "%Y-%m-%d" INTEGRATION_NAME: str = "PassiveTotal" DEFAULT_REQUEST_TIMEOUT = "20" PROFILE_TYPE = ["actor", "backdoor", "tool"] SOURCE = ["osint", "riskiq"] DEFAULT_PAGE_NUMBER = 0 DEFAULT_SIZE = 50 MESSAGES: dict[str, str] = { "AUTHENTICATION_ERROR": "Unauthenticated. Check the configured Username and API secret.", "PAGE_NOT_FOUND_ERROR": "No record(s) found.", "INTERNAL_SERVER_ERROR": "The server encountered an internal error for PassiveTotal and was unable to complete " "your request.", "BAD_REQUEST_ERROR": "An error occurred while fetching the data.", "REQUEST_TIMEOUT_VALIDATION": "HTTP(S) Request timeout parameter must be a positive integer.", "REQUEST_TIMEOUT_EXCEED_ERROR": "Value is too large for HTTP(S) Request Timeout.", "NO_RECORDS_FOUND": "No {0} were found for the given argument(s).", "EMPTY_WHOIS_ARGUMENT": "query or field argument should not be empty.", "EMPTY_DOMAIN_ARGUMENT": "domain argument should not be empty.", "INVALID_DIRECTION_VALUE": "The given value for direction is invalid. Supported values: children, parents.", "INVALID_QUERY_VALUE": "The given value for query is invalid.", "MISSING_SCHEMA_ERROR": "Invalid API URL. No schema supplied: http(s).", "INVALID_SCHEMA_ERROR": "Invalid API URL. Supplied schema is invalid, supports http(s).", "CONNECTION_ERROR": "Connectivity failed. Check your internet connection, the API URL or try increasing the HTTP(s)" " Request Timeout.", "PROXY_ERROR": "Proxy Error - cannot connect to proxy. Either try clearing the 'Use system proxy' check-box or " "check the host, authentication details and connection details for the proxy.", "INVALID_VALUE_IN_FIELD_ARG": "Invalid field type {}. Valid field types are domain, email, name, organization, " "address, phone, nameserver.", "INVALID_IP": "IP is not valid. Please enter a valid IP address.", "EMPTY_GET_WHOIS_ARGUMENT": "query argument should not be empty.", "INVALID_VALUE_IN_HISTORY_ARG": "Invalid history value {}. Valid history values are true, false.", "INVALID_WHOLE_NUMBER": "Argument {} should be 0 or a positive integer.", "INVALID_SINGLE_SELECT": "Invalid argument {}. Valid values are {}.", "INVALID_QUERY_COOKIE_DOMAIN": "Argument query should be a valid domain that " "does not contain any special characters other than hyphen (-) and full stop (.)", "INVALID_QUERY_COOKIE_NAME": "Argument query should be a valid cookie name that does not contain " "spaces, separator character or tabs.", "REQUIRED_ARGUMENT": "Invalid argument value. {} is a required argument.", "EMPTY_IP_ARGUMENT": "IP(s) not specified", "INVALID_IP_ARGUMENT": "Invalid IP - {}", "INVALID_INDICATOR_TYPE": "Invalid indicator type {}. Valid values are certficate_sha1, certificate_sha1, domain, " "email, hash_md5, hash_sha256, ip, pdb_path, soa_email, url, whois_email.", "INVALID_SOURCE": "Invalid indicator source {}. Valid values are osint, riskiq.", "INVALID_PAGE_SIZE": "{} is an invalid value for page size. Page size must be between 1 and int32.", "INVALID_PAGE_NUMBER": "{} is an invalid value for page number. Page number must be between 0 and int32.", "INVALID_PROFILE_TYPE": "Invalid profile type {}. Valid profile types are actor, backdoor, tool.", "REQUIRED_INDICATOR_VALUE": "'indicator_value' must be specified if the arguments 'source' or 'category' are used.", "INVALID_PRIORITY_LEVEL": "Invalid priority level {}. Valid priority level are low, medium, high.", "NOT_VALID_PAGE_SIZE": "{} is an invalid value for page size. Page size must be between 1 and 1000.", } URL_SUFFIX: dict[str, str] = { "TEST_MODULE": "/v2/account", "SSL_CERT_SEARCH": "/v2/ssl-certificate/search", "GET_PDNS_DETAILS": "/v2/dns/passive", "WHOIS_SEARCH": "/v2/whois/search", "WHOIS_GET": "/v2/whois", "GET_COMPONENTS": "/v2/host-attributes/components", "GET_TRACKERS": "/v2/host-attributes/trackers", "GET_ARTICLES": "/v2/articles/indicator", "GET_HOST_PAIRS": "/v2/host-attributes/pairs", "GET_SERVICES": "/v2/services", "GET_ADDRESSES_BY_COOKIE_NAME": "v2/cookies/name/{0}/addresses", "GET_ADDRESSES_BY_COOKIE_DOMAIN": "v2/cookies/domain/{0}/addresses", "GET_HOSTS_BY_COOKIE_NAME": "v2/cookies/name/{0}/hosts", "GET_HOSTS_BY_COOKIE_DOMAIN": "v2/cookies/domain/{0}/hosts", "GET_DATA_CARD_SUMMARY": "v2/cards/summary", "GET_REPUTATION": "v2/reputation", "LIST_INTEL_PROFILE_INDICATOR": "v2/intel-profiles/{}/indicators", "LIST_INTEL_PROFILE": "v2/intel-profiles", "LIST_INTEL_PROFILE_BY_INDICATOR": "v2/intel-profiles/indicator", "LIST_ASI_INSIGHTS": "/v2/attack-surface/priority", "LIST_ATTACK_SURFACE": "v2/attack-surface", "LIST_THIRD_PARTY_ASI": "v2/attack-surface/third-party", "LIST_ASI_ASSETS": "v2/attack-surface/insight", "THIRD_PARTY_ASI_INSIGHTS": "v2/attack-surface/third-party/{}/priority/{}", "LIST_ASI_VULNERABLE_COMPONENTS": "v2/attack-surface/vuln-intel/components", "LIST_ASI_VULNERABILITIES": "v2/attack-surface/vuln-intel/cves", "LIST_ASI_OBSERVATIONS": "v2/attack-surface/vuln-intel/cves/{}/observations", "LIST_THIRD_PARTY_ASI_ASSETS": "v2/attack-surface/third-party/{}/insight/{}", "LIST_THIRD_PARTY_ASI_VULNERABLE_COMPONENTS": "v2/attack-surface/vuln-intel/third-party/{}/components", "LIST_THIRD_PARTY_ASI_VULNERABILITIES": "v2/attack-surface/vuln-intel/third-party/{}/cves", "LIST_THIRD_PARTY_ASI_OBSERVATIONS": "v2/attack-surface/vuln-intel/third-party/{}/cves/{}/observations", } ISO_DATE: dict[str, str] = {DATE_TIME_FORMAT: '"yyyy-mm-dd hh:mm:ss"', DATE_FORMAT: '"yyyy-mm-dd"'} VALID_DIRECTION_FOR_HOST_PAIRS = ["children", "parents"] REQUEST_TIMEOUT_MAX_VALUE = 9223372036 COMPANY_NAME = "PaloAltoNetworks" PRODUCT_NAME = "XSOAR" INDICATOR_TYPE = [ "certficate_sha1", "certificate_sha1", "domain", "email", "hash_md5", "hash_sha256", "ip", "pdb_path", "soa_email", "url", "whois_email", ] PRIORITY = ["high", "medium", "low"] UI_LINK = "https://community.riskiq.com/attack-surfaces/" class Client(BaseClient): """ Client to use in integration with powerful http_request. It extends the base client and uses the http_request method for the API request. Handle some exceptions externally. """ def __init__(self, base_url, request_timeout, verify, proxy, auth): super().__init__(base_url=base_url, verify=verify, proxy=proxy, auth=auth) self.request_timeout = request_timeout def http_request(self, method: str, url_suffix: str, json_data=None, params=None, headers=None) -> dict[str, Any]: """ Override http_request method from BaseClient class. This method will print an error based on status code and exceptions. :type method: ``str`` :param method: The HTTP method, for example: GET, POST, and so on. :type url_suffix: ``str`` :param url_suffix: The API endpoint. :type json_data: ``dict`` :param json_data: The dictionary to send in a 'POST' request. :type params: ``dict`` :param params: URL parameters to specify the query. :type headers: ``dict`` :param headers: Headers to send in the request. If None, will use self._headers. :return: Depends on the resp_type parameter :rtype: ``dict`` or ``str`` or ``requests.Response`` """ try: if not headers: headers = {} headers["X-RISKIQ"] = f"{COMPANY_NAME}-{PRODUCT_NAME}-{get_demisto_version_as_str()}" resp = self._http_request( method=method, url_suffix=url_suffix, json_data=json_data, params=params, headers=headers, timeout=self.request_timeout, resp_type="response", ok_codes=(200, 400, 401, 404, 407, 500), proxies=handle_proxy(), ) except MissingSchema: raise ValueError(MESSAGES["MISSING_SCHEMA_ERROR"]) except InvalidSchema: raise ValueError(MESSAGES["INVALID_SCHEMA_ERROR"]) except DemistoException as e: if "Proxy Error" in str(e): raise ConnectionError(MESSAGES["PROXY_ERROR"]) elif "ConnectionError" in str(e) or "ConnectTimeout" in str(e): raise ConnectionError(MESSAGES["CONNECTION_ERROR"]) else: raise e # Providing errors based on status code status_code = resp.status_code if status_code != 200: error_message = "" if resp.json().get("message", ""): error_message = "Reason: {}".format(resp.json().get("message", "")) status_code_message_map = { 400: "{} {}".format(MESSAGES["BAD_REQUEST_ERROR"], error_message), 401: MESSAGES["AUTHENTICATION_ERROR"], 404: MESSAGES["PAGE_NOT_FOUND_ERROR"], 407: MESSAGES["PROXY_ERROR"], } if status_code in status_code_message_map: demisto.info(f"Response code: {status_code}. Reason: {status_code_message_map[status_code]}") raise ValueError(status_code_message_map[status_code]) elif status_code >= 500: demisto.info("Response code: {}. Reason: {}".format(status_code, MESSAGES["INTERNAL_SERVER_ERROR"])) raise ValueError(MESSAGES["INTERNAL_SERVER_ERROR"]) else: resp.raise_for_status() return resp.json() """ HELPER FUNCTIONS """ def get_request_timeout() -> Any | None: """ Validate and return the request timeout parameter. The parameter must be a positive integer. Default value is set to 20 seconds for API request timeout. :params req_timeout: Request timeout value. :return: boolean """ try: request_timeout = demisto.params().get("request_timeout", DEFAULT_REQUEST_TIMEOUT) request_timeout = request_timeout if request_timeout else DEFAULT_REQUEST_TIMEOUT request_timeout = int(request_timeout) except ValueError: raise ValueError(MESSAGES["REQUEST_TIMEOUT_VALIDATION"]) if request_timeout <= 0: raise ValueError(MESSAGES["REQUEST_TIMEOUT_VALIDATION"]) elif request_timeout > REQUEST_TIMEOUT_MAX_VALUE: raise ValueError(MESSAGES["REQUEST_TIMEOUT_EXCEED_ERROR"]) return request_timeout def remove_empty_elements_for_context(src): """ Recursively remove empty lists, empty dicts, empty string or None elements from a dictionary. :type src: ``dict`` :param src: Input dictionary. :return: Dictionary with all empty lists,empty string and empty dictionaries removed. :rtype: ``dict`` """ def empty(x): return x is None or x == "" or x == {} or x == [] if not isinstance(src, dict | list): return src elif isinstance(src, list): return [v for v in (remove_empty_elements_for_context(v) for v in src) if not empty(v)] else: return {k: v for k, v in ((k, remove_empty_elements_for_context(v)) for k, v in src.items()) if not empty(v)} def get_host_attribute_context_data(records: list[dict[str, Any]]) -> tuple[list, list]: """ Prepares context data for get components and get trackers command :param records: API response :return: standard entry command results list and custom entry context """ custom_ec = createContext(data=records, removeNull=True) standard_results: list[CommandResults] = [] for record in records: if record.get("hostname"): hostname = record.get("hostname") dbot_score = Common.DBotScore( indicator=hostname, indicator_type=DBotScoreType.DOMAIN, integration_name=INTEGRATION_NAME, score=Common.DBotScore.NONE, reliability=demisto.params().get("integrationReliability"), ) if auto_detect_indicator_type(hostname) == FeedIndicatorType.Domain: domain_ioc = Common.Domain(domain=hostname, dbot_score=dbot_score) # add standard output with standard readable output standard_results.append( CommandResults( indicator=domain_ioc, readable_output=tableToMarkdown("", domain_ioc.to_context().get(Common.Domain.CONTEXT_PATH)), ) ) elif record.get("address"): address = record.get("address") dbot_score = Common.DBotScore( indicator=address, indicator_type=DBotScoreType.IP, integration_name=INTEGRATION_NAME, score=Common.DBotScore.NONE, reliability=demisto.params().get("integrationReliability"), ) if auto_detect_indicator_type(address) == FeedIndicatorType.IP: ip_ioc = Common.IP(ip=address, dbot_score=dbot_score) # add standard output with standard readable output standard_results.append( CommandResults( indicator=ip_ioc, readable_output=tableToMarkdown("", ip_ioc.to_context().get(Common.IP.CONTEXT_PATH)) ) ) return standard_results, custom_ec def get_components_hr(components: list[dict[str, Any]]) -> str: """ Prepares human readable text for get components command :param components: Components data response :return: Human readable output for components """ hr_table: list[dict[str, Any]] = [] for component in components: hr_row = { "Hostname": component.get("hostname", ""), "Address": component.get("address", ""), "First (GMT)": component.get("firstSeen", ""), "Last (GMT)": component.get("lastSeen", ""), "Category": component.get("category", ""), "Value": component.get("label", ""), "Version": component.get("version", ""), } hr_table.append(hr_row) hr_headers = ["Hostname", "Address", "First (GMT)", "Last (GMT)", "Category", "Value", "Version"] hr = f"### Total Retrieved Record(s): {len(components)}\n" return hr + tableToMarkdown("COMPONENTS", hr_table, hr_headers, removeNull=True) def get_trackers_hr(trackers: list[dict[str, Any]]) -> str: """ Prepares human readable text for get trackers command :param trackers: Trackers data response :return: Human readable output for trackers """ hr_table: list[dict[str, Any]] = [] for tracker in trackers: hr_row = { "Hostname": tracker.get("hostname", ""), "Address": tracker.get("address", ""), "First (GMT)": tracker.get("firstSeen", ""), "Last (GMT)": tracker.get("lastSeen", ""), "Type": tracker.get("attributeType", ""), "Value": tracker.get("attributeValue", ""), } hr_table.append(hr_row) hr_headers = ["Hostname", "Address", "First (GMT)", "Last (GMT)", "Type", "Value"] hr = f"### Total Retrieved Record(s): {len(trackers)}\n" return hr + tableToMarkdown("TRACKERS", hr_table, hr_headers, removeNull=True) def get_host_pairs_hr(host_pairs: list[dict[str, Any]]) -> str: """ Prepares human readable text for get host pairs command :param host_pairs: Host pairs data response :return: Human readable output for host pairs """ hr_table: list[dict[str, Any]] = [] for pair in host_pairs: hr_row = { "Parent Hostname": pair.get("parent", ""), "Child Hostname": pair.get("child", ""), "First (GMT)": pair.get("firstSeen", ""), "Last (GMT)": pair.get("lastSeen", ""), "Cause": pair.get("cause", ""), } hr_table.append(hr_row) hr_headers = ["Parent Hostname", "Child Hostname", "First (GMT)", "Last (GMT)", "Cause"] hr = f"### Total Retrieved Record(s): {len(host_pairs)}\n" return hr + tableToMarkdown("HOST PAIRS", hr_table, hr_headers, removeNull=True) def get_common_arguments(args: dict[str, Any]) -> dict[str, Any]: """ Validates the common arguments and prepares parameter dictionary This method is used in commands "get-trackers", "get-components", "get-host-pairs" :param args: The general arguments :return: dict of params or message describing error in argument validation """ params: dict[str, Any] = {} if not args.get("query"): raise ValueError(MESSAGES["INVALID_QUERY_VALUE"]) params["query"] = args.get("query") date_arguments = ["start", "end"] for argument in date_arguments: if args.get(argument): params[argument] = args.get(argument, "") return params def get_valid_whois_search_arguments(args: dict[str, Any]) -> tuple[str, str]: """ Get and Validate arguments for pt-whois-search command. :param args: it contain arguments of pt-whois-search command :return: validated arguments 'query' and 'field' """ query = args.get("query", "") field = args.get("field", "") if query.strip() == "" or field.strip() == "": raise ValueError(MESSAGES["EMPTY_WHOIS_ARGUMENT"]) if field not in ("domain", "email", "name", "organization", "address", "phone", "nameserver"): raise ValueError(MESSAGES["INVALID_VALUE_IN_FIELD_ARG"].format(field)) return query, field def get_valid_get_whois_arguments(args: dict[str, Any]) -> tuple[str, str]: """ Get and Validate arguments for pt-get-whois command. :param args: it contain arguments of pt-get-whois command :return: validated arguments 'query' and 'history' """ query = args.get("query", "").strip() arg_history = args.get("history", "").strip() history = arg_history.lower() if query == "": raise ValueError(MESSAGES["EMPTY_GET_WHOIS_ARGUMENT"]) if history and history not in ("true", "false"): raise ValueError(MESSAGES["INVALID_VALUE_IN_HISTORY_ARG"].format(arg_history)) return query, history def nested_to_flat(src: dict[str, Any], key: str) -> dict[str, Any]: """ Convert nested dictionary to flat by contact the keys. Also converts keys in pascal string format. :param src: sub-dictionary that needs to convert from nested to flat. (e.g. "foo": {"bar": "some-value"}) :param key: main key of sub-dictionary (e.g "foo") :return: flat dictionary with pascal formatted keys (e.g. {"FooBar": "some-value"}) """ flat_dict: dict[str, str] = {} for sub_key, sub_value in src.items(): pascal_key = f"{key}{sub_key[0].upper() + sub_key[1:]}" flat_dict[pascal_key] = sub_value return flat_dict def prepare_context_dict( response_dict: dict[str, Any], keys_with_hierarchy: tuple = (), exclude_keys: tuple = () ) -> dict[str, str]: """ Prepare the context dictionary as per the standards. :param response_dict: dictionary getting from API response that contains sub-dictionaries :param keys_with_hierarchy: list of keys that contains sub-dictionary as its value. :param exclude_keys: keys need to exclude. :return: single level dictionary """ simple_dict: dict[str, str] = {} for key, value in response_dict.items(): if key in keys_with_hierarchy: simple_dict.update(nested_to_flat(response_dict.get(key, {}), key)) elif key not in exclude_keys: simple_dict[key] = value return simple_dict def get_context_for_whois_commands(domains: list[dict[str, Any]], score=0) -> tuple[list, list]: """ Prepare context for whois and domain reputation commands. :param domains: list of domains return from response :param score: :return: command results for standard context and custom context for whois and domain reputation command """ command_results: list[CommandResults] = [] custom_context: list[dict[str, Any]] = [] # set domain standard context for domain in domains: # set domain standard context if auto_detect_indicator_type(domain.get("domain", "")) == FeedIndicatorType.Domain: standard_context_domain = Common.Domain( domain=domain.get("domain", ""), creation_date=domain.get("registered", ""), updated_date=domain.get("registryUpdatedAt", ""), expiration_date=domain.get("expiresAt", ""), name_servers=domain.get("nameServers", ""), organization=domain.get("organization", ""), admin_name=domain.get("admin", {}).get("name", ""), admin_email=domain.get("admin", {}).get("email", ""), admin_phone=domain.get("admin", {}).get("telephone", ""), admin_country=domain.get("admin", {}).get("country", ""), registrar_name=domain.get("registrar", ""), registrant_email=domain.get("registrant", {}).get("email", ""), registrant_name=domain.get("registrant", {}).get("name", ""), registrant_phone=domain.get("registrant", {}).get("telephone", ""), registrant_country=domain.get("registrant", {}).get("country", ""), dbot_score=Common.DBotScore( indicator=domain.get("domain", ""), indicator_type=DBotScoreType.DOMAIN, integration_name=INTEGRATION_NAME, score=score, reliability=demisto.params().get("integrationReliability"), ), ) # add standard output with standard readable output command_results.append( CommandResults( indicator=standard_context_domain, readable_output=tableToMarkdown("", standard_context_domain.to_context().get(Common.Domain.CONTEXT_PATH)), ) ) # set custom context for whois commands custom_context.append( prepare_context_dict( response_dict=domain, keys_with_hierarchy=("registrant", "admin", "billing", "tech"), exclude_keys=("zone", "rawText"), ) ) return command_results, createContext(custom_context, removeNull=True) def get_context_for_get_whois_commands(domains: list[dict[str, Any]]) -> list: """ Prepare context for pt-get-whois command. :param domains: list of domains return from response :return: command results for custom context for whois command """ custom_context: list[dict[str, Any]] = [] # set domain standard context for domain in domains: custom_context.append( prepare_context_dict( response_dict=domain, keys_with_hierarchy=("registrant", "admin", "billing", "tech"), exclude_keys=("zone", "rawText"), ) ) return createContext(custom_context, removeNull=True) def prepare_hr_cell_for_whois_info(domain_info: dict[str, Any]) -> str: """ Prepare cell information for Registrant, Admin, Billing and Tech columns. :param domain_info: domain information as a directory :return: domain information as a readable format """ hr_cell_info: list[str] = [] for key, value in domain_info.items(): hr_cell_info.append(f"**{key[0].upper() + key[1:]}:** {value}") return ",\n".join(hr_cell_info) def get_human_readable_for_whois_commands(domains: list[dict[str, Any]], is_reputation_command=False): """ Prepare readable output for whois commands :param domains: list of domains return from response :param is_reputation_command: true if the command is execute for reputation command else false, default is false :return: markdown of whois commands based on domains passed """ hr_table_content: list[dict[str, Any]] = [] table_name = "Domain(s)" for domain in domains: hr_row = { "Domain": domain.get("domain", ""), "WHOIS Server": domain.get("whoisServer", ""), "Registrar": domain.get("registrar", ""), "Contact Email": domain.get("contactEmail", ""), "Name Servers": ", ".join(domain.get("nameServers", [])), "Creation Date (GMT)": domain.get("registered", ""), "Expire Date (GMT)": domain.get("expiresAt", ""), "Updated Date (GMT)": domain.get("registryUpdatedAt", ""), "Last Scanned (GMT)": domain.get("lastLoadedAt", ""), "Registrant": prepare_hr_cell_for_whois_info(domain.get("registrant", {})), "Admin": prepare_hr_cell_for_whois_info(domain.get("admin", {})), "Billing": prepare_hr_cell_for_whois_info(domain.get("billing", {})), "Tech": prepare_hr_cell_for_whois_info(domain.get("tech", {})), } hr_table_content.append(hr_row) hr = "" if not is_reputation_command: hr += "### Total Retrieved Record(s): " + str(len(domains)) + "\n" table_name = "Associated Domains" hr += tableToMarkdown( name=table_name, t=hr_table_content, headers=[ "Domain", "WHOIS Server", "Registrar", "Contact Email", "Name Servers", "Registrant", "Admin", "Billing", "Tech", "Creation Date (GMT)", "Expire Date (GMT)", "Updated Date (GMT)", "Last Scanned (GMT)", ], removeNull=True, ) return hr def get_human_readable_for_articles_commands(articles: list[dict[str, Any]]): """ Prepare readable output for pt-get-articles command :param articles: list of articles return from response :return: markdown of article command based on articles passed """ hr_table_content: list[dict[str, Any]] = [] table_name = "Article(s)" for article in articles: hr_row = { "GUID": article.get("guid", ""), "Title": article.get("title", ""), "Summary": article.get("summary", ""), "Type": article.get("type", ""), "Tags": ", ".join(article.get("tags", [])) if article.get("tags", []) else "", "Categories": ", ".join(article.get("categories", [])) if article.get("categories", []) else "", "Article Link": article.get("link", ""), "Published Date (GMT)": article.get("publishedDate", ""), } hr_table_content.append(hr_row) hr = "### Total Retrieved Record(s): " + str(len(articles)) + "\n" hr += tableToMarkdown( name=table_name, t=hr_table_content, headers=["GUID", "Title", "Summary", "Type", "Tags", "Categories", "Article Link", "Published Date (GMT)"], removeNull=True, ) return hr def get_human_readable_for_data_card_command(results: dict[str, Any]) -> str: """ Parse and convert the Data Card Summary in the response into human-readable markdown string. :type results: ``List[Dict[str, Any]]`` :param results: Details of urls. :return: Human Readable string containing information of data card. :rtype: ``str`` """ hr_table_content: list[dict[str, Any]] = [] summary = results.get("data_summary", {}) summary = {pascalToSpace(underscoreToCamelCase(k)): v for k, v in summary.items()} hr_row = { "Name": results.get("name", ""), "Type": results.get("type", ""), "Netblock": results.get("netblock", ""), "Autonomous System Number": results.get("asn", ""), "Host Provider": results.get("hosting_provider", ""), "Operating System": results.get("os", ""), "Data Card Summary": get_data_card_summary(summary), } hr_table_content.append(hr_row) return tableToMarkdown( "Data Card Summary", hr_table_content, headers=[ "Name", "Type", "Netblock", "Autonomous System Number", "Host Provider", "Operating System", "Data Card Summary", ], removeNull=True, ) def get_human_readable_for_reputation_command(results: dict[str, Any], query: str) -> str: """ Parse and convert the response into human-readable markdown string. :type results: ``List[Dict[str, Any]]`` :param results: Details of urls. :type query: ``str`` :param query: Value of the indicator. :return: Human Readable string containing information. :rtype: ``str`` """ classification = results.get("classification", "") reputation_score = results.get("score", "") reputation_message = f"The reputation score for '{query}' is {reputation_score} and is classified as '{classification}'.\n" hr_table_content: list[dict[str, Any]] = [] rules = results.get("rules", []) for rule in rules: link = rule.get("link") if link: name = f"[{rule.get('name', '')}]({rule.get('link')})" else: name = rule.get("name", "") hr_row = {"Name": name, "Description": rule.get("description", ""), "Severity": rule.get("severity", "")} hr_table_content.append(hr_row) hr_table = tableToMarkdown("Reputation Rules", hr_table_content, headers=["Name", "Description", "Severity"]) return reputation_message + hr_table def prepare_human_readable_dict_for_ssl(results: list[dict[str, Any]]) -> list[dict[str, Any]]: """ Preparing human-readable dictionary for ssl certificate command. :param results: ssl certificates details :return: human-readable dict """ return [ { "First (GMT)": epochToTimestamp(result.get("firstSeen", "")) if result.get("firstSeen") else None, "Last (GMT)": epochToTimestamp(result.get("lastSeen", "")) if result.get("lastSeen") else None, "SSL Version": result.get("sslVersion", 0), "Expires (GMT)": result.get("expirationDate", ""), "Issued (GMT)": result.get("issueDate", ""), "Sha1": result.get("sha1", ""), "Serial Number": result.get("serialNumber", ""), "Subject Country": result.get("subjectCountry", ""), "Issuer Common Name": result.get("issuerCommonName", ""), "Issuer Province": result.get("issuerProvince", ""), "Subject State/Province Name": result.get("subjectStateOrProvinceName", ""), "Subject Street Address": result.get("subjectStreetAddress", ""), "Issuer State/Province Name": result.get("issuerStateOrProvinceName", ""), "Issuer Country": result.get("issuerCountry", ""), "Subject Locality Name": result.get("subjectLocalityName", ""), "Subject Alternative Names": ", ".join(result.get("subjectAlternativeNames", [])), "Issuer Organization Unit Name": result.get("issuerOrganizationUnitName", ""), "Issuer Organization Name": result.get("issuerOrganizationName", ""), "Subject Organization Name": result.get("subjectOrganizationName", ""), "Issuer Locality Name": result.get("issuerLocalityName", ""), "Subject Common Name": result.get("subjectCommonName", ""), "Subject Province": result.get("subjectProvince", ""), "Subject Organization Unit Name": result.get("subjectOrganizationUnitName", ""), "Issuer Street Address": result.get("issuerStreetAddress", ""), } for result in results ] def prepare_human_readable_dict_for_pdns(results: list[dict[str, Any]]) -> list[dict[str, Any]]: """ Prepare human-readable dictionary for passive DNS command. :param results: passive DNS details. :return: human-readable dict """ return [ { "First (GMT)": result.get("firstSeen", ""), "Last (GMT)": result.get("lastSeen", ""), "Source": ", ".join(result.get("source", [])), "Value": result.get("value", ""), "Collected (GMT)": result.get("collected", ""), "Record Type": result.get("recordType", ""), "Resolve": result.get("resolve", ""), "Resolve Type": result.get("resolveType", ""), "Record Hash": result.get("recordHash", ""), } for result in results ] def get_ssl_cert_search_hr(results: list[dict[str, Any]]) -> str: """ Retrieved information of ssl certificates and convert it into human-readable markdown string. :param results: ssl certificates details :return: human-readable string """ ssl_cert_search_hr: list[dict[str, Any]] = prepare_human_readable_dict_for_ssl(results) hr = "### Total Retrieved Record(s): " + str(len(results)) + "\n" hr += tableToMarkdown( "SSL certificate(s)", ssl_cert_search_hr, [ "Sha1", "Serial Number", "Issued (GMT)", "Expires (GMT)", "SSL Version", "First (GMT)", "Last (GMT)", "Issuer Common Name", "Subject Common Name", "Subject Alternative Names", "Issuer Organization Name", "Subject Organization Name", "Issuer Locality Name", "Subject Locality Name", "Issuer State/Province Name", "Subject State/Province Name", "Issuer Country", "Subject Country", "Issuer Street Address", "Subject Street Address", "Issuer Organization Unit Name", "Subject Organization Unit Name", ], removeNull=True, ) return hr def get_pdns_details_hr(results: list[dict[str, Any]], total_record: int) -> str: """ Retrieved information of passive DNS and convert it into human-readable markdown string. :param results: passive DNS details :param total_record: number of record retrieved from response :return: human-readable string """ pdns_details_hr: list[dict[str, Any]] = prepare_human_readable_dict_for_pdns(results) table_headers = [ "Resolve", "Resolve Type", "Record Type", "Collected (GMT)", "First (GMT)", "Last (GMT)", "Source", "Record Hash", ] hr = "### Total Retrieved Record(s): " + str(total_record) + "\n" hr += tableToMarkdown("PDNS detail(s)", pdns_details_hr, table_headers, removeNull=True) return hr def create_pdns_standard_context(results: list[dict[str, Any]]) -> list[CommandResults]: """ Preparing standard context and dbotScore for pdns command. here, standard context includes ip and domain model. :param results: pdns details from response :return: list of CommandResults of standard context """ standard_results: list[CommandResults] = [] for result in results: resolve_type = result.get("resolveType", "") resolve = result.get("resolve", "") if resolve_type == "domain": dbot_score = Common.DBotScore(resolve, resolve_type, INTEGRATION_NAME, Common.DBotScore.NONE) if auto_detect_indicator_type(resolve) == FeedIndicatorType.Domain: domain_ioc = Common.Domain(resolve, dbot_score) # add standard output with standard readable output standard_results.append( CommandResults( indicator=domain_ioc, readable_output=tableToMarkdown("", domain_ioc.to_context().get(Common.Domain.CONTEXT_PATH)), ) ) elif resolve_type == "ip": dbot_score = Common.DBotScore(resolve, resolve_type, INTEGRATION_NAME, Common.DBotScore.NONE) if auto_detect_indicator_type(resolve) == FeedIndicatorType.IP: ip_ioc = Common.IP(resolve, dbot_score) # add standard output with standard readable output standard_results.append( CommandResults( indicator=ip_ioc, readable_output=tableToMarkdown("", ip_ioc.to_context().get(Common.IP.CONTEXT_PATH)) ) ) return standard_results def get_services_hr(total_records: int, results: list) -> str: services_hr = [] for result in results: current_services = result.get("currentServices", []) labels = [] for services in current_services: if services.get("label"): labels.append(services.get("label")) services_hr.append( { "Port Number": result.get("portNumber"), "Protocol": result.get("protocol"), "Status": result.get("status"), "Current Service Labels": ", ".join(labels), "First Seen Date (GMT)": result.get("firstSeen"), "Last Seen Date (GMT)": result.get("lastSeen"), "Last Scanned Date (GMT)": result.get("lastScan"), } ) table_output = tableToMarkdown( "Services", services_hr, headers=[ "Port Number", "Protocol", "Status", "Current Service Labels", "First Seen Date (GMT)", "Last Seen Date (GMT)", "Last Scanned Date (GMT)", ], removeNull=True, ) return f"### Total Retrieved Record(s) {total_records} \n {table_output}" def validate_get_cookies_arguments(args: dict[str, Any]) -> None: """ Validate arguments for get cookies command, raise ValueError on invalid arguments. :param args: stripped arguments provided by user """ # check if page is a valid whole number try: if int(args.get("page", "0")) < 0: raise ValueError except ValueError: raise ValueError(MESSAGES["INVALID_WHOLE_NUMBER"].format("page")) # check if the single-select values of arguments are valid or not valid_values = { "search_by": [ "get addresses by cookie domain", "get addresses by cookie name", "get hosts by cookie domain", "get hosts by cookie name", ], "order": ["desc", "asc"], "sort": ["first seen", "last seen"], } for argument_name, valid_value in valid_values.items(): if args.get(argument_name) not in valid_value: raise ValueError(MESSAGES["INVALID_SINGLE_SELECT"].format(argument_name, ",".join(valid_value))) # validate query param based on search_by if "domain" in args["search_by"]: # The domain should only contain the characters a-z, A-Z, hyphen (-) and fullstops (.). if not args["query"] or re.search("[^a-zA-Z0-9.-]", args["query"]): raise ValueError(MESSAGES["INVALID_QUERY_COOKIE_DOMAIN"]) else: """ Valid cookie name can be any US-ASCII characters, except control characters, spaces, separator character or tabs.""" if not args["query"] or re.search(r'[?^()<>@,;:/="\[\]{}\\\t\n\s]', args["query"]): raise ValueError(MESSAGES["INVALID_QUERY_COOKIE_NAME"]) def get_cookies_hr(results: list[dict[str, Any]], hostname_header: str, total_records: int): """ Retrieved information of cookies and convert it into human-readable markdown string. :param results: cookie details :param hostname_header: The header for the hostname column, should be either 'Hostname' or 'IP Address' :param total_records: Total number of available records :return: human-readable string """ hr_results = [ { hostname_header: result.get("hostname", ""), "Cookie Name": result.get("cookieName", ""), "Cookie Domain": result.get("cookieDomain", ""), "First Seen Date (GMT)": result.get("firstSeen", ""), "Last Seen Date (GMT)": result.get("lastSeen", ""), } for result in results ] table_headers = [hostname_header, "Cookie Name", "Cookie Domain", "First Seen Date (GMT)", "Last Seen Date (GMT)"] hr = "### Total Record(s): " + str(total_records) + "\n" hr += "### Total Retrieved Record(s): " + str(len(hr_results)) + "\n" hr += tableToMarkdown("Cookies", hr_results, table_headers, removeNull=True) return hr def calculate_dbot_score(classification: str) -> int: """ Calculate te dbot score according to the classification provided :param classification: The classification received from he api response :return: Dbot Score """ if classification == "UNKNOWN": score = Common.DBotScore.NONE # unknown elif classification == "MALICIOUS": score = Common.DBotScore.BAD # bad elif classification == "SUSPICIOUS": score = Common.DBotScore.SUSPICIOUS # suspicious else: score = Common.DBotScore.GOOD # good return score def get_standard_context(score: int, ip: str) -> Common.IP: """ Prepare standard context for ip reputation command :param score: The Dbot score :param ip: IP Address :return: IP indicator object """ dbot_score = Common.DBotScore( indicator=ip, integration_name="PassiveTotal", indicator_type=DBotScoreType.IP, score=score, reliability=demisto.params().get("integrationReliability"), ) return Common.IP(ip=ip, dbot_score=dbot_score) def get_data_card_summary(summary: dict) -> str: """ Prepare data card summary :param summary: data card summary response :return: human readable string """ data_card_summary = "" for key, value in summary.items(): if value.get("count") == 0: data_card_summary += "{}: {}, ".format(key, value.get("count")) else: data_card_summary += "{}: [{}]({}), ".format(key, value.get("count"), value.get("link")) return data_card_summary[:-2] def validate_list_intel_profile_args(args: dict[str, str]) -> tuple[dict[str, Any], int]: """ Validate arguments for pt-list-intel-profiles, raise ValueError on invalid arguments. :param args: The command arguments provided by the user. :return: Parameters to send in request """ params: dict[str, Any] = {} query = args.get("query", "") if query: params["query"] = query profile_type = args.get("type", "").lower() if profile_type: if profile_type not in PROFILE_TYPE: raise ValueError(MESSAGES["INVALID_PROFILE_TYPE"].format(profile_type)) params["type"] = profile_type indicator_value = args.get("indicator_value", "") if indicator_value: params["query"] = indicator_value source = args.get("source", "").lower() if source: if not indicator_value: raise ValueError(MESSAGES["REQUIRED_INDICATOR_VALUE"]) if source not in SOURCE: raise ValueError(MESSAGES["INVALID_SOURCE"].format(source)) params["sources"] = source category = args.get("category", "").lower() if category: if not indicator_value: raise ValueError(MESSAGES["REQUIRED_INDICATOR_VALUE"]) params["categories"] = category page_size = validate_page_size_args(args) return params, page_size def get_human_readable_for_intel_profile_command(results: list[dict[str, Any]]) -> str: """ Parse and convert the response into human-readable markdown string. :param results: Details of profiles. :return: Human Readable string containing information. """ hr_list = [] for profile in results: hr_record = { "ID": profile.get("id", ""), "Title": profile.get("title", ""), "Aliases": ", ".join(f"{i}" for i in profile.get("aliases", [])), "Public Indicators": profile.get("osintIndicatorsCount", ""), "RiskIQ Indicators": profile.get("riskIqIndicatorsCount", ""), } hr_list.append(hr_record) return tableToMarkdown( "Profile(s)", hr_list, ["ID", "Title", "Aliases", "Public Indicators", "RiskIQ Indicators"], removeNull=True ) def validate_page_and_size_args(args: dict[str, str]) -> dict: """ Validate page and size arguments for all commands, raise ValueError on invalid arguments. :param args: The command arguments provided by the user. :return: Parameters to send in request """ params: dict[str, Any] = {} page_size = arg_to_number(args.get("page_size", DEFAULT_SIZE)) if page_size is not None: if page_size < 1 or page_size > 2147483647: raise ValueError(MESSAGES["INVALID_PAGE_SIZE"].format(page_size)) else: page_size = int(DEFAULT_SIZE) params["size"] = page_size page_number = arg_to_number(args.get("page_number", DEFAULT_PAGE_NUMBER)) if page_number: if page_number < 0 or page_number > 2147483647: raise ValueError(MESSAGES["INVALID_PAGE_NUMBER"].format(page_number)) else: page_number = int(DEFAULT_PAGE_NUMBER) params["page"] = page_number return params def validate_list_intel_profile_indicators_args(args: dict[str, Any]) -> tuple[str, dict]: """ Validate arguments of list_intel_profile_indicators commands, raise ValueError on invalid arguments. :param args: The command arguments provided by the user. :return: Parameters to send in request """ profile_id = args.get("id", "") if not profile_id: raise ValueError(MESSAGES["REQUIRED_ARGUMENT"].format("id")) params = validate_page_and_size_args(args) indicator_type = args.get("type", "").lower() if indicator_type: if indicator_type not in INDICATOR_TYPE: raise ValueError(MESSAGES["INVALID_INDICATOR_TYPE"].format(indicator_type)) params["types"] = indicator_type indicator_value = args.get("indicator_value", "") if indicator_value: params["query"] = indicator_value source = args.get("source", "").lower() if source: if source not in SOURCE: raise ValueError(MESSAGES["INVALID_SOURCE"].format(source)) params["sources"] = source category = args.get("category", "").lower() if category: params["categories"] = category return profile_id, params def get_human_readable_for_intel_profile_indicator_command(indicators: dict[str, Any]) -> str: """ Parse and convert the intel profile indicator list into human-readable markdown string. :param indicators: Details of indicators. :return: Human Readable string containing information of intel profile indicators. """ hr_table_content: list[dict[str, Any]] = [] total_records = indicators.get("totalCount", 0) for indicator in indicators.get("results", []): hr_row = { "ID": indicator.get("id", ""), "Artifact Value": indicator.get("value", ""), "Type": indicator.get("type", ""), "First Seen (GMT)": indicator.get("firstSeen", ""), "Last Seen (GMT)": indicator.get("lastSeen", ""), "Source": "OSINT" if indicator.get("osint", True) else "RiskIQ", } hr_table_content.append(hr_row) hr = f"### Total Retrieved Indicator(s) {total_records}\n" hr += tableToMarkdown( "Indicator(s)", hr_table_content, headers=["ID", "Artifact Value", "Type", "First Seen (GMT)", "Last Seen (GMT)", "Source"], removeNull=True, ) return hr def validate_list_my_asi_insights_args(args: dict[str, Any]) -> tuple[str, int]: """ Validate arguments of pt-list-my-attack-surface-insights, pt-list-third-party-asi-insights command, raise ValueError on invalid arguments. :param args: The command arguments provided by the user. :return: Parameters to send in request """ priority = args.get("priority", "").lower() if priority: if priority not in PRIORITY: raise ValueError(MESSAGES["INVALID_PRIORITY_LEVEL"].format(priority)) else: raise ValueError(MESSAGES["REQUIRED_ARGUMENT"].format("priority")) page_size = validate_page_size_args(args) return priority, page_size def prepare_context_for_my_asi_insights(response, priority_level) -> dict[str, Any]: """ Prepare context data for pt-list-my-attack-surface-insights, pt-list-third-party-asi-insights command :param response: API response. :param priority_level: The priority level provided by the user. :return: context data """ context_data = {"priorityLevel": priority_level} insights = response.get("insights", []) for insight in insights: link = insight.get("link", "") if link: # retrieve segment_by and insight_id from the link received from api response link_split = link.split("?") insight["insightId"] = link_split[0].split("/")[-1] query_parameters = parse.parse_qs(link_split[1]) insight["segmentBy"] = query_parameters.get("segmentBy", "")[0] context_data["insight"] = insights return context_data def get_human_readable_for_my_asi_insights_command( results: dict[str, Any], priority: str, active_insights: int, total_insights: int, total_observations: int ) -> str: """ Parse and convert the asi insight list into human-readable markdown string. :param results: Details of insights. :param priority: Priority of insights. :param active_insights: Total active insights :param total_insights: Total number of insights :param total_observations: Total observations :return: Human Readable string containing information. """ hr_table_content: list[dict[str, Any]] = [] insights = results.get("insight", {}) for insight in insights: hr_row = { "Name": insight.get("name", ""), "Description": insight.get("description", ""), "Observations": insight.get("observationCount", ""), "Insight ID": insight.get("insightId", ""), "Segment By": insight.get("segmentBy", ""), } hr_table_content.append(hr_row) # sort on the basis of observation count sorted_hr_table = sorted(hr_table_content, key=lambda item: item["Observations"], reverse=True) table_heading = ( f"{priority.capitalize()} Severity Insights\n{active_insights} Active of {total_insights} " f"Insights - {total_observations} Observations\n" ) hr = tableToMarkdown( table_heading, sorted_hr_table, headers=["Name", "Description", "Observations", "Insight ID", "Segment By"], removeNull=True, ) return hr def get_human_readable_for_attack_surface_command(response: list[dict[str, Any]]) -> str: """ Parse and convert the attack surface list into human-readable markdown string. :param response: Details of attack surface. :return: Human Readable string containing information of attack surface. """ hr_table_content: list[dict[str, Any]] = [] for result in response: hr_row = { "ID": result.get("id", ""), "Name": f"[{result.get('name', '')}]({UI_LINK}{result.get('id', '')})", "High Severity": f"{result.get('priorities', {}).get('high', {}).get('observationCount', 0)} observations", "Medium Severity": f"{result.get('priorities', {}).get('medium', {}).get('observationCount', 0)} observations", "Low Severity": f"{result.get('priorities', {}).get('low', {}).get('observationCount', 0)} observations", } hr_table_content.append(hr_row) return tableToMarkdown( "Attack Surface(s)", hr_table_content, headers=["ID", "Name", "High Severity", "Medium Severity", "Low Severity"], removeNull=True, ) def validate_list_my_asi_assets_args(args: dict[str, Any]) -> tuple[str, dict]: """ Validate arguments of list_my_asi_assets_command commands, raise ValueError on invalid arguments. :param args: The command arguments provided by the user. :return: Parameters to send in request """ insight_id = args.get("id", "") if not insight_id: raise ValueError(MESSAGES["REQUIRED_ARGUMENT"].format("id")) segment_by = args.get("segment_by", "") if not segment_by: raise ValueError(MESSAGES["REQUIRED_ARGUMENT"].format("segment_by")) params = validate_page_and_size_args(args) params["segmentBy"] = segment_by return insight_id, params def get_human_readable_for_my_asi_assets_command(results: dict[str, Any]) -> str: """ Parse and convert the asi asset list into human-readable markdown string. :param results: Details of assets. :return: Human Readable string containing information. """ hr_table_content: list[dict[str, Any]] = [] assets = results.get("assets", []) for asset in assets: hr_row = { "Name": asset.get("name", ""), "Type": asset.get("type", ""), "First Seen (GMT)": asset.get("firstSeen", ""), "Last Seen (GMT)": asset.get("lastSeen", ""), } hr_table_content.append(hr_row) hr = tableToMarkdown( "Asset(s)", hr_table_content, headers=["Name", "Type", "First Seen (GMT)", "Last Seen (GMT)"], removeNull=True ) return hr def get_human_readable_for_my_asi_vulnerable_components_command(results: list[dict[str, Any]]) -> str: """ Parse and convert the asi vulnerable component list into human-readable markdown string. :param results: Details of vulnerable component. :return: Human Readable string containing information. """ hr_table_content: list[dict[str, Any]] = [] for component in results: hr_row = { "Name": component.get("name", ""), "Type": component.get("type", ""), "Severity": component.get("severity", ""), "Asset Count": component.get("count", ""), } hr_table_content.append(hr_row) hr = tableToMarkdown( "Vulnerable Component(s)", hr_table_content, headers=["Name", "Type", "Severity", "Asset Count"], removeNull=True ) return hr def get_human_readable_for_my_asi_vulnerabilities_command(results: list[dict[str, Any]]) -> str: """ Parse and convert the asi vulnerabilities list into human-readable markdown string. :param results: Details of vulnerability. :return: Human Readable string containing information. """ hr_table_content: list[dict[str, Any]] = [] for component in results: hr_row = { "CVE ID": component.get("cveId", ""), "CWE ID": f'{", ".join("{}".format(i.get("cweId")) for i in component.get("cwes", []))} ', "RiskIQ Priority Score": component.get("priorityScore", ""), "Asset Count": component.get("observationCount", ""), } hr_table_content.append(hr_row) hr = tableToMarkdown( "Vulnerabilities", hr_table_content, headers=["CVE ID", "CWE ID", "RiskIQ Priority Score", "Asset Count"], removeNull=True ) return hr def get_human_readable_for_my_asi_observations_command(results: dict[str, Any]) -> str: """ Parse and convert the asi observations list into human-readable markdown string. :param results: Details of observations. :return: Human Readable string containing information. """ hr_table_content: list[dict[str, Any]] = [] assets = results.get("assets", []) for asset in assets: hr_row = { "Name": asset.get("name", ""), "Type": asset.get("type", ""), "First Seen (GMT)": asset.get("firstSeen", ""), "Last Seen (GMT)": asset.get("lastSeen", ""), } hr_table_content.append(hr_row) hr = tableToMarkdown( "Observation(s)", hr_table_content, headers=["Name", "Type", "First Seen (GMT)", "Last Seen (GMT)"], removeNull=True ) return hr def validate_page_size_args(args: dict[str, str]) -> int: """ Validate page_size argument for all command which does not supports pagination, raise ValueError on invalid arguments. :param args: The command arguments provided by the user. :return: Validated page_size argument """ page_size = arg_to_number(args.get("page_size", DEFAULT_SIZE)) if page_size is not None: if page_size < 1 or page_size > 1000: raise ValueError(MESSAGES["NOT_VALID_PAGE_SIZE"].format(page_size)) else: page_size = int(DEFAULT_SIZE) return page_size """ REQUESTS FUNCTIONS """ def test_function(client: Client) -> str: """ Performs test connectivity by valid http response :param client: client object which is used to get response from api :return: raise ValueError if any error occurred during connection """ client.http_request(method="GET", url_suffix=URL_SUFFIX["TEST_MODULE"]) return "ok" @logger def get_components_command(client: Client, args: dict[str, Any]) -> str | list[CommandResults]: """ Retrieves the host attribute components for a domain or IP address. :param client: Client object :param args: The command arguments provided by user :return: Standard command result or no records found message """ # Trim the arguments for argument in args: args[argument] = args[argument].strip() # Retrieve arguments and prepare query data params = get_common_arguments(args) # http call resp = client.http_request(method="GET", url_suffix=URL_SUFFIX["GET_COMPONENTS"], params=params) total_records = resp.get("totalRecords", 0) if total_records == 0: return MESSAGES["NO_RECORDS_FOUND"].format("component(s)") results = resp.get("results", []) # Creating entry context command_results, custom_ec = get_host_attribute_context_data(results) # Creating human-readable hr = get_components_hr(results) command_results.insert( 0, CommandResults( outputs_prefix="PassiveTotal.Component", outputs_key_field="", outputs=custom_ec, readable_output=hr, raw_response=resp, ), ) return command_results @logger def pt_whois_search_command(client_obj: Client, args: dict[str, Any]) -> list[CommandResults] | str: """ Gets WHOIS information records based on field matching queries :param client_obj: client object which is used to get response from API :param args: it contain arguments of pt-whois-search :return: command output """ # Retrieve arguments query, field = get_valid_whois_search_arguments(args) params = {"query": query, "field": field} # http call response = client_obj.http_request(method="GET", url_suffix=URL_SUFFIX["WHOIS_SEARCH"], params=params) domains = response.get("results", []) if len(domains) <= 0: return MESSAGES["NO_RECORDS_FOUND"].format("domain information") # Creating entry context command_results, custom_ec = get_context_for_whois_commands(domains) # Creating human-readable hr = get_human_readable_for_whois_commands(domains) command_results.insert( 0, CommandResults( outputs_prefix="PassiveTotal.WHOIS", outputs_key_field=["domain", "lastLoadedAt"], outputs=custom_ec, readable_output=hr, raw_response=response, ), ) return command_results @logger def get_trackers_command(client: Client, args: dict[str, Any]) -> str | list[CommandResults]: """ Retrieves the host attribute trackers for a domain or IP address. :param client: Client object :param args: The command arguments provided by user :return: Standard command result or no records found message """ # Trim the arguments for argument in args: args[argument] = args[argument].strip() # Retrieve arguments and prepare query data params = get_common_arguments(args) # http call resp = client.http_request(method="GET", url_suffix=URL_SUFFIX["GET_TRACKERS"], params=params) total_records = resp.get("totalRecords", 0) if total_records == 0: return MESSAGES["NO_RECORDS_FOUND"].format("tracker(s)") results = resp.get("results", []) # Creating entry context command_results, custom_ec = get_host_attribute_context_data(results) # Creating human-readable hr = get_trackers_hr(results) command_results.insert( 0, CommandResults( outputs_prefix="PassiveTotal.Tracker", outputs_key_field="", outputs=custom_ec, readable_output=hr, raw_response=resp, ), ) return command_results @logger def ssl_cert_search_command(client: Client, args: dict[str, Any]) -> str | CommandResults: """ Retrieve SSL certificates based on various field and its value. :param client: client object. :param args: Demisto argument(s) provided by the user. :return: standard command result """ # Retrieve arguments field: str = args.get("field", "") query: str = args.get("query", "") # Building url url_suffix: str = URL_SUFFIX["SSL_CERT_SEARCH"] # Prepare query data request_data: dict[str, Any] = {"field": field, "query": query} # http call resp: dict[str, Any] = client.http_request("GET", url_suffix, request_data) results: list[dict[str, Any]] = resp.get("results", []) if len(results) <= 0: return MESSAGES["NO_RECORDS_FOUND"].format("SSL certificate(s)") # Creating entry context custom_ec = createContext(results, removeNull=True) # Creating human-readable hr = get_ssl_cert_search_hr(results) return CommandResults( outputs_prefix="PassiveTotal.SSL", outputs_key_field="sha1", outputs=custom_ec, readable_output=hr, raw_response=resp ) @logger def get_pdns_details_command(client: Client, args: dict[str, Any]) -> str | list[CommandResults]: """ Retrieve passive DNS details based on ip or host. :param client: client object. :param args: Demisto argument(s) provided by the user. :return: standard command result """ # Retrieve arguments params = get_common_arguments(args) params["timeout"] = args.get("timeout", 7) # http call resp = client.http_request("GET", url_suffix=URL_SUFFIX["GET_PDNS_DETAILS"], params=params) total_record = resp.get("totalRecords", 0) if total_record <= 0: return MESSAGES["NO_RECORDS_FOUND"].format("PDNS Record(s)") # Creating entry context results = resp.get("results", []) custom_ec = createContext(results, removeNull=True) command_results = create_pdns_standard_context(results) # Creating human-readable hr = get_pdns_details_hr(results, total_record) # Building custom output path output_path = "PassiveTotal.PDNS(val.{0} == obj.{0} && val.{1} == obj.{1} && val.{2} == obj.{2})".format( "resolve", "recordType", "resolveType" ) command_results.insert( 0, CommandResults( outputs_prefix=output_path, outputs_key_field="", outputs=custom_ec, readable_output=hr, raw_response=resp ), ) return command_results @logger def get_host_pairs_command(client: Client, args: dict[str, Any]) -> str | CommandResults: """ Retrieves the host attribute pairs related to a domain or IP address. :param client: Client object :param args: The command arguments provided by user :return: Standard command result or no records found message """ # Trim the arguments for argument in args: args[argument] = args[argument].strip() # Retrieve arguments and prepare query data params = get_common_arguments(args) if args.get("direction") not in VALID_DIRECTION_FOR_HOST_PAIRS: raise ValueError(MESSAGES["INVALID_DIRECTION_VALUE"]) params["direction"] = args.get("direction") # http call resp = client.http_request(method="GET", url_suffix=URL_SUFFIX["GET_HOST_PAIRS"], params=params) total_records = resp.get("totalRecords", 0) if total_records == 0: return MESSAGES["NO_RECORDS_FOUND"].format("host pair(s)") results = resp.get("results", []) # Creating entry context custom_ec = createContext(data=results, removeNull=True) # Creating human-readable hr = get_host_pairs_hr(results) return CommandResults( outputs_prefix="PassiveTotal.HostPair", outputs_key_field="", outputs=custom_ec, readable_output=hr, raw_response=resp ) @logger def domain_reputation_command(client_obj: Client, args: dict[str, Any]) -> str | list[CommandResults]: """ Reputation command for domain. :param client_obj: Client object :param args: The command arguments provided by user :return: Standard command result or no records found message """ # Retrieve arguments domains = argToList(args.get("domain", "")) # argument validation if len(domains) == 0: raise ValueError("domain(s) not specified") command_results: list[CommandResults] = [] custom_domain_context: list[dict[str, Any]] = [] domain_responses: list[dict[str, Any]] = [] custom_reputation_response = [] for domain in domains: # argument validation if domain.strip() == "": raise ValueError(MESSAGES["EMPTY_DOMAIN_ARGUMENT"]) params = {"query": domain, "field": "domain"} # http call response = client_obj.http_request(method="GET", url_suffix=URL_SUFFIX["WHOIS_SEARCH"], params=params) reputation_response = client_obj.http_request(method="GET", url_suffix=URL_SUFFIX["GET_REPUTATION"], params=params) hr_response = get_human_readable_for_reputation_command(reputation_response, domain) custom_reputation_response.append(hr_response) custom_reputation_context = remove_empty_elements(reputation_response) domains_response = response.get("results", []) if len(domains_response) <= 0: continue classification = reputation_response.get("classification", "") dbot_score = calculate_dbot_score(classification) # Creating entry context standard_results, custom_context = get_context_for_whois_commands(domains_response, dbot_score) # Preparing context data command_results.extend(standard_results) custom_context.append(custom_reputation_context) final_context = {k: v for x in custom_context for k, v in x.items()} custom_domain_context.append(final_context) domain_responses += domains_response # Creating human-readable domain_standard_hr = get_human_readable_for_whois_commands(domain_responses, is_reputation_command=True) final_hr = domain_standard_hr for x in custom_reputation_response: final_hr += x command_results.insert( 0, CommandResults( readable_output=final_hr, outputs_prefix="PassiveTotal.Domain", outputs_key_field="domain", outputs=custom_domain_context, ), ) return command_results @logger def get_services_command(client: Client, args: dict[str, Any]) -> CommandResults: """ Retrieves the services for the specified IP address. :param client: Client object. :param args: The command arguments provided by user. :return: Standard command result or no records found message. """ # Trim the argument and remove ' quotes surrounding ip ip = args["ip"].strip().strip("'") # Checking whether ip is valid or not if not is_ip_valid(ip, accept_v6_ips=True): raise ValueError(MESSAGES["INVALID_IP"]) # http call resp = client.http_request(method="GET", url_suffix=URL_SUFFIX["GET_SERVICES"], params={"query": ip}) total_records = resp.get("totalRecords", 0) if total_records == 0: return CommandResults(readable_output=MESSAGES["NO_RECORDS_FOUND"].format("services")) results = [{**response, "ip": ip} for response in resp.get("results", [])] # Creating context context_output = remove_empty_elements(results) # Creating human-readable hr = get_services_hr(total_records, results) return CommandResults( outputs_prefix="PassiveTotal.Service", outputs_key_field=["ip", "portNumber"], outputs=context_output, readable_output=hr, raw_response=resp, ) @logger def pt_get_whois_command(client_obj: Client, args: dict[str, Any]) -> CommandResults: """ Gets WHOIS information records based on queries :param client_obj: client object which is used to get response from API :param args: it contain arguments of pt-get-whois :return: command output """ # Retrieve arguments query, history = get_valid_get_whois_arguments(args) params = {"query": query, "history": history} # http call response = client_obj.http_request(method="GET", url_suffix=URL_SUFFIX["WHOIS_GET"], params=params) domains = response.get("results", []) if len(domains) <= 0 and "domain" in response: domains = [response] if len(domains) <= 0: return CommandResults(readable_output=MESSAGES["NO_RECORDS_FOUND"].format("domain information")) # Creating entry context custom_context = get_context_for_get_whois_commands(domains) # Creating human-readable hr = get_human_readable_for_whois_commands(domains) return CommandResults( outputs_prefix="PassiveTotal.WHOIS", outputs_key_field=["domain", "lastLoadedAt"], outputs=custom_context, readable_output=hr, raw_response=response, ) @logger def get_cookies_command(client: Client, args: dict[str, str]) -> str | CommandResults: """ Retrieve cookies with hostnames or addresses based on cookie name or cookie domain. :param client: Client object :param args: The command arguments provided by user :return: Standard command result or no records found message """ default_values = {"page": "0", "sort": "last seen", "order": "desc"} # Trim the arguments and fill empty optional args with default values for argument in args: args[argument] = args[argument].strip() if not args[argument] and argument in list(default_values.keys()): args[argument] = default_values[argument] # Validate arguments validate_get_cookies_arguments(args) # Prepare params for http request params = { "page": args.get("page"), "sort": "lastSeen" if args.get("sort") == "last seen" else "firstSeen", "order": args.get("order"), } # Prepare the url suffix as per search_by and query argument url_suffix = URL_SUFFIX["_".join(args["search_by"].upper().split())].format(args["query"]) # Make the http request resp = client.http_request(method="GET", url_suffix=url_suffix, params=params) # Get results from response results = resp.get("results", []) # Get total records from response total_records = resp.get("totalRecords", 0) # return standard no records found message on empty results if len(results) <= 0: return "Total Record(s): " + str(total_records) + "\n" + MESSAGES["NO_RECORDS_FOUND"].format("cookies") # creating entry context entry_context = createContext(results, removeNull=True) # create human readable by providing it results and the first column header name human_readable = get_cookies_hr(results, "Hostname" if "hosts" in url_suffix else "IP Address", total_records) # return CommandResults objects return CommandResults( outputs_prefix="PassiveTotal.Cookie", outputs_key_field=["hostname", "cookieName", "cookieDomain"], outputs=entry_context, readable_output=human_readable, raw_response=resp, ) @logger def pt_get_articles_command(client_obj: Client, args: dict[str, Any]) -> CommandResults: """ Gets an article information based on queries :param client_obj: client object which is used to get response from API :param args: it contain arguments of pt-get-articles :return: command output """ # Retrieve arguments query = args.get("query", "").strip() article_type = args.get("type", "").strip() if query == "": raise ValueError(MESSAGES["EMPTY_GET_WHOIS_ARGUMENT"]) params = {"query": query} if article_type != "": params["type"] = article_type # http call response = client_obj.http_request(method="GET", url_suffix=URL_SUFFIX["GET_ARTICLES"], params=params) articles = response.get("articles", []) if not articles or len(articles) <= 0: return CommandResults(readable_output=MESSAGES["NO_RECORDS_FOUND"].format("articles")) # Creating entry context custom_ec_for_articles = remove_empty_elements(articles) # Creating human-readable hr = get_human_readable_for_articles_commands(articles) return CommandResults( outputs_prefix="PassiveTotal.Article", outputs_key_field="guid", outputs=custom_ec_for_articles, readable_output=hr, raw_response=response, ) @logger def get_data_card_summary_command(client_obj: Client, args: dict[str, Any]) -> CommandResults: """ Retrieves a summary data card associated with the given query. :param client_obj: client object which is used to get response from API :param args: it contain arguments of pt-data-card-get :return: command output """ # Retrieve arguments query = args.get("query", "").strip() if not query: raise ValueError(MESSAGES["REQUIRED_ARGUMENT"].format("query")) params = {"query": query} # http call response = client_obj.http_request(method="GET", url_suffix=URL_SUFFIX["GET_DATA_CARD_SUMMARY"], params=params) context_data = remove_empty_elements(response) hr_response = get_human_readable_for_data_card_command(response) return CommandResults( outputs_prefix="PassiveTotal.DataCard", outputs_key_field="name", outputs=context_data, readable_output=hr_response, raw_response=response, ) @logger def get_reputation_command(client_obj: Client, args: dict[str, Any]) -> CommandResults: """ Gets reputation for a given domain, host or IP. :param client_obj: client object which is used to get response from API :param args: it contain arguments of pt-reputation-get :return: command output """ # Retrieve arguments query = args.get("query", "").strip() if not query: raise ValueError(MESSAGES["REQUIRED_ARGUMENT"].format("query")) params = {"query": query} # http call response = client_obj.http_request(method="GET", url_suffix=URL_SUFFIX["GET_REPUTATION"], params=params) context_data = remove_empty_elements(response) context_data["query"] = query hr_response = get_human_readable_for_reputation_command(response, query) return CommandResults( outputs_prefix="PassiveTotal.Reputation", outputs_key_field="query", outputs=context_data, readable_output=hr_response, raw_response=response, ) @logger def ip_reputation_command(client_obj: Client, args: dict[str, Any]) -> list[CommandResults]: """ Reputation command for IP. :param client_obj: Client object :param args: The command arguments provided by user :return: Standard command result """ # Retrieve arguments ips = [x.strip() for x in argToList(args.get("ip", "")) if x.strip()] # argument validation if len(ips) == 0: raise ValueError(MESSAGES["EMPTY_IP_ARGUMENT"]) command_results: list[CommandResults] = [] for ip in ips: if not is_ip_valid(ip, True): raise ValueError(MESSAGES["INVALID_IP_ARGUMENT"].format(ip)) params = { "query": ip, } # http call response = client_obj.http_request(method="GET", url_suffix=URL_SUFFIX["GET_REPUTATION"], params=params) classification = response.get("classification", "") dbot_score = calculate_dbot_score(classification) standard_context = get_standard_context(dbot_score, ip) context_data = remove_empty_elements(response) context_data["query"] = ip human_readable = get_human_readable_for_reputation_command(response, ip) command_results.append( CommandResults( readable_output=human_readable, outputs_prefix="PassiveTotal.IP", outputs_key_field="query", outputs=context_data, indicator=standard_context, ) ) return command_results @logger def get_intel_profile_command(client_obj: Client, args: dict[str, Any]) -> CommandResults: """ Retrieves the list of all profiles. :param client_obj: client object which is used to get response from API :param args: it contain arguments of pt-list-intel-profiles :return: command output """ # Retrieve arguments params, page_size = validate_list_intel_profile_args(args) profile_id = args.get("id") if profile_id: url_suffix = f'{URL_SUFFIX["LIST_INTEL_PROFILE"]}/{profile_id}' elif args.get("indicator_value"): url_suffix = URL_SUFFIX["LIST_INTEL_PROFILE_BY_INDICATOR"] else: url_suffix = URL_SUFFIX["LIST_INTEL_PROFILE"] # http call response = client_obj.http_request(method="GET", url_suffix=url_suffix, params=params) if profile_id: profiles = [response] else: profiles = response.get("results", []) if not profiles: return CommandResults(readable_output=MESSAGES["NO_RECORDS_FOUND"].format("profiles")) profiles = profiles[:page_size] context_data = remove_empty_elements_for_context(profiles) hr_response = get_human_readable_for_intel_profile_command(profiles) return CommandResults( outputs_prefix="PassiveTotal.IntelProfile", outputs_key_field="id", outputs=context_data, readable_output=hr_response, raw_response=response, ) @logger def list_intel_profile_indicators_command(client_obj: Client, args: dict[str, Any]) -> CommandResults: """ Retrieves the indicators for the given profile. :param client_obj: client object which is used to get response from API :param args: it contain arguments of pt-list-intel-profile-indicator :return: command output """ profile_id, params = validate_list_intel_profile_indicators_args(args) response = client_obj.http_request( method="GET", url_suffix=URL_SUFFIX["LIST_INTEL_PROFILE_INDICATOR"].format(profile_id), params=params ) indicators = response.get("results", []) if not indicators or len(indicators) <= 0: return CommandResults(readable_output=MESSAGES["NO_RECORDS_FOUND"].format("indicators")) for indicator in indicators: del indicator["profileId"] context_data = {"indicator": remove_empty_elements(indicators), "id": profile_id} hr_response = get_human_readable_for_intel_profile_indicator_command(response) return CommandResults( outputs_prefix="PassiveTotal.IntelProfile", outputs_key_field="id", outputs=context_data, readable_output=hr_response, raw_response=response, ) @logger def list_my_asi_insights_command(client_obj: Client, args: dict[str, Any]) -> CommandResults: """ Retrieves the attack surface insight information of the individual's account. :param client_obj: client object which is used to get response from API :param args: it contain arguments of pt-list-my-attack-surface-insights :return: command output """ priority_level, page_size = validate_list_my_asi_insights_args(args) url_suffix = f'{URL_SUFFIX["LIST_ASI_INSIGHTS"]}/{priority_level}' response = client_obj.http_request(method="GET", url_suffix=url_suffix) insights = response.get("insights", []) response["insights"] = insights[:page_size] context_data = prepare_context_for_my_asi_insights(response, priority_level) summary = { "name": "pt-list-my-attack-surface-insights", "activeInsightCount": response.get("activeInsightCount", ""), "totalInsightCount": response.get("totalInsightCount", ""), "totalObservations": response.get("totalObservations", ""), } outputs = { "PassiveTotal.Insight(val.priorityLevel == obj.priorityLevel)": context_data, "PassiveTotal.Summary.Insight(val.name == obj.name)": summary, } hr_response = get_human_readable_for_my_asi_insights_command( context_data, priority_level, summary["activeInsightCount"], summary["totalInsightCount"], summary["totalObservations"] ) outputs = remove_empty_elements_for_context(outputs) return CommandResults(outputs=outputs, readable_output=hr_response, raw_response=response) @logger def list_third_party_asi_command(client_obj: Client, args: dict[str, Any]) -> CommandResults: """ Retrieves the attack surface observations by severity level for the given third-party account. :param client_obj: client object which is used to get response from API :param args: it contain arguments of pt-list-third-party-attack-surface :return: command output """ params = validate_page_and_size_args(args) vendor_id = arg_to_number(args.get("id")) url_suffix = URL_SUFFIX["LIST_THIRD_PARTY_ASI"] if vendor_id: url_suffix = f"{URL_SUFFIX['LIST_THIRD_PARTY_ASI']}/{vendor_id}" params = {} response = client_obj.http_request(method="GET", url_suffix=url_suffix, params=params) if vendor_id: context_data = [remove_empty_elements(response)] else: context_data = remove_empty_elements(response.get("vendors", [])) hr_response = get_human_readable_for_attack_surface_command(context_data) for data in context_data: data["priority"] = data.pop("priorities") summary = { "name": "pt-list-third-party-attack-surface", "totalCount": response.get("totalCount", ""), "totalPages": response.get("totalPages", ""), "nextPage": response.get("nextPage", ""), } outputs = { "PassiveTotal.ThirdParty(val.id == obj.id)": context_data, "PassiveTotal.Summary.ThirdPartyASI(val.name == obj.name)": summary, } outputs = remove_empty_elements_for_context(outputs) return CommandResults(outputs=outputs, readable_output=hr_response, raw_response=response) @logger def list_my_attack_surfaces_command(client_obj: Client, args: dict[str, Any]) -> CommandResults: """ Retrieves the attack surface information of the individual's account. :param client_obj: client object which is used to get response from API :param args: It contain arguments of pt-list-my-attack-surfaces :return: command output """ page_size = validate_page_size_args(args) response = client_obj.http_request(method="GET", url_suffix=URL_SUFFIX["LIST_ATTACK_SURFACE"]) if isinstance(response, dict): response = [response] # type: ignore response = response[:page_size] # type: ignore context_data = remove_empty_elements_for_context(response) for data in context_data: data["priority"] = data.pop("priorities") hr_response = get_human_readable_for_attack_surface_command(response) # type: ignore return CommandResults( outputs_prefix="PassiveTotal.AttackSurface", outputs_key_field="id", outputs=context_data, readable_output=hr_response, raw_response=response, ) @logger def list_third_party_asi_insights_command(client_obj: Client, args: dict[str, Any]): """ Retrieves the attack surface insight information of the given third-party account. :param client_obj: client object which is used to get response from API :param args: It contain arguments of pt-list-third-party-attack-surface-insights :return: command output """ vendor_id = arg_to_number(args.get("id", "")) if not vendor_id: raise ValueError(MESSAGES["REQUIRED_ARGUMENT"].format("id")) priority, page_size = validate_list_my_asi_insights_args(args) url_suffix = URL_SUFFIX["THIRD_PARTY_ASI_INSIGHTS"].format(vendor_id, priority) response = client_obj.http_request(method="GET", url_suffix=url_suffix) insights = response.get("insights", []) response["insights"] = insights[:page_size] context_data_out = prepare_context_for_my_asi_insights(response, priority) context_data_out.pop("priorityLevel") context_data = {"Insight": context_data_out, "id": vendor_id, "priorityLevel": priority} summary = { "name": "pt-list-third-party-attack-surface-insights", "activeInsightCount": response.get("activeInsightCount", ""), "totalInsightCount": response.get("totalInsightCount", ""), "totalObservations": response.get("totalObservations", ""), } outputs = { "PassiveTotal.ThirdParty(val.id == obj.id)": context_data, "PassiveTotal.Summary.ThirdPartyInsight(val.name == obj.name)": summary, } outputs = remove_empty_elements_for_context(outputs) hr_response = get_human_readable_for_my_asi_insights_command( context_data["Insight"], # type:ignore priority, # type:ignore summary["activeInsightCount"], summary["totalInsightCount"], summary["totalObservations"], ) return CommandResults(outputs=outputs, raw_response=response, readable_output=hr_response) @logger def list_my_asi_assets_command(client_obj: Client, args: dict[str, Any]) -> CommandResults: """ Retrieves the attack surface asset information of the individual's account. :param client_obj: client object which is used to get response from API :param args: it contain arguments of pt-list-attack-surface-assets :return: command output """ insight_id, params = validate_list_my_asi_assets_args(args) url_suffix = f'{URL_SUFFIX["LIST_ASI_ASSETS"]}/{insight_id}' response = client_obj.http_request(method="GET", url_suffix=url_suffix, params=params) context_data = {"asset": response.get("assets", []), "insightId": insight_id, "segmentBy": params["segmentBy"]} summary = { "name": "pt-list-my-attack-surface-assets", "totalCount": response.get("totalCount", ""), "totalPages": response.get("totalPages", ""), "nextPage": response.get("nextPage", ""), } outputs = { "PassiveTotal.Asset(val.insightId == obj.insightId && val.segmentBy == obj.segmentBy)": context_data, "PassiveTotal.Summary.Asset(val.name == obj.name)": summary, } outputs = remove_empty_elements_for_context(outputs) hr_response = get_human_readable_for_my_asi_assets_command(response) return CommandResults(outputs=outputs, readable_output=hr_response, raw_response=response) @logger def list_my_asi_vulnerable_components_command(client_obj: Client, args: dict[str, Any]) -> CommandResults: """ Retrieves the attack surface vulnerable component information of the individual's account. :param client_obj: client object which is used to get response from API :param args: it contain arguments of pt-list-my-attack-surface-vulnerable-components :return: command output """ params = validate_page_and_size_args(args) response = client_obj.http_request(method="GET", url_suffix=URL_SUFFIX["LIST_ASI_VULNERABLE_COMPONENTS"], params=params) result = response.get("vulnerableComponents") if not result: return CommandResults(readable_output=MESSAGES["NO_RECORDS_FOUND"].format("vulnerable components")) summary = { "name": "pt-list-my-attack-surface-vulnerable-components", "totalCount": response.get("totalCount", ""), "totalPages": response.get("totalPages", ""), "nextPage": response.get("nextPage", ""), } outputs = { "PassiveTotal.VulnerableComponent(val.name == obj.name && val.type == obj.type)": result, "PassiveTotal.Summary.VulnerableComponent(val.name == obj.name)": summary, } outputs = remove_empty_elements_for_context(outputs) hr_response = get_human_readable_for_my_asi_vulnerable_components_command(result) return CommandResults(outputs=outputs, readable_output=hr_response, raw_response=response) @logger def list_my_asi_vulnerabilities_command(client_obj: Client, args: dict[str, Any]) -> CommandResults: """ Retrieves the attack surface vulnerable component information of the individual's account. :param client_obj: client object which is used to get response from API :param args: it contain arguments of pt-list-my-attack-surface-vulnerabilities :return: command output """ params = validate_page_and_size_args(args) response = client_obj.http_request(method="GET", url_suffix=URL_SUFFIX["LIST_ASI_VULNERABILITIES"], params=params) result = response.get("cves") if not result: return CommandResults(readable_output=MESSAGES["NO_RECORDS_FOUND"].format("vulnerabilities")) summary = { "name": "pt-list-my-attack-surface-vulnerabilities", "totalCount": response.get("totalCount", ""), "totalPages": response.get("totalPages", ""), "nextPage": response.get("nextPage", ""), } outputs = { "PassiveTotal.Vulnerability(val.cveId == obj.cveId)": result, "PassiveTotal.Summary.Vulnerability(val.name == obj.name)": summary, } outputs = remove_empty_elements_for_context(outputs) hr_response = get_human_readable_for_my_asi_vulnerabilities_command(result) return CommandResults(outputs=outputs, readable_output=hr_response, raw_response=response) @logger def list_third_party_asi_vulnerable_components_command(client_obj: Client, args: dict[str, Any]) -> CommandResults: """ Retrieves the attack surface vulnerable component information of the given third-party account. :param client_obj: client object which is used to get response from API :param args: it contain arguments of pt-list-third-party-attack-surface-vulnerable-components :return: command output """ vendor_id = arg_to_number(args.get("id", "")) if not vendor_id: raise ValueError(MESSAGES["REQUIRED_ARGUMENT"].format("id")) params = validate_page_and_size_args(args) response = client_obj.http_request( method="GET", url_suffix=URL_SUFFIX["LIST_THIRD_PARTY_ASI_VULNERABLE_COMPONENTS"].format(vendor_id), params=params ) result = response.get("vulnerableComponents") if not result: return CommandResults(readable_output=MESSAGES["NO_RECORDS_FOUND"].format("third party vulnerable components")) context_data = {"id": vendor_id, "VulnerableComponent": result} summary = { "name": "pt-list-third-party-attack-surface-vulnerable-components", "totalCount": response.get("totalCount", ""), "totalPages": response.get("totalPages", ""), "nextPage": response.get("nextPage", ""), } outputs = { "PassiveTotal.ThirdParty(val.id == obj.id)": context_data, "PassiveTotal.Summary.ThirdPartyVulnerableComponent(val.name == obj.name)": summary, } outputs = remove_empty_elements_for_context(outputs) hr_response = get_human_readable_for_my_asi_vulnerable_components_command(result) return CommandResults(outputs=outputs, readable_output=hr_response, raw_response=response) @logger def list_my_asi_observations_command(client_obj: Client, args: dict[str, Any]) -> CommandResults: """ Retrieves the attack surface vulnerability observation information of the individual's account. :param client_obj: client object which is used to get response from API :param args: it contain arguments of pt-list-my-attack-surface-observations :return: command output """ cve_id = args.get("cve_id") if not cve_id: raise ValueError(MESSAGES["REQUIRED_ARGUMENT"].format("cve_id")) params = validate_page_and_size_args(args) response = client_obj.http_request(method="GET", url_suffix=URL_SUFFIX["LIST_ASI_OBSERVATIONS"].format(cve_id), params=params) result = response.get("assets") if not result: return CommandResults(readable_output=MESSAGES["NO_RECORDS_FOUND"].format("observations")) summary = { "name": "pt-list-my-attack-surface-observations", "totalCount": response.get("totalCount", ""), "totalPages": response.get("totalPages", ""), "nextPage": response.get("nextPage", ""), } result = {"cveId": response.get("cveId", ""), "cwe": response.get("cwes", []), "asset": response.get("assets", [])} outputs = { "PassiveTotal.Observation(val.cveId == obj.cveId)": result, "PassiveTotal.Summary.Observation(val.name == obj.name)": summary, } outputs = remove_empty_elements_for_context(outputs) hr_response = get_human_readable_for_my_asi_observations_command(response) return CommandResults(outputs=outputs, readable_output=hr_response, raw_response=response) @logger def list_third_party_asi_assets_command(client_obj: Client, args: dict[str, Any]): """ Retrieves the attack surface asset information of the given third-party account. :param client_obj: client object which is used to get response from API :param args: it contain arguments of pt-list-third-party-attack-surface-assets :return: command output """ vendor_id = arg_to_number(args.get("vendor_id", "")) if not vendor_id: raise ValueError(MESSAGES["REQUIRED_ARGUMENT"].format("vendor_id")) insight_id, params = validate_list_my_asi_assets_args(args) response = client_obj.http_request( method="GET", url_suffix=URL_SUFFIX["LIST_THIRD_PARTY_ASI_ASSETS"].format(vendor_id, insight_id), params=params ) context_data = { "id": vendor_id, "InsightAsset": {"asset": response.get("assets", []), "insightId": insight_id, "segmentBy": params["segmentBy"]}, } summary = { "name": "pt-list-third-party-attack-surface-assets", "totalCount": response.get("totalCount", ""), "totalPages": response.get("totalPages", ""), "nextPage": response.get("nextPage", ""), } outputs = { "PassiveTotal.ThirdParty(val.id == obj.id)": context_data, "PassiveTotal.Summary.ThirdPartyInsightAsset(val.name == obj.name)": summary, } outputs = remove_empty_elements_for_context(outputs) hr_response = get_human_readable_for_my_asi_assets_command(response) return CommandResults(outputs=outputs, raw_response=response, readable_output=hr_response) @logger def list_third_party_asi_observations_command(client_obj: Client, args: dict[str, Any]) -> CommandResults: """ Retrieves the attack surface vulnerability observation information of the given third-party account. :param client_obj: client object which is used to get response from API :param args: it contain arguments of pt-list-third-party-attack-surface-observations :return: command output """ vendor_id = arg_to_number(args.get("id", "")) if not vendor_id: raise ValueError(MESSAGES["REQUIRED_ARGUMENT"].format("id")) cve_id = args.get("cve_id") if not cve_id: raise ValueError(MESSAGES["REQUIRED_ARGUMENT"].format("cve_id")) params = validate_page_and_size_args(args) response = client_obj.http_request( method="GET", url_suffix=URL_SUFFIX["LIST_THIRD_PARTY_ASI_OBSERVATIONS"].format(vendor_id, cve_id), params=params ) result = response.get("assets") if not result: return CommandResults(readable_output=MESSAGES["NO_RECORDS_FOUND"].format("third party observations")) # prepare context summary = { "name": "pt-list-third-party-attack-surface-observations", "totalCount": response.get("totalCount", ""), "totalPages": response.get("totalPages", ""), "nextPage": response.get("nextPage", ""), } result = { "id": vendor_id, "Observation": {"cveId": response.get("cveId", ""), "cwe": response.get("cwes", []), "asset": response.get("assets", [])}, } outputs = { "PassiveTotal.ThirdParty(val.id == obj.id)": result, "PassiveTotal.Summary.ThirdPartyObservation(val.name == obj.name)": summary, } outputs = remove_empty_elements_for_context(outputs) hr_response = get_human_readable_for_my_asi_observations_command(response) return CommandResults(outputs=outputs, readable_output=hr_response, raw_response=response) @logger def list_third_party_attack_surface_vulnerabilities_command(client_obj: Client, args: dict[str, Any]) -> CommandResults: """ Retrieves the attack surface vulnerability information of the given third party account. :param client_obj: client object which is used to get response from API :param args: it contain arguments of pt-list-third-party-attack-surface-vulnerabilities :return: command output """ vendor_id = arg_to_number(args.get("id", "")) if not vendor_id: raise ValueError(MESSAGES["REQUIRED_ARGUMENT"].format("id")) params = validate_page_and_size_args(args) response = client_obj.http_request( method="GET", url_suffix=URL_SUFFIX["LIST_THIRD_PARTY_ASI_VULNERABILITIES"].format(vendor_id), params=params ) result = response.get("cves") if not result: return CommandResults(readable_output=MESSAGES["NO_RECORDS_FOUND"].format("third party vulnerabilities")) context_data = {"id": vendor_id, "Vulnerability": result} summary = { "name": "pt-list-third-party-attack-surface-vulnerabilities", "totalCount": response.get("totalCount", ""), "totalPages": response.get("totalPages", ""), "nextPage": response.get("nextPage", ""), } outputs = { "PassiveTotal.ThirdParty(val.id == obj.id)": context_data, "PassiveTotal.Summary.ThirdPartyVulnerability(val.name == obj.name)": summary, } outputs = remove_empty_elements_for_context(outputs) hr_response = get_human_readable_for_my_asi_vulnerabilities_command(result) return CommandResults(outputs=outputs, readable_output=hr_response, raw_response=response) def main() -> None: """ PARSE AND VALIDATE INTEGRATION PARAMS """ # Commands dict commands = { "pt-ssl-cert-search": ssl_cert_search_command, "pt-get-pdns-details": get_pdns_details_command, "pt-whois-search": pt_whois_search_command, "pt-get-components": get_components_command, "pt-get-trackers": get_trackers_command, "pt-get-host-pairs": get_host_pairs_command, "pt-get-services": get_services_command, "domain": domain_reputation_command, "pt-get-whois": pt_get_whois_command, "pt-get-cookies": get_cookies_command, "pt-get-articles": pt_get_articles_command, "pt-get-data-card": get_data_card_summary_command, "pt-get-reputation": get_reputation_command, "ip": ip_reputation_command, "pt-list-intel-profiles": get_intel_profile_command, "pt-list-intel-profile-indicators": list_intel_profile_indicators_command, "pt-list-third-party-attack-surface": list_third_party_asi_command, "pt-list-my-attack-surface-insights": list_my_asi_insights_command, "pt-list-third-party-attack-surface-insights": list_third_party_asi_insights_command, "pt-list-my-attack-surface-assets": list_my_asi_assets_command, "pt-list-my-attack-surface-vulnerable-components": list_my_asi_vulnerable_components_command, "pt-list-my-attack-surface-vulnerabilities": list_my_asi_vulnerabilities_command, "pt-list-my-attack-surface-observations": list_my_asi_observations_command, "pt-list-third-party-attack-surface-assets": list_third_party_asi_assets_command, "pt-list-third-party-attack-surface-vulnerable-components": list_third_party_asi_vulnerable_components_command, "pt-list-third-party-attack-surface-vulnerabilities": list_third_party_attack_surface_vulnerabilities_command, "pt-list-third-party-attack-surface-observations": list_third_party_asi_observations_command, "pt-list-my-attack-surfaces": list_my_attack_surfaces_command, } command = demisto.command() demisto.debug(f"Command being called is {command}") try: # Retrieve XSOAR params base_url = demisto.params().get("url") username = demisto.params().get("credentials", {}).get("identifier") or demisto.params().get("username") secret = demisto.params().get("credentials", {}).get("password") or demisto.params().get("secret") verify_certificate = not demisto.params().get("insecure", False) proxy = demisto.params().get("proxy", False) request_timeout = get_request_timeout() # prepare client class object client = Client( base_url=base_url, request_timeout=request_timeout, verify=verify_certificate, proxy=proxy, auth=(username, secret) ) # This is the call made when pressing the integration Test button. if demisto.command() == "test-module": result = test_function(client) demisto.results(result) elif command in commands: args = {key: value.strip() for key, value in demisto.args().items()} return_results(commands[command](client, args)) # Log exceptions except Exception as e: demisto.error(traceback.format_exc()) # print the traceback return_error(f"Error: {e!s}") def init(): if __name__ in ("__main__", "__builtin__", "builtins"): main() init()