Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shadowserver Accessible Cisco Smart Install with tests and docs #1122

Merged
2 commits merged into from Nov 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ CHANGELOG
### Bots
#### Parsers
- Modify Bot default ruleset: changed conficker rule to catch more spellings
- Shadowserver Parser: Add Accessible Cisco Smart Install

### Documentation

Expand Down
1 change: 1 addition & 0 deletions intelmq/bots/parsers/shadowserver/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ E.g. `Botnet-Drone-Hadoop` for the feed corresponding to:
https://www.shadowserver.org/wiki/pmwiki.php/Services/Botnet-Drone-Hadoop

Possible feednames:
* `Accessible-Cisco-Smart-Install`
* `Accessible-CWMP`
* `Accessible-RDP`
* `Accessible-Telnet`
Expand Down
25 changes: 25 additions & 0 deletions intelmq/bots/parsers/shadowserver/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
def get_feed(feedname):
# TODO should this be case insensitive?
feed_idx = {
"Accessible-Cisco-Smart-Install": accessible_cisco_smart_install,
"Accessible-CWMP": accessible_cwmp,
"Accessible-RDP": accessible_rdp,
"Accessible-SMB": accessible_smb,
Expand Down Expand Up @@ -1338,3 +1339,27 @@ def validate_fqdn(value):
'classification.identifier': 'accessiblevnc',
}
}

accessible_cisco_smart_install = {
'required_fields': [
('time.source', 'timestamp', add_UTC_to_timestamp),
('source.ip', 'ip'),
('source.port', 'port'),
],
'optional_fields': [
('protocol.transport', 'protocol'),
('source.reverse_dns', 'hostname'),
# ('classification.identifier', 'tag'), # This will be 'accessible-cisco-smart-install' in constant fields
('source.asn', 'asn'),
('source.geolocation.cc', 'geo'),
('source.geolocation.region', 'region'),
('source.geolocation.city', 'city'),
('extra.', 'naics', invalidate_zero),
('extra.', 'sic', invalidate_zero),
],
'constant_fields': {
'protocol.application': 'cisco-smart-install',
'classification.type': 'vulnerable service',
'classification.identifier': 'accessible-cisco-smart-install',
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"timestamp","ip","protocol","port","hostname","tag","asn","geo","region","city","naics","sic"
"2017-11-18 08:42:45","198.51.100.103","tcp","4786","198-51-100-103.example.net","cisco-smart-install","8559","AT","WIEN","VIENNA","0","0"
"2017-11-18 08:47:54","198.51.100.218","tcp","4786","","cisco-smart-install","35609","AT","WIEN","VIENNA","0","0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"timestamp","ip","protocol","port","hostname","tag","asn","geo","region","city","naics","sic"
"2017-11-18 08:42:45","198.51.100.103","tcp",4786,"198-51-100-103.example.net","cisco-smart-install",8559,"AT","WIEN","VIENNA",0,0
"2017-11-18 08:47:54","198.51.100.218","tcp",4786,,"cisco-smart-install",35609,"AT","WIEN","VIENNA",0,0
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# -*- coding: utf-8 -*-

import os
import unittest

import intelmq.lib.test as test
import intelmq.lib.utils as utils
from intelmq.bots.parsers.shadowserver.parser import ShadowserverParserBot

with open(os.path.join(os.path.dirname(__file__), 'accessible-cisco-smart-install.csv')) as handle:
EXAMPLE_FILE = handle.read()
EXAMPLE_LINES = EXAMPLE_FILE.splitlines()

with open(os.path.join(os.path.dirname(__file__),
'accessible-cisco-smart-install-reconstructed.csv')) as handle:
RECONSTRUCTED_FILE = handle.read()
RECONSTRUCTED_LINES = RECONSTRUCTED_FILE.splitlines()

EXAMPLE_REPORT = {"feed.name": "ShadowServer Accessible Cisco Smart Install",
"raw": utils.base64_encode(EXAMPLE_FILE),
"__type": "Report",
"time.observation": "2015-01-01T00:00:00+00:00",
}
EVENTS = [{'__type': 'Event',
'feed.name': 'ShadowServer Accessible Cisco Smart Install',
'classification.identifier': 'accessible-cisco-smart-install',
'classification.type': 'vulnerable service',
'protocol.application': 'cisco-smart-install',
'protocol.transport': 'tcp',
'raw': utils.base64_encode('\n'.join([RECONSTRUCTED_LINES[0],
RECONSTRUCTED_LINES[1], ''])),
'source.asn': 8559,
'source.geolocation.cc': 'AT',
'source.geolocation.city': 'VIENNA',
'source.geolocation.region': 'WIEN',
'source.ip': '198.51.100.103',
'source.port': 4786,
'extra': '{"tag": "cisco-smart-install"}',
'source.reverse_dns': '198-51-100-103.example.net',
'time.observation': '2015-01-01T00:00:00+00:00',
'time.source': '2017-11-18T08:42:45+00:00'},
{'__type': 'Event',
'feed.name': 'ShadowServer Accessible Cisco Smart Install',
'classification.identifier': 'accessible-cisco-smart-install',
'classification.type': 'vulnerable service',
'protocol.application': 'cisco-smart-install',
'protocol.transport': 'tcp',
'raw': utils.base64_encode('\n'.join([RECONSTRUCTED_LINES[0],
RECONSTRUCTED_LINES[2], ''])),
'source.asn': 35609,
'source.geolocation.cc': 'AT',
'source.geolocation.city': 'VIENNA',
'source.geolocation.region': 'WIEN',
'source.ip': '198.51.100.218',
'source.port': 4786,
'extra': '{"tag": "cisco-smart-install"}',
'time.observation': '2015-01-01T00:00:00+00:00',
'time.source': '2017-11-18T08:47:54+00:00'},
]


class TestShadowserverParserBot(test.BotTestCase, unittest.TestCase):
"""
A TestCase for a ShadowserverParserBot.
"""

@classmethod
def set_bot(cls):
cls.bot_reference = ShadowserverParserBot
cls.default_input_message = EXAMPLE_REPORT
cls.sysconfig = {'feedname': 'Accessible-Cisco-Smart-Install'}

def test_event(self):
""" Test if correct Event has been produced. """
self.run_bot()
for i, EVENT in enumerate(EVENTS):
self.assertMessageEqual(i, EVENT)


if __name__ == '__main__': # pragma: no cover
unittest.main()