Skip to content

Commit bcc7e14

Browse files
Add the Network Threat Intelligence endpoints
1 parent 9a15ef9 commit bcc7e14

File tree

1 file changed

+139
-6
lines changed

1 file changed

+139
-6
lines changed

ReversingLabs/SDK/a1000.py

Lines changed: 139 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import datetime
99
import requests
1010
import time
11+
from urllib import parse
1112
from warnings import warn
1213

1314
from ReversingLabs.SDK.helper import ADVANCED_SEARCH_SORTING_CRITERIA, DEFAULT_USER_AGENT, RESPONSE_CODE_ERROR_MAP, \
@@ -58,6 +59,13 @@ class A1000(object):
5859
__ADVANCED_SEARCH_ENDPOINT = "/api/samples/search/"
5960
__ADVANCED_SEARCH_ENDPOINT_V2 = "/api/samples/v2/search/"
6061
__LIST_CONTAINERS_ENDPOINT = "/api/samples/containers/"
62+
__URL_REPORT_ENDPOINT = "/api/network-threat-intel/url/"
63+
__DOMAIN_REPORT_ENDPOINT = "/api/network-threat-intel/domain/{domain}/"
64+
__IP_REPORT_ENDPOINT = "/api/network-threat-intel/ip/{ip}/report/"
65+
__IP_TO_DOMAIN_ENDPOINT = "/api/network-threat-intel/ip/{ip}/resolutions/"
66+
__URLS_FROM_IP_ENDPOINT = "/api/network-threat-intel/ip/{ip}/urls/"
67+
__FILES_FROM_IP_ENDPOINT = "/api/network-threat-intel/ip/{ip}/downloaded_files/"
68+
6169

6270
# Used by the deprecated get_results method
6371
__FIELDS = ("id", "sha1", "sha256", "sha512", "md5", "category", "file_type", "file_subtype", "identification_name",
@@ -1780,7 +1788,7 @@ def start_or_stop_yara_cloud_retro_scan(self, operation, ruleset_name):
17801788
:param ruleset_name: name of the YARA ruleset that the Cloud Retro scan should be run on
17811789
:type ruleset_name: str
17821790
:return: response
1783-
:rtype: requests.Response::
1791+
:rtype: requests.Response
17841792
"""
17851793
if operation not in ("START", "STOP", "CLEAR"):
17861794
raise WrongInputError("operation parameter must be either 'START', 'STOP' or 'CLEAR'")
@@ -1805,7 +1813,7 @@ def get_yara_cloud_retro_scan_status(self, ruleset_name):
18051813
:param ruleset_name: name of the YARA ruleset for which to check for the Cloud Retro scan status
18061814
:type ruleset_name: str
18071815
:return: response
1808-
:rtype: requests.Response::
1816+
:rtype: requests.Response
18091817
"""
18101818
if not isinstance(ruleset_name, str):
18111819
raise WrongInputError("ruleset_name parameter must be a string")
@@ -2049,7 +2057,7 @@ def list_containers_for_hashes(self, sample_hashes):
20492057
or MD5)
20502058
:type sample_hashes list[str]
20512059
:return: response
2052-
:rtype: requests.Response::
2060+
:rtype: requests.Response
20532061
"""
20542062
if not isinstance(sample_hashes, list):
20552063
raise WrongInputError("sample_hashes parameter must be a list of strings.")
@@ -2069,6 +2077,131 @@ def list_containers_for_hashes(self, sample_hashes):
20692077

20702078
return response
20712079

2080+
def network_url_report(self, requested_url):
2081+
"""Accepts a URL string and returns a report about the requested URL.
2082+
:param requested_url: URL for analysis
2083+
:type requested_url: str
2084+
:return: response
2085+
:rtype: requests.Response
2086+
"""
2087+
2088+
if not isinstance(requested_url, str):
2089+
raise WrongInputError("url parameter must be string.")
2090+
2091+
encoded_url = parse.quote_plus(requested_url)
2092+
2093+
endpoint = "{endpoint}?url={url}".format(
2094+
endpoint=self.__URL_REPORT_ENDPOINT,
2095+
url=encoded_url
2096+
)
2097+
2098+
url = self._url.format(endpoint=endpoint)
2099+
2100+
response = self.__get_request(url=url)
2101+
2102+
self.__raise_on_error(response)
2103+
2104+
return response
2105+
2106+
def network_domain_report(self, domain):
2107+
"""Accepts a domain string and returns a report about the requested domain.
2108+
:param domain: domain for analysis
2109+
:type domain: str
2110+
:return: response
2111+
:rtype: requests.Response
2112+
"""
2113+
if not isinstance(domain, str):
2114+
raise WrongInputError("domain parameter must be string.")
2115+
2116+
endpoint = self.__DOMAIN_REPORT_ENDPOINT.format(domain=domain)
2117+
2118+
url = self._url.format(endpoint=endpoint)
2119+
2120+
response = self.__get_request(url=url)
2121+
2122+
self.__raise_on_error(response)
2123+
2124+
return response
2125+
2126+
def network_ip_addr_report(self, ip_addr):
2127+
"""Accepts an IP address string and returns a report about the requested IP address.
2128+
:param ip_addr: IP address for analysis
2129+
:type ip_addr: str
2130+
:return: response
2131+
:rtype: requests.Response
2132+
"""
2133+
response = self.__ip_addr_endpoints(
2134+
ip_addr=ip_addr,
2135+
specific_endpoint=self.__IP_REPORT_ENDPOINT
2136+
)
2137+
2138+
return response
2139+
2140+
def network_ip_to_domain(self, ip_addr):
2141+
"""Accepts an IP address string and returns a list of IP-to-domain mappings.
2142+
:param ip_addr: requested IP address
2143+
:type ip_addr: str
2144+
:return: response
2145+
:rtype: requests.Response
2146+
"""
2147+
response = self.__ip_addr_endpoints(
2148+
ip_addr=ip_addr,
2149+
specific_endpoint=self.__IP_TO_DOMAIN_ENDPOINT
2150+
)
2151+
2152+
return response
2153+
2154+
def network_urls_from_ip(self, ip_addr):
2155+
"""Accepts an IP address string and returns a list of URLs hosted on the requested IP address.
2156+
:param ip_addr: requested IP address
2157+
:type ip_addr: str
2158+
:return: response
2159+
:rtype: requests.Response
2160+
"""
2161+
response = self.__ip_addr_endpoints(
2162+
ip_addr=ip_addr,
2163+
specific_endpoint=self.__URLS_FROM_IP_ENDPOINT
2164+
)
2165+
2166+
return response
2167+
2168+
def network_files_from_ip(self, ip_addr):
2169+
"""Accepts an IP address string and returns a list of hashes and
2170+
classifications for files found on the requested IP address.
2171+
:param ip_addr: requested IP address
2172+
:type ip_addr: str
2173+
:return: response
2174+
:rtype: requests.Response
2175+
"""
2176+
response = self.__ip_addr_endpoints(
2177+
ip_addr=ip_addr,
2178+
specific_endpoint=self.__FILES_FROM_IP_ENDPOINT
2179+
)
2180+
2181+
return response
2182+
2183+
def __ip_addr_endpoints(self, ip_addr, specific_endpoint):
2184+
"""Private method for all IP related endpoints from the Network Threat Intelligence API.
2185+
:param ip_addr: requested IP address
2186+
:type ip_addr: str
2187+
:param specific_endpoint: requested endpoint string
2188+
:type specific_endpoint: str
2189+
:return: response
2190+
:rtype: requests.Response
2191+
"""
2192+
if not isinstance(ip_addr, str):
2193+
raise WrongInputError("ip_addr parameter must be string.")
2194+
2195+
endpoint = specific_endpoint.format(ip=ip_addr)
2196+
2197+
url = self._url.format(endpoint=endpoint)
2198+
2199+
response = self.__get_request(url=url)
2200+
2201+
self.__raise_on_error(response)
2202+
2203+
return response
2204+
20722205
def __get_token(self, username, password):
20732206
"""Returns an obtained token using the provided username and password.
20742207
:return: token string
@@ -2237,9 +2370,6 @@ def __create_post_payload(custom_filename=None, file_url=None, crawler=None, ar
22372370
if threat_name:
22382371
data['threat_name'] = threat_name
22392372

2240-
if len(data) == 0:
2241-
data = None
2242-
22432373
if name:
22442374
data['name'] = name
22452375

@@ -2252,6 +2382,9 @@ def __create_post_payload(custom_filename=None, file_url=None, crawler=None, ar
22522382
if ticloud:
22532383
data['ticloud'] = ticloud
22542384

2385+
if not data:
2386+
return None
2387+
22552388
return data
22562389

22572390
def __analysis_is_finished(self, sample_hashes):

0 commit comments

Comments
 (0)