add: scan module

This commit is contained in:
cr0hn
2016-02-23 14:24:48 +01:00
parent 6137fb3558
commit e1e5acade0
2 changed files with 270 additions and 0 deletions

View File

@@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
import logging
from modules import IModule
from libs.core.structs import CommonData
from libs.core.models import StringField, BoolField, IntegerField
from .scan_main import action_scan_main
log = logging.getLogger()
# ----------------------------------------------------------------------
class ModuleModel(CommonData):
ports = StringField(default="5672,6379,5555", label="comma separated ports")
target = StringField(required=True)
own_ips = BoolField(label="Try to find all IPs registered for this company")
concurrency = IntegerField(label="maximum parallels scans", default=10)
# ----------------------------------------------------------------------
class ScanProcessModule(IModule):
"""
Try to extract information from remote processes
"""
__model__ = ModuleModel
__submodules__ = {
'default': dict(
action=action_scan_main
)
}
name = "scan"
description = "do a scans trying to find open brokers / MQ"

View File

@@ -0,0 +1,234 @@
# -*- coding: utf-8 -*-
import six
import zmq
import redis
import socket
import logging
import eventlet
import ipaddress
import amqp.connection
from functools import partial
from threading import Thread, BoundedSemaphore
from .patch import patch_transport
from enteletaor_lib.libs.contrib.inetnum import get_inet_num
# Monkey patch for AMQP lib
patch_transport()
# Path thread library
eventlet.monkey_patch(socket=True, select=True, thread=True)
# Reconfigure AMQP LOGGER
logging.getLogger('amqp').setLevel(100)
log = logging.getLogger()
# ----------------------------------------------------------------------
def _do_scan(config, sem, host):
"""
This function try to find brokers services open in remote servers
"""
handlers = {
'Redis': handle_redis,
'RabbitMQ': handle_amqp,
'ZeroMQ': handle_zmq
}
log.warning(" > Analyzing host '%s' " % host)
for port in config.ports.split(","):
# Check each serve
for server, handle in six.iteritems(handlers):
try:
log.debug(" >> Trying '%s' port '%s'" % (host, port))
# Try to check if port is open
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(1)
result = s.connect_ex((host, int(port)))
except socket.gaierror as e:
log.warning("%s : %s error: %s" % (server, port, e))
continue
# Is port open?
if result == 0:
if handle(host, port, config) is True:
log.error(" <!!> Open '%s' server found in port '%s'" % (server, port))
else:
log.debug(" <i> Port %s is closed" % port)
sem.release()
# ----------------------------------------------------------------------
def action_scan_main(config):
# --------------------------------------------------------------------------
# Resolve target
# --------------------------------------------------------------------------
all_ips = build_targets(config)
# --------------------------------------------------------------------------
# Preparing scan
# --------------------------------------------------------------------------
target_number = len(all_ips)
log.warning(" - Number of targets to analyze: %s" % target_number)
# Semaphore
sem = BoundedSemaphore(config.concurrency)
threads = []
# Map parameters
_fn = partial(_do_scan, config, sem)
log.error(" - Starting scan")
# --------------------------------------------------------------------------
# Do scan
# --------------------------------------------------------------------------
for x in all_ips:
sem.acquire()
t = Thread(target=_fn, args=(x,))
threads.append(t)
t.start()
for t in threads:
t.join()
# --------------------------------------------------------------------------
def build_targets(config):
results = set()
# Split targets
for t in config.target.split("-"):
try:
results.update(str(x) for x in ipaddress.ip_network(t, strict=False))
except ValueError:
# --------------------------------------------------------------------------
# If reach this, is not a IPs, is a domain
# --------------------------------------------------------------------------
# Try to get all assigned IP of domain
if config.own_ips is True:
# Extract domain
try:
val = get_inet_num(t.split(".")[-2])
if val is not None:
for v in val:
log.debug(" -> Detected registered network '%s'. Added for scan." % v)
results.update(str(x) for x in ipaddress.ip_network(v, strict=False))
except KeyError:
# Invalid domain
log.debug(" <ii> Error while try to extract domain: '%s'" % t)
# --------------------------------------------------------------------------
# Get all IPs for domain
# --------------------------------------------------------------------------
# If target is a domain, remove CDIR
_target_cdir = t.split("/")
_cleaned_target = _target_cdir[0]
try:
# Resolve
host_ip = socket.gethostbyname(_cleaned_target)
except socket.gaierror:
# Try with the hostname with "www." again
try:
host_ip = socket.gethostbyname("www.%s" % _cleaned_target)
except socket.gaierror:
log.error(" <ii> Unable to resolve '%s'" % _cleaned_target)
continue
# Add CDIR to result
scan_target = "%s%s" % (host_ip, "/%s" % _target_cdir[1] if len(_target_cdir) > 1 else "")
results.update(str(x) for x in ipaddress.ip_network(scan_target, strict=False))
return results
# --------------------------------------------------------------------------
# These 3 functions determinate if server has listen one of these services:
# - Redis server
# - RabbitMQ server
# - ZeroMQ PUB/SUB pattern
#
# Each function try to connect or do some action and determinate if service
# is on or not.
# --------------------------------------------------------------------------
def handle_redis(host, port=6379, extra_config=None):
# log.debug(" * Connection to Redis: %s : %s" % (host, port))
try:
redis.StrictRedis(host=host, port=port, socket_connect_timeout=1, socket_timeout=1).config_get()
return True
except Exception:
return False
# ----------------------------------------------------------------------
def handle_amqp(host, port=5672, extra_config=None):
host_and_port = "%s:%s" % (host, port)
# log.debug(" * Connection to RabbitMQ: %s : %s" % (host, port))
try:
amqp.connection.Connection(host=host_and_port,
connect_timeout=1,
read_timeout=1,
socket_timeout=1)
return True
except Exception:
return False
# ----------------------------------------------------------------------
def handle_zmq(host, port=5555, extra_config=None):
# log.debug(" * Connection to ZeroMQ: %s : %s" % (host, port))
context = zmq.Context()
# Configure
socket = context.socket(zmq.SUB)
socket.setsockopt(zmq.SUBSCRIBE, b"") # All topics
socket.setsockopt(zmq.LINGER, 0) # All topics
socket.RCVTIMEO = 1000 # timeout: 1 sec
# Connect
socket.connect("tcp://%s:%s" % (host, port))
# Try to receive
try:
socket.recv()
return True
except Exception:
return False
finally:
socket.close()