Permalink
Browse files

ENH: contrib: malware name mapping: custom rules

  • Loading branch information...
wagner-certat committed Jan 31, 2019
1 parent 28b70d6 commit 38b89834bd786e5fb7ca76b8ff4dff92faeb21ba
Showing with 58 additions and 13 deletions.
  1. +3 −1 CHANGELOG.md
  2. +11 −0 contrib/malware_name_mapping/README.md
  3. +44 −12 contrib/malware_name_mapping/download_mapping.py
@@ -62,7 +62,9 @@ CHANGELOG
- `intelmqdump`: Inspecting dumps locks the dump file using unix file locks (#574).

### Contrib
* `malware_name_mapping`: Added the script `apply_mapping_eventdb.py` to apply the mapping to an eventdb.
- `malware_name_mapping`:
- Added the script `apply_mapping_eventdb.py` to apply the mapping to an eventdb.
- Possibility to add local rules using the download tool.

### Known issues

@@ -23,6 +23,17 @@ A default rule can optionally be added the the end of the rules with the `-d` fl
With this rule, the field `classification.identifier` is set to `malware.name` if the first is empty and the latter is not.
As this is the last rule, it is kind of "last resort" to fill the identifier field.

### Local rules

Additional arbitrary mappings can be added with parameters to the download tool using the `-e` (expression) and `-i` (identifier) flags:
```
-e "^some-expression$" -i "some-identifier"
```
and multiple ones:
```
-e "^some-expression$" -i "some-identifier" -e "^other-expression$" -i "other-identifier"
```

Modify Bot
----------

@@ -11,33 +11,54 @@
import requests
import sys

from typing import Optional


URL = 'https://raw.githubusercontent.com/certtools/malware_name_mapping/master/mapping.csv'


def main(url: str=URL, add_default=False):
def none_len(arg: Optional[list]):
if arg:
return len(arg)
else:
return 0


def generate_rule(expression: str, identifier: str, name=None):
return {"rulename": name if name else "%s-%s" % (identifier,
hashlib.sha1(expression.encode()).hexdigest()[:10]),
"if": {"classification.taxonomy": "malicious code",
"malware.name": expression
},
"then": {"classification.identifier": identifier, }}


def main(url: str=URL, add_default=False, params=None):
download = requests.get(url)
download.raise_for_status()
rules = [{"rulename": "%s-%s" % (line[1], hashlib.sha1(line[0].encode()).hexdigest()[:10]),
"if": {"classification.taxonomy": "malicious code",
"malware.name": line[0]
},
"then": {"classification.identifier": line[1], }}
rules = [generate_rule(*line[:2])
for line in csv.reader(io.StringIO(download.text))]

if add_default:
rules.append(
{"rulename": "default",
"if": {"malware.name": ".*",
"classification.identifier": ""},
"then": {"classification.identifier": "{msg[malware.name]}", }})
rules.append(generate_rule(".*", "{msg[malware.name]}", name="default"))

if params:
rules.extend((generate_rule(rule[0][0], rule[1][0]) for rule in params))

return json.dumps(rules, indent=4, separators=(',', ': '))


if __name__ == '__main__':
parser = argparse.ArgumentParser(
prog='download_mapping',
description='Downloads malware family mapping and converts it to modify syntax.',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog='''
You can specify additional rules to be added to the file by using:
-e "^some-expression$" -i "some-identifier"
and multiple ones:
-e "^some-expression$" -i "some-identifier" -e "^other-expression$" -i "other-identifier"
'''
)

parser.add_argument('filename', nargs='?',
@@ -48,9 +69,20 @@ def main(url: str=URL, add_default=False):
parser.add_argument('--add-default', '-d',
help='Add a default rule to use the malware name as identifier.',
const=True, action='store_const')
parser.add_argument('--expression', '-e',
nargs=1, action='append',
help='Expression for an additional rule.')
parser.add_argument('--identifier', '-i',
nargs=1, action='append',
help='Identifier for an additional rule.')
args = parser.parse_args()

rules = main(url=args.url, add_default=args.add_default)
if none_len(args.expression) != none_len(args.identifier):
print('Additional rules must always consist of an expression and an identifier. '
'Got %d expressions and %d identifiers.' % (len(args.expression), len(args.identifier)),
file=sys.stderr)
exit(1)
rules = main(url=args.url, add_default=args.add_default, params=zip(args.expression, args.identifier))
if args.filename:
try:
with open(args.filename, 'wt') as output:

0 comments on commit 38b8983

Please sign in to comment.