Skip to content

Commit

Permalink
Made an initial push of input validation logic. It is functional at t…
Browse files Browse the repository at this point in the history
…his commit.
  • Loading branch information
lanmaster53 committed Oct 31, 2019
1 parent ade4da5 commit 8ca33f7
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 2 deletions.
26 changes: 24 additions & 2 deletions recon/core/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import yaml
# framework libs
from recon.core import framework
from recon.utils import validators

#=================================================
# MODULE CLASS
Expand Down Expand Up @@ -130,6 +131,26 @@ def hosts_to_domains(self, hosts, exclusions=[]):
del elements[0]
return domains

def _validate_input(self):
validator_type = self.meta.get('validator')
if not validator_type:
# passthru, no validator required
self.debug('No validator required.')
return
validator = None
validator_name = validator_type.capitalize() + 'Validator'
for obj in [self, validators]:
if hasattr(obj, validator_name):
validator = getattr(validators, validator_name)()
if not validator:
# passthru, no validator defined
self.debug('No validator defined.')
return
inputs = self._get_source(self.options['source'], self._default_source)
for _input in inputs:
validator.validate(_input)
self.debug('All inputs validated.')

#==================================================
# OPTIONS METHODS
#==================================================
Expand Down Expand Up @@ -278,8 +299,9 @@ def do_input(self, params):
self.output('Source option not available for this module.')

def run(self):
self._summary_counts = {}
self._validate_options()
self._validate_input()
self._summary_counts = {}
pre = self.module_pre()
params = [pre] if pre is not None else []
# provide input if a default query is specified in the module
Expand All @@ -302,7 +324,7 @@ def do_run(self, params):
except (Timeout, socket.timeout):
self.print_exception()
self.error('A request took too long to complete. If the issue persists, increase the global TIMEOUT option.')
except framework.FrameworkException:
except (framework.FrameworkException, validators.ValidationException):
self.print_exception()
except Exception:
self.print_exception()
Expand Down
63 changes: 63 additions & 0 deletions recon/utils/validators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import re


class ValidationException(Exception):
def __init__(self, input, validator):
Exception.__init__(self, f"Input failed {validator} validation: {input}")


class BaseValidator(object):

def __init__(self, regex, validator=None, flags=0):
if isinstance(regex, str):
self.match_object = re.compile(regex, flags)
else:
self.match_object = regex
self.validator = validator

def validate(self, value):
if self.match_object.match(value) is None:
raise ValidationException(value, self.validator)


class DomainValidator(BaseValidator):

def __init__(self):
regex = (
r"(?=^.{4,253}\.?$)(^((?!-)[a-zA-Z0-9-]{1,63}(?<!-)\.)+[a-zA-Z]{2,63}\.?$)"
)
super(DomainValidator, self).__init__(regex, 'domain')


class UrlValidator(BaseValidator):

def __init__(self):
regex = (
# {http,ftp}s:// (not required)
r"^((?:http|ftp)s?://)?"
# Domain
r"(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+"
r"(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|"
# Localhost
r"localhost|"
# IPv6 address
r"\[[a-f0-9:]+\]|"
# IPv4 address
r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})"
# Optional port
r"(?::\d+)?"
# Path
r"(?:/?|[/?]\S+)$"
)
super(UrlValidator, self).__init__(regex, 'url')


class EmailValidator(BaseValidator):

def __init__(self):
regex = (
r"^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9]"
r"(?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9]"
r"(?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$"
)
super(EmailValidator, self).__init__(regex, 'email')

0 comments on commit 8ca33f7

Please sign in to comment.