Adapted zecora-z FTPScanner class.

This commit is contained in:
Zloooy 2019-11-13 22:17:42 +03:00
parent c0dbcf154a
commit b05cd4373d
8 changed files with 90 additions and 53 deletions

View File

@ -2,18 +2,22 @@
config = {
"parser" :
{
"name":"GDocsHashParser",
"name":"Parser",
"init_args":{}
},
"address_generator" :
{
"name":"GDocsAddressGenerator",
"name":"IpGenerator",
"init_args":{}
},
"scanner" :
{
"name":"GDocsScanner",
"init_args":{}
"name":"FTPScanner",
"init_args":{
"credentials": (
("admin", "admin")
)
}
},
"storage" :
{
@ -21,21 +25,22 @@ config = {
"init_args":
{
"path":"results.json",
"json_scheme":{
"status":
"json_scheme":
{
"gdoc_prefix":
"ftp_status":
[
{
"@hash": "gdoc_hash",
"@title": "gdoc_title"
"@ip":"ipv4_str",
"@port":"port",
"@login":"login",
"@password":"password",
"@ftp_version":"ftp_version",
}
]
}
}
}
}
}
'''scheme for url scanner
{
@ -54,3 +59,15 @@ config = {
}
}
}'''
'''scheme for gdocs scanner
"status":
{
"gdoc_prefix":
[
{
"@hash": "gdoc_hash",
"@title": "gdoc_title"
}
]
}
'''

View File

@ -72,6 +72,7 @@ class MainPresenter:
get_return_annotations(IpGenerator.get_next_address).union(get_return_annotations(CoreModel.scan_address)),
get_argument_annotations(self.storage.put_responce)
)
input()
self.exit_lock = RLock()
def startScan(self, ipRanges, portsStr, threadNumber, timeout):
@ -174,6 +175,7 @@ class ScanWorker(QObject):
)
print(scan_result)
scan_address.update(scan_result)
print(scan_address)
self.previous_address = scan_address
self.storage.put_responce(
*convert_for_storage(scan_address)
@ -181,9 +183,9 @@ class ScanWorker(QObject):
string_scan_address = " ".join(key + ":" + str(scan_address[key]) for
key in scan_address.keys())
if scan_result == 0:
self.log_signal.emit('%s is open' % string_scan_address)
self.log_signal.emit(string_scan_address)
else:
self.log_signal.emit('%s is closed' % string_scan_address)
self.log_signal.emit(string_scan_address)
self.stop()
def stop(self):

View File

@ -30,6 +30,7 @@ class ConvertTable():
function.__annotations__.items() if
key!='return')
if input_args.issubset(from_keys) and to_key.issubset(function.__annotations__['return']):
print("found converter for %s!!!" % to_key)
return input_args, function
raise Exception("There is no converter for %s to %s" % (from_keys,
to_key))
@ -38,23 +39,31 @@ class ConvertTable():
def get_metaconverter(self, from_keys, to_keys):
'''This function constructs and returns new function used to provide fast
conversion from from_keys to to_keys'''
print("from_keys",from_keys)
print("to_keys",to_keys)
converters_args = []
converters = []
for key in to_keys:
keys_to_convert, converter = None, None
if key in from_keys:
print("%s is in from_keys" % key)
keys_to_convert = [key]
converter = lambda x : {key: x}
else:
print("getting converter for %s." % key)
keys_to_convert, converter = self.get_converter(from_keys, key)
print("needed keys: %s" % " ".join(keys_to_convert))
converters_args.append(keys_to_convert)
converters.append(converter)
def metaconverter(args_dict):
if args_dict == None:
return [None] * len(converters)
res = []
print(converters)
print(converters_args)
for i,conv in enumerate(converters):
print(converters_args[i])
print(args_dict)
args = [args_dict[arg] for arg in converters_args[i]]
res.append(*[value for key, value in conv(*args).items()])
return res

View File

@ -1,17 +1,15 @@
from core.prototypes.AbstractAddressGenerator import AbstractAddressGenerator
from core.prototypes.AbstractModuleClass import internal
from threading import RLock
import ipaddress
from types import GeneratorType
class IpGenerator(AbstractAddressGenerator):
def set_parsed_fields(self, ips : 'ipv4_ranges', ports : 'ports') -> None:
def set_parsed_fields(self, ips : 'ipv4_objects', ports : 'ports') -> None:
self.ips = ips
self.ports = ports
self.lock = RLock()
@internal
def get_next_port_number(self, previous_port):
return (self.ports.index(previous_port) + 1) % len(self.ports)

View File

@ -1,6 +1,5 @@
import ipaddress
from core.prototypes.AbstractParser import AbstractParser
from core.prototypes.AbstractModuleClass import internal
class Parser(AbstractParser):
@ -9,10 +8,9 @@ class Parser(AbstractParser):
'ports'}:
result = dict()
result['ports'] = self.parse_port_field(ports)
result['ipv4_ranges'] = self.get_all_addresses(ips)
result['ipv4_objects'] = self.get_all_addresses(ips)
return result
@internal
def parse_port_field(self, ports):
"""
Parses ports from string, returns them as integers in the list.
@ -40,7 +38,6 @@ class Parser(AbstractParser):
# Change to default ports from constant
return [21, 22, 23, 25, 80, 443, 110, 111, 135, 139, 445, 8080, 8443, 53, 143, 989, 990, 3306, 1080, 5554, 6667, 2222, 4444, 666, 6666, 1337, 2020, 31337]
@internal
def parse_address_field(self, ips):
"""
Parses ip input string, returns the generator over them.
@ -62,7 +59,6 @@ class Parser(AbstractParser):
for host in ip_obj:
yield host
@internal
def get_all_addresses(self, ips):
ip_objects = set()
inputs = [ip.strip() for ip in ips.split(',')]

View File

@ -9,21 +9,27 @@ MAX_ERRORS = 3
class FTPScanner(AbstractScanner):
def __init__(self, timeout):
def __init__(self, timeout:"timeout", credentials:"credentials"):
self.__timeout__ = timeout
self.__credantials__ = credentials
def scan_address(self, host: 'ipv4_str or hostname', port: 'port', credentials: 'tuples with login and password') -> {'scan_result'}:
def scan_address(self, host: 'ipv4_str', port: 'port') -> {'ftp_version', 'ftp_status', 'login', 'password'}:
result = self.ftp_anonymous_login(host, port, self.__timeout__)
if result['status'] == 'error' or result['anonymous_login']:
if result['ftp_status'] == 'ok':
#Что-то делать с ошибками
return result
result['credentials'] = self.ftp_bruteforce(
host, port, credentials, self.__timeout__)
if not result['ftp_status'].startswith('530'):
return result
return self.ftp_bruteforce(
host, port, self.__credentials__, self.__timeout__)
@staticmethod
def ftp_anonymous_login(host, port, timeout):
'''Get version and check if anonympous login is enabled'''
result = {}
result = {
key:None for key in ['ftp_version', 'ftp_status', 'login',
'password']
}
ftp_connection = FTP(timeout=timeout)
try:
version = ftp_connection.connect(host=host, port=port)
@ -31,15 +37,14 @@ class FTPScanner(AbstractScanner):
result['ftp_version'] = version.lstrip('220 ')
# Try to login as anonymous user
ftp_connection.login()
result['anonymous_login'] = True
result['status'] = 'ok'
result['ftp_status'] = 'ok'
except ftplib.error_perm as e:
if str(e).startswith("530"):
result['status'] = 'ok'
result['ftp_status'] = 'ok'
result['anonymous_login'] = False
except ftplib.all_errors as e:
result['status'] = 'error'
result['error_type'] = str(e)
#status - error
result['ftp_status'] = str(e)
return result
finally:
ftp_connection.close()
@ -52,6 +57,11 @@ class FTPScanner(AbstractScanner):
# but we also want to reconnect if necessary.
# That is why I use cred iterator to pick up new login/pass only when
# we need to.
result = {
key:None for key in ['ftp_version', 'ftp_status', 'login',
'password']
}
result['ftp_status'] = "error"
error_count = 0
it = iter(creds)
cred = next(it, "")
@ -66,7 +76,10 @@ class FTPScanner(AbstractScanner):
try:
ftp_connection.login(user, password)
ftp_connection.close()
return user, password
result['ftp_status'] = 'ok'
result['login'] = user
result['password'] = password
return result
except ftplib.error_perm as e:
# Password was wrong, checking another
cred = next(it, "")
@ -82,4 +95,4 @@ class FTPScanner(AbstractScanner):
break
finally:
ftp_connection.close()
return None
return result

View File

@ -46,18 +46,18 @@ def run_mumble():
class TestFTPScanner(unittest.TestCase):
def test_closed_port(self):
scanner = FTPScanner(timeout=10)
result = scanner.scan_address('127.0.0.1', 31337, credentials=TEST_CREDS)
scanner = FTPScanner(timeout=10, credentials=TEST_CREDS)
result = scanner.scan_address('127.0.0.1', 31337)
print(result)
self.assertEqual(result['status'], 'error', "Should be error")
self.assertTrue("Connection refused" in result['error_type'], "Connection refused")
#self.assertEqual(result['status'], 'Connection refused', "Should be error")
self.assertTrue("Connection refused" in result['ftp_status'], "Connection refused")
def test_mumble(self):
p = multiprocessing.Process(target=run_mumble)
p.start()
sleep(5)
scanner = FTPScanner(timeout=10)
result = scanner.scan_address('127.0.0.1', PORT, credentials=TEST_CREDS)
scanner = FTPScanner(timeout=10, credentials=TEST_CREDS)
result = scanner.scan_address('127.0.0.1', PORT)
print(result)
self.assertEqual(result['status'], 'error', "Should be error")
self.assertTrue("timed out" in result['error_type'], "Timed out")
@ -68,10 +68,11 @@ class TestFTPScanner(unittest.TestCase):
p = multiprocessing.Process(target=run_anonymous_ftp, args=(temp_dir,))
p.start()
sleep(5)
scanner = FTPScanner(timeout=10)
result = scanner.scan_address('127.0.0.1', PORT, credentials=TEST_CREDS)
scanner = FTPScanner(timeout=10, credentials=TEST_CREDS)
result = scanner.scan_address('127.0.0.1', PORT)
print(result)
self.assertEqual(result['anonymous_login'], True, "Should be True")
self.assertEqual(result['login'], None, "Should be True")
self.assertEqual(result['password'], None, "Should be True")
p.terminate()
os.rmdir(temp_dir)
@ -80,10 +81,11 @@ class TestFTPScanner(unittest.TestCase):
p = multiprocessing.Process(target=run_bruteforce_ftp, args=(temp_dir,))
p.start()
sleep(5)
scanner = FTPScanner(timeout=10)
result = scanner.scan_address('127.0.0.1', PORT, credentials=TEST_CREDS)
scanner = FTPScanner(timeout=10, credentials=TEST_CREDS)
result = scanner.scan_address('127.0.0.1', PORT)
print(result)
self.assertEqual(result['credentials'], TEST_CREDS[-1], "Should be True")
self.assertEqual(result['login'], TEST_CREDS[-1][0], "Should be True")
self.assertEqual(result['password'], TEST_CREDS[-1][1], "Should be True")
p.terminate()
os.rmdir(temp_dir)

View File

@ -1 +1 @@
{"200": {"https://docs.google.com/document/d/": [{"hash": "11Sz_PyqL268V9xmcEjYqEhufFGleT5TowdKEu5cTFak", "title": null}, {"hash": "11Sz_PyqL268V9xmcEjYqEhufFGleT5TowdKEu5cTFal", "title": null}, {"hash": "11Sz_PyqL268V9xmcEjYqEhufFGleT5TowdKEu5cTFam", "title": null}]}}
{"timed out": [{"ip": "122.3.42.1", "port": 20, "login": null, "password": null, "ftp_version": null}, {"ip": "122.3.42.1", "port": 21, "login": null, "password": null, "ftp_version": null}]}