mirror of https://github.com/MISP/misp-modules
new: [action_mod] Added MatterMost module and deleted test modules
parent
cac0c19eed
commit
89bc8bf19c
|
@ -1 +1 @@
|
||||||
__all__ = ['testaction', 'blockaction', 'writeaction']
|
__all__ = ['testaction', 'mattermost']
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from jinja2.sandbox import SandboxedEnvironment
|
||||||
|
|
||||||
|
default_template = """
|
||||||
|
# Tutorial: How to use jinja2 templating
|
||||||
|
|
||||||
|
:warning: For these examples, we consider the module received data under the MISP core format
|
||||||
|
|
||||||
|
1. You can use the dot `.` notation or the subscript syntax `[]` to access attributes of a variable
|
||||||
|
- `{% raw %}{{ Event.info }}{% endraw %}` -> {{ Event.info }}
|
||||||
|
- `{% raw %}{{ Event['info'] }}{% endraw %}` -> {{ Event['info'] }}
|
||||||
|
|
||||||
|
2. Jinja2 allows you to easily create list:
|
||||||
|
```{% raw %}
|
||||||
|
{% for attribute in Event.Attribute %}
|
||||||
|
- {{ attribute.value }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endraw %}```
|
||||||
|
|
||||||
|
Gives:
|
||||||
|
{% for attribute in Event.Attribute %}
|
||||||
|
- {{ attribute.value }}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
3. Jinja2 allows you to add logic
|
||||||
|
```{% raw %}
|
||||||
|
{% if "tlp:white" in Event.Tag %}
|
||||||
|
- This Event has the TLP:WHITE tag
|
||||||
|
{% else %}
|
||||||
|
- This Event doesn't have the TLP:WHITE tag
|
||||||
|
{% endif %}
|
||||||
|
{% endraw %}```
|
||||||
|
|
||||||
|
Gives:
|
||||||
|
{% if "tlp:white" in Event.Tag %}
|
||||||
|
- This Event has the TLP:WHITE tag
|
||||||
|
{% else %}
|
||||||
|
- This Event doesn't have the TLP:WHITE tag
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
## Jinja2 allows you to modify variables by using filters
|
||||||
|
|
||||||
|
3. The `reverse` filter
|
||||||
|
- `{% raw %}{{ Event.info | reverse }}{% endraw %}` -> {{ Event.info | reverse }}
|
||||||
|
|
||||||
|
4. The `format` filter
|
||||||
|
- `{% raw %}{{ "%s :: %s" | format(Event.Attribute[0].type, Event.Attribute[0].value) }}{% endraw %}` -> {{ "%s :: %s" | format(Event.Attribute[0].type, Event.Attribute[0].value) }}
|
||||||
|
|
||||||
|
5.The `groupby` filter
|
||||||
|
```{% raw %}
|
||||||
|
{% for type, attributes in Event.Attribute|groupby("type") %}
|
||||||
|
- {{ type }}{% for attribute in attributes %}
|
||||||
|
- {{ attribute.value }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endraw %}```
|
||||||
|
|
||||||
|
Gives:
|
||||||
|
{% for type, attributes in Event.Attribute|groupby("type") %}
|
||||||
|
- {{ type }}{% for attribute in attributes %}
|
||||||
|
- {{ attribute.value }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def renderTemplate(data, template=default_template):
|
||||||
|
env = SandboxedEnvironment()
|
||||||
|
return env.from_string(template).render(data)
|
|
@ -1,63 +0,0 @@
|
||||||
import json
|
|
||||||
import base64
|
|
||||||
|
|
||||||
misperrors = {'error': 'Error'}
|
|
||||||
|
|
||||||
# config fields that your code expects from the site admin
|
|
||||||
moduleconfig = {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
# blocking modules break the exection of the chain of actions (such as publishing)
|
|
||||||
blocking = True
|
|
||||||
|
|
||||||
# returns either "boolean" or "data"
|
|
||||||
# Boolean is used to simply signal that the execution has finished.
|
|
||||||
# For blocking modules the actual boolean value determines whether we break execution
|
|
||||||
returns = 'boolean'
|
|
||||||
|
|
||||||
|
|
||||||
# the list of hook-points that it can hook
|
|
||||||
hooks = ['publish']
|
|
||||||
|
|
||||||
|
|
||||||
moduleinfo = {'version': '0.1', 'author': 'Andras Iklody',
|
|
||||||
'description': 'This module is merely a test, always returning true. Triggers on event publishing.',
|
|
||||||
'module-type': ['action']}
|
|
||||||
|
|
||||||
|
|
||||||
def handler(q=False):
|
|
||||||
if q is False:
|
|
||||||
return False
|
|
||||||
r = {"data": False, "error": "Barf."}
|
|
||||||
return r
|
|
||||||
|
|
||||||
|
|
||||||
def introspection():
|
|
||||||
modulesetup = {}
|
|
||||||
try:
|
|
||||||
responseType
|
|
||||||
modulesetup['responseType'] = responseType
|
|
||||||
except NameError:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
inputSource
|
|
||||||
modulesetup['resultType'] = resultType
|
|
||||||
except NameError:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
hooks
|
|
||||||
modulesetup['hooks'] = hooks
|
|
||||||
except NameError:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
hooks
|
|
||||||
modulesetup['blocking'] = blocking
|
|
||||||
except NameError:
|
|
||||||
pass
|
|
||||||
return modulesetup
|
|
||||||
|
|
||||||
|
|
||||||
def version():
|
|
||||||
moduleinfo['config'] = moduleconfig
|
|
||||||
return moduleinfo
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
import json
|
||||||
|
from mattermostdriver import Driver
|
||||||
|
from ._utils import utils
|
||||||
|
|
||||||
|
misperrors = {'error': 'Error'}
|
||||||
|
|
||||||
|
# config fields that your code expects from the site admin
|
||||||
|
moduleconfig = {
|
||||||
|
'params': {
|
||||||
|
'mattermost_hostname': {
|
||||||
|
'type': 'string',
|
||||||
|
'description': 'The Mattermost domain',
|
||||||
|
'value': 'example.mattermost.com',
|
||||||
|
},
|
||||||
|
'bot_access_token': {
|
||||||
|
'type': 'string',
|
||||||
|
'description': 'Access token generated when you created the bot account',
|
||||||
|
},
|
||||||
|
'channel_id': {
|
||||||
|
'type': 'string',
|
||||||
|
'description': 'The channel you added the bot to',
|
||||||
|
},
|
||||||
|
'message_template': {
|
||||||
|
'type': 'large_string',
|
||||||
|
'description': 'The template to be used to generate the message to be posted',
|
||||||
|
'value': 'The **template** will be rendered using *Jinja2*!',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
# Blocking modules break the exection of the current of action
|
||||||
|
'blocking': False,
|
||||||
|
# Indicates whether parts of the data passed to this module should be filtered. Filtered data can be found under the `filteredItems` key
|
||||||
|
'support_filters': True,
|
||||||
|
# Indicates whether the data passed to this module should be compliant with the MISP core format
|
||||||
|
'expect_misp_core_format': False,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# returns either "boolean" or "data"
|
||||||
|
# Boolean is used to simply signal that the execution has finished.
|
||||||
|
# For blocking modules the actual boolean value determines whether we break execution
|
||||||
|
returns = 'boolean'
|
||||||
|
|
||||||
|
moduleinfo = {'version': '0.1', 'author': 'Sami Mokaddem',
|
||||||
|
'description': 'Simplistic module to send message to a Mattermost channel.',
|
||||||
|
'module-type': ['action']}
|
||||||
|
|
||||||
|
|
||||||
|
def createPost(request):
|
||||||
|
params = request['params']
|
||||||
|
mm = Driver({
|
||||||
|
'url': params['mattermost_hostname'],
|
||||||
|
'token': params['bot_access_token'],
|
||||||
|
'scheme': 'https',
|
||||||
|
'basepath': '/api/v4',
|
||||||
|
'port': 443,
|
||||||
|
})
|
||||||
|
mm.login()
|
||||||
|
|
||||||
|
data = {}
|
||||||
|
if 'matchingData' in request:
|
||||||
|
data = request['matchingData']
|
||||||
|
else:
|
||||||
|
data = request['data']
|
||||||
|
|
||||||
|
if params['message_template']:
|
||||||
|
message = utils.renderTemplate(data, params['message_template'])
|
||||||
|
else:
|
||||||
|
message = '```\n{}\n```'.format(json.dumps(data))
|
||||||
|
|
||||||
|
mm.posts.create_post(options={
|
||||||
|
'channel_id': params['channel_id'],
|
||||||
|
'message': message
|
||||||
|
})
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def handler(q=False):
|
||||||
|
if q is False:
|
||||||
|
return False
|
||||||
|
request = json.loads(q)
|
||||||
|
createPost(request)
|
||||||
|
r = {"data": True}
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def introspection():
|
||||||
|
modulesetup = {}
|
||||||
|
try:
|
||||||
|
modulesetup['config'] = moduleconfig
|
||||||
|
except NameError:
|
||||||
|
pass
|
||||||
|
return modulesetup
|
||||||
|
|
||||||
|
|
||||||
|
def version():
|
||||||
|
moduleinfo['config'] = moduleconfig
|
||||||
|
return moduleinfo
|
|
@ -1,34 +1,36 @@
|
||||||
import json
|
import json
|
||||||
import base64
|
from ._utils import utils
|
||||||
|
|
||||||
misperrors = {'error': 'Error'}
|
misperrors = {'error': 'Error'}
|
||||||
|
|
||||||
# config fields that your code expects from the site admin
|
# config fields that your code expects from the site admin
|
||||||
moduleconfig = {
|
moduleconfig = {
|
||||||
'foo': {
|
'params': {
|
||||||
'type': 'string',
|
'foo': {
|
||||||
'description': 'blablabla',
|
'type': 'string',
|
||||||
'value': 'xyz'
|
'description': 'blablabla',
|
||||||
|
'value': 'xyz'
|
||||||
|
},
|
||||||
|
'Data extraction path': {
|
||||||
|
# Extracted data can be found under the `matchingData` key
|
||||||
|
'type': 'hash_path',
|
||||||
|
'description': 'Only post content extracted from this path',
|
||||||
|
'value': 'Attribute.{n}.AttributeTag.{n}.Tag.name',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'bar': {
|
# Blocking modules break the exection of the current of action
|
||||||
'type': 'string',
|
'blocking': False,
|
||||||
'value': 'meh'
|
# Indicates whether parts of the data passed to this module should be extracted. Extracted data can be found under the `filteredItems` key
|
||||||
}
|
'support_filters': False,
|
||||||
};
|
# Indicates whether the data passed to this module should be compliant with the MISP core format
|
||||||
|
'expect_misp_core_format': False,
|
||||||
# blocking modules break the exection of the chain of actions (such as publishing)
|
}
|
||||||
blocking = False
|
|
||||||
|
|
||||||
# returns either "boolean" or "data"
|
# returns either "boolean" or "data"
|
||||||
# Boolean is used to simply signal that the execution has finished.
|
# Boolean is used to simply signal that the execution has finished.
|
||||||
# For blocking modules the actual boolean value determines whether we break execution
|
# For blocking modules the actual boolean value determines whether we break execution
|
||||||
returns = 'boolean'
|
returns = 'boolean'
|
||||||
|
|
||||||
|
|
||||||
# the list of hook-points that it can hook
|
|
||||||
hooks = ['publish']
|
|
||||||
|
|
||||||
|
|
||||||
moduleinfo = {'version': '0.1', 'author': 'Andras Iklody',
|
moduleinfo = {'version': '0.1', 'author': 'Andras Iklody',
|
||||||
'description': 'This module is merely a test, always returning true. Triggers on event publishing.',
|
'description': 'This module is merely a test, always returning true. Triggers on event publishing.',
|
||||||
'module-type': ['action']}
|
'module-type': ['action']}
|
||||||
|
@ -37,33 +39,16 @@ moduleinfo = {'version': '0.1', 'author': 'Andras Iklody',
|
||||||
def handler(q=False):
|
def handler(q=False):
|
||||||
if q is False:
|
if q is False:
|
||||||
return False
|
return False
|
||||||
r = True
|
request = json.loads(q) # noqa
|
||||||
result = json.loads(q) # noqa
|
success = True
|
||||||
output = '' # Insert your magic here!
|
r = {"data": success}
|
||||||
r = {"data": r}
|
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
def introspection():
|
def introspection():
|
||||||
modulesetup = {}
|
modulesetup = {}
|
||||||
try:
|
try:
|
||||||
responseType
|
modulesetup['config'] = moduleconfig
|
||||||
modulesetup['responseType'] = responseType
|
|
||||||
except NameError:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
inputSource
|
|
||||||
modulesetup['resultType'] = resultType
|
|
||||||
except NameError:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
hooks
|
|
||||||
modulesetup['hooks'] = hooks
|
|
||||||
except NameError:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
hooks
|
|
||||||
modulesetup['blocking'] = blocking
|
|
||||||
except NameError:
|
except NameError:
|
||||||
pass
|
pass
|
||||||
return modulesetup
|
return modulesetup
|
||||||
|
|
|
@ -1,68 +0,0 @@
|
||||||
import json
|
|
||||||
import base64
|
|
||||||
|
|
||||||
misperrors = {'error': 'Error'}
|
|
||||||
|
|
||||||
# config fields that your code expects from the site admin
|
|
||||||
moduleconfig = {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
# blocking modules break the exection of the chain of actions (such as publishing)
|
|
||||||
blocking = False
|
|
||||||
|
|
||||||
# returns either "boolean" or "data"
|
|
||||||
# Boolean is used to simply signal that the execution has finished.
|
|
||||||
# For blocking modules the actual boolean value determines whether we break execution
|
|
||||||
returns = 'boolean'
|
|
||||||
|
|
||||||
|
|
||||||
# the list of hook-points that it can hook
|
|
||||||
hooks = ['publish']
|
|
||||||
|
|
||||||
|
|
||||||
moduleinfo = {'version': '0.1', 'author': 'Andras Iklody',
|
|
||||||
'description': 'This module is merely a test, writing a tmp file with the event info.',
|
|
||||||
'module-type': ['action']}
|
|
||||||
|
|
||||||
|
|
||||||
def handler(q=False):
|
|
||||||
if q is False:
|
|
||||||
return False
|
|
||||||
request = json.loads(q)
|
|
||||||
data = request["data"]
|
|
||||||
f = open("/var/www/MISP7/app/tmp/output.txt","w+")
|
|
||||||
f.write(data["Event"]["info"])
|
|
||||||
f.close()
|
|
||||||
r = {"data": True}
|
|
||||||
return r
|
|
||||||
|
|
||||||
|
|
||||||
def introspection():
|
|
||||||
modulesetup = {}
|
|
||||||
try:
|
|
||||||
responseType
|
|
||||||
modulesetup['responseType'] = responseType
|
|
||||||
except NameError:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
inputSource
|
|
||||||
modulesetup['resultType'] = resultType
|
|
||||||
except NameError:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
hooks
|
|
||||||
modulesetup['hooks'] = hooks
|
|
||||||
except NameError:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
hooks
|
|
||||||
modulesetup['blocking'] = blocking
|
|
||||||
except NameError:
|
|
||||||
pass
|
|
||||||
return modulesetup
|
|
||||||
|
|
||||||
|
|
||||||
def version():
|
|
||||||
moduleinfo['config'] = moduleconfig
|
|
||||||
return moduleinfo
|
|
Loading…
Reference in New Issue