pymisp 2.5.7.1__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-2.5.7.1.dist-info → pymisp-2.5.8.dist-info}/METADATA +4 -4
- {pymisp-2.5.7.1.dist-info → pymisp-2.5.8.dist-info}/RECORD +5 -68
- CHANGELOG.txt +0 -5393
- 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
- {pymisp-2.5.7.1.dist-info → pymisp-2.5.8.dist-info}/LICENSE +0 -0
- {pymisp-2.5.7.1.dist-info → pymisp-2.5.8.dist-info}/WHEEL +0 -0
examples/load_csv.py
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
|
|
4
|
-
import argparse
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
|
|
7
|
-
from pymisp.tools import CSVLoader
|
|
8
|
-
|
|
9
|
-
from pymisp import MISPEvent
|
|
10
|
-
|
|
11
|
-
try:
|
|
12
|
-
from keys import misp_url, misp_key, misp_verifycert
|
|
13
|
-
from pymisp import PyMISP
|
|
14
|
-
offline = False
|
|
15
|
-
except ImportError as e:
|
|
16
|
-
offline = True
|
|
17
|
-
print(f'Unable to import MISP parameters, unable to POST on MISP: {e}')
|
|
18
|
-
|
|
19
|
-
'''
|
|
20
|
-
Example:
|
|
21
|
-
* If the CSV file has fieldnames matching the object-relation:
|
|
22
|
-
|
|
23
|
-
load_csv.py -n file -p /tmp/foo.csv
|
|
24
|
-
|
|
25
|
-
CSV sample file: tests/csv_testfiles/valid_fieldnames.csv
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
* If you want to force the fieldnames:
|
|
29
|
-
|
|
30
|
-
load_csv.py -n file -p /tmp/foo.csv -f SHA1 fileName size-in-bytes
|
|
31
|
-
|
|
32
|
-
CSV sample file: tests/csv_testfiles/invalid_fieldnames.csv
|
|
33
|
-
'''
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if __name__ == '__main__':
|
|
37
|
-
parser = argparse.ArgumentParser(description='Load a CSV file as MISP objects')
|
|
38
|
-
parser.add_argument("-n", "--object_name", type=str, required=True, help="Template name of the objects in the CSV.")
|
|
39
|
-
parser.add_argument("-p", "--path", required=True, type=Path, help="Path to the CSV file.")
|
|
40
|
-
parser.add_argument("-f", "--fieldnames", nargs='*', default=[], help="Fieldnames of the CSV, have to match the object-relation allowed in the template. If empty, the fieldnames of the CSV have to match the template.")
|
|
41
|
-
parser.add_argument("-s", "--skip_fieldnames", action='store_true', help="Skip fieldnames in the CSV.")
|
|
42
|
-
parser.add_argument("-d", "--dump", action='store_true', help="(Debug) Dump the object in the terminal.")
|
|
43
|
-
parser.add_argument("--delimiter", type=str, default=',', help="Delimiter between firlds in the CSV. Default: ','.")
|
|
44
|
-
parser.add_argument("--quotechar", type=str, default='"', help="Quote character of the fields in the CSV. Default: '\"'.")
|
|
45
|
-
|
|
46
|
-
# Interact with MISP
|
|
47
|
-
misp_group = parser.add_mutually_exclusive_group()
|
|
48
|
-
misp_group.add_argument('-i', '--new_event', type=str, help="Info field of the new event")
|
|
49
|
-
misp_group.add_argument('-u', '--update_event', type=int, help="ID of the existing event to update")
|
|
50
|
-
|
|
51
|
-
args = parser.parse_args()
|
|
52
|
-
|
|
53
|
-
if not args.fieldnames:
|
|
54
|
-
has_fieldnames = True
|
|
55
|
-
else:
|
|
56
|
-
has_fieldnames = args.skip_fieldnames
|
|
57
|
-
csv_loader = CSVLoader(template_name=args.object_name, csv_path=args.path,
|
|
58
|
-
fieldnames=args.fieldnames, has_fieldnames=has_fieldnames,
|
|
59
|
-
delimiter=args.delimiter, quotechar=args.quotechar)
|
|
60
|
-
|
|
61
|
-
objects = csv_loader.load()
|
|
62
|
-
if args.dump:
|
|
63
|
-
for o in objects:
|
|
64
|
-
print(o.to_json())
|
|
65
|
-
else:
|
|
66
|
-
if offline:
|
|
67
|
-
print('You are in offline mode, quitting.')
|
|
68
|
-
else:
|
|
69
|
-
misp = PyMISP(url=misp_url, key=misp_key, ssl=misp_verifycert)
|
|
70
|
-
if args.new_event:
|
|
71
|
-
event = MISPEvent()
|
|
72
|
-
event.info = args.new_event
|
|
73
|
-
for o in objects:
|
|
74
|
-
event.add_object(**o)
|
|
75
|
-
new_event = misp.add_event(event, pythonify=True)
|
|
76
|
-
if isinstance(new_event, str):
|
|
77
|
-
print(new_event)
|
|
78
|
-
elif 'id' in new_event:
|
|
79
|
-
print(f'Created new event {new_event.id}')
|
|
80
|
-
else:
|
|
81
|
-
print('Something went wrong:')
|
|
82
|
-
print(new_event)
|
|
83
|
-
elif args.update_event:
|
|
84
|
-
for o in objects:
|
|
85
|
-
new_object = misp.add_object(args.update_event, o, pythonify=True)
|
|
86
|
-
if isinstance(new_object, str):
|
|
87
|
-
print(new_object)
|
|
88
|
-
elif new_object.attributes:
|
|
89
|
-
print(f'New {new_object.name} object added to {args.update_event}')
|
|
90
|
-
else:
|
|
91
|
-
print('Something went wrong:')
|
|
92
|
-
print(new_event)
|
|
93
|
-
else:
|
|
94
|
-
print('you need to pass either a event info field (flag -i), or the event ID you want to update (flag -u)')
|
examples/lookup.py
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
|
|
4
|
-
from pymisp.tools import ext_lookups
|
|
5
|
-
import argparse
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
if __name__ == '__main__':
|
|
9
|
-
|
|
10
|
-
parser = argparse.ArgumentParser(description='Search is galaxies or taxonomies.')
|
|
11
|
-
parser.add_argument("-q", "--query", help="Query.")
|
|
12
|
-
|
|
13
|
-
args = parser.parse_args()
|
|
14
|
-
|
|
15
|
-
tag_gal = ext_lookups.revert_tag_from_galaxies(args.query)
|
|
16
|
-
tag_tax = ext_lookups.revert_tag_from_taxonomies(args.query)
|
|
17
|
-
|
|
18
|
-
found_tax = ext_lookups.search_taxonomies(args.query)
|
|
19
|
-
found_gal = ext_lookups.search_galaxies(args.query)
|
|
20
|
-
|
|
21
|
-
if tag_gal:
|
|
22
|
-
print(tag_gal)
|
|
23
|
-
if tag_tax:
|
|
24
|
-
print(tag_tax)
|
|
25
|
-
if found_tax:
|
|
26
|
-
print(found_tax)
|
|
27
|
-
if found_gal:
|
|
28
|
-
print(found_gal)
|
examples/misp2cef.py
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
#
|
|
4
|
-
# Export IOC's from MISP in CEF format
|
|
5
|
-
# Based on cef_export.py MISP module by Hannah Ward
|
|
6
|
-
|
|
7
|
-
import sys
|
|
8
|
-
import datetime
|
|
9
|
-
from pymisp import PyMISP, MISPAttribute
|
|
10
|
-
from keys import misp_url, misp_key, misp_verifycert
|
|
11
|
-
|
|
12
|
-
cefconfig = {"Default_Severity":1, "Device_Vendor":"MISP", "Device_Product":"MISP", "Device_Version":1}
|
|
13
|
-
|
|
14
|
-
cefmapping = {"ip-src":"src", "ip-dst":"dst", "hostname":"dhost", "domain":"destinationDnsDomain",
|
|
15
|
-
"md5":"fileHash", "sha1":"fileHash", "sha256":"fileHash",
|
|
16
|
-
"filename|md5":"fileHash", "filename|sha1":"fileHash", "filename|sha256":"fileHash",
|
|
17
|
-
"url":"request"}
|
|
18
|
-
|
|
19
|
-
mispattributes = {'input':list(cefmapping.keys())}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def make_cef(event):
|
|
23
|
-
for attr in event["Attribute"]:
|
|
24
|
-
if attr["to_ids"] and attr["type"] in cefmapping:
|
|
25
|
-
if '|' in attr["type"] and '|' in attr["value"]:
|
|
26
|
-
value = attr["value"].split('|')[1]
|
|
27
|
-
else:
|
|
28
|
-
value = attr["value"]
|
|
29
|
-
response = "{} host CEF:0|{}|{}|{}|{}|{}|{}|msg={} customerURI={} externalId={} {}={}".format(
|
|
30
|
-
datetime.datetime.fromtimestamp(int(attr["timestamp"])).strftime("%b %d %H:%M:%S"),
|
|
31
|
-
cefconfig["Device_Vendor"],
|
|
32
|
-
cefconfig["Device_Product"],
|
|
33
|
-
cefconfig["Device_Version"],
|
|
34
|
-
attr["category"],
|
|
35
|
-
attr["category"],
|
|
36
|
-
cefconfig["Default_Severity"],
|
|
37
|
-
event["info"].replace("\\","\\\\").replace("=","\\=").replace('\n','\\n') + "(MISP Event #" + event["id"] + ")",
|
|
38
|
-
misp_url + 'events/view/' + event["id"],
|
|
39
|
-
attr["uuid"],
|
|
40
|
-
cefmapping[attr["type"]],
|
|
41
|
-
value,
|
|
42
|
-
)
|
|
43
|
-
print(str(bytes(response, 'utf-8'), 'utf-8'))
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
def init_misp():
|
|
47
|
-
global mymisp
|
|
48
|
-
mymisp = PyMISP(misp_url, misp_key, misp_verifycert)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def echeck(r):
|
|
52
|
-
if r.get('errors'):
|
|
53
|
-
if r.get('message') == 'No matches.':
|
|
54
|
-
return
|
|
55
|
-
else:
|
|
56
|
-
print(r['errors'])
|
|
57
|
-
sys.exit(1)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def find_events():
|
|
61
|
-
r = mymisp.search(controller='events', published=True, to_ids=True)
|
|
62
|
-
echeck(r)
|
|
63
|
-
if not r.get('response'):
|
|
64
|
-
return
|
|
65
|
-
for ev in r['response']:
|
|
66
|
-
make_cef(ev['Event'])
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if __name__ == '__main__':
|
|
70
|
-
init_misp()
|
|
71
|
-
find_events()
|
examples/misp2clamav.py
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
# vim: tabstop=4 shiftwidth=4 expandtab
|
|
4
|
-
#
|
|
5
|
-
# Export file hashes from MISP to ClamAV hdb file
|
|
6
|
-
|
|
7
|
-
import sys
|
|
8
|
-
from pymisp import PyMISP, MISPAttribute
|
|
9
|
-
from keys import misp_url, misp_key, misp_verifycert
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def init_misp():
|
|
13
|
-
global mymisp
|
|
14
|
-
mymisp = PyMISP(misp_url, misp_key, misp_verifycert)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def echeck(r):
|
|
18
|
-
if r.get('errors'):
|
|
19
|
-
if r.get('message') == 'No matches.':
|
|
20
|
-
return
|
|
21
|
-
else:
|
|
22
|
-
print(r['errors'])
|
|
23
|
-
sys.exit(1)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def find_hashes(htype):
|
|
27
|
-
r = mymisp.search(controller='attributes', type_attribute=htype)
|
|
28
|
-
echeck(r)
|
|
29
|
-
if not r.get('response'):
|
|
30
|
-
return
|
|
31
|
-
for a in r['response']['Attribute']:
|
|
32
|
-
attribute = MISPAttribute(mymisp.describe_types)
|
|
33
|
-
attribute.from_dict(**a)
|
|
34
|
-
if '|' in attribute.type and '|' in attribute.value:
|
|
35
|
-
c, value = attribute.value.split('|')
|
|
36
|
-
comment = '{} - {}'.format(attribute.comment, c)
|
|
37
|
-
else:
|
|
38
|
-
comment = attribute.comment
|
|
39
|
-
value = attribute.value
|
|
40
|
-
mhash = value.replace(':', ';')
|
|
41
|
-
mfile = 'MISP event {} {}'.format(a['event_id'], comment.replace(':', ';').replace('\r', '').replace('\n', ''))
|
|
42
|
-
print('{}:*:{}:73'.format(mhash, mfile))
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if __name__ == '__main__':
|
|
46
|
-
init_misp()
|
|
47
|
-
find_hashes('md5')
|
|
48
|
-
find_hashes('sha1')
|
|
49
|
-
find_hashes('sha256')
|
|
50
|
-
find_hashes('filename|md5')
|
|
51
|
-
find_hashes('filename|sha1')
|
|
52
|
-
find_hashes('filename|sha256')
|
examples/openioc_to_misp.py
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
|
|
4
|
-
import argparse
|
|
5
|
-
|
|
6
|
-
from pymisp import PyMISP
|
|
7
|
-
from keys import misp_url, misp_key, misp_verifycert
|
|
8
|
-
from pymisp.tools import load_openioc_file
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if __name__ == '__main__':
|
|
12
|
-
parser = argparse.ArgumentParser(description='Convert an OpenIOC file to a MISPEvent. Optionnaly send it to MISP.')
|
|
13
|
-
parser.add_argument("-i", "--input", required=True, help="Input file")
|
|
14
|
-
group = parser.add_mutually_exclusive_group(required=True)
|
|
15
|
-
group.add_argument("-o", "--output", help="Output file")
|
|
16
|
-
group.add_argument("-m", "--misp", action='store_true', help="Create new event on MISP")
|
|
17
|
-
|
|
18
|
-
args = parser.parse_args()
|
|
19
|
-
|
|
20
|
-
misp_event = load_openioc_file(args.input)
|
|
21
|
-
|
|
22
|
-
if args.misp:
|
|
23
|
-
pymisp = PyMISP(misp_url, misp_key, misp_verifycert, debug=True)
|
|
24
|
-
pymisp.add_event(misp_event)
|
|
25
|
-
else:
|
|
26
|
-
with open(args.output, 'w') as f:
|
|
27
|
-
f.write(misp_event.to_json())
|
examples/proofpoint_tap.py
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
import requests
|
|
2
|
-
from requests.auth import HTTPBasicAuth
|
|
3
|
-
import json
|
|
4
|
-
from pymisp import ExpandedPyMISP, MISPEvent
|
|
5
|
-
from keys import misp_url, misp_key, misp_verifycert, proofpoint_sp, proofpoint_secret
|
|
6
|
-
import urllib3
|
|
7
|
-
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
|
8
|
-
|
|
9
|
-
if proofpoint_secret == '<proofpoint secret>':
|
|
10
|
-
print('Set the proofpoint_secret in keys.py before running. Exiting...')
|
|
11
|
-
quit()
|
|
12
|
-
|
|
13
|
-
# initialize PyMISP and set url for Panorama
|
|
14
|
-
misp = ExpandedPyMISP(url=misp_url, key=misp_key, ssl=misp_verifycert)
|
|
15
|
-
|
|
16
|
-
urlSiem = "https://tap-api-v2.proofpoint.com/v2/siem/all"
|
|
17
|
-
|
|
18
|
-
alertType = ("messagesDelivered", "messagesBlocked", "clicksPermitted", "clicksBlocked")
|
|
19
|
-
|
|
20
|
-
# max query is 1h, and we want Proofpoint TAP api to return json
|
|
21
|
-
queryString = {
|
|
22
|
-
"sinceSeconds": "3600",
|
|
23
|
-
"format": "json"
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
responseSiem = requests.request("GET", urlSiem, params=queryString, auth=HTTPBasicAuth(proofpoint_sp, proofpoint_secret))
|
|
29
|
-
if 'Credentials authentication failed' in responseSiem.text:
|
|
30
|
-
print('Credentials invalid, please edit keys.py and try again')
|
|
31
|
-
quit()
|
|
32
|
-
|
|
33
|
-
jsonDataSiem = json.loads(responseSiem.text)
|
|
34
|
-
|
|
35
|
-
for alert in alertType:
|
|
36
|
-
for messages in jsonDataSiem[alert]:
|
|
37
|
-
# initialize and set MISPEvent()
|
|
38
|
-
event = MISPEvent()
|
|
39
|
-
if alert == "messagesDelivered" or alert == "messagesBlocked":
|
|
40
|
-
if alert == "messagesDelivered":
|
|
41
|
-
event.info = alert
|
|
42
|
-
event.distribution = 0 # Optional, defaults to MISP.default_event_distribution in MISP config
|
|
43
|
-
event.threat_level_id = 2 # setting this to 0 breaks the integration
|
|
44
|
-
event.analysis = 0 # Optional, defaults to 0 (initial analysis)
|
|
45
|
-
else:
|
|
46
|
-
event.info = alert
|
|
47
|
-
event.distribution = 0 # Optional, defaults to MISP.default_event_distribution in MISP config
|
|
48
|
-
event.threat_level_id = 2 # BLOCKED = LOW
|
|
49
|
-
event.analysis = 0 # Optional, defaults to 0 (initial analysis)
|
|
50
|
-
|
|
51
|
-
recipient = event.add_attribute('email-dst', messages["recipient"][0])
|
|
52
|
-
recipient.comment = 'recipient address'
|
|
53
|
-
|
|
54
|
-
sender = event.add_attribute('email-src', messages["sender"])
|
|
55
|
-
sender.comment = 'sender address'
|
|
56
|
-
|
|
57
|
-
if messages["fromAddress"] is not None and messages["fromAddress"] != "" :
|
|
58
|
-
fromAddress = event.add_attribute('email-src-display-name', messages["fromAddress"])
|
|
59
|
-
|
|
60
|
-
headerFrom = event.add_attribute('email-header', messages["headerFrom"])
|
|
61
|
-
headerFrom.comment = 'email header from'
|
|
62
|
-
|
|
63
|
-
senderIP = event.add_attribute('ip-src', messages["senderIP"])
|
|
64
|
-
senderIP.comment = 'sender IP'
|
|
65
|
-
|
|
66
|
-
subject = event.add_attribute('email-subject', messages["subject"])
|
|
67
|
-
subject.comment = 'email subject'
|
|
68
|
-
|
|
69
|
-
if messages["quarantineFolder"] is not None and messages["quarantineFolder"] != "":
|
|
70
|
-
quarantineFolder = event.add_attribute('comment', messages["quarantineFolder"])
|
|
71
|
-
quarantineFolder.comment = 'quarantine folder'
|
|
72
|
-
|
|
73
|
-
if messages["quarantineRule"] is not None and messages["quarantineRule"] != "":
|
|
74
|
-
quarantineRule = event.add_attribute('comment', messages["quarantineRule"])
|
|
75
|
-
quarantineRule.comment = 'quarantine rule'
|
|
76
|
-
|
|
77
|
-
messageSize = event.add_attribute('size-in-bytes', messages["messageSize"])
|
|
78
|
-
messageSize.comment = 'size of email in bytes'
|
|
79
|
-
|
|
80
|
-
malwareScore = event.add_attribute('comment', messages["malwareScore"])
|
|
81
|
-
malwareScore.comment = 'malware score'
|
|
82
|
-
|
|
83
|
-
phishScore = event.add_attribute('comment', messages["phishScore"])
|
|
84
|
-
phishScore.comment = 'phish score'
|
|
85
|
-
|
|
86
|
-
spamScore = event.add_attribute('comment', messages["spamScore"])
|
|
87
|
-
spamScore.comment = 'spam score'
|
|
88
|
-
|
|
89
|
-
imposterScore = event.add_attribute('comment', messages["impostorScore"])
|
|
90
|
-
imposterScore.comment = 'impostor score'
|
|
91
|
-
|
|
92
|
-
completelyRewritten = event.add_attribute('comment', messages["completelyRewritten"])
|
|
93
|
-
completelyRewritten.comment = 'proofpoint url defense'
|
|
94
|
-
|
|
95
|
-
# grab the threat info for each message in TAP
|
|
96
|
-
for threatInfo in messages["threatsInfoMap"]:
|
|
97
|
-
threat_type = {
|
|
98
|
-
"url": "url",
|
|
99
|
-
"attachment": "email-attachment",
|
|
100
|
-
"message": "email-body"
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
threat = event.add_attribute(threat_type.get(threatInfo["threatType"]), threatInfo["threat"])
|
|
104
|
-
threat.comment = 'threat'
|
|
105
|
-
|
|
106
|
-
threatUrl = event.add_attribute('link', threatInfo["threatUrl"])
|
|
107
|
-
threatUrl.comment = 'link to threat in TAP'
|
|
108
|
-
|
|
109
|
-
threatStatus = event.add_attribute('comment', threatInfo["threatStatus"])
|
|
110
|
-
threatStatus.comment = "proofpoint's threat status"
|
|
111
|
-
|
|
112
|
-
event.add_tag(threatInfo["classification"])
|
|
113
|
-
|
|
114
|
-
# get campaignID from each TAP alert and query campaign API
|
|
115
|
-
if threatInfo["campaignID"] is not None and threatInfo["campaignID"] != "":
|
|
116
|
-
urlCampaign = "https://tap-api-v2.proofpoint.com/v2/campaign/" + threatInfo["campaignID"]
|
|
117
|
-
responseCampaign = requests.request("GET", urlCampaign, auth=HTTPBasicAuth(proofpoint_sp, proofpoint_secret))
|
|
118
|
-
|
|
119
|
-
jsonDataCampaign = json.loads(responseCampaign.text)
|
|
120
|
-
|
|
121
|
-
campaignType = ("actors", "families", "malware", "techniques")
|
|
122
|
-
|
|
123
|
-
# loop through campaignType and grab tags to add to MISP event
|
|
124
|
-
for tagType in campaignType:
|
|
125
|
-
for tag in jsonDataCampaign[tagType]:
|
|
126
|
-
event.add_tag(tag['name'])
|
|
127
|
-
|
|
128
|
-
# grab which policy route the message took
|
|
129
|
-
for policy in messages["policyRoutes"]:
|
|
130
|
-
policyRoute = event.add_attribute('comment', policy)
|
|
131
|
-
policyRoute.comment = 'email policy route'
|
|
132
|
-
|
|
133
|
-
# was the threat in the body of the email or is it an attachment?
|
|
134
|
-
for parts in messages["messageParts"]:
|
|
135
|
-
disposition = event.add_attribute('comment', parts["disposition"])
|
|
136
|
-
disposition.comment = 'email body or attachment'
|
|
137
|
-
|
|
138
|
-
# sha256 hash of threat
|
|
139
|
-
if parts["sha256"] is not None and parts["sha256"] != "":
|
|
140
|
-
sha256 = event.add_attribute('sha256', parts["sha256"])
|
|
141
|
-
sha256.comment = 'sha256 hash'
|
|
142
|
-
|
|
143
|
-
# md5 hash of threat
|
|
144
|
-
if parts["md5"] is not None and parts["md5"] != "":
|
|
145
|
-
md5 = event.add_attribute('md5', parts["md5"])
|
|
146
|
-
md5.comment = 'md5 hash'
|
|
147
|
-
|
|
148
|
-
# filename of threat
|
|
149
|
-
if parts["filename"] is not None and parts["filename"] != "":
|
|
150
|
-
filename = event.add_attribute('filename', parts["filename"])
|
|
151
|
-
filename.comment = 'filename'
|
|
152
|
-
|
|
153
|
-
misp.add_event(event.to_json())
|
|
154
|
-
|
|
155
|
-
if alert == "clicksPermitted" or alert == "clicksBlocked":
|
|
156
|
-
if alert == "clicksPermitted":
|
|
157
|
-
print(alert + " is a permitted click")
|
|
158
|
-
event.info = alert
|
|
159
|
-
event.distribution = 0 # Optional, defaults to MISP.default_event_distribution in MISP config
|
|
160
|
-
event.threat_level_id = 2 # setting this to 0 breaks the integration
|
|
161
|
-
event.analysis = 0 # Optional, defaults to 0 (initial analysis)
|
|
162
|
-
else:
|
|
163
|
-
print(alert + " is a blocked click")
|
|
164
|
-
event.info = alert
|
|
165
|
-
event.distribution = 0 # Optional, defaults to MISP.default_event_distribution in MISP config
|
|
166
|
-
event.threat_level_id = 2 # BLOCKED = LOW
|
|
167
|
-
event.analysis = 0 # Optional, defaults to 0 (initial analysis)
|
|
168
|
-
|
|
169
|
-
event.add_tag(messages["classification"])
|
|
170
|
-
|
|
171
|
-
campaignId = event.add_attribute('campaign-id', messages["campaignId"][0])
|
|
172
|
-
campaignId.comment = 'campaignId'
|
|
173
|
-
|
|
174
|
-
clickIP = event.add_attribute('ip-src', messages["clickIP"])
|
|
175
|
-
clickIP.comment = 'clickIP'
|
|
176
|
-
|
|
177
|
-
clickTime = event.add_attribute('datetime', messages["clickTime"])
|
|
178
|
-
clickTime.comment = 'clicked threat'
|
|
179
|
-
|
|
180
|
-
threatTime = event.add_attribute('datetime', messages["threatTime"])
|
|
181
|
-
threatTime.comment = 'identified threat'
|
|
182
|
-
|
|
183
|
-
GUID = event.add_attribute('comment', messages["GUID"])
|
|
184
|
-
GUID.comment = 'PPS message ID'
|
|
185
|
-
|
|
186
|
-
recipient = event.add_attribute('email-dst', messages["recipient"][0])
|
|
187
|
-
recipient.comment = 'recipient address'
|
|
188
|
-
|
|
189
|
-
sender = event.add_attribute('email-src', messages["sender"])
|
|
190
|
-
sender.comment = 'sender address'
|
|
191
|
-
|
|
192
|
-
senderIP = event.add_attribute('ip-src', messages["senderIP"])
|
|
193
|
-
senderIP.comment = 'sender IP'
|
|
194
|
-
|
|
195
|
-
threatURL = event.add_attribute('link', messages["threatURL"])
|
|
196
|
-
threatURL.comment = 'link to threat in TAP'
|
|
197
|
-
|
|
198
|
-
url = event.add_attribute('link', messages["url"])
|
|
199
|
-
url.comment = 'malicious url clicked'
|
|
200
|
-
|
|
201
|
-
userAgent = event.add_attribute('user-agent', messages["userAgent"])
|
|
202
|
-
|
|
203
|
-
misp.add_event(event.to_json())
|
examples/proofpoint_vap.py
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import requests
|
|
2
|
-
import json
|
|
3
|
-
from pymisp import ExpandedPyMISP, MISPEvent, MISPOrganisation
|
|
4
|
-
from keys import misp_url, misp_key, misp_verifycert, proofpoint_key
|
|
5
|
-
|
|
6
|
-
# initialize PyMISP and set url for Panorama
|
|
7
|
-
misp = ExpandedPyMISP(url=misp_url, key=misp_key, ssl=misp_verifycert)
|
|
8
|
-
|
|
9
|
-
urlVap = "https://tap-api-v2.proofpoint.com/v2/people/vap?window=30" # Window can be 14, 30, and 90 Days
|
|
10
|
-
|
|
11
|
-
headers = {
|
|
12
|
-
'Authorization': "Basic " + proofpoint_key
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
responseVap = requests.request("GET", urlVap, headers=headers)
|
|
16
|
-
|
|
17
|
-
jsonDataVap = json.loads(responseVap.text)
|
|
18
|
-
|
|
19
|
-
for alert in jsonDataVap["users"]:
|
|
20
|
-
orgc = MISPOrganisation()
|
|
21
|
-
orgc.name = 'Proofpoint'
|
|
22
|
-
orgc.id = '#{ORGC.ID}' # organisation id
|
|
23
|
-
orgc.uuid = '#{ORGC.UUID}' # organisation uuid
|
|
24
|
-
# initialize and set MISPEvent()
|
|
25
|
-
event = MISPEvent()
|
|
26
|
-
event.Orgc = orgc
|
|
27
|
-
event.info = 'Very Attacked Person ' + jsonDataVap["interval"]
|
|
28
|
-
event.distribution = 0 # Optional, defaults to MISP.default_event_distribution in MISP config
|
|
29
|
-
event.threat_level_id = 2 # setting this to 0 breaks the integration
|
|
30
|
-
event.analysis = 0 # Optional, defaults to 0 (initial analysis)
|
|
31
|
-
|
|
32
|
-
totalVapUsers = event.add_attribute('counter', jsonDataVap["totalVapUsers"], comment="Total VAP Users")
|
|
33
|
-
|
|
34
|
-
averageAttackIndex = event.add_attribute('counter', jsonDataVap["averageAttackIndex"], comment="Average Attack Count")
|
|
35
|
-
|
|
36
|
-
vapAttackIndexThreshold = event.add_attribute('counter', jsonDataVap["vapAttackIndexThreshold"], comment="Attack Threshold")
|
|
37
|
-
|
|
38
|
-
emails = event.add_attribute('email-dst', alert["identity"]["emails"], comment="Email Destination")
|
|
39
|
-
|
|
40
|
-
attack = event.add_attribute('counter', alert["threatStatistics"]["attackIndex"], comment="Attack Count")
|
|
41
|
-
|
|
42
|
-
vip = event.add_attribute('other', str(alert["identity"]["vip"]), comment="VIP")
|
|
43
|
-
|
|
44
|
-
guid = event.add_attribute('other', alert["identity"]["guid"], comment="GUID")
|
|
45
|
-
|
|
46
|
-
if alert["identity"]["customerUserId"] is not None:
|
|
47
|
-
customerUserId = event.add_attribute('other', alert["identity"]["customerUserId"], comment="Customer User Id")
|
|
48
|
-
|
|
49
|
-
if alert["identity"]["department"] is not None:
|
|
50
|
-
department = event.add_attribute(alert['other', "identity"]["department"], comment="Department")
|
|
51
|
-
|
|
52
|
-
if alert["identity"]["location"] is not None:
|
|
53
|
-
location = event.add_attribute('other', alert["identity"]["location"], comment="Location")
|
|
54
|
-
|
|
55
|
-
if alert["identity"]["name"] is not None:
|
|
56
|
-
|
|
57
|
-
name = event.add_attribute('target-user', alert["identity"]["name"], comment="Name")
|
|
58
|
-
|
|
59
|
-
if alert["identity"]["title"] is not None:
|
|
60
|
-
|
|
61
|
-
title = event.add_attribute('other', alert["identity"]["title"], comment="Title")
|
|
62
|
-
|
|
63
|
-
event.add_tag("VAP")
|
|
64
|
-
|
|
65
|
-
misp.add_event(event.to_json())
|
examples/search.py
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
|
|
4
|
-
from pymisp import PyMISP
|
|
5
|
-
from keys import misp_url, misp_key,misp_verifycert
|
|
6
|
-
import argparse
|
|
7
|
-
import os
|
|
8
|
-
import json
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def init(url, key):
|
|
12
|
-
return PyMISP(url, key, misp_verifycert, 'json')
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def search(m, quiet, url, controller, out=None, **kwargs):
|
|
16
|
-
result = m.search(controller, **kwargs)
|
|
17
|
-
if quiet:
|
|
18
|
-
for e in result['response']:
|
|
19
|
-
print('{}{}{}\n'.format(url, '/events/view/', e['Event']['id']))
|
|
20
|
-
elif out is None:
|
|
21
|
-
print(json.dumps(result['response']))
|
|
22
|
-
else:
|
|
23
|
-
with open(out, 'w') as f:
|
|
24
|
-
f.write(json.dumps(result['response']))
|
|
25
|
-
|
|
26
|
-
if __name__ == '__main__':
|
|
27
|
-
parser = argparse.ArgumentParser(description='Get all the events matching a value for a given param.')
|
|
28
|
-
parser.add_argument("-p", "--param", required=True, help="Parameter to search (e.g. category, org, values, type_attribute, etc.)")
|
|
29
|
-
parser.add_argument("-s", "--search", required=True, help="String to search.")
|
|
30
|
-
parser.add_argument("-a", "--attributes", action='store_true', help="Search attributes instead of events")
|
|
31
|
-
parser.add_argument("-q", "--quiet", action='store_true', help="Only display URLs to MISP")
|
|
32
|
-
parser.add_argument("-o", "--output", help="Output file")
|
|
33
|
-
|
|
34
|
-
args = parser.parse_args()
|
|
35
|
-
|
|
36
|
-
if args.output is not None and os.path.exists(args.output):
|
|
37
|
-
print('Output file already exists, abort.')
|
|
38
|
-
exit(0)
|
|
39
|
-
|
|
40
|
-
misp = init(misp_url, misp_key)
|
|
41
|
-
kwargs = {args.param: args.search}
|
|
42
|
-
|
|
43
|
-
if args.attributes:
|
|
44
|
-
controller='attributes'
|
|
45
|
-
else:
|
|
46
|
-
controller='events'
|
|
47
|
-
|
|
48
|
-
search(misp, args.quiet, misp_url, controller, args.output, **kwargs)
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
# Example of specifying special attribute type in your search: here yara attribute
|
|
4
|
-
|
|
5
|
-
from pymisp import PyMISP
|
|
6
|
-
from keys import misp_url, misp_key,misp_verifycert
|
|
7
|
-
import argparse
|
|
8
|
-
import os
|
|
9
|
-
import json
|
|
10
|
-
|
|
11
|
-
def init(url, key):
|
|
12
|
-
return PyMISP(url, key, misp_verifycert, 'json')
|
|
13
|
-
|
|
14
|
-
def search(m, quiet, url, out=None, custom_type_attribute="yara"):
|
|
15
|
-
controller='attributes'
|
|
16
|
-
result = m.search(controller, type_attribute = custom_type_attribute)
|
|
17
|
-
if quiet:
|
|
18
|
-
for e in result['response']:
|
|
19
|
-
print('{}{}{}\n'.format(url, '/events/view/', e['Event']['id']))
|
|
20
|
-
elif out is None:
|
|
21
|
-
print(json.dumps(result['response']))
|
|
22
|
-
else:
|
|
23
|
-
with open(out, 'w') as f:
|
|
24
|
-
f.write(json.dumps(result['response']))
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if __name__ == '__main__':
|
|
28
|
-
parser = argparse.ArgumentParser(description='Get all the events matching a value for a given param.')
|
|
29
|
-
parser.add_argument("-q", "--quiet", action='store_true', help="Only display URLs to MISP")
|
|
30
|
-
parser.add_argument("-o", "--output", help="Output file")
|
|
31
|
-
|
|
32
|
-
args = parser.parse_args()
|
|
33
|
-
|
|
34
|
-
if args.output is not None and os.path.exists(args.output):
|
|
35
|
-
print('Output file already exists, abort.')
|
|
36
|
-
exit(0)
|
|
37
|
-
|
|
38
|
-
misp = init(misp_url, misp_key)
|
|
39
|
-
|
|
40
|
-
search(misp, args.quiet, misp_url, args.output)
|
examples/search_sighting.py
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
|
|
4
|
-
from pymisp import PyMISP
|
|
5
|
-
from keys import misp_url, misp_key, misp_verifycert
|
|
6
|
-
import argparse
|
|
7
|
-
import os
|
|
8
|
-
import json
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def init(url, key):
|
|
12
|
-
return PyMISP(url, key, misp_verifycert, 'json')
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def search_sighting(m, context, out=None, **kwargs):
|
|
16
|
-
|
|
17
|
-
result = m.search_sightings(context, **kwargs)
|
|
18
|
-
if out is None:
|
|
19
|
-
print(json.dumps(result['response']))
|
|
20
|
-
else:
|
|
21
|
-
with open(out, 'w') as f:
|
|
22
|
-
f.write(json.dumps(result['response']))
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if __name__ == '__main__':
|
|
26
|
-
parser = argparse.ArgumentParser(description='Get all the events matching a value.')
|
|
27
|
-
parser.add_argument("-c", "--context", default="", help="Context in which to search. Could be empty, attribute or event")
|
|
28
|
-
parser.add_argument("-i", "--id", type=int, help="If context is set, the ID in which the search should be done")
|
|
29
|
-
parser.add_argument("-o", "--output", help="Output file")
|
|
30
|
-
|
|
31
|
-
args = parser.parse_args()
|
|
32
|
-
|
|
33
|
-
if args.output is not None and os.path.exists(args.output):
|
|
34
|
-
print('Output file already exists, abord.')
|
|
35
|
-
exit(0)
|
|
36
|
-
|
|
37
|
-
misp = init(misp_url, misp_key)
|
|
38
|
-
kwargs = {}
|
|
39
|
-
if len(args.context) > 0:
|
|
40
|
-
kwargs['id'] = args.id
|
|
41
|
-
|
|
42
|
-
search_sighting(misp, args.context, args.output, **kwargs)
|