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

DomainTools Expert Bot (initial version) #1004

Draft
wants to merge 5 commits into
base: develop
Choose a base branch
from
Draft
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
8 changes: 8 additions & 0 deletions intelmq/bots/BOTS
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,14 @@
"redis_cache_ttl": "86400"
}
},
"Domaintools": {
"description": "Domaintools expert is a bot which queries domaintools.com for a scoring of a domain name",
"module": "intelmq.bots.experts.domaintools.expert",
"parameters": {
"user": "",
"password": ""
}
},
"Field Reducer": {
"description": "The field reducer bot is capable of removing fields from events.",
"module": "intelmq.bots.experts.field_reducer.expert",
Expand Down
13 changes: 13 additions & 0 deletions intelmq/bots/experts/domaintools/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Domaintools expert

This expert bot is an example on how to query domaintools.

It does require an API from domaintools.

Documentation on domaintools: https://www.domaintools.com/resources/api-documentation/
Specifically, this bot can query a domain for the reputation score in domaintools: https://www.domaintools.com/resources/api-documentation/reputation/

It will add the score in the extra field: ``extra.domaintools_score``.


Authors: Juan Ortega Valiente, Aaron Kaplan
1 change: 1 addition & 0 deletions intelmq/bots/experts/domaintools/REQUIREMENTS.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
domaintools_api==0.1.7
Empty file.
75 changes: 75 additions & 0 deletions intelmq/bots/experts/domaintools/expert.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
"""
domaintools expert: query domtaintools.com to get a reputation score for a domain name

"""
from intelmq.lib.bot import Bot
try:
from domaintools import API, exceptions
except ImportError:
API = None


class DomaintoolsExpertBot(Bot):

def init(self):
self.logger.info("Loading Domaintools expert.")

if not API:
raise ValueError("need to have the domaintools API installed. See https://github.com/domaintools/python_api.")

if not self.parameters.user:
raise ValueError("need to specify user for domaintools expert in runtime.conf.")

if not self.parameters.password:
raise ValueError("need to specify password for the user for domaintools expert in runtime.conf.")

self.api = API(self.parameters.user, self.parameters.password)

if not self.valid_credentials():
raise ValueError("invalid credentials found in runtime.conf.")

def valid_credentials(self):
resp = self.api.reputation(fqdn, include_reasons=False)
try:
resp['risk_score']
return True
except exceptions.NotAuthorizedException:
return False

def get_score(self, fqdn):
# don't include a reason in the JSON response
resp = self.api.reputation(fqdn, include_reasons=False)

try:
score = resp['risk_score']
except exceptions.NotFoundException:
score = None
except exceptions.BadRequestException:
raise

return score

def process(self):
event = self.receive_message()
extra = {}

for key in ["source.", "destination."]:
key_fqdn = key + "fqdn"

if key_fqdn not in event:
continue

score = self.get_score(event.get(key_fqdn))

if score:
extra["domaintools_score_" + key_fqdn] = score

extra.update(event.get("extra"))
event.update("extra", extra)

self.send_message(event)
self.acknowledge_message()


BOT = DomaintoolsExpertBot
Empty file.
49 changes: 49 additions & 0 deletions intelmq/tests/bots/experts/domaintools/test_expert.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# -*- coding: utf-8 -*-
"""
Testing GethostbynameExpertBot.
"""

import unittest

import intelmq.lib.test as test
from intelmq.bots.experts.domaintools.expert import DomaintoolsExpertBot

EXAMPLE_INPUT = {"__type": "Event",
"source.fqdn": "google.com",
"time.observation": "2015-01-01T00:00:00+00:00"
}
EXAMPLE_OUTPUT = {"__type": "Event",
"source.fqdn": "google.com",
"extra": '{"domaintools_score": 0}',
"time.observation": "2015-01-01T00:00:00+00:00"
}
NONEXISTING_INPUT = {"__type": "Event",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually the lib raises the BadRequestException for this test which is not equivalent to 'not existing', but the result is similar.

"source.fqdn": "example.invalid",
"destination.fqdn": "example.invalid",
"time.observation": "2015-01-01T00:00:00+00:00"
}


@test.skip_internet()
class TestDomaintoolsExpertBot(test.BotTestCase, unittest.TestCase):
"""
A TestCase for DomaintoolsExpertBot.
"""

@classmethod
def set_bot(self):
self.bot_reference = DomaintoolsExpertBot
self.sysconfig = {'user': 'example01', 'password': 'mysecret'}

def test_existing(self):
self.input_message = EXAMPLE_INPUT
self.run_bot()
self.assertMessageEqual(0, EXAMPLE_OUTPUT)

def test_non_existing(self):
self.input_message = NONEXISTING_INPUT
self.run_bot()
self.assertMessageEqual(0, NONEXISTING_INPUT)

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