mirror of
https://github.com/ChronosX88/PyNesca.git
synced 2024-11-21 20:52:18 +00:00
Adapted zecora-z FTPScanner class.
This commit is contained in:
parent
c0dbcf154a
commit
b05cd4373d
37
config.py
37
config.py
@ -2,18 +2,22 @@
|
|||||||
config = {
|
config = {
|
||||||
"parser" :
|
"parser" :
|
||||||
{
|
{
|
||||||
"name":"GDocsHashParser",
|
"name":"Parser",
|
||||||
"init_args":{}
|
"init_args":{}
|
||||||
},
|
},
|
||||||
"address_generator" :
|
"address_generator" :
|
||||||
{
|
{
|
||||||
"name":"GDocsAddressGenerator",
|
"name":"IpGenerator",
|
||||||
"init_args":{}
|
"init_args":{}
|
||||||
},
|
},
|
||||||
"scanner" :
|
"scanner" :
|
||||||
{
|
{
|
||||||
"name":"GDocsScanner",
|
"name":"FTPScanner",
|
||||||
"init_args":{}
|
"init_args":{
|
||||||
|
"credentials": (
|
||||||
|
("admin", "admin")
|
||||||
|
)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"storage" :
|
"storage" :
|
||||||
{
|
{
|
||||||
@ -21,20 +25,21 @@ config = {
|
|||||||
"init_args":
|
"init_args":
|
||||||
{
|
{
|
||||||
"path":"results.json",
|
"path":"results.json",
|
||||||
"json_scheme":{
|
"json_scheme":
|
||||||
"status":
|
|
||||||
{
|
{
|
||||||
"gdoc_prefix":
|
"ftp_status":
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"@hash": "gdoc_hash",
|
"@ip":"ipv4_str",
|
||||||
"@title": "gdoc_title"
|
"@port":"port",
|
||||||
|
"@login":"login",
|
||||||
|
"@password":"password",
|
||||||
|
"@ftp_version":"ftp_version",
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
'''scheme for url scanner
|
'''scheme for url scanner
|
||||||
@ -54,3 +59,15 @@ config = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}'''
|
}'''
|
||||||
|
'''scheme for gdocs scanner
|
||||||
|
"status":
|
||||||
|
{
|
||||||
|
"gdoc_prefix":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"@hash": "gdoc_hash",
|
||||||
|
"@title": "gdoc_title"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
@ -72,6 +72,7 @@ class MainPresenter:
|
|||||||
get_return_annotations(IpGenerator.get_next_address).union(get_return_annotations(CoreModel.scan_address)),
|
get_return_annotations(IpGenerator.get_next_address).union(get_return_annotations(CoreModel.scan_address)),
|
||||||
get_argument_annotations(self.storage.put_responce)
|
get_argument_annotations(self.storage.put_responce)
|
||||||
)
|
)
|
||||||
|
input()
|
||||||
self.exit_lock = RLock()
|
self.exit_lock = RLock()
|
||||||
|
|
||||||
def startScan(self, ipRanges, portsStr, threadNumber, timeout):
|
def startScan(self, ipRanges, portsStr, threadNumber, timeout):
|
||||||
@ -174,6 +175,7 @@ class ScanWorker(QObject):
|
|||||||
)
|
)
|
||||||
print(scan_result)
|
print(scan_result)
|
||||||
scan_address.update(scan_result)
|
scan_address.update(scan_result)
|
||||||
|
print(scan_address)
|
||||||
self.previous_address = scan_address
|
self.previous_address = scan_address
|
||||||
self.storage.put_responce(
|
self.storage.put_responce(
|
||||||
*convert_for_storage(scan_address)
|
*convert_for_storage(scan_address)
|
||||||
@ -181,9 +183,9 @@ class ScanWorker(QObject):
|
|||||||
string_scan_address = " ".join(key + ":" + str(scan_address[key]) for
|
string_scan_address = " ".join(key + ":" + str(scan_address[key]) for
|
||||||
key in scan_address.keys())
|
key in scan_address.keys())
|
||||||
if scan_result == 0:
|
if scan_result == 0:
|
||||||
self.log_signal.emit('%s is open' % string_scan_address)
|
self.log_signal.emit(string_scan_address)
|
||||||
else:
|
else:
|
||||||
self.log_signal.emit('%s is closed' % string_scan_address)
|
self.log_signal.emit(string_scan_address)
|
||||||
self.stop()
|
self.stop()
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
|
@ -30,6 +30,7 @@ class ConvertTable():
|
|||||||
function.__annotations__.items() if
|
function.__annotations__.items() if
|
||||||
key!='return')
|
key!='return')
|
||||||
if input_args.issubset(from_keys) and to_key.issubset(function.__annotations__['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
|
return input_args, function
|
||||||
raise Exception("There is no converter for %s to %s" % (from_keys,
|
raise Exception("There is no converter for %s to %s" % (from_keys,
|
||||||
to_key))
|
to_key))
|
||||||
@ -38,23 +39,31 @@ class ConvertTable():
|
|||||||
def get_metaconverter(self, from_keys, to_keys):
|
def get_metaconverter(self, from_keys, to_keys):
|
||||||
'''This function constructs and returns new function used to provide fast
|
'''This function constructs and returns new function used to provide fast
|
||||||
conversion from from_keys to to_keys'''
|
conversion from from_keys to to_keys'''
|
||||||
|
print("from_keys",from_keys)
|
||||||
|
print("to_keys",to_keys)
|
||||||
converters_args = []
|
converters_args = []
|
||||||
converters = []
|
converters = []
|
||||||
for key in to_keys:
|
for key in to_keys:
|
||||||
keys_to_convert, converter = None, None
|
keys_to_convert, converter = None, None
|
||||||
if key in from_keys:
|
if key in from_keys:
|
||||||
|
print("%s is in from_keys" % key)
|
||||||
keys_to_convert = [key]
|
keys_to_convert = [key]
|
||||||
converter = lambda x : {key: x}
|
converter = lambda x : {key: x}
|
||||||
else:
|
else:
|
||||||
|
print("getting converter for %s." % key)
|
||||||
keys_to_convert, converter = self.get_converter(from_keys, 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_args.append(keys_to_convert)
|
||||||
converters.append(converter)
|
converters.append(converter)
|
||||||
|
|
||||||
def metaconverter(args_dict):
|
def metaconverter(args_dict):
|
||||||
if args_dict == None:
|
if args_dict == None:
|
||||||
return [None] * len(converters)
|
return [None] * len(converters)
|
||||||
res = []
|
res = []
|
||||||
|
print(converters)
|
||||||
|
print(converters_args)
|
||||||
for i,conv in enumerate(converters):
|
for i,conv in enumerate(converters):
|
||||||
|
print(converters_args[i])
|
||||||
|
print(args_dict)
|
||||||
args = [args_dict[arg] for arg in converters_args[i]]
|
args = [args_dict[arg] for arg in converters_args[i]]
|
||||||
res.append(*[value for key, value in conv(*args).items()])
|
res.append(*[value for key, value in conv(*args).items()])
|
||||||
return res
|
return res
|
||||||
|
@ -1,17 +1,15 @@
|
|||||||
from core.prototypes.AbstractAddressGenerator import AbstractAddressGenerator
|
from core.prototypes.AbstractAddressGenerator import AbstractAddressGenerator
|
||||||
from core.prototypes.AbstractModuleClass import internal
|
|
||||||
from threading import RLock
|
from threading import RLock
|
||||||
import ipaddress
|
import ipaddress
|
||||||
from types import GeneratorType
|
from types import GeneratorType
|
||||||
|
|
||||||
class IpGenerator(AbstractAddressGenerator):
|
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.ips = ips
|
||||||
self.ports = ports
|
self.ports = ports
|
||||||
self.lock = RLock()
|
self.lock = RLock()
|
||||||
|
|
||||||
@internal
|
|
||||||
def get_next_port_number(self, previous_port):
|
def get_next_port_number(self, previous_port):
|
||||||
return (self.ports.index(previous_port) + 1) % len(self.ports)
|
return (self.ports.index(previous_port) + 1) % len(self.ports)
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import ipaddress
|
import ipaddress
|
||||||
from core.prototypes.AbstractParser import AbstractParser
|
from core.prototypes.AbstractParser import AbstractParser
|
||||||
from core.prototypes.AbstractModuleClass import internal
|
|
||||||
|
|
||||||
|
|
||||||
class Parser(AbstractParser):
|
class Parser(AbstractParser):
|
||||||
@ -9,10 +8,9 @@ class Parser(AbstractParser):
|
|||||||
'ports'}:
|
'ports'}:
|
||||||
result = dict()
|
result = dict()
|
||||||
result['ports'] = self.parse_port_field(ports)
|
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
|
return result
|
||||||
|
|
||||||
@internal
|
|
||||||
def parse_port_field(self, ports):
|
def parse_port_field(self, ports):
|
||||||
"""
|
"""
|
||||||
Parses ports from string, returns them as integers in the list.
|
Parses ports from string, returns them as integers in the list.
|
||||||
@ -40,7 +38,6 @@ class Parser(AbstractParser):
|
|||||||
# Change to default ports from constant
|
# 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]
|
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):
|
def parse_address_field(self, ips):
|
||||||
"""
|
"""
|
||||||
Parses ip input string, returns the generator over them.
|
Parses ip input string, returns the generator over them.
|
||||||
@ -62,7 +59,6 @@ class Parser(AbstractParser):
|
|||||||
for host in ip_obj:
|
for host in ip_obj:
|
||||||
yield host
|
yield host
|
||||||
|
|
||||||
@internal
|
|
||||||
def get_all_addresses(self, ips):
|
def get_all_addresses(self, ips):
|
||||||
ip_objects = set()
|
ip_objects = set()
|
||||||
inputs = [ip.strip() for ip in ips.split(',')]
|
inputs = [ip.strip() for ip in ips.split(',')]
|
||||||
|
@ -9,21 +9,27 @@ MAX_ERRORS = 3
|
|||||||
|
|
||||||
|
|
||||||
class FTPScanner(AbstractScanner):
|
class FTPScanner(AbstractScanner):
|
||||||
def __init__(self, timeout):
|
def __init__(self, timeout:"timeout", credentials:"credentials"):
|
||||||
self.__timeout__ = timeout
|
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__)
|
result = self.ftp_anonymous_login(host, port, self.__timeout__)
|
||||||
if result['status'] == 'error' or result['anonymous_login']:
|
if result['ftp_status'] == 'ok':
|
||||||
|
#Что-то делать с ошибками
|
||||||
return result
|
return result
|
||||||
result['credentials'] = self.ftp_bruteforce(
|
if not result['ftp_status'].startswith('530'):
|
||||||
host, port, credentials, self.__timeout__)
|
|
||||||
return result
|
return result
|
||||||
|
return self.ftp_bruteforce(
|
||||||
|
host, port, self.__credentials__, self.__timeout__)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def ftp_anonymous_login(host, port, timeout):
|
def ftp_anonymous_login(host, port, timeout):
|
||||||
'''Get version and check if anonympous login is enabled'''
|
'''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)
|
ftp_connection = FTP(timeout=timeout)
|
||||||
try:
|
try:
|
||||||
version = ftp_connection.connect(host=host, port=port)
|
version = ftp_connection.connect(host=host, port=port)
|
||||||
@ -31,15 +37,14 @@ class FTPScanner(AbstractScanner):
|
|||||||
result['ftp_version'] = version.lstrip('220 ')
|
result['ftp_version'] = version.lstrip('220 ')
|
||||||
# Try to login as anonymous user
|
# Try to login as anonymous user
|
||||||
ftp_connection.login()
|
ftp_connection.login()
|
||||||
result['anonymous_login'] = True
|
result['ftp_status'] = 'ok'
|
||||||
result['status'] = 'ok'
|
|
||||||
except ftplib.error_perm as e:
|
except ftplib.error_perm as e:
|
||||||
if str(e).startswith("530"):
|
if str(e).startswith("530"):
|
||||||
result['status'] = 'ok'
|
result['ftp_status'] = 'ok'
|
||||||
result['anonymous_login'] = False
|
result['anonymous_login'] = False
|
||||||
except ftplib.all_errors as e:
|
except ftplib.all_errors as e:
|
||||||
result['status'] = 'error'
|
#status - error
|
||||||
result['error_type'] = str(e)
|
result['ftp_status'] = str(e)
|
||||||
return result
|
return result
|
||||||
finally:
|
finally:
|
||||||
ftp_connection.close()
|
ftp_connection.close()
|
||||||
@ -52,6 +57,11 @@ class FTPScanner(AbstractScanner):
|
|||||||
# but we also want to reconnect if necessary.
|
# but we also want to reconnect if necessary.
|
||||||
# That is why I use cred iterator to pick up new login/pass only when
|
# That is why I use cred iterator to pick up new login/pass only when
|
||||||
# we need to.
|
# we need to.
|
||||||
|
result = {
|
||||||
|
key:None for key in ['ftp_version', 'ftp_status', 'login',
|
||||||
|
'password']
|
||||||
|
}
|
||||||
|
result['ftp_status'] = "error"
|
||||||
error_count = 0
|
error_count = 0
|
||||||
it = iter(creds)
|
it = iter(creds)
|
||||||
cred = next(it, "")
|
cred = next(it, "")
|
||||||
@ -66,7 +76,10 @@ class FTPScanner(AbstractScanner):
|
|||||||
try:
|
try:
|
||||||
ftp_connection.login(user, password)
|
ftp_connection.login(user, password)
|
||||||
ftp_connection.close()
|
ftp_connection.close()
|
||||||
return user, password
|
result['ftp_status'] = 'ok'
|
||||||
|
result['login'] = user
|
||||||
|
result['password'] = password
|
||||||
|
return result
|
||||||
except ftplib.error_perm as e:
|
except ftplib.error_perm as e:
|
||||||
# Password was wrong, checking another
|
# Password was wrong, checking another
|
||||||
cred = next(it, "")
|
cred = next(it, "")
|
||||||
@ -82,4 +95,4 @@ class FTPScanner(AbstractScanner):
|
|||||||
break
|
break
|
||||||
finally:
|
finally:
|
||||||
ftp_connection.close()
|
ftp_connection.close()
|
||||||
return None
|
return result
|
||||||
|
@ -46,18 +46,18 @@ def run_mumble():
|
|||||||
|
|
||||||
class TestFTPScanner(unittest.TestCase):
|
class TestFTPScanner(unittest.TestCase):
|
||||||
def test_closed_port(self):
|
def test_closed_port(self):
|
||||||
scanner = FTPScanner(timeout=10)
|
scanner = FTPScanner(timeout=10, credentials=TEST_CREDS)
|
||||||
result = scanner.scan_address('127.0.0.1', 31337, credentials=TEST_CREDS)
|
result = scanner.scan_address('127.0.0.1', 31337)
|
||||||
print(result)
|
print(result)
|
||||||
self.assertEqual(result['status'], 'error', "Should be error")
|
#self.assertEqual(result['status'], 'Connection refused', "Should be error")
|
||||||
self.assertTrue("Connection refused" in result['error_type'], "Connection refused")
|
self.assertTrue("Connection refused" in result['ftp_status'], "Connection refused")
|
||||||
|
|
||||||
def test_mumble(self):
|
def test_mumble(self):
|
||||||
p = multiprocessing.Process(target=run_mumble)
|
p = multiprocessing.Process(target=run_mumble)
|
||||||
p.start()
|
p.start()
|
||||||
sleep(5)
|
sleep(5)
|
||||||
scanner = FTPScanner(timeout=10)
|
scanner = FTPScanner(timeout=10, credentials=TEST_CREDS)
|
||||||
result = scanner.scan_address('127.0.0.1', PORT, credentials=TEST_CREDS)
|
result = scanner.scan_address('127.0.0.1', PORT)
|
||||||
print(result)
|
print(result)
|
||||||
self.assertEqual(result['status'], 'error', "Should be error")
|
self.assertEqual(result['status'], 'error', "Should be error")
|
||||||
self.assertTrue("timed out" in result['error_type'], "Timed out")
|
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 = multiprocessing.Process(target=run_anonymous_ftp, args=(temp_dir,))
|
||||||
p.start()
|
p.start()
|
||||||
sleep(5)
|
sleep(5)
|
||||||
scanner = FTPScanner(timeout=10)
|
scanner = FTPScanner(timeout=10, credentials=TEST_CREDS)
|
||||||
result = scanner.scan_address('127.0.0.1', PORT, credentials=TEST_CREDS)
|
result = scanner.scan_address('127.0.0.1', PORT)
|
||||||
print(result)
|
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()
|
p.terminate()
|
||||||
os.rmdir(temp_dir)
|
os.rmdir(temp_dir)
|
||||||
|
|
||||||
@ -80,10 +81,11 @@ class TestFTPScanner(unittest.TestCase):
|
|||||||
p = multiprocessing.Process(target=run_bruteforce_ftp, args=(temp_dir,))
|
p = multiprocessing.Process(target=run_bruteforce_ftp, args=(temp_dir,))
|
||||||
p.start()
|
p.start()
|
||||||
sleep(5)
|
sleep(5)
|
||||||
scanner = FTPScanner(timeout=10)
|
scanner = FTPScanner(timeout=10, credentials=TEST_CREDS)
|
||||||
result = scanner.scan_address('127.0.0.1', PORT, credentials=TEST_CREDS)
|
result = scanner.scan_address('127.0.0.1', PORT)
|
||||||
print(result)
|
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()
|
p.terminate()
|
||||||
os.rmdir(temp_dir)
|
os.rmdir(temp_dir)
|
||||||
|
|
||||||
|
@ -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}]}
|
Loading…
Reference in New Issue
Block a user