add: scan module with multithreading and async scans.

add: new requirements
add: default action for modules
add: banner
fix: set log level
fix: cmd boolean args handler
fix: log messages
fix: metavar: __name__ -> __tool_name__
This commit is contained in:
cr0hn
2016-02-23 14:24:21 +01:00
parent 369a97089d
commit 6137fb3558
13 changed files with 717 additions and 338 deletions

763
.idea/workspace.xml generated

File diff suppressed because it is too large Load Diff

View File

@@ -29,9 +29,9 @@ def run_console(config):
if not isinstance(config, GlobalExecutionParameters):
raise TypeError("Expected GlobalParameters, got '%s' instead" % type(config))
logging.warning("Starting Enteletaor execution")
logging.error("Starting Enteletaor execution")
run(config)
logging.warning("Done!")
logging.error("Done!")
# ----------------------------------------------------------------------

View File

@@ -1,9 +1,39 @@
# -*- coding: utf-8 -*-
__name__ = "enteletaor"
__tool_name__ = "enteletaor"
__author__ = "Daniel Garcia (cr0hn) - @ggdaniel"
__site__ = "https://github.com/cr0hn/enteletaor"
__version__ = "1.0.0"
__banner__ = """
``
`````..``
``..-:::::--.```...----`
````...---:://////:--.--::::.
````...--::://///////::::://-``` ``
`.--:////////////////////////-``````
.-///////////:::/:://///:///////-.....
`.::///////////:////////:///://+///:...--.
`--:::::///:::////////////////://////------
`.-----:///:://////:--..--://///://///::::::
`.....-:////////+/:-.` ``-:///:/::///////-
``````-//////::++/:.` `.://///:///////`
```-/+/////:+++/-.` `.-////://+//+/-```
`//////::/+///:.` `.:///::/+////-``````
-///////:://///:-`` `.-://////////:-.....`
:::::://///://///:------://////::///:-----.`
------//////:////////////////:::///:::::--`
.--.../+//+//:///:////////:///////////::.`
..`..-/+/////:////::://///++++++++//-.
``````:++////////////////++++//:--.`
`` ```:///:::://///////:::--...````
./:::--.--://////::---...````
`----...```.--::::--..``
``..`````
``
____ _ _ ___ ____ _ ____ ___ ____ ____ ____
|___ |\ | | |___ | |___ | |__| | | |__/
|___ | \| | |___ |___ |___ | | | |__| | \\
"""
# --------------------------------------------------------------------------
# Generic global config

View File

@@ -4,7 +4,7 @@ import logging
__tool__ = "enteletaor"
log = logging.getLogger(__name__)
log = logging.getLogger()
# ----------------------------------------------------------------------

View File

@@ -0,0 +1 @@
# -*- coding: utf-8 -*-

View File

@@ -0,0 +1,63 @@
#!/usr/bin/env python
#
# Fork of:
#
# https://github.com/UndergroundLabs/ripe-inetnum-search
#
import six
import json
import netaddr
import requests
import logging
# ----------------------------------------------------------------------
def get_inet_num(search_term):
"""
Get intetnums for a domain
:param search_term: keywork without dots, no domains are allowed. domain.com -> invalid |---| domain -> valid
:type search_term: str
:return: iterable with IP/CIDR notation or None
:rtype: list(str) | None
"""
# Disable request logging
requests_log = logging.getLogger("requests")
requests_log.addHandler(logging.NullHandler())
requests_log.propagate = False
# Search the RIPE database
# There is an issue with RIPE. When making a request and including
# the type-filter inetnum, the JSON response also includes other types.
request = requests.get('http://rest.db.ripe.net/search.json', params={
'query-string': search_term,
'type-filter': 'inetnum'
})
json_results = json.loads(request.text)
try:
# Filter any object that doesn't have the type 'inetnum'
ranges = [x['primary-key']['attribute'][0]['value']
for x in json_results['objects']['object']
if x['type'] == 'inetnum']
except KeyError:
return None
# Turn the IP range string into CIDR
cidrs = []
for _range in ranges:
_range = _range.split(' - ');
cidrs.append(netaddr.iprange_to_cidrs(_range[0], _range[1]))
results = set()
# Print the CIDR's
for cidr in cidrs:
results.add(str(cidr[0]))
return results

View File

@@ -6,6 +6,7 @@ import argparse as _argparse
from .structs import AppSettings
from ...modules import IModule
from ...config import __banner__
from ...data import GlobalExecutionParameters
log = logging.getLogger()
@@ -80,7 +81,7 @@ def build_arg_parser(config=None, modules=None, parser=None):
# Build command line
# --------------------------------------------------------------------------
if parser is None:
parser = STBArgumentParser(description='%s' % str(AppSettings.tool_name).capitalize(),
parser = STBArgumentParser(description='%s' % __banner__,
epilog=_build_examples(modules),
formatter_class=_argparse.RawTextHelpFormatter)
_extract_parameters(config, parser)
@@ -96,26 +97,39 @@ def build_arg_parser(config=None, modules=None, parser=None):
mod_parser = main_subparser.add_parser(mod_class.name,
help=mod_class.description)
sub_modules_enabled = False
# If module has raw argsubparser, add it
if hasattr(mod_class, "__submodules__"):
sub_module_actions = mod_parser.add_subparsers(help="%s commands:" % mod_name, dest="module_%s" % mod_name)
sub_module_actions.required = True
if len([x for x in mod_class.__submodules__ if x != "default"]) > 0:
for x, y in six.iteritems(mod_class.__submodules__):
sub_help = y['help']
sub_action = y.get('cmd_args', None)
# New sub-module added
sub_modules_enabled = True
sub_sub_parser = sub_module_actions.add_parser(x, help=sub_help)
sub_module_actions = mod_parser.add_subparsers(help="%s commands:" % mod_name, dest="module_%s" % mod_name)
sub_module_actions.required = True
# Add module parameters
if hasattr(mod_class, "__model__"):
_extract_parameters(mod_class.__model__(), sub_sub_parser, mod_name)
for x, y in six.iteritems(mod_class.__submodules__):
if sub_action is not None:
# Add sub parser
sub_action(sub_sub_parser)
else:
# Skip default action info
if x == "default":
continue
sub_help = y['help']
sub_action = y.get('cmd_args', None)
sub_sub_parser = sub_module_actions.add_parser(x, help=sub_help)
# Add module parameters
if hasattr(mod_class, "__model__"):
_extract_parameters(mod_class.__model__(), sub_sub_parser, mod_name)
if sub_action is not None:
# Add sub parser
sub_action(sub_sub_parser)
if sub_modules_enabled is False:
# Add module parameters
if hasattr(mod_class, "__model__"):
_extract_parameters(mod_class.__model__(), mod_parser, mod_name)
@@ -210,7 +224,7 @@ def _resolve_action(field):
'StringField': ("store", str),
'SelectField': ("store", str),
'IntegerField': ("store", int),
'BoolField': ("store_true", bool),
'BoolField': ("store_true", None),
'IncrementalIntegerField': ("count", None)
}
@@ -218,8 +232,5 @@ def _resolve_action(field):
results = type_maps[in_type]
if in_type == "BoolField":
results[0] = "store_%s" % str(field.default).lower()
return results

View File

@@ -22,13 +22,13 @@ def load_config():
"""
try:
from config import __author__, __name__, __site__, __version__
from config import __author__, __tool_name__, __site__, __version__
except ImportError:
__author__ = __name__ = __site__ = __version__ = "unknown"
from .structs import AppSettings
AppSettings.author = __author__
AppSettings.tool_name = __name__
AppSettings.tool_name = __tool_name__
AppSettings.project_site = __site__
AppSettings.version = __version__

View File

@@ -11,17 +11,17 @@ def setup_logging():
"""
Setup initial logging configuration
"""
from ...config import __name__, DEBUG_LEVEL
from ...config import __tool_name__, DEBUG_LEVEL
# Init logger
logger = logging.getLogger('')
logger = logging.getLogger()
# Set log level
logger.setLevel(abs(DEBUG_LEVEL * 10) % 50)
logger.setLevel(abs(50 - (DEBUG_LEVEL if DEBUG_LEVEL < 5 else 5) * 10))
# Set file log format
file_format = logging.Formatter('[%(levelname)s] %(asctime)s - %(message)s', "%Y-%m-%d %H:%M:%S")
log_file = logging.FileHandler(filename="%s.log" % __name__)
log_file = logging.FileHandler(filename="%s.log" % __tool_name__)
log_file.setFormatter(file_format)
# Handler: console

View File

@@ -25,4 +25,5 @@ def set_log_level(parsed_args):
"""
if hasattr(parsed_args, "verbosity"):
log.setLevel(abs(parsed_args.verbosity * 10) % 50)
# log.setLevel(abs(50 - (parsed_args.verbosity * 10)))
log.setLevel(abs(50 - ((parsed_args.verbosity if parsed_args.verbosity < 5 else 5) * 10)))

View File

@@ -14,7 +14,10 @@ class IModule:
def run(self, module_config):
if hasattr(self, "__submodules__"):
self.__submodules__[module_config.sub_action]['action'](module_config)
try:
self.__submodules__[module_config.sub_action]['action'](module_config)
except KeyError:
self.__submodules__["default"]['action'](module_config)
else:
raise NotImplemented("Run method must be override")

View File

@@ -0,0 +1,113 @@
# -*- coding: utf-8 -*-
"""
This file contains monkey patches for
"""
from __future__ import absolute_import
def new_transport_init(self, host, connect_timeout):
import errno
import re
import socket
import ssl
# Jython does not have this attribute
try:
from socket import SOL_TCP
except ImportError: # pragma: no cover
from socket import IPPROTO_TCP as SOL_TCP # noqa
try:
from ssl import SSLError
except ImportError:
class SSLError(Exception): # noqa
pass
from struct import pack, unpack
from amqp.exceptions import UnexpectedFrame
from amqp.utils import get_errno, set_cloexec
_UNAVAIL = errno.EAGAIN, errno.EINTR, errno.ENOENT
AMQP_PORT = 5672
EMPTY_BUFFER = bytes()
# Yes, Advanced Message Queuing Protocol Protocol is redundant
AMQP_PROTOCOL_HEADER = 'AMQP\x01\x01\x00\x09'.encode('latin_1')
# Match things like: [fe80::1]:5432, from RFC 2732
IPV6_LITERAL = re.compile(r'\[([\.0-9a-f:]+)\](?::(\d+))?')
# --------------------------------------------------------------------------
# __init__ content:
# --------------------------------------------------------------------------
self.connected = True
msg = None
port = AMQP_PORT
m = IPV6_LITERAL.match(host)
if m:
host = m.group(1)
if m.group(2):
port = int(m.group(2))
else:
if ':' in host:
host, port = host.rsplit(':', 1)
port = int(port)
self.sock = None
last_err = None
for res in socket.getaddrinfo(host, port, 0,
socket.SOCK_STREAM, SOL_TCP):
af, socktype, proto, canonname, sa = res
try:
self.sock = socket.socket(af, socktype, proto)
try:
set_cloexec(self.sock, True)
except NotImplementedError:
pass
self.sock.settimeout(connect_timeout)
self.sock.connect(sa)
except socket.error as exc:
msg = exc
self.sock.close()
self.sock = None
last_err = msg
continue
break
if not self.sock:
# Didn't connect, return the most recent error message
raise socket.error(last_err)
try:
# self.sock.settimeout(None)
self.sock.setsockopt(SOL_TCP, socket.TCP_NODELAY, 1)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
self._setup_transport()
self._write(AMQP_PROTOCOL_HEADER)
except (OSError, IOError, socket.error) as exc:
if get_errno(exc) not in _UNAVAIL:
self.connected = False
raise
# --------------------------------------------------------------------------
# amqlib
# --------------------------------------------------------------------------
def patch_transport():
"""
This function path transport constructor to fix timeout in sockets
"""
from amqp.transport import _AbstractTransport
_AbstractTransport.__init__ = new_transport_init

View File

@@ -1,9 +1,17 @@
six
flask
wtforms
eventlet
colorlog
ipaddress
# MQ/Brokers requirements
redis
kombu
celery
kombu
pyzmq
amqp
# contrib dependencies
requests
netaddr