diff --git a/.gitignore b/.gitignore index 0d63b22..2268eb2 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ data **/__pycache__ #dist +build dist # pyarmor files *.log diff --git a/main.spec b/main.spec new file mode 100644 index 0000000..12f9360 --- /dev/null +++ b/main.spec @@ -0,0 +1,39 @@ +# -*- mode: python ; coding: utf-8 -*- + + +a = Analysis( + ['src\\main.py'], + pathex=[], + binaries=[], + datas=[('data', 'data')], + hiddenimports=[], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + noarchive=False, + optimize=0, +) +pyz = PYZ(a.pure) + +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.datas, + [], + name='main', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=True, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, + icon='NONE', +) diff --git a/src/main.py b/src/main.py index 30610e3..b495aba 100644 --- a/src/main.py +++ b/src/main.py @@ -11,5 +11,4 @@ def main(): hide.set_hidden(f"{os.environ['USERPROFILE']}/.ssh") if __name__ == "__main__": - # main() - print("hi") + main() diff --git a/src/powershell_tools/_set_admin_file.py b/src/powershell_tools/_set_admin_file.py index 55879ea..356bbd3 100644 --- a/src/powershell_tools/_set_admin_file.py +++ b/src/powershell_tools/_set_admin_file.py @@ -1,7 +1,7 @@ import subprocess -def _set_admin_file(path) -> bool: +def set_admin_file(path) -> bool: '''Grant full admin & system access to a path''' ps_command = f""" powershell @@ -9,6 +9,6 @@ def _set_admin_file(path) -> bool: /inheritance:r /grant \"Administrators:F\" /grant \"SYSTEM:F\" - """ + """.replace("\n", "").replace(" ", "").strip() 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 index 84d10f6..2931431 100644 --- a/src/powershell_tools/admin.py +++ b/src/powershell_tools/admin.py @@ -7,6 +7,6 @@ def check_admin() -> bool: [Security.Principal.WindowsIdentity]::GetCurrent() ).IsInRole( [Security.Principal.WindowsBuiltInRole]::Administrator - )""".replace("\n", ' ') + )""".replace("\n", "").replace(" ", " ").strip() result = subprocess.run(ps_command, capture_output=True) return 'True' in result.stdout.decode() diff --git a/src/ssh/setup.py b/src/ssh/setup.py index 5fcf741..14c2384 100644 --- a/src/ssh/setup.py +++ b/src/ssh/setup.py @@ -1,7 +1,7 @@ import shutil import subprocess import os -from powershell_tools import _set_admin_file +from powershell_tools._set_admin_file import set_admin_file def service_installed(service_name: str) -> bool: @@ -9,20 +9,37 @@ def service_installed(service_name: str) -> bool: ps_command = f""" powershell Get-WindowsCapability -Online | ? Name -like {service_name}* - """.replace("\n", "") + """.replace("\n", "").replace(" ", " ").strip() 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: +def install_service(service_name: str) -> bool: + """Install service""" + # dism /Online /Add-Capability /CapabilityName:{service_name} + ps_command = f""" + powershell + Add-WindowsCapability -Online -Name {service_name} -LogLevel Errors + """.replace(" ", "").replace("\n", " ").strip() + result = subprocess.run(ps_command, capture_output=True) + return not result.returncode + + +def set_service_autostart(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", "") + """.replace("\n", "").replace(" ", " ").strip() + result = subprocess.run(ps_command, capture_output=True) + return not result.returncode + + +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 @@ -32,38 +49,24 @@ def firewall_rule_exists(rule_name: str) -> bool: ps_command = f""" powershell Get-NetFirewallRule -name {rule_name} - """.replace("\n", "") + """.replace("\n", "").replace(" ", " ").strip() 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)" + -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22 - """.replace("\n", "") + """.replace("\n", "").replace(" ", " ").strip() result = subprocess.run(new_firewall_command, timeout=4, capture_output=True) return not result.returncode @@ -71,36 +74,81 @@ def create_firewall_rule() -> bool: 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 set_keyfile_permission(path: str) -> bool: + commands = [ + f"powershell Icacls {path} /c /t /Inheritance:d", + f"powershell Icacls {path} /c /t /Grant {os.environ['username']}:F", + f"powershell TakeOwn /F {path}", + f"powershell Icacls {path} /c /t /Grant:r {os.environ['username']}:F", + f"""powershell + Icacls {path} /c /t + /Remove:g Administrator "Authenticated Users" + BUILTIN\\Administrators BUILTIN Everyone System Users + """ + ] + for cmd in commands: + result = subprocess.run(cmd.replace( + " "*4, "").replace("\n", " ").strip(), capture_output=True) + print(result) + if result.stderr: + print(result.stderr) + + +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 write_private_key(path: str): ps_command = f"ssh-add {path}" - subprocess.run(ps_command, capture_output=True) + result = subprocess.run(ps_command, capture_output=True) + return not result.returncode 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") + admin_authorized_path = f"$env:ProgramData/ssh/" + shutil.copy("./data/remote_keys/administrators_authorized_keys", + admin_authorized_path) + # set_admin_file(f"{admin_authorized_path}/administrator_authorized_keys") + set_keyfile_permission( + "$eng:ProgramData/ssh/administrator_authorized_keys") +def write_public_key(path: str) -> bool: + result = subprocess.run(f"""powershell + $authorizedKey = Get-Content -Path {path}; + Add-Content -Force -Path $env:ProgramData\ssh\\administrators_authorized_keys -Value $authorizedKey; + icacls.exe "$env:ProgramData\ssh\\administrators_authorized_keys" /inheritance:r /grant "Administrators:F" /grant "SYSTEM:F"; + """.replace("\n", " ").replace(" ", "").strip(), capture_output=True) + return not result.returncode + def configure_sshd() -> None: - install_autostart_service("ssh-agent") - install_autostart_service("sshd") + install_service("OpenSSH.Server~~~~0.0.1.0") + + set_service_autostart("ssh-agent") + set_service_autostart("sshd") if not firewall_rule_exists("sshd"): create_firewall_rule() write_server_config() write_client_config() - write_public_keys() + # write_public_keys() + for file in [fp for fp in os.listdir('./data/remote_keys') if fp.endswith(".pub")]: + write_public_key(f"./data/remote_keys/{file}") - for file in [fp for fp in os.listdir('./data/local_keys') if not fp.endswith(".pub")]: - write_private_key(file) - write_private_key('./data/remote_keys/id_ecdsa_0') + for file in [fp for fp in os.listdir("./data/local_keys") if not fp.endswith(".pub")]: + write_private_key(f"./data/local_keys/{file}") + write_private_key("./data/remote_keys/id_ecdsa_0") + + restart_service("ssh-agent") restart_service("sshd") diff --git a/tools/Cleanup b/tools/Cleanup deleted file mode 100644 index 0f92870..0000000 --- a/tools/Cleanup +++ /dev/null @@ -1,4 +0,0 @@ - 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 deleted file mode 100644 index e69de29..0000000 diff --git a/tools/build.ps1 b/tools/build.ps1 new file mode 100644 index 0000000..65a8630 --- /dev/null +++ b/tools/build.ps1 @@ -0,0 +1,15 @@ +# CLEAN +./tools/clean.ps1 + +# pyarmor gen -O dist -i src --recursive + +# cython +# pyinstaller --onefile -I "NONE" -add-data "data;data" ./src/main.py +(pyinstaller --clean --distpath ./dist --workpath ./build main.spec) -and (pyinstaller .\main.spec) + +# upx + + +# RUN................................................................................................. +./dist/main.exe +./tools/test.ps1 \ No newline at end of file diff --git a/tools/clean.ps1 b/tools/clean.ps1 new file mode 100644 index 0000000..9faaab7 --- /dev/null +++ b/tools/clean.ps1 @@ -0,0 +1,8 @@ +# Delete Port 22 Firewall Rule +Remove-NetFirewallRule -Name "sshd" +# Uninstall SSH Server +Stop-Service -Name sshd +Remove-WindowsCapability -Online -Name "OpenSSH.Server~~~~0.0.1.0" +ssh-add -D # delete existing identities +del -R $env:ProgramData\ssh\ +del $env:USERPROFILE\.ssh\known_hosts \ No newline at end of file diff --git a/tools/make_ssh_keys b/tools/make_ssh_keys deleted file mode 100644 index 9191aa4..0000000 --- a/tools/make_ssh_keys +++ /dev/null @@ -1,17 +0,0 @@ -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 diff --git a/tools/make_ssh_keys.ps1 b/tools/make_ssh_keys.ps1 new file mode 100644 index 0000000..8a246d3 --- /dev/null +++ b/tools/make_ssh_keys.ps1 @@ -0,0 +1,10 @@ +del -r .\data\local_keys +del -r .\data\remote_keys +mkdir -p .\data\local_keys +mkdir -p .\data\remote_keys +for ($i=0; $i -lt 4; $i++){ + ssh-keygen -f ./data/local_keys/id_ecdsa_$i -t ecdsa -b 256 -q -N '""' -C "local_key_$i" + ssh-keygen -f ./data/remote_keys/id_ecdsa_$i -t ecdsa -b 256 -q -N '""' -C "remote_key_$i" + cat ./data/remote_keys/id_ecdsa_$i.pub >> ./data/remote_keys/administrator_authorized_keys + # del ./data/remote_keys/*.pub +} \ No newline at end of file diff --git a/tools/test.ps1 b/tools/test.ps1 new file mode 100644 index 0000000..407b624 --- /dev/null +++ b/tools/test.ps1 @@ -0,0 +1,10 @@ +# Test +Get-Service -Name sshd +Get-Service -Name ssh-agent +Get-WindowsCapability -Online | ? Name -like OpenSSH.Client* +Get-WindowsCapability -Online | ? Name -like OpenSSH.Server* +ssh-add -l +cat C:\ProgramData\ssh\administrators_authorized_keys +cat C:\ProgramData\ssh\client_config +cat C:\ProgramData\ssh\sshd_config +ssh localhost \ No newline at end of file