Fix: A lot of improvements in framework.
Add: 5 new attacks in redis module
This commit is contained in:
@@ -19,4 +19,4 @@ These attacks can be executed in all of brokers/MQ:
|
||||
#. Looking for sensible information (i.e. user/password)
|
||||
#. Remote command injection
|
||||
#. Listing remote process
|
||||
|
||||
#. Reject all messages stored in queues to avoid clients to receive them
|
||||
|
||||
@@ -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.warning("Starting Enteletaor execution")
|
||||
run(config)
|
||||
logging.warning("[*] Done!")
|
||||
logging.warning("Done!")
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
@@ -52,5 +52,4 @@ def run(config):
|
||||
from .libs.core.structs import AppSettings
|
||||
|
||||
# Run modules
|
||||
for mod_name, mod_obj in six.iteritems(AppSettings.modules):
|
||||
mod_obj().run(config)
|
||||
AppSettings.modules[config.action]().run(config)
|
||||
|
||||
@@ -24,9 +24,9 @@ def main():
|
||||
# Start!
|
||||
run_console(config)
|
||||
except KeyboardInterrupt:
|
||||
log.warning("[*] CTRL+C caught. Exiting...")
|
||||
log.warning("CTRL+C caught. Exiting...")
|
||||
except Exception as e:
|
||||
log.critical("[!] Unhandled exception: %s" % str(e))
|
||||
log.critical("Unhandled exception: %s" % str(e))
|
||||
log.debug("", exc_info=True)
|
||||
|
||||
if __name__ == "__main__" and __package__ is None:
|
||||
|
||||
@@ -88,16 +88,37 @@ def build_arg_parser(config=None, modules=None, parser=None):
|
||||
# --------------------------------------------------------------------------
|
||||
# Add sub parsers for each module
|
||||
# --------------------------------------------------------------------------
|
||||
subparsers = parser.add_subparsers(help='available commands:')
|
||||
main_subparser = parser.add_subparsers(help='available commands:', dest='module_name')
|
||||
main_subparser.required = True
|
||||
|
||||
for mod_name, mod_instance in six.iteritems(modules):
|
||||
for mod_name, mod_class in six.iteritems(modules):
|
||||
# Add subparser to module
|
||||
mod_parser = subparsers.add_parser(mod_instance.name,
|
||||
help=mod_instance.description)
|
||||
mod_parser = main_subparser.add_parser(mod_class.name,
|
||||
help=mod_class.description)
|
||||
|
||||
# Has module parameters?
|
||||
if hasattr(mod_instance, "__model__"):
|
||||
_extract_parameters(mod_instance.__model__(), mod_parser, mod_name)
|
||||
# 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
|
||||
|
||||
for x, y in six.iteritems(mod_class.__submodules__):
|
||||
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)
|
||||
else:
|
||||
# Add module parameters
|
||||
if hasattr(mod_class, "__model__"):
|
||||
_extract_parameters(mod_class.__model__(), mod_parser, mod_name)
|
||||
|
||||
return parser
|
||||
|
||||
@@ -120,15 +141,17 @@ def _extract_parameters(config, parser, prefix=None):
|
||||
used_opts = set()
|
||||
for x, v in six.iteritems(config.vars):
|
||||
# cmd options
|
||||
params = ["--%s%s" % ("%s-" % prefix if prefix is not None else "", # Add sub-module prefix?
|
||||
x)
|
||||
]
|
||||
params = ["--%s%s" % (
|
||||
# Add sub-module prefix?
|
||||
"%s-" % prefix if prefix is not None and AppSettings.parallel_running is True else "",
|
||||
x.replace("_", "-"))
|
||||
]
|
||||
|
||||
if x[0] not in used_opts:
|
||||
used_opts.add(x[0])
|
||||
|
||||
# If parameter is form sub-module don't add it
|
||||
if prefix is None:
|
||||
if AppSettings.parallel_running is False or prefix is None:
|
||||
params.append("-%s" % x[0])
|
||||
|
||||
# Type configs
|
||||
@@ -139,12 +162,17 @@ def _extract_parameters(config, parser, prefix=None):
|
||||
dest=x,
|
||||
help=str(v.label),
|
||||
default=v.default,
|
||||
action=action
|
||||
action=action,
|
||||
required=v.required
|
||||
)
|
||||
|
||||
if type_ is not None:
|
||||
named_params["type"] = type_
|
||||
|
||||
# Field has choices?
|
||||
if hasattr(v, "choices"):
|
||||
named_params["choices"] = dict(v.choices).keys()
|
||||
|
||||
parser.add_argument(*params, **named_params)
|
||||
|
||||
|
||||
@@ -178,8 +206,9 @@ def _resolve_action(field):
|
||||
:rtype: (str, type)
|
||||
"""
|
||||
type_maps = {
|
||||
'FloatField': ("store", str),
|
||||
'StringField': ("store", int),
|
||||
'FloatField': ("store", float),
|
||||
'StringField': ("store", str),
|
||||
'SelectField': ("store", str),
|
||||
'IntegerField': ("store", int),
|
||||
'BoolField': ("store_true", bool),
|
||||
'IncrementalIntegerField': ("count", None)
|
||||
|
||||
@@ -17,18 +17,17 @@ def setup_logging():
|
||||
logger = logging.getLogger('')
|
||||
|
||||
# Set log level
|
||||
logger.setLevel(abs(5 - DEBUG_LEVEL) % 5)
|
||||
logger.setLevel(abs(DEBUG_LEVEL * 10) % 50)
|
||||
|
||||
# Set file log format
|
||||
file_format = logging.Formatter('[%(levelname)s] %(asctime)s - %(message)s', "%Y-%m-%d %H:%M:%S")
|
||||
|
||||
# Handler: file
|
||||
log_file = logging.FileHandler(filename="%s.log" % __name__)
|
||||
log_file.setFormatter(file_format)
|
||||
|
||||
# Handler: console
|
||||
formatter = ColoredFormatter(
|
||||
"[ %(log_color)s%(levelname)-8s%(reset)s] %(blue)s%(message)s",
|
||||
"[ %(log_color)s*%(reset)s ] %(blue)s%(message)s",
|
||||
# "[ %(log_color)s%(levelname)-8s%(reset)s] %(blue)s%(message)s",
|
||||
datefmt=None,
|
||||
reset=True,
|
||||
log_colors={
|
||||
|
||||
@@ -2,29 +2,73 @@
|
||||
|
||||
import six
|
||||
|
||||
|
||||
from wtforms import (Form as Model,
|
||||
DateTimeField,
|
||||
StringField as _StringField,
|
||||
IntegerField as _IntegerField,
|
||||
FloatField as _FloatField,
|
||||
BooleanField as _BooleanField,
|
||||
SelectField as _SelectField,
|
||||
DecimalField, validators)
|
||||
from wtforms.fields.core import Field as _Field, Label as _Label
|
||||
|
||||
from wtforms.utils import unset_value
|
||||
|
||||
from wtforms.fields.core import Field as _Field, Label as _Label, UnboundField as _UnboundField
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Monkey patch fo Field to add:
|
||||
# - New parameter: required
|
||||
# --------------------------------------------------------------------------
|
||||
def new_field__init__(self, label=None, validators=None, filters=tuple(),
|
||||
description='', id=None, default=None, widget=None,
|
||||
render_kw=None, _form=None, _name=None, _prefix='',
|
||||
_translations=None, _meta=None, required=False):
|
||||
|
||||
self.required = required
|
||||
|
||||
self.__old___init__(label=label, validators=validators, filters=filters,
|
||||
description=description, id=id, default=default, widget=widget,
|
||||
render_kw=render_kw, _form=_form, _name=_name, _prefix=_prefix,
|
||||
_translations=_translations, _meta=_meta)
|
||||
|
||||
if not hasattr(_Field, "__old___init__"):
|
||||
_Field.__old___init__ = _Field.__init__
|
||||
_Field.__init__ = new_field__init__
|
||||
|
||||
BaseField = _Field
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Monkey patch fo wftorm to add:
|
||||
# - Enforce type checking
|
||||
# - Change default str(..) actcion
|
||||
# ----------------------------------------------------------------------
|
||||
# --------------------------------------------------------------------------
|
||||
# Validate
|
||||
def new_module_validate(self):
|
||||
"""
|
||||
This function add the feature that checks data type in fields
|
||||
"""
|
||||
for name, func in six.iteritems(self._fields):
|
||||
if hasattr(func, "validator"):
|
||||
if func.validator() is False:
|
||||
self._errors = {name: "Data type incorrect"}
|
||||
return False
|
||||
self._errors = {}
|
||||
|
||||
if type(self._fields[name]) != type(self._fields[name].__type__):
|
||||
self._errors[name] = ("Data type incorrect or not default value "
|
||||
"provided. Got %s. Expected: %s" % (
|
||||
type(self._fields[name].data),
|
||||
self._fields[name].__type__))
|
||||
|
||||
return False
|
||||
|
||||
# Checks required if object is an instance
|
||||
if type(self) is type:
|
||||
if self._fields[name].required is True:
|
||||
if self._fields[name].data is None and self._fields[name].default is None:
|
||||
self._errors = {name: "Field '%s' is required" % name}
|
||||
return False
|
||||
|
||||
return self.old_validate()
|
||||
|
||||
@@ -37,25 +81,27 @@ if not hasattr(Model, "old_validate"):
|
||||
# Field Monkey path
|
||||
# --------------------------------------------------------------------------
|
||||
def new_field_str(self):
|
||||
if self.__type__ is str:
|
||||
return str(self.data)
|
||||
else:
|
||||
return self.data
|
||||
|
||||
|
||||
def new_file_repr(self):
|
||||
return str(self.data)
|
||||
|
||||
_Field.__str__ = new_field_str
|
||||
_Field.__repr__ = new_field_str
|
||||
_Field.__repr__ = new_file_repr
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Label Monkey path
|
||||
# --------------------------------------------------------------------------
|
||||
def new_label_str(self):
|
||||
return self.text
|
||||
return str(self.text)
|
||||
|
||||
_Label.__str__ = new_label_str
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Base rename
|
||||
# --------------------------------------------------------------------------
|
||||
BaseField = _Field
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# New types:
|
||||
@@ -66,8 +112,15 @@ BaseField = _Field
|
||||
def _validator(self):
|
||||
to_check = self.data
|
||||
if to_check is None:
|
||||
to_check = self.default
|
||||
return isinstance(to_check, self.__type__)
|
||||
if self.data is None:
|
||||
return True
|
||||
else:
|
||||
to_check = self.default
|
||||
else:
|
||||
if not isinstance(to_check, self.__type__):
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
@@ -99,7 +152,17 @@ FloatField.validator = _validator
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
class BoolField(_FloatField):
|
||||
class BoolField(_BooleanField):
|
||||
"""Improved bool data that checks types"""
|
||||
__type__ = bool
|
||||
BoolField.validator = _validator
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Especial fields
|
||||
# --------------------------------------------------------------------------
|
||||
# ----------------------------------------------------------------------
|
||||
class SelectField(_SelectField):
|
||||
"""Improved bool data that checks types"""
|
||||
__type__ = str
|
||||
SelectField.validator = _validator
|
||||
|
||||
@@ -38,9 +38,38 @@ class CommonData(Model):
|
||||
if self.validate() is False:
|
||||
raise TypeError("\n".join("'%s' <- %s" % (x, y) for x, y in six.iteritems(self.errors)))
|
||||
|
||||
# Add extra vars from modules
|
||||
try:
|
||||
module_name = kwargs['module_name']
|
||||
fake_kwargs = dict(kwargs)
|
||||
|
||||
# Add metavars: action / subactions
|
||||
self.action = fake_kwargs.pop('module_name')
|
||||
self.sub_action = None
|
||||
|
||||
# Is a sub-action selected
|
||||
for x, y in six.iteritems(fake_kwargs):
|
||||
if x.startswith("module_"):
|
||||
self.sub_action = fake_kwargs.pop(x)
|
||||
break
|
||||
|
||||
module_model = getattr(AppSettings.modules[module_name], "__model__", None)
|
||||
|
||||
if module_model is not None:
|
||||
# Load module model to check parameters
|
||||
module_model(**fake_kwargs)
|
||||
|
||||
# If not errors, set vars and values
|
||||
for x, v in six.iteritems(fake_kwargs):
|
||||
if x not in self.vars:
|
||||
setattr(self, x, v)
|
||||
except KeyError:
|
||||
# No module name available -> not an error. Class must be loading from another locations
|
||||
pass
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
@classmethod
|
||||
def from_argparser(cls, argparse_data, **kwargs):
|
||||
def from_argparser(cls, argparse_data):
|
||||
"""
|
||||
Load parameters from argparser
|
||||
"""
|
||||
@@ -48,7 +77,7 @@ class CommonData(Model):
|
||||
if not isinstance(argparse_data, Namespace):
|
||||
raise TypeError("Expected Namespace, got '%s' instead" % type(argparse_data))
|
||||
|
||||
return cls(**kwargs)
|
||||
return cls(**argparse_data.__dict__)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def __repr__(self):
|
||||
@@ -77,7 +106,6 @@ class CommonResultsExecutionData(CommonData):
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# class AppSettings(Singleton, Model):
|
||||
class _AppSettings(CommonData):
|
||||
"""Global app settings"""
|
||||
|
||||
@@ -89,5 +117,6 @@ class _AppSettings(CommonData):
|
||||
# Loaded dinamically
|
||||
hooks = None
|
||||
modules = None
|
||||
parallel_running = False
|
||||
|
||||
AppSettings = _AppSettings()
|
||||
|
||||
@@ -25,4 +25,4 @@ def set_log_level(parsed_args):
|
||||
"""
|
||||
|
||||
if hasattr(parsed_args, "verbosity"):
|
||||
log.setLevel(abs(5 - parsed_args.verbosity) % 5)
|
||||
log.setLevel(abs(parsed_args.verbosity * 10) % 50)
|
||||
@@ -14,9 +14,11 @@ class IModule:
|
||||
name = None
|
||||
description = None
|
||||
|
||||
@abc.abstractmethod
|
||||
def run(self, module_config):
|
||||
pass
|
||||
if hasattr(self, "__submodules__"):
|
||||
self.__submodules__[module_config.sub_action]['action'](module_config)
|
||||
else:
|
||||
raise NotImplemented("Run method must be override")
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
102
enteletaor_lib/modules/dump/__init__.py
Normal file
102
enteletaor_lib/modules/dump/__init__.py
Normal file
@@ -0,0 +1,102 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import pickle
|
||||
import logging
|
||||
|
||||
from time import sleep
|
||||
from modules import IModule
|
||||
from kombu import Connection
|
||||
from kombu.simple import Empty
|
||||
from kombu.exceptions import SerializationError
|
||||
|
||||
from ...libs.core.structs import CommonData, AppSettings
|
||||
from ...libs.core.models import IntegerField, StringField, SelectField, validators
|
||||
|
||||
log = logging.getLogger()
|
||||
|
||||
REDIS = "10.211.55.69"
|
||||
|
||||
|
||||
class ModuleModel(CommonData):
|
||||
interval = IntegerField(default=4)
|
||||
target = StringField([validators.required()])
|
||||
export_results = StringField(default="")
|
||||
import_results = StringField(default=None)
|
||||
broker_type = SelectField(default="redis", choices=[
|
||||
("redis", "Redis server"),
|
||||
("zmq", "ZeroMQ"),
|
||||
("amqp", "RabbitMQ broker")
|
||||
])
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
class RemoteProcessModule(IModule):
|
||||
"""
|
||||
Try to extract information from remote processes
|
||||
"""
|
||||
__model__ = ModuleModel
|
||||
|
||||
name = "dump"
|
||||
description = "connect to remote server/s and dumps all available information"
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def run(self, config):
|
||||
# --------------------------------------------------------------------------
|
||||
# Ver dirty monkey patch to avoid kombu write into screen
|
||||
# --------------------------------------------------------------------------
|
||||
try:
|
||||
import sys
|
||||
sys.stderr = open("/dev/null")
|
||||
except IOError:
|
||||
pass
|
||||
|
||||
dump_from_celery(config)
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def dump_from_celery(config):
|
||||
"""
|
||||
Start dumping information
|
||||
"""
|
||||
URL = '%s://%s' % (config.broker_type, config.target)
|
||||
|
||||
# with Connection('redis://%s' % REDIS) as conn:
|
||||
with Connection(URL) as conn:
|
||||
in_queue = conn.SimpleQueue('celery')
|
||||
|
||||
while 1:
|
||||
try:
|
||||
while 1:
|
||||
message = in_queue.get(block=False, timeout=1)
|
||||
# message = in_queue.get(block=False, timeout=1)
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Try to deserialize
|
||||
# --------------------------------------------------------------------------
|
||||
# Is Pickle info?
|
||||
try:
|
||||
deserialized = pickle.loads(message.body)
|
||||
except SerializationError:
|
||||
pass
|
||||
|
||||
# Read info
|
||||
remote_process = deserialized['task'].split(".")[-1]
|
||||
remote_args = deserialized['args']
|
||||
|
||||
# Show info
|
||||
_show_info(remote_process, remote_args)
|
||||
|
||||
except Empty:
|
||||
# Queue is empty -> wait
|
||||
log.error("No more messages from server. Waiting for %s seconds and try again.." % config.interval)
|
||||
sleep(2)
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def _show_info(process, args):
|
||||
|
||||
log.error("Found process information:")
|
||||
log.error(" - Remote process name: '%s'" % process)
|
||||
log.error(" - Input parameters:")
|
||||
for i, x in enumerate(args):
|
||||
log.error(" -> P%s: %s" % (i, x))
|
||||
@@ -1,27 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from libs.core.structs import CommonData
|
||||
from libs.core.models import FloatField
|
||||
from .. import IModule
|
||||
|
||||
|
||||
class ModuleModel(CommonData):
|
||||
start_execution = FloatField(default=1.0)
|
||||
end_execution = FloatField(default=1.2)
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
class HelpModule(IModule):
|
||||
"""
|
||||
Long description of module
|
||||
"""
|
||||
|
||||
__model__ = ModuleModel
|
||||
|
||||
name = "help"
|
||||
description = "long description"
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def run(self, config):
|
||||
print("hoooola")
|
||||
|
||||
55
enteletaor_lib/modules/redis/__init__.py
Normal file
55
enteletaor_lib/modules/redis/__init__.py
Normal file
@@ -0,0 +1,55 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
|
||||
from modules import IModule
|
||||
from libs.core.models import StringField, IntegerField
|
||||
from libs.core.structs import CommonData
|
||||
|
||||
from .cmd_actions import parser_redis_dump, parser_redis_server_disconnect
|
||||
from .redis_dump import action_redis_dump
|
||||
from .redis_info import action_redis_server_info
|
||||
from .redis_clients import action_redis_server_connected
|
||||
from .redis_disconnect import action_redis_server_disconnect
|
||||
|
||||
|
||||
log = logging.getLogger()
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
class ModuleModel(CommonData):
|
||||
target = StringField(required=True)
|
||||
port = IntegerField(default=6379)
|
||||
db = IntegerField(default=0)
|
||||
export_results = StringField()
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
class RedisModule(IModule):
|
||||
"""
|
||||
Try to extract information from remote processes
|
||||
"""
|
||||
__model__ = ModuleModel
|
||||
__submodules__ = {
|
||||
'dump': dict(
|
||||
help="dumps all keys in Redis database",
|
||||
cmd_args=parser_redis_dump,
|
||||
action=action_redis_dump
|
||||
),
|
||||
'info': dict(
|
||||
help="open a remote shell through Redis server",
|
||||
action=action_redis_server_info
|
||||
),
|
||||
'connected': dict(
|
||||
help="get connected users to Redis server",
|
||||
action=action_redis_server_connected
|
||||
),
|
||||
'disconnect': dict(
|
||||
help="disconnect one or all users from Redis server",
|
||||
cmd_args=parser_redis_server_disconnect,
|
||||
action=action_redis_server_disconnect
|
||||
),
|
||||
}
|
||||
|
||||
name = "redis"
|
||||
description = "some attacks over Redis service"
|
||||
22
enteletaor_lib/modules/redis/cmd_actions.py
Normal file
22
enteletaor_lib/modules/redis/cmd_actions.py
Normal file
@@ -0,0 +1,22 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
This file contains command line actions for argparser
|
||||
"""
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def parser_redis_dump(parser):
|
||||
"""
|
||||
Dump all redis database information
|
||||
"""
|
||||
parser.add_argument("--no-raw", action="store_true", dest="no_raw", default=False,
|
||||
help="do not show displays raw database info into screen")
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def parser_redis_server_disconnect(parser):
|
||||
parser.add_argument("-c", action="store", dest="client", help="user to disconnect")
|
||||
parser.add_argument("--all", action="store_true", dest="disconnect_all", default=False,
|
||||
help="disconnect all users")
|
||||
|
||||
29
enteletaor_lib/modules/redis/redis_clients.py
Normal file
29
enteletaor_lib/modules/redis/redis_clients.py
Normal file
@@ -0,0 +1,29 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import six
|
||||
import redis
|
||||
import logging
|
||||
|
||||
log = logging.getLogger()
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def action_redis_server_connected(config):
|
||||
"""
|
||||
Dump all redis information
|
||||
"""
|
||||
log.warning("Trying to connect with redis server...")
|
||||
|
||||
# Connection with redis
|
||||
con = redis.StrictRedis(host=config.target, port=config.port, db=config.db)
|
||||
|
||||
log.error("Connected users to '%s':" % config.target)
|
||||
|
||||
for c in con.client_list():
|
||||
|
||||
# Skip local host connections
|
||||
client = c['addr']
|
||||
db = c['db']
|
||||
|
||||
log.error(" - %s (DB: %s)" % (client, db))
|
||||
|
||||
43
enteletaor_lib/modules/redis/redis_disconnect.py
Normal file
43
enteletaor_lib/modules/redis/redis_disconnect.py
Normal file
@@ -0,0 +1,43 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import six
|
||||
import redis
|
||||
import logging
|
||||
|
||||
log = logging.getLogger()
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def action_redis_server_disconnect(config):
|
||||
"""
|
||||
Disconnect one or more users from server
|
||||
"""
|
||||
log.warning("Trying to connect with redis server...")
|
||||
|
||||
# Connection with redis
|
||||
con = redis.StrictRedis(host=config.target, port=config.port, db=config.db)
|
||||
|
||||
clients = {x['addr']: x['addr'] for x in con.client_list()}
|
||||
|
||||
# Disconnect all clients?
|
||||
if config.disconnect_all:
|
||||
for c in clients:
|
||||
con.client_kill(c)
|
||||
|
||||
log.error(" - Disconnected client '%s'" % c)
|
||||
|
||||
# Disconnect only one user
|
||||
else:
|
||||
# Check client format
|
||||
if config.client is None or ":" not in config.client:
|
||||
log.error("Invalid client format. Client must be format: IP:PORT, i.e: 10.211.55.2:61864")
|
||||
return
|
||||
|
||||
try:
|
||||
_c = clients[config.client]
|
||||
|
||||
con.client_kill(_c)
|
||||
|
||||
log.error(" - Disconnected client '%s'" % _c)
|
||||
except KeyError:
|
||||
log.warning("Client '%s' doesn't appear to be connected to server" % config.client)
|
||||
56
enteletaor_lib/modules/redis/redis_dump.py
Normal file
56
enteletaor_lib/modules/redis/redis_dump.py
Normal file
@@ -0,0 +1,56 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import redis
|
||||
import logging
|
||||
import pprint
|
||||
|
||||
log = logging.getLogger()
|
||||
|
||||
def dump_keys(con):
|
||||
|
||||
for key in con.keys('*'):
|
||||
key_type = con.type(key).lower()
|
||||
if key_type == b"kv":
|
||||
val = con.get(key)
|
||||
if key_type == b"hash":
|
||||
val = con.hgetall(key)
|
||||
if key_type == b"zet":
|
||||
val = con.zrange(key, 0, -1)
|
||||
if key_type == b"set":
|
||||
val = con.mget(key)
|
||||
|
||||
if val is not None:
|
||||
if isinstance(val, list):
|
||||
if val[0] is None:
|
||||
continue
|
||||
|
||||
yield val
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def action_redis_dump(config):
|
||||
"""
|
||||
Dump all redis information
|
||||
"""
|
||||
log.error("Trying to connect with redis server...")
|
||||
|
||||
# Connection with redis
|
||||
con = redis.StrictRedis(host=config.target, port=config.port, db=config.db)
|
||||
|
||||
# Export results?
|
||||
export_file = None
|
||||
if config.export_results:
|
||||
export_file = open(config.export_results, "w")
|
||||
|
||||
for val in dump_keys(con):
|
||||
# Display results?
|
||||
if config.no_raw is False:
|
||||
log.warning(val)
|
||||
|
||||
# Dump to file?
|
||||
if export_file is not None:
|
||||
export_file.write(str(val))
|
||||
|
||||
# Close file descriptor
|
||||
if export_file is not None:
|
||||
export_file.close()
|
||||
24
enteletaor_lib/modules/redis/redis_info.py
Normal file
24
enteletaor_lib/modules/redis/redis_info.py
Normal file
@@ -0,0 +1,24 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import six
|
||||
import redis
|
||||
import logging
|
||||
|
||||
log = logging.getLogger()
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def action_redis_server_info(config):
|
||||
"""
|
||||
Dump all redis information
|
||||
"""
|
||||
log.warning("Trying to connect with redis server...")
|
||||
|
||||
# Connection with redis
|
||||
con = redis.StrictRedis(host=config.target, port=config.port, db=config.db)
|
||||
|
||||
log.error("Config for server '%s':" % config.target)
|
||||
|
||||
for x, y in six.iteritems(con.config_get()):
|
||||
log.error(" - %s: %s" % (x, y))
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
# # -*- coding: utf-8 -*-
|
||||
#
|
||||
# from .. import IModule
|
||||
#
|
||||
#
|
||||
# # ----------------------------------------------------------------------
|
||||
# class SetupModule(IModule):
|
||||
# """
|
||||
# Long description of module
|
||||
# """
|
||||
#
|
||||
# name = "setup"
|
||||
# description = "long description"
|
||||
#
|
||||
# def params(self):
|
||||
# pass
|
||||
#
|
||||
# def run(self, config):
|
||||
# pass
|
||||
#
|
||||
Reference in New Issue
Block a user