From bef354ac4431bbb50546c2bb9b6a68a38bd04a82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 4 Aug 2015 16:24:55 +0200 Subject: [PATCH] Preliminary version of the file uploader --- examples/add_attachement.py | 43 ------------------------------ examples/upload.py | 42 +++++++++++++++++++++++++++++ pymisp/api.py | 53 ++++++++++++++++++++++++++++++++++++- 3 files changed, 94 insertions(+), 44 deletions(-) delete mode 100755 examples/add_attachement.py create mode 100755 examples/upload.py diff --git a/examples/add_attachement.py b/examples/add_attachement.py deleted file mode 100755 index 0151897..0000000 --- a/examples/add_attachement.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from pymisp import PyMISP -from keys import priv -import argparse -import os -import glob -import base64 -import json -import time - -url = 'https://misppriv.circl.lu' - - -def init(url, key): - return PyMISP(url, key, True, 'json') - - -def upload_file(m, eid, path): - curevent = misp.get_event(eid) - j = curevent.json() - if j.get("Event"): - with open(path, "rb") as curfile: - j["Event"].update({"data": base64.b64encode(curfile.read())}) - j["Event"]["timestamp"] = int(time.time()) - out = misp.update_event(args.event, json.dumps(j)) - print out, out.text - - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Send malware sample to MISP.') - parser.add_argument("-u", "--upload", type=str, required=True, help="File or directory of files to upload.") - parser.add_argument("-e", "--event", type=int, help="Event to update with a sample (if none, create a new event).") - args = parser.parse_args() - - misp = init(url, priv) - - if os.path.isfile(args.upload): - upload_file(misp, args.event, args.upload) - elif os.path.isdir(args.upload): - for filename in glob.iglob(os.path.join(args.upload + '*')): - upload_file(misp, args.event, filename) diff --git a/examples/upload.py b/examples/upload.py new file mode 100755 index 0000000..6954e4f --- /dev/null +++ b/examples/upload.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from pymisp import PyMISP +from keys import priv +import argparse +import os +import glob + +url = 'https://misppriv.circl.lu' + + +def init(url, key): + return PyMISP(url, key, True, 'json') + + +def upload_files(m, eid, paths, distrib, ids, categ, info, analysis, threat): + out = m.upload_sample(eid, paths, distrib, ids, categ, info, analysis, threat) + print out, out.text + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Send malware sample to MISP.') + parser.add_argument("-u", "--upload", type=str, required=True, help="File or directory of files to upload.") + parser.add_argument("-e", "--event", type=int, help="Not supplying an event ID will cause MISP to create a single new event for all of the POSTed malware samples.") + parser.add_argument("-d", "--distrib", type=int, help="The distribution setting used for the attributes and for the newly created event, if relevant. [0-3].") + parser.add_argument("-ids", action='store_true', help="You can flag all attributes created during the transaction to be marked as \"to_ids\" or not.") + parser.add_argument("-c", "--categ", help="The category that will be assigned to the uploaded samples. Valid options are: Payload delivery, Artifacts dropped, Payload Installation, External Analysis.") + parser.add_argument("-i", "--info", help="Used to populate the event info field if no event ID supplied.") + parser.add_argument("-a", "--analysis", type=int, help="The analysis level of the newly created event, if applicatble. [0-2]") + parser.add_argument("-t", "--threat", type=int, help="The threat level ID of the newly created event, if applicatble. [0-3]") + args = parser.parse_args() + + misp = init(url, priv) + + files = [] + if os.path.isfile(args.upload): + files = [args.upload] + elif os.path.isdir(args.upload): + files = [f for f in glob.iglob(os.path.join(args.upload + '*'))] + + upload_files(misp, args.event, files, args.distrib, args.ids, args.categ, args.info, args.analysis, args.threat) diff --git a/pymisp/api.py b/pymisp/api.py index b02e28b..2e01894 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -6,7 +6,8 @@ import json import datetime import requests - +import os +import base64 class PyMISP(object): """ @@ -117,6 +118,56 @@ class PyMISP(object): session = self.__prepare_session() return session.delete(self.rest.format(event_id)) + # ######### Create/update events through the API ######### + + def _create_event(self, distribution, threat_level_id, analysis, info): + # Setup details of a new event + if distribution not in [0, 1, 2, 3]: + return False + if threat_level_id not in [0, 1, 2, 3]: + return False + if analysis not in [0, 1, 2]: + return False + return {'distribution': int(distribution), 'info': info, + 'threat_level_id': int(threat_level_id), 'analysis': analysis} + + def upload_sample(self, event_id, filepaths, distribution, to_ids, category, + info, analysis, threat_level_id): + to_post = {'request': {'files': []}} + if not isinstance(event_id, int): + # New event + postcontent = self._create_event(distribution, threat_level_id, + analysis, info) + if postcontent: + to_post['request'].update(postcontent) + else: + # invalid new event + return False + else: + to_post['request'].update({'event_id': int(event_id)}) + + if to_ids not in [True, False]: + return False + to_post['request'].update({'to_ids': to_ids}) + + if category not in ['Payload delivery', 'Artifacts dropped', + 'Payload Installation', 'External Analysis']: + return False + to_post['request'].update({'category': category}) + + files = [] + for path in filepaths: + if not os.path.isfile(path): + continue + with open(path, 'rb') as f: + files.append({'filename': os.path.basename(path), + 'data': base64.b64encode(f.read())}) + + to_post['request']['files'] = files + + session = self.__prepare_session() + return session.post(self.rest.format('upload_sample'), data=json.dumps(to_post)) + # ######## REST Search ######### def __prepare_rest_search(self, values, not_values):