forked from patriziotufarolo/cybersaiyan-taxii2misp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cs.py
279 lines (227 loc) · 8.14 KB
/
cs.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
import re
import datetime, pytz
import atexit
import hashlib
import uuid
import os
import sqlite3
db_conn = sqlite3.connect('db.db', check_same_thread=False)
db_cursor = db_conn.cursor()
db_cursor.execute("CREATE TABLE IF NOT EXISTS hashes (hash text, uuid text)")
db_conn.commit()
from flask import Flask, Response
from apscheduler.schedulers.background import BackgroundScheduler
from cabby import create_client
from stix.core import STIXPackage
from pymisp import MISPEvent, MISPAttribute, MISPOrganisation
from io import StringIO
from logging.config import dictConfig
"""
Variables
"""
LISTEN_ADDRESS = os.getenv("CS_MISP_FEED_LISTEN_ADDRESS", "0.0.0.0")
LISTEN_PORT = os.getenv("CS_MISP_FEED_LISTEN_PORT", 8080)
SCHEDULED_INTERVAL = int(os.getenv("CS_MISP_FEED_SCHEDULED_INTERVAL",
str(60 * 30)))
CYBERSAIYAN_FEED_URL = \
os.getenv("CS_TAXII_URL", "infosharing.cybersaiyan.it")
CYBERSAIYAN_COLLECTION_NAME = \
os.getenv("CS_TAXII_COLLECTION_NAME",'CS-COMMUNITY-TAXII')
TAXII_USE_TLS = True
TAXII_DISCOVERY_PATH = \
os.getenv("CS_TAXII_DISCOVERY_SERVICE", '/taxii-discovery-service')
utc = pytz.UTC
TLPS = ["white", "green", "amber", "red"]
TLP = {**dict(zip(TLPS,range(len(TLPS)))),**{i:TLPS[i]
for i in range(len(TLPS))}}
fake_index_template = """<html>
<head>
<title>CyberSaiyan Info-Sharing - TAXII to MISP</title>
</head>
<body>
<h1>Cyber Saiyan Info-Sharing - TAXII to MISP</h1>
<hr>
<pre>
<a href="#">../</a>
{body}
</pre>
<hr>
</body>
</html>
""".strip()
"""
App declaration
"""
dictConfig({
'version': 1,
'formatters': {'default': {
'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s',
}},
'handlers': {'wsgi': {
'class': 'logging.StreamHandler',
'stream': 'ext://sys.stdout',
'formatter': 'default'
}},
'root': {
'level': 'INFO',
'handlers': ['wsgi']
}
})
app = Flask(__name__)
scheduler = BackgroundScheduler()
"""
Variables to fill for feed
"""
f_hashes, f_manifest, f_events = list(), dict(), dict()
"""
Application handlers
"""
@app.route('/')
def srv_get_event_list():
links = []
for event_uuid in f_manifest:
links.append('<a href="{u}.json">{u}.json</a>\t01-Jan-1970 00:00\t-'
.format(u=event_uuid))
links.append('<a href="{filename}">{filename}</a>\t01-Jan-1970 00:00\t-'
.format(filename="hashes.csv"))
links.append('<a href="{filename}">{filename}</a>\t01-Jan-1970 00:00\t-'
.format(filename="manifest.json"))
links = '\n'.join(links)
return fake_index_template.format(body=links)
@app.route('/<path:path>')
def srv_get_event(path):
path = path.lower()
if path == "manifest.json":
return f_manifest, 200
elif path.lower() == "hashes.csv":
return Response('\n'.join(['{},{}'.format(f_hash[0], f_hash[1])
for f_hash in f_hashes]),
mimetype="text/csv")
elif path == "events":
return f_events
else:
path = re.sub(r'.(json|csv)$', "", path)
if path in f_events:
return {
"Event": f_events[path]
}
else:
return "<h1>404 Not found</h1>", 404
def poll_taxii():
global f_hashes, f_manifest, f_events
results_dict = {}
client = create_client(
CYBERSAIYAN_FEED_URL,
use_https=TAXII_USE_TLS,
discovery_path=TAXII_DISCOVERY_PATH
)
blocks = client.poll(collection_name=CYBERSAIYAN_COLLECTION_NAME)
for block in blocks:
content = block.content
if content:
if type(content) == str:
continue
elif type(content) == bytes:
content = content.decode('utf-8')
pkg = STIXPackage.from_xml(StringIO(content))
title = pkg.stix_header.title
information_source = pkg.stix_header.information_source.identity.name
cs_event = (title, information_source)
cs_event_hash = hash(cs_event)
db_cursor.execute("SELECT uuid FROM hashes WHERE hash = '%s'" % cs_event_hash)
element = db_cursor.fetchone()
if element:
e_uuid = element[0]
else:
e_uuid = str(uuid.uuid4())
db_cursor.execute("INSERT INTO hashes VALUES (?,?)", (cs_event_hash,e_uuid,))
if cs_event_hash not in results_dict:
results_dict[cs_event_hash] = MISPEvent()
m_ev = results_dict[cs_event_hash]
m_ev.info = str(pkg.stix_header.description)
m_ev.analysis = 0
m_ev.uuid = e_uuid
#m_ev.org = "CyberSaiyan"
csorg = MISPOrganisation()
csorg.name = "CyberSaiyan"
csorg.uuid = "8aaa81ed-72ef-4fb1-8e96-fa1bc200faeb"
m_ev.orgc = csorg
marking = pkg.stix_header.handling.marking
tlp = 0
found_tlp = False
for m in marking:
for struct in m.marking_structures:
if struct._XSI_TYPE == "tlpMarking:TLPMarkingStructureType":
found_tlp = True
tlp = max(TLP[struct.color.lower()], tlp)
if tlp == 0 and not found_tlp:
tlp = TLP["amber"]
m_ev.add_tag("tlp:"+TLP[tlp])
m_ev.add_tag("CyberSaiyan")
indicators = pkg.indicators
last_ts = utc.localize(datetime.datetime(1970,1,1))
for indicator in indicators:
cur_ts = indicator.timestamp
if cur_ts > last_ts:
last_ts = cur_ts
obj = indicator.observable.object_
obj_d = obj.properties.to_dict()
attr_type = obj_d["xsi:type"]
if attr_type == "AddressObjectType":
attr = MISPAttribute()
attr.category = "Network activity"
attr.type = "ip-dst"
attr.value = obj_d["address_value"]
attr.disable_correlation = False
attr.to_ids = True
elif attr_type == "DomainNameObjectType":
attr = MISPAttribute()
attr.category = "Network activity"
attr.type = "domain"
attr.value = obj_d["value"]
attr.disable_correlation = False
attr.to_ids = True
elif attr_type == "URIObjectType":
attr = MISPAttribute()
attr.category = "Network activity"
attr.type = "url"
attr.value = obj_d["value"]
attr.disable_correlation = False
attr.to_ids = True
elif attr_type == "FileObjectType":
hash_type = obj_d["hashes"][0]["type"]["value"].lower()
hash_value = obj_d["hashes"][0]["simple_hash_value"]
attr = MISPAttribute()
attr.category = "Payload delivery"
assert hash_type in ('md5', "sha1", "sha224",
"sha256", "sha384", "sha512", "ssdeep")
attr.type = hash_type
attr.value = hash_value
attr.disable_correlation = False
attr.to_ids = True
m_ev.date = last_ts.strftime("%Y-%m-%d")
m_ev.attributes.append(attr)
db_conn.commit()
c_hashes, c_manifest, c_events = list(), dict(), dict()
for event in results_dict.values():
e_feed = event.to_feed(with_meta=True).get("Event")
c_hashes += [[h, event.uuid] for h in e_feed.pop("_hashes")]
c_manifest.update(e_feed.pop('_manifest'))
c_events[event.uuid] = e_feed
f_hashes, f_manifest, f_events = c_hashes, c_manifest, c_events
def task_poll_taxii():
try:
poll_taxii()
except Exception as e:
app.logger.exception("Error during poll")
if __name__ == "__main__":
app.logger.info("Importing events for the first time")
task_poll_taxii()
app.logger.info("Done")
scheduler.add_job(func=task_poll_taxii,
trigger="interval",
seconds=SCHEDULED_INTERVAL)
scheduler.start()
atexit.register(lambda: scheduler.shutdown())
atexit.register(lambda: db_conn.close())
app.run(host=LISTEN_ADDRESS, port=LISTEN_PORT)