pymisp 2.5.7__py3-none-any.whl → 2.5.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pymisp might be problematic. Click here for more details.
- pymisp/api.py +1 -0
- pymisp/data/misp-objects/objects/rmm/definition.json +1 -1
- {pymisp-2.5.7.dist-info → pymisp-2.5.8.dist-info}/METADATA +4 -4
- {pymisp-2.5.7.dist-info → pymisp-2.5.8.dist-info}/RECORD +6 -135
- CHANGELOG.txt +0 -5380
- examples/__init__.py +0 -0
- examples/add_attributes_from_csv.py +0 -74
- examples/add_email_object.py +0 -29
- examples/add_fail2ban_object.py +0 -86
- examples/add_feed.py +0 -25
- examples/add_file_object.py +0 -47
- examples/add_filetype_object_from_csv.py +0 -53
- examples/add_generic_object.py +0 -26
- examples/add_github_user.py +0 -65
- examples/add_gitlab_user.py +0 -56
- examples/add_named_attribute.py +0 -25
- examples/add_organisations.py +0 -57
- examples/add_ssh_authorized_keys.py +0 -29
- examples/add_user.py +0 -22
- examples/add_vehicle_object.py +0 -22
- examples/addtag2.py +0 -45
- examples/asciidoc_generator.py +0 -114
- examples/cache_all.py +0 -10
- examples/copyTagsFromAttributesToEvent.py +0 -68
- examples/copy_list.py +0 -93
- examples/create_events.py +0 -26
- examples/cytomic_orion.py +0 -549
- examples/del.py +0 -22
- examples/delete_user.py +0 -16
- examples/edit_organisation.py +0 -20
- examples/edit_user.py +0 -20
- examples/falsepositive_disabletoids.py +0 -136
- examples/fetch_events_feed.py +0 -15
- examples/fetch_warninglist_hits.py +0 -38
- examples/freetext.py +0 -22
- examples/generate_file_objects.py +0 -78
- examples/generate_meta_feed.py +0 -15
- examples/get.py +0 -37
- examples/get_csv.py +0 -37
- examples/get_network_activity.py +0 -187
- examples/last.py +0 -48
- examples/load_csv.py +0 -94
- examples/lookup.py +0 -28
- examples/misp2cef.py +0 -71
- examples/misp2clamav.py +0 -52
- examples/openioc_to_misp.py +0 -27
- examples/proofpoint_tap.py +0 -203
- examples/proofpoint_vap.py +0 -65
- examples/search.py +0 -48
- examples/search_attributes_yara.py +0 -40
- examples/search_sighting.py +0 -42
- examples/server_sync_check_conn.py +0 -32
- examples/sharing_groups.py +0 -15
- examples/show_sightings.py +0 -168
- examples/stats_report.py +0 -405
- examples/sync_sighting.py +0 -171
- examples/tags.py +0 -25
- examples/test_sign.py +0 -19
- examples/trustar_misp.py +0 -59
- examples/up.py +0 -21
- examples/upload.py +0 -60
- examples/users_list.py +0 -15
- examples/vmray_automation.py +0 -281
- examples/vt_to_misp.py +0 -182
- examples/warninglists.py +0 -22
- examples/yara.py +0 -38
- examples/yara_dump.py +0 -98
- tests/57c4445b-c548-4654-af0b-4be3950d210f.json +0 -1
- tests/__init__.py +0 -0
- tests/csv_testfiles/invalid_fieldnames.csv +0 -11
- tests/csv_testfiles/valid_fieldnames.csv +0 -4
- tests/email_testfiles/mail_1.eml.zip +0 -0
- tests/email_testfiles/mail_1.msg +0 -0
- tests/email_testfiles/mail_1_bom.eml +0 -858
- tests/email_testfiles/mail_1_headers_only.eml +0 -28
- tests/email_testfiles/mail_2.eml +0 -32
- tests/email_testfiles/mail_3.eml +0 -170
- tests/email_testfiles/mail_3.msg +0 -0
- tests/email_testfiles/mail_4.msg +0 -0
- tests/email_testfiles/mail_5.msg +0 -0
- tests/email_testfiles/mail_multiple_to.eml +0 -15
- tests/email_testfiles/source +0 -1
- tests/git-vuln-finder-quagga.json +0 -1493
- tests/misp_event.json +0 -76
- tests/mispevent_testfiles/attribute.json +0 -21
- tests/mispevent_testfiles/attribute_del.json +0 -23
- tests/mispevent_testfiles/def_param.json +0 -53
- tests/mispevent_testfiles/event.json +0 -8
- tests/mispevent_testfiles/event_obj_attr_tag.json +0 -57
- tests/mispevent_testfiles/event_obj_def_param.json +0 -62
- tests/mispevent_testfiles/event_obj_tag.json +0 -29
- tests/mispevent_testfiles/event_tags.json +0 -18
- tests/mispevent_testfiles/existing_event.json +0 -4599
- tests/mispevent_testfiles/existing_event_edited.json +0 -4601
- tests/mispevent_testfiles/galaxy.json +0 -25
- tests/mispevent_testfiles/malware.json +0 -19
- tests/mispevent_testfiles/malware_exist.json +0 -163
- tests/mispevent_testfiles/misp_custom_obj.json +0 -38
- tests/mispevent_testfiles/overwrite_file/definition.json +0 -457
- tests/mispevent_testfiles/proposals.json +0 -35
- tests/mispevent_testfiles/shadow.json +0 -148
- tests/mispevent_testfiles/sighting.json +0 -5
- tests/mispevent_testfiles/simple.json +0 -2
- tests/mispevent_testfiles/test_object_template/definition.json +0 -29
- tests/new_misp_event.json +0 -34
- tests/reportlab_testfiles/HTML_event.json +0 -1
- tests/reportlab_testfiles/galaxy_1.json +0 -1250
- tests/reportlab_testfiles/image_event.json +0 -2490
- tests/reportlab_testfiles/japanese_test.json +0 -156
- tests/reportlab_testfiles/japanese_test_heavy.json +0 -318
- tests/reportlab_testfiles/long_event.json +0 -3730
- tests/reportlab_testfiles/mainly_objects_1.json +0 -1092
- tests/reportlab_testfiles/mainly_objects_2.json +0 -977
- tests/reportlab_testfiles/sighting_1.json +0 -305
- tests/reportlab_testfiles/sighting_2.json +0 -221
- tests/reportlab_testfiles/to_delete1.json +0 -804
- tests/reportlab_testfiles/to_delete2.json +0 -1
- tests/reportlab_testfiles/to_delete3.json +0 -1
- tests/reportlab_testfiles/very_long_event.json +0 -1006
- tests/reportlab_testoutputs/to_delete1.json.pdf +0 -391
- tests/reportlab_testoutputs/to_delete2.json.pdf +0 -506
- tests/reportlab_testoutputs/to_delete3.json.pdf +0 -277
- tests/search_index_result.json +0 -69
- tests/sharing_groups.json +0 -98
- tests/stix1.xml-utf8 +0 -110
- tests/stix2.json +0 -1
- tests/test_analyst_data.py +0 -123
- tests/test_emailobject.py +0 -157
- tests/test_fileobject.py +0 -20
- tests/test_mispevent.py +0 -473
- tests/test_reportlab.py +0 -431
- tests/testlive_comprehensive.py +0 -3734
- tests/testlive_sync.py +0 -474
- {pymisp-2.5.7.dist-info → pymisp-2.5.8.dist-info}/LICENSE +0 -0
- {pymisp-2.5.7.dist-info → pymisp-2.5.8.dist-info}/WHEEL +0 -0
examples/sync_sighting.py
DELETED
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
'''
|
|
4
|
-
Koen Van Impe
|
|
5
|
-
|
|
6
|
-
Sync sightings between MISP instances
|
|
7
|
-
|
|
8
|
-
Put this script in crontab to run every /15 or /60
|
|
9
|
-
*/5 * * * * mispuser /usr/bin/python3 /home/mispuser/PyMISP/examples/sync_sighting.py
|
|
10
|
-
|
|
11
|
-
Uses a drift file to keep track of latest timestamp synced (config)
|
|
12
|
-
Install on "clients", these push the sightings back to authoritative MISP instance
|
|
13
|
-
|
|
14
|
-
'''
|
|
15
|
-
|
|
16
|
-
from pymisp import PyMISP
|
|
17
|
-
from keys import misp_url, misp_key, misp_verifycert
|
|
18
|
-
from keys import misp_authoritive_url, misp_authoritive_key, misp_authoritive_verifycert
|
|
19
|
-
|
|
20
|
-
import sys
|
|
21
|
-
import time
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def init(url, key, verifycert):
|
|
25
|
-
'''
|
|
26
|
-
Template to get MISP module started
|
|
27
|
-
'''
|
|
28
|
-
return PyMISP(url, key, verifycert, 'json')
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def search_sightings(misp, timestamp, timestamp_now):
|
|
32
|
-
'''
|
|
33
|
-
Search all the local sightings
|
|
34
|
-
Extend the sighting with the attribute UUID
|
|
35
|
-
'''
|
|
36
|
-
completed_sightings = []
|
|
37
|
-
|
|
38
|
-
try:
|
|
39
|
-
found_sightings = misp.search_sightings(date_from=timestamp, date_to=timestamp_now)
|
|
40
|
-
except Exception as e:
|
|
41
|
-
sys.exit("Unable to search for sightings")
|
|
42
|
-
|
|
43
|
-
if found_sightings is not None and 'response' in found_sightings:
|
|
44
|
-
for s in found_sightings['response']:
|
|
45
|
-
if 'Sighting' in s:
|
|
46
|
-
sighting = s['Sighting']
|
|
47
|
-
if 'attribute_id' in sighting:
|
|
48
|
-
attribute_id = sighting['attribute_id']
|
|
49
|
-
|
|
50
|
-
# Query the attribute to get the uuid
|
|
51
|
-
# We need this to update the sighting on the other instance
|
|
52
|
-
try:
|
|
53
|
-
attribute = misp.get_attribute(attribute_id)
|
|
54
|
-
except Exception as e:
|
|
55
|
-
if module_DEBUG:
|
|
56
|
-
print("Unable to fetch attribute UUID for ID %s " % attribute_id)
|
|
57
|
-
continue
|
|
58
|
-
|
|
59
|
-
if 'Attribute' in attribute and 'uuid' in attribute['Attribute']:
|
|
60
|
-
attribute_uuid = attribute['Attribute']['uuid']
|
|
61
|
-
completed_sightings.append({'attribute_uuid': attribute_uuid, 'date_sighting': sighting['date_sighting'], 'source': sighting['source'], 'type': sighting['type'], 'uuid': sighting['uuid']})
|
|
62
|
-
else:
|
|
63
|
-
if module_DEBUG:
|
|
64
|
-
print("No information returned for attribute ID %s " % attribute_id)
|
|
65
|
-
continue
|
|
66
|
-
|
|
67
|
-
return completed_sightings
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def sync_sightings(misp, misp_authoritive, found_sightings, verify_before_push, custom_sighting_text):
|
|
71
|
-
'''
|
|
72
|
-
Walk through all the sightings
|
|
73
|
-
'''
|
|
74
|
-
if found_sightings is not None:
|
|
75
|
-
for sighting in found_sightings:
|
|
76
|
-
attribute_uuid = sighting['attribute_uuid']
|
|
77
|
-
date_sighting = sighting['date_sighting']
|
|
78
|
-
source = sighting['source']
|
|
79
|
-
if not source:
|
|
80
|
-
source = custom_sighting_text
|
|
81
|
-
type = sighting['type']
|
|
82
|
-
|
|
83
|
-
# Fail safe
|
|
84
|
-
if verify_before_push:
|
|
85
|
-
if sighting_exists(misp_authoritive, sighting):
|
|
86
|
-
continue
|
|
87
|
-
else:
|
|
88
|
-
continue
|
|
89
|
-
else:
|
|
90
|
-
push_sighting(misp_authoritive, attribute_uuid, date_sighting, source, type)
|
|
91
|
-
continue
|
|
92
|
-
return True
|
|
93
|
-
return False
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
def push_sighting(misp_authoritive, attribute_uuid, date_sighting, source, type):
|
|
97
|
-
'''
|
|
98
|
-
Push sighting to the authoritative server
|
|
99
|
-
'''
|
|
100
|
-
if attribute_uuid:
|
|
101
|
-
try:
|
|
102
|
-
misp_authoritive.sighting(uuid=attribute_uuid, source=source, type=type, timestamp=date_sighting)
|
|
103
|
-
if module_DEBUG:
|
|
104
|
-
print("Pushed sighting for %s on %s" % (attribute_uuid, date_sighting))
|
|
105
|
-
return True
|
|
106
|
-
except Exception as e:
|
|
107
|
-
if module_DEBUG:
|
|
108
|
-
print("Unable to update attribute %s " % (attribute_uuid))
|
|
109
|
-
return False
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
def sighting_exists(misp_authoritive, sighting):
|
|
113
|
-
'''
|
|
114
|
-
Check if the sighting exists on the authoritative server
|
|
115
|
-
sightings/restSearch/attribute for uuid is not supported in MISP
|
|
116
|
-
|
|
117
|
-
optionally to implement
|
|
118
|
-
'''
|
|
119
|
-
return False
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
def set_drift_timestamp(drift_timestamp, drift_timestamp_path):
|
|
123
|
-
'''
|
|
124
|
-
Save the timestamp in a (local) file
|
|
125
|
-
'''
|
|
126
|
-
try:
|
|
127
|
-
with open(drift_timestamp_path, 'w+') as f:
|
|
128
|
-
f.write(str(drift_timestamp))
|
|
129
|
-
return True
|
|
130
|
-
except IOError:
|
|
131
|
-
sys.exit("Unable to write drift_timestamp %s to %s" % (drift_timestamp, drift_timestamp_path))
|
|
132
|
-
return False
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
def get_drift_timestamp(drift_timestamp_path):
|
|
136
|
-
'''
|
|
137
|
-
From when do we start with the sightings?
|
|
138
|
-
'''
|
|
139
|
-
try:
|
|
140
|
-
with open(drift_timestamp_path) as f:
|
|
141
|
-
drift = f.read()
|
|
142
|
-
if drift:
|
|
143
|
-
drift = int(float(drift))
|
|
144
|
-
else:
|
|
145
|
-
drift = 0
|
|
146
|
-
except IOError:
|
|
147
|
-
drift = 0
|
|
148
|
-
|
|
149
|
-
return drift
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
if __name__ == '__main__':
|
|
153
|
-
misp = init(misp_url, misp_key, misp_verifycert)
|
|
154
|
-
misp_authoritive = init(misp_authoritive_url, misp_authoritive_key, misp_authoritive_verifycert)
|
|
155
|
-
drift_timestamp_path = '/home/mispuser/PyMISP/examples/sync_sighting.drift'
|
|
156
|
-
|
|
157
|
-
drift_timestamp = get_drift_timestamp(drift_timestamp_path=drift_timestamp_path)
|
|
158
|
-
timestamp_now = time.time()
|
|
159
|
-
module_DEBUG = True
|
|
160
|
-
|
|
161
|
-
# Get all attribute sightings
|
|
162
|
-
found_sightings = search_sightings(misp, drift_timestamp, timestamp_now)
|
|
163
|
-
if found_sightings is not None and len(found_sightings) > 0:
|
|
164
|
-
if sync_sightings(misp, misp_authoritive, found_sightings, verify_before_push=False, custom_sighting_text="Custom Sighting"):
|
|
165
|
-
set_drift_timestamp(timestamp_now, drift_timestamp_path)
|
|
166
|
-
if module_DEBUG:
|
|
167
|
-
print("Sighting drift file updated to %s " % (timestamp_now))
|
|
168
|
-
else:
|
|
169
|
-
sys.exit("Unable to sync sync_sightings")
|
|
170
|
-
else:
|
|
171
|
-
sys.exit("No sightings found")
|
examples/tags.py
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
|
|
4
|
-
from pymisp import ExpandedPyMISP
|
|
5
|
-
from keys import misp_url, misp_key, misp_verifycert
|
|
6
|
-
import argparse
|
|
7
|
-
import json
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def get_tags(m):
|
|
11
|
-
result = m.get_all_tags(True)
|
|
12
|
-
r = result
|
|
13
|
-
print(json.dumps(r) + '\n')
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if __name__ == '__main__':
|
|
17
|
-
parser = argparse.ArgumentParser(description='Get tags from MISP instance.')
|
|
18
|
-
|
|
19
|
-
args = parser.parse_args()
|
|
20
|
-
|
|
21
|
-
misp = ExpandedPyMISP(misp_url, misp_key, misp_verifycert)
|
|
22
|
-
|
|
23
|
-
tags = misp.tags(pythonify=True)
|
|
24
|
-
for tag in tags:
|
|
25
|
-
print(tag.to_json())
|
examples/test_sign.py
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
|
|
4
|
-
import argparse
|
|
5
|
-
|
|
6
|
-
from pymisp import mispevent
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if __name__ == '__main__':
|
|
10
|
-
parser = argparse.ArgumentParser(description='Sign & verify a MISP event.')
|
|
11
|
-
parser.add_argument("-i", "--input", required=True, help="Json file")
|
|
12
|
-
parser.add_argument("-u", "--uid", required=True, help="GPG UID")
|
|
13
|
-
args = parser.parse_args()
|
|
14
|
-
|
|
15
|
-
me = mispevent.MISPEvent()
|
|
16
|
-
me.load(args.input)
|
|
17
|
-
|
|
18
|
-
me.sign(args.uid)
|
|
19
|
-
me.verify(args.uid)
|
examples/trustar_misp.py
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
from trustar import TruStar, datetime_to_millis
|
|
2
|
-
from datetime import datetime, timedelta
|
|
3
|
-
from keys import misp_url, misp_key, misp_verifycert
|
|
4
|
-
from pymisp import PyMISP, MISPEvent, MISPOrganisation, MISPObject
|
|
5
|
-
|
|
6
|
-
# enclave_ids = '7a33144f-aef3-442b-87d4-dbf70d8afdb0' # RHISAC
|
|
7
|
-
enclave_ids = None
|
|
8
|
-
|
|
9
|
-
time_interval = {'days': 30, 'hours': 0}
|
|
10
|
-
|
|
11
|
-
distribution = None # Optional, defaults to MISP.default_event_distribution in MISP config
|
|
12
|
-
threat_level_id = None # Optional, defaults to MISP.default_event_threat_level in MISP config
|
|
13
|
-
analysis = None # Optional, defaults to 0 (initial analysis)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
tru = TruStar()
|
|
18
|
-
|
|
19
|
-
misp = PyMISP(misp_url, misp_key, misp_verifycert)
|
|
20
|
-
|
|
21
|
-
now = datetime.now()
|
|
22
|
-
|
|
23
|
-
# date range for pulling reports is last 4 hours when script is run
|
|
24
|
-
to_time = datetime.now()
|
|
25
|
-
from_time = to_time - timedelta(**time_interval)
|
|
26
|
-
|
|
27
|
-
# convert to millis since epoch
|
|
28
|
-
to_time = datetime_to_millis(to_time)
|
|
29
|
-
from_time = datetime_to_millis(from_time)
|
|
30
|
-
|
|
31
|
-
if not enclave_ids:
|
|
32
|
-
reports = tru.get_reports(from_time=from_time,
|
|
33
|
-
to_time=to_time)
|
|
34
|
-
else:
|
|
35
|
-
reports = tru.get_reports(from_time=from_time,
|
|
36
|
-
to_time=to_time,
|
|
37
|
-
is_enclave=True,
|
|
38
|
-
enclave_ids=enclave_ids)
|
|
39
|
-
|
|
40
|
-
# loop through each trustar report and create MISP events for each
|
|
41
|
-
for report in reports:
|
|
42
|
-
# initialize and set MISPEvent()
|
|
43
|
-
event = MISPEvent()
|
|
44
|
-
event.info = report.title
|
|
45
|
-
event.distribution = distribution
|
|
46
|
-
event.threat_level_id = threat_level_id
|
|
47
|
-
event.analysis = analysis
|
|
48
|
-
|
|
49
|
-
# get tags for report
|
|
50
|
-
for tag in tru.get_enclave_tags(report.id):
|
|
51
|
-
event.add_tag(tag.name)
|
|
52
|
-
|
|
53
|
-
obj = MISPObject('trustar_report', standalone=False, strict=True)
|
|
54
|
-
# get indicators for report
|
|
55
|
-
for indicator in tru.get_indicators_for_report(report.id):
|
|
56
|
-
obj.add_attribute(indicator.type, indicator.value)
|
|
57
|
-
event.add_object(obj)
|
|
58
|
-
# post each event to MISP via API
|
|
59
|
-
misp.add_event(event)
|
examples/up.py
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
|
|
4
|
-
from pymisp import ExpandedPyMISP, MISPEvent
|
|
5
|
-
from keys import misp_url, misp_key, misp_verifycert
|
|
6
|
-
import argparse
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if __name__ == '__main__':
|
|
10
|
-
parser = argparse.ArgumentParser(description="Update a MISP event.")
|
|
11
|
-
parser.add_argument("-e", "--event", required=True, help="Event ID to update.")
|
|
12
|
-
parser.add_argument("-i", "--input", required=True, help="Input file")
|
|
13
|
-
|
|
14
|
-
args = parser.parse_args()
|
|
15
|
-
|
|
16
|
-
misp = ExpandedPyMISP(misp_url, misp_key, misp_verifycert)
|
|
17
|
-
|
|
18
|
-
me = MISPEvent()
|
|
19
|
-
me.load_file(args.input)
|
|
20
|
-
|
|
21
|
-
result = misp.update_event(me, args.event)
|
examples/upload.py
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
|
|
4
|
-
from pymisp import ExpandedPyMISP, MISPEvent, MISPAttribute
|
|
5
|
-
from keys import misp_url, misp_key, misp_verifycert
|
|
6
|
-
import argparse
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
|
|
9
|
-
if __name__ == '__main__':
|
|
10
|
-
parser = argparse.ArgumentParser(description='Send malware sample to MISP.')
|
|
11
|
-
parser.add_argument("-u", "--upload", type=str, required=True, help="File or directory of files to upload.")
|
|
12
|
-
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].")
|
|
13
|
-
parser.add_argument("-c", "--comment", type=str, help="Comment for the uploaded file(s).")
|
|
14
|
-
parser.add_argument('-m', '--is-malware', action='store_true', help='The file(s) to upload are malwares')
|
|
15
|
-
parser.add_argument('--expand', action='store_true', help='(Only if the file is a malware) Run lief expansion (creates objects)')
|
|
16
|
-
parser.add_argument("-e", "--event", type=int, default=None, help="Not supplying an event ID will cause MISP to create a single new event for all of the POSTed malware samples.")
|
|
17
|
-
parser.add_argument("-i", "--info", help="Used to populate the event info field if no event ID supplied.")
|
|
18
|
-
args = parser.parse_args()
|
|
19
|
-
|
|
20
|
-
misp = ExpandedPyMISP(misp_url, misp_key, misp_verifycert)
|
|
21
|
-
|
|
22
|
-
files = []
|
|
23
|
-
p = Path(args.upload)
|
|
24
|
-
if p.is_file():
|
|
25
|
-
files = [p]
|
|
26
|
-
elif p.is_dir():
|
|
27
|
-
files = [f for f in p.glob('**/*') if f.is_file()]
|
|
28
|
-
else:
|
|
29
|
-
print('invalid upload path (must be file or dir)')
|
|
30
|
-
exit(0)
|
|
31
|
-
|
|
32
|
-
if args.is_malware:
|
|
33
|
-
arg_type = 'malware-sample'
|
|
34
|
-
else:
|
|
35
|
-
arg_type = 'attachment'
|
|
36
|
-
|
|
37
|
-
# Create attributes
|
|
38
|
-
attributes = []
|
|
39
|
-
for f in files:
|
|
40
|
-
a = MISPAttribute()
|
|
41
|
-
a.type = arg_type
|
|
42
|
-
a.value = f.name
|
|
43
|
-
a.data = f
|
|
44
|
-
a.comment = args.comment
|
|
45
|
-
a.distribution = args.distrib
|
|
46
|
-
if args.expand and arg_type == 'malware-sample':
|
|
47
|
-
a.expand = 'binary'
|
|
48
|
-
attributes.append(a)
|
|
49
|
-
|
|
50
|
-
if args.event:
|
|
51
|
-
for a in attributes:
|
|
52
|
-
misp.add_attribute(args.event, a)
|
|
53
|
-
else:
|
|
54
|
-
m = MISPEvent()
|
|
55
|
-
m.info = args.info
|
|
56
|
-
m.distribution = args.distrib
|
|
57
|
-
m.attributes = attributes
|
|
58
|
-
if args.expand and arg_type == 'malware-sample':
|
|
59
|
-
m.run_expansions()
|
|
60
|
-
misp.add_event(m)
|
examples/users_list.py
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
|
|
4
|
-
from pymisp import ExpandedPyMISP
|
|
5
|
-
from keys import misp_url, misp_key, misp_verifycert
|
|
6
|
-
import argparse
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if __name__ == '__main__':
|
|
10
|
-
parser = argparse.ArgumentParser(description='Get a list of the sharing groups from the MISP instance.')
|
|
11
|
-
|
|
12
|
-
misp = ExpandedPyMISP(misp_url, misp_key, misp_verifycert)
|
|
13
|
-
|
|
14
|
-
users_list = misp.users(pythonify=True)
|
|
15
|
-
print(users_list)
|
examples/vmray_automation.py
DELETED
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
"""
|
|
4
|
-
Jens Thom (VMRay), Koen Van Impe
|
|
5
|
-
|
|
6
|
-
VMRay automatic import
|
|
7
|
-
Put this script in crontab to run every /15 or /60
|
|
8
|
-
*/5 * * * * mispuser /usr/bin/python3 /home/mispuser/PyMISP/examples/vmray_automation.py
|
|
9
|
-
|
|
10
|
-
Calls "vmray_import" for all events that have an 'incomplete' VMray analysis
|
|
11
|
-
|
|
12
|
-
Do inline config in "main".
|
|
13
|
-
If your MISP user is not an admin, you cannot use `get_config`,
|
|
14
|
-
use `overwrite_config` instead.
|
|
15
|
-
Example config:
|
|
16
|
-
config = {
|
|
17
|
-
"vmray_import_enabled": True,
|
|
18
|
-
"vmray_import_apikey": vmray_api_key,
|
|
19
|
-
"vmray_import_url": vmray_server,
|
|
20
|
-
"vmray_import_disable_tags": False,
|
|
21
|
-
"vmray_import_disable_misp_objects": False,
|
|
22
|
-
"vmray_import_ignore_analysis_finished": False,
|
|
23
|
-
"services_port": 6666,
|
|
24
|
-
"services_url": "http://localhost",
|
|
25
|
-
"Artifacts": "1",
|
|
26
|
-
"VTI": "1",
|
|
27
|
-
"IOCs": "1",
|
|
28
|
-
"Analysis Details": "1",
|
|
29
|
-
}
|
|
30
|
-
"""
|
|
31
|
-
|
|
32
|
-
import logging
|
|
33
|
-
import urllib
|
|
34
|
-
|
|
35
|
-
from typing import Any, Dict, List, Optional
|
|
36
|
-
|
|
37
|
-
import requests
|
|
38
|
-
|
|
39
|
-
from keys import misp_key, misp_url, misp_verifycert
|
|
40
|
-
from pymisp import ExpandedPyMISP
|
|
41
|
-
|
|
42
|
-
# Suppress those "Unverified HTTPS request is being made"
|
|
43
|
-
import urllib3
|
|
44
|
-
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def is_url(url: str) -> bool:
|
|
48
|
-
try:
|
|
49
|
-
result = urllib.parse.urlparse(url)
|
|
50
|
-
return result.scheme and result.netloc
|
|
51
|
-
except ValueError:
|
|
52
|
-
return False
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
class VMRayAutomationException(Exception):
|
|
56
|
-
pass
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
class VMRayAutomation:
|
|
60
|
-
def __init__(
|
|
61
|
-
self,
|
|
62
|
-
misp_url: str,
|
|
63
|
-
misp_key: str,
|
|
64
|
-
verify_cert: bool = False,
|
|
65
|
-
debug: bool = False,
|
|
66
|
-
) -> None:
|
|
67
|
-
# setup logging
|
|
68
|
-
log_level = logging.DEBUG if debug else logging.INFO
|
|
69
|
-
log_format = "%(asctime)s - %(name)s - %(levelname)8s - %(message)s"
|
|
70
|
-
|
|
71
|
-
logging.basicConfig(level=log_level, format=log_format)
|
|
72
|
-
logging.getLogger("pymisp").setLevel(log_level)
|
|
73
|
-
self.logger = logging.getLogger(self.__class__.__name__)
|
|
74
|
-
|
|
75
|
-
self.misp_url = misp_url.rstrip("/")
|
|
76
|
-
self.misp_key = misp_key
|
|
77
|
-
self.verifycert = verify_cert
|
|
78
|
-
self.misp = ExpandedPyMISP(misp_url, misp_key, ssl=verify_cert, debug=debug)
|
|
79
|
-
self.config = {}
|
|
80
|
-
self.tag_incomplete = 'workflow:state="incomplete"'
|
|
81
|
-
|
|
82
|
-
@staticmethod
|
|
83
|
-
def _setting_enabled(value: bool) -> bool:
|
|
84
|
-
if not value:
|
|
85
|
-
raise VMRayAutomationException(
|
|
86
|
-
"VMRay import is disabled. "
|
|
87
|
-
"Please enable `vmray_import` in the MISP settings."
|
|
88
|
-
)
|
|
89
|
-
|
|
90
|
-
return True
|
|
91
|
-
|
|
92
|
-
@staticmethod
|
|
93
|
-
def _setting_apikey(value: str) -> str:
|
|
94
|
-
if not value:
|
|
95
|
-
raise VMRayAutomationException(
|
|
96
|
-
"VMRay API key not set. Please set the API key in the MISP settings."
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
return value
|
|
100
|
-
|
|
101
|
-
@staticmethod
|
|
102
|
-
def _setting_url(value: str) -> str:
|
|
103
|
-
if not value:
|
|
104
|
-
raise VMRayAutomationException(
|
|
105
|
-
"VMRay URL not set. Please set the URL in the MISP settings."
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
if not is_url(value):
|
|
109
|
-
raise VMRayAutomationException("Not a valid URL")
|
|
110
|
-
|
|
111
|
-
return value
|
|
112
|
-
|
|
113
|
-
@staticmethod
|
|
114
|
-
def _setting_disabled(value: str) -> bool:
|
|
115
|
-
return value.lower() in ["no", "false"]
|
|
116
|
-
|
|
117
|
-
@staticmethod
|
|
118
|
-
def _services_port(value: int) -> bool:
|
|
119
|
-
if value == 0:
|
|
120
|
-
return 6666
|
|
121
|
-
return value
|
|
122
|
-
|
|
123
|
-
@staticmethod
|
|
124
|
-
def services_url(value: str) -> bool:
|
|
125
|
-
if not is_url(value):
|
|
126
|
-
raise VMRayAutomationException("Services URL is not valid.")
|
|
127
|
-
|
|
128
|
-
return value
|
|
129
|
-
|
|
130
|
-
@property
|
|
131
|
-
def vmray_settings(self) -> Dict[str, Any]:
|
|
132
|
-
return {
|
|
133
|
-
"vmray_import_enabled": self._setting_enabled,
|
|
134
|
-
"vmray_import_apikey": self._setting_apikey,
|
|
135
|
-
"vmray_import_url": self._setting_url,
|
|
136
|
-
"vmray_import_disable_tags": self._setting_disabled,
|
|
137
|
-
"vmray_import_disable_misp_objects": self._setting_disabled,
|
|
138
|
-
"vmray_import_ignore_analysis_finished": self._setting_disabled,
|
|
139
|
-
"services_port": self._services_port,
|
|
140
|
-
"services_url": self.services_url,
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
def _get_misp_settings(self) -> List[Dict[str, Any]]:
|
|
144
|
-
misp_headers = {
|
|
145
|
-
"Content-Type": "application/json",
|
|
146
|
-
"Accept": "application/json",
|
|
147
|
-
"Authorization": self.misp_key,
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
response = requests.get(
|
|
151
|
-
f"{self.misp_url}/servers/serverSettings.json",
|
|
152
|
-
verify=self.verifycert,
|
|
153
|
-
headers=misp_headers,
|
|
154
|
-
)
|
|
155
|
-
|
|
156
|
-
if response.status_code == 200:
|
|
157
|
-
settings = response.json()
|
|
158
|
-
if "finalSettings" in settings:
|
|
159
|
-
return settings["finalSettings"]
|
|
160
|
-
|
|
161
|
-
raise VMRayAutomationException("Could not get settings from MISP server.")
|
|
162
|
-
|
|
163
|
-
def get_config(self) -> None:
|
|
164
|
-
self.logger.debug("Loading confing...")
|
|
165
|
-
# get settings from MISP server
|
|
166
|
-
settings = self._get_misp_settings()
|
|
167
|
-
for setting in settings:
|
|
168
|
-
config_name = setting["setting"].replace("Plugin.Import_", "")
|
|
169
|
-
if config_name in self.vmray_settings:
|
|
170
|
-
func = self.vmray_settings[config_name]
|
|
171
|
-
value = func(setting["value"])
|
|
172
|
-
self.config[config_name] = value
|
|
173
|
-
|
|
174
|
-
# set default `vmray_import` settings
|
|
175
|
-
self.config.setdefault("VTI", "1")
|
|
176
|
-
self.config.setdefault("IOCs", "1")
|
|
177
|
-
self.config.setdefault("Artifacts", "0")
|
|
178
|
-
self.config.setdefault("Analysis Details", "1")
|
|
179
|
-
|
|
180
|
-
self.logger.info("Loading config: Done.")
|
|
181
|
-
|
|
182
|
-
def overwrite_config(self, config: Dict[str, Any]) -> None:
|
|
183
|
-
self.config.update(config)
|
|
184
|
-
|
|
185
|
-
def _get_sample_id(self, value: str) -> Optional[int]:
|
|
186
|
-
vmray_sample_id_text = "VMRay Sample ID: "
|
|
187
|
-
if not value.startswith(vmray_sample_id_text):
|
|
188
|
-
self.logger.warning("Invalid Sample ID: %s.", value)
|
|
189
|
-
return None
|
|
190
|
-
|
|
191
|
-
return int(value.replace(vmray_sample_id_text, ""))
|
|
192
|
-
|
|
193
|
-
def _call_vmray_import(self, sample_id: int, event_id: str) -> Dict[str, Any]:
|
|
194
|
-
url = f"{self.config['services_url']}:{self.config['services_port']}/query"
|
|
195
|
-
|
|
196
|
-
config = {"Sample ID": sample_id}
|
|
197
|
-
for key, value in self.config.items():
|
|
198
|
-
vmray_config_key = key.replace("vmray_import_", "")
|
|
199
|
-
config[vmray_config_key] = str(value)
|
|
200
|
-
|
|
201
|
-
data = {
|
|
202
|
-
"module": "vmray_import",
|
|
203
|
-
"event_id": event_id,
|
|
204
|
-
"config": config,
|
|
205
|
-
"data": "",
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
self.logger.debug("calling `vmray_import`: url=%s, config=%s", url, config)
|
|
209
|
-
response = requests.post(url, json=data)
|
|
210
|
-
if response.status_code != 200:
|
|
211
|
-
raise VMRayAutomationException(
|
|
212
|
-
f"MISP modules returned status code `{response.status_code}`"
|
|
213
|
-
)
|
|
214
|
-
|
|
215
|
-
json_response = response.json()
|
|
216
|
-
if "error" in json_response:
|
|
217
|
-
error = json_response["error"]
|
|
218
|
-
raise VMRayAutomationException(f"MISP modules returned error: {error}")
|
|
219
|
-
|
|
220
|
-
return json_response
|
|
221
|
-
|
|
222
|
-
def _add_event_attributes(self, event_id: int, attributes: Dict[str, Any]) -> None:
|
|
223
|
-
event = self.misp.get_event(event_id, pythonify=True)
|
|
224
|
-
for attr in attributes["Attribute"]:
|
|
225
|
-
event.add_attribute(**attr)
|
|
226
|
-
|
|
227
|
-
self.misp.update_event(event)
|
|
228
|
-
|
|
229
|
-
def _add_event_objects(self, event_id: int, objects: Dict[str, Any]) -> None:
|
|
230
|
-
event = self.misp.get_event(event_id, pythonify=True)
|
|
231
|
-
for obj in objects["Object"]:
|
|
232
|
-
event.add_object(**obj)
|
|
233
|
-
|
|
234
|
-
if "Tag" in objects:
|
|
235
|
-
for tag in objects["Tag"]:
|
|
236
|
-
event.add_tag(tag["name"])
|
|
237
|
-
|
|
238
|
-
self.misp.update_event(event)
|
|
239
|
-
|
|
240
|
-
def _add_misp_event(self, event_id: int, response: Dict[str, Any]) -> None:
|
|
241
|
-
if self.config["vmray_import_disable_misp_objects"]:
|
|
242
|
-
self._add_event_attributes(event_id, response["results"])
|
|
243
|
-
else:
|
|
244
|
-
self._add_event_objects(event_id, response["results"])
|
|
245
|
-
|
|
246
|
-
def import_incomplete_analyses(self) -> None:
|
|
247
|
-
self.logger.info("Searching for attributes with tag='%s'", self.tag_incomplete)
|
|
248
|
-
result = self.misp.search("attributes", tags=self.tag_incomplete)
|
|
249
|
-
attributes = result["Attribute"]
|
|
250
|
-
|
|
251
|
-
for attr in attributes:
|
|
252
|
-
event_id = int(attr["event_id"])
|
|
253
|
-
self.logger.info("Processing event ID `%d`.", event_id)
|
|
254
|
-
|
|
255
|
-
sample_id = self._get_sample_id(attr["value"])
|
|
256
|
-
if not sample_id:
|
|
257
|
-
continue
|
|
258
|
-
|
|
259
|
-
response = self._call_vmray_import(sample_id, event_id)
|
|
260
|
-
self._add_misp_event(event_id, response)
|
|
261
|
-
self.misp.untag(attr["uuid"], self.tag_incomplete)
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
def main():
|
|
265
|
-
debug = False
|
|
266
|
-
config = {
|
|
267
|
-
"Artifacts": "0",
|
|
268
|
-
"VTI": "1",
|
|
269
|
-
"IOCs": "1",
|
|
270
|
-
"Analysis Details": "0",
|
|
271
|
-
"vmray_import_disable_misp_objects": False,
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
automation = VMRayAutomation(misp_url, misp_key, misp_verifycert, debug)
|
|
275
|
-
automation.get_config() # only possible with admin user
|
|
276
|
-
automation.overwrite_config(config)
|
|
277
|
-
automation.import_incomplete_analyses()
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
if __name__ == "__main__":
|
|
281
|
-
main()
|