From b05cd4373d5ba0b709eaefb1a20390296bcef778 Mon Sep 17 00:00:00 2001 From: Zloooy Date: Wed, 13 Nov 2019 22:17:42 +0300 Subject: [PATCH] Adapted zecora-z FTPScanner class. --- config.py | 47 +++++++++++++++-------- core/MainPresenter.py | 6 ++- core/communication/ConvertTable.py | 11 +++++- modules/address_generation/IpGenerator.py | 4 +- modules/address_generation/Parser.py | 6 +-- modules/network_scan/FTPScanner.py | 41 +++++++++++++------- modules/network_scan/test_FTPScanner.py | 26 +++++++------ results.json | 2 +- 8 files changed, 90 insertions(+), 53 deletions(-) diff --git a/config.py b/config.py index d444d27..67b286d 100644 --- a/config.py +++ b/config.py @@ -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,17 +25,18 @@ config = { "init_args": { "path":"results.json", - "json_scheme":{ - "status": - { - "gdoc_prefix": - [ - { - "@hash": "gdoc_hash", - "@title": "gdoc_title" - } - ] - } + "json_scheme": + { + "ftp_status": + [ + { + "@ip":"ipv4_str", + "@port":"port", + "@login":"login", + "@password":"password", + "@ftp_version":"ftp_version", + } + ] } } } @@ -54,3 +59,15 @@ config = { } } }''' +'''scheme for gdocs scanner +"status": +{ + "gdoc_prefix": + [ + { + "@hash": "gdoc_hash", + "@title": "gdoc_title" + } + ] +} +''' diff --git a/core/MainPresenter.py b/core/MainPresenter.py index e3492a1..60f0853 100644 --- a/core/MainPresenter.py +++ b/core/MainPresenter.py @@ -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): diff --git a/core/communication/ConvertTable.py b/core/communication/ConvertTable.py index f27856d..4de5a4b 100644 --- a/core/communication/ConvertTable.py +++ b/core/communication/ConvertTable.py @@ -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 diff --git a/modules/address_generation/IpGenerator.py b/modules/address_generation/IpGenerator.py index 056066a..2b69ba9 100644 --- a/modules/address_generation/IpGenerator.py +++ b/modules/address_generation/IpGenerator.py @@ -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) diff --git a/modules/address_generation/Parser.py b/modules/address_generation/Parser.py index a421b27..019a3ce 100644 --- a/modules/address_generation/Parser.py +++ b/modules/address_generation/Parser.py @@ -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(',')] diff --git a/modules/network_scan/FTPScanner.py b/modules/network_scan/FTPScanner.py index 3f2ab40..2093721 100644 --- a/modules/network_scan/FTPScanner.py +++ b/modules/network_scan/FTPScanner.py @@ -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__) - return result + 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 diff --git a/modules/network_scan/test_FTPScanner.py b/modules/network_scan/test_FTPScanner.py index e97826e..8b852ce 100644 --- a/modules/network_scan/test_FTPScanner.py +++ b/modules/network_scan/test_FTPScanner.py @@ -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) diff --git a/results.json b/results.json index 4d473bd..90e772e 100644 --- a/results.json +++ b/results.json @@ -1 +1 @@ -{"200": {"https://docs.google.com/document/d/": [{"hash": "11Sz_PyqL268V9xmcEjYqEhufFGleT5TowdKEu5cTFak", "title": null}, {"hash": "11Sz_PyqL268V9xmcEjYqEhufFGleT5TowdKEu5cTFal", "title": null}, {"hash": "11Sz_PyqL268V9xmcEjYqEhufFGleT5TowdKEu5cTFam", "title": null}]}} \ No newline at end of file +{"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}]} \ No newline at end of file