2019-11-21 13:10:29 +01:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
"""
|
|
|
|
Module (type "expansion") to query a Lastline report from an analysis link.
|
|
|
|
"""
|
|
|
|
import json
|
|
|
|
import lastline_api
|
2020-07-28 11:47:53 +02:00
|
|
|
from . import check_input_attribute, checking_error, standard_error_message
|
2019-11-21 13:10:29 +01:00
|
|
|
|
|
|
|
|
|
|
|
misperrors = {
|
|
|
|
"error": "Error",
|
|
|
|
}
|
|
|
|
|
|
|
|
mispattributes = {
|
|
|
|
"input": [
|
|
|
|
"link",
|
|
|
|
],
|
|
|
|
"output": ["text"],
|
|
|
|
"format": "misp_standard",
|
|
|
|
}
|
|
|
|
|
|
|
|
moduleinfo = {
|
|
|
|
"version": "0.1",
|
|
|
|
"author": "Stefano Ortolani",
|
|
|
|
"description": "Get a Lastline report from an analysis link.",
|
|
|
|
"module-type": ["expansion"],
|
|
|
|
}
|
|
|
|
|
|
|
|
moduleconfig = [
|
|
|
|
"username",
|
|
|
|
"password",
|
2020-01-27 07:43:46 +01:00
|
|
|
"verify_ssl",
|
2019-11-21 13:10:29 +01:00
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
def introspection():
|
|
|
|
return mispattributes
|
|
|
|
|
|
|
|
|
|
|
|
def version():
|
|
|
|
moduleinfo["config"] = moduleconfig
|
|
|
|
return moduleinfo
|
|
|
|
|
|
|
|
|
|
|
|
def handler(q=False):
|
|
|
|
if q is False:
|
|
|
|
return False
|
|
|
|
|
|
|
|
request = json.loads(q)
|
|
|
|
|
|
|
|
# Parse the init parameters
|
|
|
|
try:
|
2019-12-28 15:57:15 +01:00
|
|
|
config = request["config"]
|
|
|
|
auth_data = lastline_api.LastlineAbstractClient.get_login_params_from_dict(config)
|
2020-07-28 15:23:24 +02:00
|
|
|
if not request.get('attribute') or not check_input_attribute(request['attribute'], requirements=('type', 'value')):
|
2020-07-28 11:47:53 +02:00
|
|
|
return {'error': f'{standard_error_message}, {checking_error} that is the link to a Lastline analysis.'}
|
2019-11-21 13:10:29 +01:00
|
|
|
analysis_link = request['attribute']['value']
|
|
|
|
# The API url changes based on the analysis link host name
|
2019-12-28 15:57:15 +01:00
|
|
|
api_url = lastline_api.get_portal_url_from_task_link(analysis_link)
|
2019-11-21 13:10:29 +01:00
|
|
|
except Exception as e:
|
|
|
|
misperrors["error"] = "Error parsing configuration: {}".format(e)
|
|
|
|
return misperrors
|
|
|
|
|
|
|
|
# Parse the call parameters
|
|
|
|
try:
|
2019-12-28 15:57:15 +01:00
|
|
|
task_uuid = lastline_api.get_uuid_from_task_link(analysis_link)
|
2019-11-21 13:10:29 +01:00
|
|
|
except (KeyError, ValueError) as e:
|
|
|
|
misperrors["error"] = "Error processing input parameters: {}".format(e)
|
|
|
|
return misperrors
|
|
|
|
|
|
|
|
# Make the API calls
|
|
|
|
try:
|
2020-01-27 07:43:46 +01:00
|
|
|
api_client = lastline_api.PortalClient(api_url, auth_data, verify_ssl=config.get('verify_ssl', True).lower() in ("true"))
|
2019-11-21 13:10:29 +01:00
|
|
|
response = api_client.get_progress(task_uuid)
|
|
|
|
if response.get("completed") != 1:
|
|
|
|
raise ValueError("Analysis is not finished yet.")
|
|
|
|
|
|
|
|
response = api_client.get_result(task_uuid)
|
|
|
|
if not response:
|
|
|
|
raise ValueError("Analysis report is empty.")
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
misperrors["error"] = "Error issuing the API call: {}".format(e)
|
|
|
|
return misperrors
|
|
|
|
|
|
|
|
# Parse and return
|
|
|
|
result_parser = lastline_api.LastlineResultBaseParser()
|
|
|
|
result_parser.parse(analysis_link, response)
|
|
|
|
|
|
|
|
event = result_parser.misp_event
|
|
|
|
event_dictionary = json.loads(event.to_json())
|
|
|
|
|
|
|
|
return {
|
|
|
|
"results": {
|
|
|
|
key: event_dictionary[key]
|
|
|
|
for key in ('Attribute', 'Object', 'Tag')
|
|
|
|
if (key in event and event[key])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
"""Test querying information from a Lastline analysis link."""
|
|
|
|
import argparse
|
|
|
|
import configparser
|
|
|
|
|
|
|
|
parser = argparse.ArgumentParser()
|
|
|
|
parser.add_argument("-c", "--config-file", dest="config_file")
|
|
|
|
parser.add_argument("-s", "--section-name", dest="section_name")
|
|
|
|
args = parser.parse_args()
|
|
|
|
c = configparser.ConfigParser()
|
|
|
|
c.read(args.config_file)
|
2019-12-28 15:57:15 +01:00
|
|
|
a = lastline_api.LastlineAbstractClient.get_login_params_from_conf(c, args.section_name)
|
2019-11-21 13:10:29 +01:00
|
|
|
|
|
|
|
j = json.dumps(
|
|
|
|
{
|
|
|
|
"config": a,
|
|
|
|
"attribute": {
|
|
|
|
"value": (
|
|
|
|
"https://user.lastline.com/portal#/analyst/task/"
|
|
|
|
"1fcbcb8f7fb400100772d6a7b62f501b/overview"
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
print(json.dumps(handler(j), indent=4, sort_keys=True))
|
|
|
|
|
|
|
|
j = json.dumps(
|
|
|
|
{
|
|
|
|
"config": a,
|
|
|
|
"attribute": {
|
|
|
|
"value": (
|
|
|
|
"https://user.lastline.com/portal#/analyst/task/"
|
|
|
|
"f3c0ae115d51001017ff8da768fa6049/overview"
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
print(json.dumps(handler(j), indent=4, sort_keys=True))
|