From b61f76c51f54ad08f9af6031cc9d75992639efb6 Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Wed, 23 Oct 2024 00:41:50 -0400 Subject: [PATCH 01/30] Add packet redirection for port 445 and init build script and instructions --- README.md | 29 ++++++++++++++++++ build.ps1 | 67 ++++++++++++++++++++++++++++++++++++++++++ examples/ntlmrelayx.py | 19 ++++++++++++ requirements.txt | 2 ++ setup.py | 2 +- 5 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 build.ps1 diff --git a/README.md b/README.md index fc9dba1871..fbe8bcf6a4 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,32 @@ +Impacket-exe +======== + +To build `examples/ntlmrelayx.py` into a standalone executable: + +Download and run `build.ps1` + +The built executable will be located in `C:\Program Files\ntlmrelayx\ntlmrelayx.exe` and will be available in the PATH + +OR + +1. Download & install python (Check "Add Python to PATH" during install): https://www.python.org/downloads/ +2. Download & install git: https://git-scm.com/downloads/win +3. Open a terminal as administrator +4. Run `git clone https://github.com/p0rtL6/impacket-exe` +5. Run `cd impacket-exe` +6. Run `py -m venv .venv` +7. Run `.venv\Scripts\activate` +8. Run `pip install -r requirements.txt` +9. Run `py setup.py install` +10. Run `pyinstaller --onefile examples\ntlmrelayx.py` + +The built executable will be located inside the `dist` folder + + + + + +(Original Readme) Impacket ======== diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000000..75252f24fb --- /dev/null +++ b/build.ps1 @@ -0,0 +1,67 @@ + +$TempPath = $env:TEMP + +$pythonInstaller = Join-Path -Path $TempPath -ChildPath "python-3.13.0.exe" + +$repositoryArchive = Join-Path -Path $TempPath -ChildPath "impacket-exe.zip" +$repositoryFolder = Join-Path -Path $TempPath -ChildPath "impacket-exe" + +$applicationFolder = "C:\Program Files\ntlmrelayx" + +# Download and install Python +Write-Host "Installing Python" +Invoke-WebRequest -Uri "https://www.python.org/ftp/python/3.13.0/python-3.13.0.exe" -OutFile $pythonInstaller +Start-Process $pythonInstaller -ArgumentList "/quiet PrependPath=1" -Wait +Remove-Item $pythonInstaller + +# Download and unzip repository +Write-Host "Downloading repository" +Invoke-WebRequest -Uri "https://github.com/p0rtL6/impacket-exe/archive/refs/heads/master.zip" -OutFile $repositoryArchive +Expand-Archive -Path $repositoryArchive -DestinationPath $repositoryFolder +Remove-Item $repositoryArchive + +# Begin build process +Write-Host "Beginning build process" +Set-Location -Path $repositoryFolder + +# Create and activate virtual environment +py -m venv .venv +.venv\Scripts\activate.ps1 + +# Setup +pip install -r requirements.txt +py setup.py install + +# Build +pyinstaller --onefile examples\ntlmrelayx.py + + +# Prepare destination folder +Write-Host "Copying executable to Program Files" +New-Item -ItemType Directory -Path $applicationFolder + +# Copy built executable into program files +Copy-Item -Path Join-Path -Path $repositoryFolder -ChildPath "dist\ntlmrelayx.exe" -Destination $applicationFolder -Force + +# Clean up +Write-Host "Cleaning up repository folder" +Remove-Item -Recurse -Force $repositoryFolder + +# Get the current PATH environment variable +Write-Host "Updating PATH" +$currentPath = [System.Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::Machine) + +# Check if the path already exists in PATH +if ($currentPath -notlike "*$applicationFolder*") { + # Append the new path to the existing PATH variable + $newPath = $currentPath + ";" + $applicationFolder + + # Set the new PATH variable + [System.Environment]::SetEnvironmentVariable("Path", $newPath, [System.EnvironmentVariableTarget]::Machine) + + Write-Host "Successfully added $applicationFolder to PATH." +} else { + Write-Host "$applicationFolder is already in PATH." +} + + diff --git a/examples/ntlmrelayx.py b/examples/ntlmrelayx.py index 1400f2123b..8353f9b417 100644 --- a/examples/ntlmrelayx.py +++ b/examples/ntlmrelayx.py @@ -50,6 +50,8 @@ from time import sleep from threading import Thread +import pydivert + from impacket import version from impacket.examples import logger from impacket.examples.ntlmrelayx.servers import SMBRelayServer, HTTPRelayServer, WCFRelayServer, RAWRelayServer @@ -236,6 +238,13 @@ def start_servers(options, threads): continue elif server is SMBRelayServer: + if options.smb_port == 445: + redirect_thread = Thread(target=redirect_smb_packets) + redirect_thread.start() + threads.add(redirect_thread) + + options.smb_port = 4445 + c.setListeningPort(options.smb_port) elif server is WCFRelayServer: c.setListeningPort(options.wcf_port) @@ -258,6 +267,16 @@ def stop_servers(threads): threads.remove(thread) del thread +def redirect_smb_packets(): + with pydivert.WinDivert("tcp.DstPort == 445 or tcp.SrcPort == 4445") as w: + for packet in w: + if packet.dst_port == 445: + packet.dst_port = 4445 + if packet.src_port == 4445: + packet.src_port = 445 + w.send(packet) + + # Process command-line arguments. if __name__ == '__main__': diff --git a/requirements.txt b/requirements.txt index dff4a2f436..73d6b38f1d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,3 +9,5 @@ ldap3>=2.5,!=2.5.2,!=2.5.0,!=2.6 ldapdomaindump>=0.9.0 flask>=1.0 pyreadline3;sys_platform == 'win32' +pydivert +pyinstaller diff --git a/setup.py b/setup.py index 7e9e7c9f40..de024b97ce 100644 --- a/setup.py +++ b/setup.py @@ -72,7 +72,7 @@ def read(fname): data_files=data_files, install_requires=['pyasn1>=0.2.3', 'pyasn1_modules', 'pycryptodomex', 'pyOpenSSL==24.0.0', 'six', 'ldap3>=2.5,!=2.5.2,!=2.5.0,!=2.6', - 'ldapdomaindump>=0.9.0', 'flask>=1.0', 'setuptools', 'charset_normalizer'], + 'ldapdomaindump>=0.9.0', 'flask>=1.0', 'setuptools', 'charset_normalizer', 'pydivert'], extras_require={':sys_platform=="win32"': ['pyreadline3'], }, classifiers=[ From d0eaa1080b38012465a1da9e3726f4b14e59ea9c Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Wed, 23 Oct 2024 01:25:37 -0400 Subject: [PATCH 02/30] Update install script, update install instructions, and add indication to relay for redirection --- README.md | 12 +++--------- examples/ntlmrelayx.py | 1 + build.ps1 => install-scripts/ntlmrelayx.ps1 | 20 +++++++++++--------- 3 files changed, 15 insertions(+), 18 deletions(-) rename build.ps1 => install-scripts/ntlmrelayx.ps1 (82%) diff --git a/README.md b/README.md index fbe8bcf6a4..ec76ab4860 100644 --- a/README.md +++ b/README.md @@ -3,17 +3,15 @@ Impacket-exe To build `examples/ntlmrelayx.py` into a standalone executable: -Download and run `build.ps1` +Download and run `install-scripts/ntlmrelayx.ps1` The built executable will be located in `C:\Program Files\ntlmrelayx\ntlmrelayx.exe` and will be available in the PATH OR 1. Download & install python (Check "Add Python to PATH" during install): https://www.python.org/downloads/ -2. Download & install git: https://git-scm.com/downloads/win -3. Open a terminal as administrator -4. Run `git clone https://github.com/p0rtL6/impacket-exe` -5. Run `cd impacket-exe` +2. Download this repository +3. Open a terminal as administrator and navigate to this repository 6. Run `py -m venv .venv` 7. Run `.venv\Scripts\activate` 8. Run `pip install -r requirements.txt` @@ -22,10 +20,6 @@ OR The built executable will be located inside the `dist` folder - - - - (Original Readme) Impacket ======== diff --git a/examples/ntlmrelayx.py b/examples/ntlmrelayx.py index 8353f9b417..bc7d0466ea 100644 --- a/examples/ntlmrelayx.py +++ b/examples/ntlmrelayx.py @@ -239,6 +239,7 @@ def start_servers(options, threads): elif server is SMBRelayServer: if options.smb_port == 445: + print("SMB Server port set to 445 - redirecting to port 4445") redirect_thread = Thread(target=redirect_smb_packets) redirect_thread.start() threads.add(redirect_thread) diff --git a/build.ps1 b/install-scripts/ntlmrelayx.ps1 similarity index 82% rename from build.ps1 rename to install-scripts/ntlmrelayx.ps1 index 75252f24fb..de89b9d97c 100644 --- a/build.ps1 +++ b/install-scripts/ntlmrelayx.ps1 @@ -1,10 +1,12 @@ +# Install ntlmrelayx -$TempPath = $env:TEMP +$startingDirectory = Get-Location +$tempPath = $env:TEMP $pythonInstaller = Join-Path -Path $TempPath -ChildPath "python-3.13.0.exe" $repositoryArchive = Join-Path -Path $TempPath -ChildPath "impacket-exe.zip" -$repositoryFolder = Join-Path -Path $TempPath -ChildPath "impacket-exe" +$repositoryFolder = Join-Path -Path $TempPath -ChildPath "impacket-exe-master" $applicationFolder = "C:\Program Files\ntlmrelayx" @@ -17,7 +19,7 @@ Remove-Item $pythonInstaller # Download and unzip repository Write-Host "Downloading repository" Invoke-WebRequest -Uri "https://github.com/p0rtL6/impacket-exe/archive/refs/heads/master.zip" -OutFile $repositoryArchive -Expand-Archive -Path $repositoryArchive -DestinationPath $repositoryFolder +Expand-Archive -Path $repositoryArchive -DestinationPath $tempPath -Force Remove-Item $repositoryArchive # Begin build process @@ -35,16 +37,18 @@ py setup.py install # Build pyinstaller --onefile examples\ntlmrelayx.py - # Prepare destination folder Write-Host "Copying executable to Program Files" -New-Item -ItemType Directory -Path $applicationFolder +New-Item -ItemType Directory -Path $applicationFolder -Force # Copy built executable into program files -Copy-Item -Path Join-Path -Path $repositoryFolder -ChildPath "dist\ntlmrelayx.exe" -Destination $applicationFolder -Force +$application = Join-Path -Path $repositoryFolder -ChildPath "dist\ntlmrelayx.exe" +Copy-Item -Path $application -Destination $applicationFolder -Force # Clean up Write-Host "Cleaning up repository folder" +deactivate +Set-Location -Path $startingDirectory Remove-Item -Recurse -Force $repositoryFolder # Get the current PATH environment variable @@ -62,6 +66,4 @@ if ($currentPath -notlike "*$applicationFolder*") { Write-Host "Successfully added $applicationFolder to PATH." } else { Write-Host "$applicationFolder is already in PATH." -} - - +} \ No newline at end of file From 7abc07eb99f1b14c76fb2e77c254ffea858dc5ba Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Wed, 23 Oct 2024 02:44:22 -0400 Subject: [PATCH 03/30] update install script to check existing python installs and remove after done + Print notification about redirecting ports --- README.md | 4 ++- examples/ntlmrelayx.py | 2 +- install-scripts/ntlmrelayx.ps1 | 53 +++++++++++++++++++++++++++++----- 3 files changed, 49 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index ec76ab4860..c3b721b49a 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,9 @@ Impacket-exe To build `examples/ntlmrelayx.py` into a standalone executable: -Download and run `install-scripts/ntlmrelayx.ps1` +Download and run `install-scripts/ntlmrelayx.ps1` as administrator +* If you get an error about the script not being signed, run `Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process +`, and type `a` when prompted The built executable will be located in `C:\Program Files\ntlmrelayx\ntlmrelayx.exe` and will be available in the PATH diff --git a/examples/ntlmrelayx.py b/examples/ntlmrelayx.py index bc7d0466ea..b60d87e16f 100644 --- a/examples/ntlmrelayx.py +++ b/examples/ntlmrelayx.py @@ -239,7 +239,7 @@ def start_servers(options, threads): elif server is SMBRelayServer: if options.smb_port == 445: - print("SMB Server port set to 445 - redirecting to port 4445") + print("[*] SMB Server port set to 445 - redirecting to port 4445") redirect_thread = Thread(target=redirect_smb_packets) redirect_thread.start() threads.add(redirect_thread) diff --git a/install-scripts/ntlmrelayx.ps1 b/install-scripts/ntlmrelayx.ps1 index de89b9d97c..d30d9c01b6 100644 --- a/install-scripts/ntlmrelayx.ps1 +++ b/install-scripts/ntlmrelayx.ps1 @@ -10,11 +10,42 @@ $repositoryFolder = Join-Path -Path $TempPath -ChildPath "impacket-exe-master" $applicationFolder = "C:\Program Files\ntlmrelayx" +$machinePythonKey = "HKLM:\Software\Python\PythonCore" +$userPythonKey = "HKCU:\Software\Python\PythonCore" + +$foundPython = $false + +# Check Local Machine Registry +if (Test-Path $machinePythonKey) { + Get-ChildItem $machinePythonKey | ForEach-Object { + $versionInfo = Get-ItemProperty $_.PSPath + if ($_.PSChildName -eq "3.13") { + $foundPython = $true + Write-Host "Python $($_.PSChildName) found in Local Machine: $($versionInfo.InstallPath)" + } + } +} + +# Check Current User Registry +if (Test-Path $userPythonKey) { + Get-ChildItem $userPythonKey | ForEach-Object { + $versionInfo = Get-ItemProperty $_.PSPath + if ($_.PSChildName -eq "3.13") { + $foundPython = $true + Write-Host "Python $($_.PSChildName) found in Current User: $($versionInfo.InstallPath)" + } + } +} + # Download and install Python -Write-Host "Installing Python" -Invoke-WebRequest -Uri "https://www.python.org/ftp/python/3.13.0/python-3.13.0.exe" -OutFile $pythonInstaller -Start-Process $pythonInstaller -ArgumentList "/quiet PrependPath=1" -Wait -Remove-Item $pythonInstaller +if (-not $foundPython) { + Write-Host "Python 3.13 is not installed, installing now" + Invoke-WebRequest -Uri "https://www.python.org/ftp/python/3.13.0/python-3.13.0-amd64.exe" -OutFile $pythonInstaller + Start-Process $pythonInstaller -ArgumentList "/quiet PrependPath=1 Include_launcher=0" -Wait + + # Refresh PATH + $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") +} # Download and unzip repository Write-Host "Downloading repository" @@ -27,12 +58,12 @@ Write-Host "Beginning build process" Set-Location -Path $repositoryFolder # Create and activate virtual environment -py -m venv .venv +python -m venv .venv .venv\Scripts\activate.ps1 # Setup pip install -r requirements.txt -py setup.py install +python setup.py install # Build pyinstaller --onefile examples\ntlmrelayx.py @@ -46,11 +77,15 @@ $application = Join-Path -Path $repositoryFolder -ChildPath "dist\ntlmrelayx.exe Copy-Item -Path $application -Destination $applicationFolder -Force # Clean up -Write-Host "Cleaning up repository folder" +Write-Host "Cleaning up" deactivate Set-Location -Path $startingDirectory Remove-Item -Recurse -Force $repositoryFolder +if (-not $foundPython) { + Start-Process $pythonInstaller -ArgumentList "/uninstall /quiet PrependPath=1" -Wait +} + # Get the current PATH environment variable Write-Host "Updating PATH" $currentPath = [System.Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::Machine) @@ -66,4 +101,6 @@ if ($currentPath -notlike "*$applicationFolder*") { Write-Host "Successfully added $applicationFolder to PATH." } else { Write-Host "$applicationFolder is already in PATH." -} \ No newline at end of file +} + +Write-Host "Done!" From adfdffe3740212fa80deb9099cfb67addb2d3530 Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Wed, 23 Oct 2024 02:46:31 -0400 Subject: [PATCH 04/30] Fix formatting --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index c3b721b49a..f48b62c068 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,7 @@ Impacket-exe To build `examples/ntlmrelayx.py` into a standalone executable: Download and run `install-scripts/ntlmrelayx.ps1` as administrator -* If you get an error about the script not being signed, run `Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process -`, and type `a` when prompted +* If you get an error about the script not being signed, run `Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process`, and type `a` when prompted The built executable will be located in `C:\Program Files\ntlmrelayx\ntlmrelayx.exe` and will be available in the PATH From d8cc4d52f10ec5ece578bee3d020d4c9a7742b4c Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Wed, 23 Oct 2024 02:56:24 -0400 Subject: [PATCH 05/30] Add installer for secretsdump --- install-scripts/secretsdump.ps1 | 106 ++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 install-scripts/secretsdump.ps1 diff --git a/install-scripts/secretsdump.ps1 b/install-scripts/secretsdump.ps1 new file mode 100644 index 0000000000..16fb7158ab --- /dev/null +++ b/install-scripts/secretsdump.ps1 @@ -0,0 +1,106 @@ +# Install secretsdump + +$startingDirectory = Get-Location +$tempPath = $env:TEMP + +$pythonInstaller = Join-Path -Path $TempPath -ChildPath "python-3.13.0.exe" + +$repositoryArchive = Join-Path -Path $TempPath -ChildPath "impacket-exe.zip" +$repositoryFolder = Join-Path -Path $TempPath -ChildPath "impacket-exe-master" + +$applicationFolder = "C:\Program Files\secretsdump" + +$machinePythonKey = "HKLM:\Software\Python\PythonCore" +$userPythonKey = "HKCU:\Software\Python\PythonCore" + +$foundPython = $false + +# Check Local Machine Registry +if (Test-Path $machinePythonKey) { + Get-ChildItem $machinePythonKey | ForEach-Object { + $versionInfo = Get-ItemProperty $_.PSPath + if ($_.PSChildName -eq "3.13") { + $foundPython = $true + Write-Host "Python $($_.PSChildName) found in Local Machine: $($versionInfo.InstallPath)" + } + } +} + +# Check Current User Registry +if (Test-Path $userPythonKey) { + Get-ChildItem $userPythonKey | ForEach-Object { + $versionInfo = Get-ItemProperty $_.PSPath + if ($_.PSChildName -eq "3.13") { + $foundPython = $true + Write-Host "Python $($_.PSChildName) found in Current User: $($versionInfo.InstallPath)" + } + } +} + +# Download and install Python +if (-not $foundPython) { + Write-Host "Python 3.13 is not installed, installing now" + Invoke-WebRequest -Uri "https://www.python.org/ftp/python/3.13.0/python-3.13.0-amd64.exe" -OutFile $pythonInstaller + Start-Process $pythonInstaller -ArgumentList "/quiet PrependPath=1 Include_launcher=0" -Wait + + # Refresh PATH + $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") +} + +# Download and unzip repository +Write-Host "Downloading repository" +Invoke-WebRequest -Uri "https://github.com/p0rtL6/impacket-exe/archive/refs/heads/master.zip" -OutFile $repositoryArchive +Expand-Archive -Path $repositoryArchive -DestinationPath $tempPath -Force +Remove-Item $repositoryArchive + +# Begin build process +Write-Host "Beginning build process" +Set-Location -Path $repositoryFolder + +# Create and activate virtual environment +python -m venv .venv +.venv\Scripts\activate.ps1 + +# Setup +pip install -r requirements.txt +python setup.py install + +# Build +pyinstaller --onefile examples\secretsdump.py + +# Prepare destination folder +Write-Host "Copying executable to Program Files" +New-Item -ItemType Directory -Path $applicationFolder -Force + +# Copy built executable into program files +$application = Join-Path -Path $repositoryFolder -ChildPath "dist\secretsdump.exe" +Copy-Item -Path $application -Destination $applicationFolder -Force + +# Clean up +Write-Host "Cleaning up" +deactivate +Set-Location -Path $startingDirectory +Remove-Item -Recurse -Force $repositoryFolder + +if (-not $foundPython) { + Start-Process $pythonInstaller -ArgumentList "/uninstall /quiet PrependPath=1" -Wait +} + +# Get the current PATH environment variable +Write-Host "Updating PATH" +$currentPath = [System.Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::Machine) + +# Check if the path already exists in PATH +if ($currentPath -notlike "*$applicationFolder*") { + # Append the new path to the existing PATH variable + $newPath = $currentPath + ";" + $applicationFolder + + # Set the new PATH variable + [System.Environment]::SetEnvironmentVariable("Path", $newPath, [System.EnvironmentVariableTarget]::Machine) + + Write-Host "Successfully added $applicationFolder to PATH." +} else { + Write-Host "$applicationFolder is already in PATH." +} + +Write-Host "Done!" From 97024971392a782e550eb48c46e3cbeceda2a549 Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Wed, 23 Oct 2024 03:06:40 -0400 Subject: [PATCH 06/30] Update README --- README.md | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index f48b62c068..f8c0bde0cf 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,41 @@ Impacket-exe ======== -To build `examples/ntlmrelayx.py` into a standalone executable: +To build a tool into an executable: -Download and run `install-scripts/ntlmrelayx.ps1` as administrator -* If you get an error about the script not being signed, run `Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process`, and type `a` when prompted +EITHER -The built executable will be located in `C:\Program Files\ntlmrelayx\ntlmrelayx.exe` and will be available in the PATH +Use one of the installers: + +* Choose the installer for the tool from the `install-scripts` folder, available options are: + +``` +ntlmrelayx +secretsdump +``` + +Run the install script as administrator in Powershell + +``` +Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process +[install script].ps1 +``` + +The built executable will be located in `C:\Program Files` and will be available in the PATH OR -1. Download & install python (Check "Add Python to PATH" during install): https://www.python.org/downloads/ -2. Download this repository -3. Open a terminal as administrator and navigate to this repository -6. Run `py -m venv .venv` -7. Run `.venv\Scripts\activate` -8. Run `pip install -r requirements.txt` -9. Run `py setup.py install` -10. Run `pyinstaller --onefile examples\ntlmrelayx.py` +* Download & install python (Check "Add Python to PATH" during install) +* Download this repository +* Open a terminal as administrator and navigate to this repository +* Run the following commands +``` +py -m venv .venv +.venv\Scripts\activate +pip install -r requirements.txt +py setup.py install +pyinstaller --onefile examples\[your tool].py +``` The built executable will be located inside the `dist` folder From cbbd5140ab7774482e60f59550a4a003a800ff78 Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Wed, 23 Oct 2024 20:23:54 -0400 Subject: [PATCH 07/30] Update Installer and README --- README.md | 13 +- impacket-exe-installer.ps1 | 272 ++++++++++++++++++++++++++++++++ install-scripts/ntlmrelayx.ps1 | 106 ------------- install-scripts/secretsdump.ps1 | 106 ------------- 4 files changed, 275 insertions(+), 222 deletions(-) create mode 100644 impacket-exe-installer.ps1 delete mode 100644 install-scripts/ntlmrelayx.ps1 delete mode 100644 install-scripts/secretsdump.ps1 diff --git a/README.md b/README.md index f8c0bde0cf..39f78a6644 100644 --- a/README.md +++ b/README.md @@ -5,24 +5,17 @@ To build a tool into an executable: EITHER -Use one of the installers: +Use the installer: -* Choose the installer for the tool from the `install-scripts` folder, available options are: - -``` -ntlmrelayx -secretsdump -``` +* Download `impacket-exe-installer.ps1`: Run the install script as administrator in Powershell ``` Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process -[install script].ps1 +impacket-exe-installer.ps1 ``` -The built executable will be located in `C:\Program Files` and will be available in the PATH - OR * Download & install python (Check "Add Python to PATH" during install) diff --git a/impacket-exe-installer.ps1 b/impacket-exe-installer.ps1 new file mode 100644 index 0000000000..fc0fe3e345 --- /dev/null +++ b/impacket-exe-installer.ps1 @@ -0,0 +1,272 @@ +# Impacket-exe Installer + +## CMD ARG CONFIG ## + +$PythonVersion = '3.13.0' +$StartingDirectory = Get-Location + +$AvailableScripts = New-Object System.Collections.Generic.HashSet[string] +$AvailableScripts.Add('ntlmrelayx') | Out-Null +$AvailableScripts.Add('secretsdump') | Out-Null + +$SelectedScripts = New-Object System.Collections.Generic.HashSet[string] + +$Options = New-object System.Collections.Hashtable +$Options['OutputDir'] = @{ + Name = 'Output Directory' + Desc = 'Set the output directory for the built executable' + Keywords = @('-o', '--output-dir') + Value = $StartingDirectory + Type = 'Path' +} + +$Flags = New-object System.Collections.Hashtable +$Flags['OverridePython'] = @{ + Name = 'Override Installed Python' + Desc = "Install Python $PythonVersion even if an existing python version is installed" + Keywords = @('-P', '--override-python') + Value = $False +} +$Flags['LeavePython'] = @{ + Name = 'Leave Installed Python' + Desc = 'If installed, do not uninstall Python $PythonVersion from the system' + Keywords = @('-L', '--leave-python') + Value = $False +} +$Flags['InstallSystemWide'] = @{ + Name = 'Install Scripts System-Wide' + Desc = 'Install scripts to C:\Program Files\ and add them to the PATH (Ignores Output Directory)' + Keywords = @('-I', '--install-systemwide') + Value = $False +} + + +function GetKeyByKeyword { + param ( + [hashtable]$HashTable, + [string]$Keyword + ) + + foreach ($Key in $HashTable.Keys) { + $Item = $HashTable[$Key] + if ($Item.Keywords -contains $Keyword) { + return $Key + } + } + return $Null +} + +$HelpMenuPadding = 25 + +function Show-HelpMenu { + Write-Host '=== Impacket-exe Installer ===' + Write-Host 'Downloads, builds, and installs scripts from the Impacket-exe repository' + Write-Host '' + Write-Host 'Usage: impacket-exe-installer.ps1 [FLAGS] [OPTIONS] ' + Write-Host '' + Write-Host 'Positional Arguments:' + Write-Host " $(''.PadRight($HelpMenuPadding)) A space seperated list of scripts you want to install" + Write-Host '' + Write-Host 'Flags:' + foreach ($Flag in $Flags.Values) { + $FormattedKeywords = $Flag['Keywords'] -join ' ' + Write-Host " $($FormattedKeywords.PadRight($HelpMenuPadding)) $($Flag['Desc']) (default: $($Flag['Value']))" + } + Write-Host '' + Write-Host 'Options:' + Write-Host " $('-h --help'.PadRight($HelpMenuPadding)) Display this menu" + foreach ($Option in $Options.Values) { + $FormattedKeywords = $Option['Keywords'] -join ' ' + Write-Host " $($FormattedKeywords.PadRight($HelpMenuPadding)) $($Option['Desc']) (default: $($Option['Value']))" + } + Write-Host '' +} + +## PARSING CMD ARGS ## + +if ($Args.Count -eq 0) { + Show-HelpMenu + exit 0 +} + +for ($I = 0; $I -lt $Args.Count; $I++) { + if ($Args[$I] -eq '-h' -or $Args[$I] -eq '--help') { + Show-HelpMenu + exit 0 + } + elseif ($Args[$I].startsWith('-')) { + $ArgParts = $Args[$I] -split '=' + $Keyword = $ArgParts[0] + $Value = $Null + + $FlagsKey = GetKeyByKeyword -HashTable $Flags -Keyword $Keyword + $OptionsKey = GetKeyByKeyword -HashTable $Options -Keyword $Keyword + + if ($ArgParts.Count -eq 2) { + $Value = $ArgParts[1] + } + elseif ($ArgParts.Count -gt 1) { + Write-Host "Error in $($Options[$OptionsKey]['Name']): Multiple equals signs`n" + Show-HelpMenu + throw + } + + if ($FlagsKey){ + $Flags[$FlagsKey]['Value'] = $True + } + elseif ($OptionsKey) { + if (-not $Value) { + $I++ + $Value = $Args[$I] + } + if (-not $Value) { + Write-Host "Error in $($Options[$OptionsKey]['Name']): No value recieved`n" + Show-HelpMenu + throw + } + if ($Options[$OptionsKey]['type'] -eq 'Path' -and -not (Test-Path $Value)) { + Write-Host "Error in $($Options[$OptionsKey]['Name']): Path does not exist`n" + Show-HelpMenu + throw + } + $Options[$OptionsKey]['Value'] = $Value + } + else { + Write-Host "Error: Unrecognized argument`n" + Show-HelpMenu + throw + } + } + elseif ($AvailableScripts.Contains($Args[$I])) { + $SelectedScripts.Add($Args[$I]) | Out-Null + } + else { + $AvailableScriptsList = $AvailableScripts -join "`n " + Write-Host "Error: Invalid installer selected, available options are:`n $AvailableScriptsList`n" + Show-HelpMenu + throw + } +} + +if ($SelectedScripts.Count -eq 0) { + Write-Host "Error: Must select at least one script to install`n" + Show-HelpMenu + throw +} + +## BEGIN INSTALLING ## + +$TempPath = $Env:TEMP + +$PythonInstaller = Join-Path -Path $TempPath -ChildPath "python-$PythonVersion.exe" + +$RepositoryArchive = Join-Path -Path $TempPath -ChildPath "impacket-exe.zip" +$RepositoryFolder = Join-Path -Path $TempPath -ChildPath "impacket-exe-master" + +$MachinePythonKey = "HKLM:\Software\Python\PythonCore" +$UserPythonKey = "HKCU:\Software\Python\PythonCore" +$FoundPython = $False + +$PythonVersionParts = $PythonVersion.Split(".") +$TruncatedPythonVersion = "$($PythonVersionParts[0]).$($PythonVersionParts[1])" + +# Check Local Machine Registry +if (Test-Path $MachinePythonKey) { + Get-ChildItem $MachinePythonKey | ForEach-Object { + if ($_.PSChildName -eq $TruncatedPythonVersion) { + $FoundPython = $True + Write-Host "Python $($_.PSChildName) found in Local Machine" + } + } +} + +# Check Current User Registry +if (Test-Path $UserPythonKey) { + Get-ChildItem $UserPythonKey | ForEach-Object { + if ($_.PSChildName -eq $TruncatedPythonVersion) { + $FoundPython = $True + Write-Host "Python $($_.PSChildName) found in Current User" + } + } +} + +# Download and install Python +if (-not $FoundPython -or $Flags['OverridePython']['Value']) { + Write-Host "Python $PythonVersion is not installed, installing now..." + Invoke-WebRequest -Uri "https://www.python.org/ftp/python/$PythonVersion/python-$PythonVersion-amd64.exe" -OutFile $PythonInstaller + Start-Process $PythonInstaller -ArgumentList "/quiet PrependPath=1 Include_launcher=0" -Wait + + # Refresh PATH + $Env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") +} + +# Download and unzip repository +Write-Host 'Downloading repository...' +Invoke-WebRequest -Uri "https://github.com/p0rtL6/impacket-exe/archive/refs/heads/master.zip" -OutFile $RepositoryArchive +Expand-Archive -Path $RepositoryArchive -DestinationPath $TempPath -Force +Remove-Item $RepositoryArchive + +# Begin build process +Write-Host 'Beginning build process...' +Set-Location -Path $RepositoryFolder + +# Create and activate virtual environment +python -m venv .venv +.venv\Scripts\activate.ps1 + +# Setup +pip install -r requirements.txt +python setup.py install + +foreach ($Script in $SelectedScripts) { + Write-Host "Building $Script..." + + # Build + pyinstaller --onefile "examples\$Script.py" + + $BuiltScriptPath = Join-Path -Path $RepositoryFolder -ChildPath "dist\$Script.exe" + + if ($Flags['InstallSystemWide']['Value']) { + # Prepare destination folder + Write-Host "Copying executable to Program Files..." + New-Item -ItemType Directory -Path 'C:\Program Files\Impacket-exe' -Force + + # Copy built executable into program files + Copy-Item -Path $BuiltScriptPath -Destination 'C:\Program Files\Impacket-exe' -Force + } + else { + Copy-Item -Path $BuiltScriptPath -Destination $Options['OutputDir']['Value'] -Force + } +} + +if ($Flags['InstallSystemWide']['Value']) { + # Get the current PATH environment variable + Write-Host "Updating PATH..." + $CurrentPath = [System.Environment]::GetEnvironmentVariable('Path', [System.EnvironmentVariableTarget]::Machine) + + # Check if the path already exists in PATH + if ($CurrentPath -notlike "*C:\Program Files\Impacket-exe*") { + # Append the new path to the existing PATH variable + $NewPath = $CurrentPath + ';' + 'C:\Program Files\Impacket-exe' + + # Set the new PATH variable + [System.Environment]::SetEnvironmentVariable('Path', $NewPath, [System.EnvironmentVariableTarget]::Machine) + + Write-Host 'Successfully added C:\Program Files\Impacket-exe to PATH.' + } else { + Write-Host 'C:\Program Files\Impacket-exe is already in PATH.' + } +} + +# Clean up +Write-Host 'Cleaning up...' +deactivate +Set-Location -Path $StartingDirectory +Remove-Item -Recurse -Force $RepositoryFolder + +if (-not $Flags['LeavePython']['Value'] -and (-not $FoundPython -or $Flags['OverridePython']['Value'])) { + Write-Host 'Uninstalling Python...' + Start-Process $PythonInstaller -ArgumentList "/uninstall /quiet PrependPath=1" -Wait +} + +Write-Host 'Done!' diff --git a/install-scripts/ntlmrelayx.ps1 b/install-scripts/ntlmrelayx.ps1 deleted file mode 100644 index d30d9c01b6..0000000000 --- a/install-scripts/ntlmrelayx.ps1 +++ /dev/null @@ -1,106 +0,0 @@ -# Install ntlmrelayx - -$startingDirectory = Get-Location -$tempPath = $env:TEMP - -$pythonInstaller = Join-Path -Path $TempPath -ChildPath "python-3.13.0.exe" - -$repositoryArchive = Join-Path -Path $TempPath -ChildPath "impacket-exe.zip" -$repositoryFolder = Join-Path -Path $TempPath -ChildPath "impacket-exe-master" - -$applicationFolder = "C:\Program Files\ntlmrelayx" - -$machinePythonKey = "HKLM:\Software\Python\PythonCore" -$userPythonKey = "HKCU:\Software\Python\PythonCore" - -$foundPython = $false - -# Check Local Machine Registry -if (Test-Path $machinePythonKey) { - Get-ChildItem $machinePythonKey | ForEach-Object { - $versionInfo = Get-ItemProperty $_.PSPath - if ($_.PSChildName -eq "3.13") { - $foundPython = $true - Write-Host "Python $($_.PSChildName) found in Local Machine: $($versionInfo.InstallPath)" - } - } -} - -# Check Current User Registry -if (Test-Path $userPythonKey) { - Get-ChildItem $userPythonKey | ForEach-Object { - $versionInfo = Get-ItemProperty $_.PSPath - if ($_.PSChildName -eq "3.13") { - $foundPython = $true - Write-Host "Python $($_.PSChildName) found in Current User: $($versionInfo.InstallPath)" - } - } -} - -# Download and install Python -if (-not $foundPython) { - Write-Host "Python 3.13 is not installed, installing now" - Invoke-WebRequest -Uri "https://www.python.org/ftp/python/3.13.0/python-3.13.0-amd64.exe" -OutFile $pythonInstaller - Start-Process $pythonInstaller -ArgumentList "/quiet PrependPath=1 Include_launcher=0" -Wait - - # Refresh PATH - $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") -} - -# Download and unzip repository -Write-Host "Downloading repository" -Invoke-WebRequest -Uri "https://github.com/p0rtL6/impacket-exe/archive/refs/heads/master.zip" -OutFile $repositoryArchive -Expand-Archive -Path $repositoryArchive -DestinationPath $tempPath -Force -Remove-Item $repositoryArchive - -# Begin build process -Write-Host "Beginning build process" -Set-Location -Path $repositoryFolder - -# Create and activate virtual environment -python -m venv .venv -.venv\Scripts\activate.ps1 - -# Setup -pip install -r requirements.txt -python setup.py install - -# Build -pyinstaller --onefile examples\ntlmrelayx.py - -# Prepare destination folder -Write-Host "Copying executable to Program Files" -New-Item -ItemType Directory -Path $applicationFolder -Force - -# Copy built executable into program files -$application = Join-Path -Path $repositoryFolder -ChildPath "dist\ntlmrelayx.exe" -Copy-Item -Path $application -Destination $applicationFolder -Force - -# Clean up -Write-Host "Cleaning up" -deactivate -Set-Location -Path $startingDirectory -Remove-Item -Recurse -Force $repositoryFolder - -if (-not $foundPython) { - Start-Process $pythonInstaller -ArgumentList "/uninstall /quiet PrependPath=1" -Wait -} - -# Get the current PATH environment variable -Write-Host "Updating PATH" -$currentPath = [System.Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::Machine) - -# Check if the path already exists in PATH -if ($currentPath -notlike "*$applicationFolder*") { - # Append the new path to the existing PATH variable - $newPath = $currentPath + ";" + $applicationFolder - - # Set the new PATH variable - [System.Environment]::SetEnvironmentVariable("Path", $newPath, [System.EnvironmentVariableTarget]::Machine) - - Write-Host "Successfully added $applicationFolder to PATH." -} else { - Write-Host "$applicationFolder is already in PATH." -} - -Write-Host "Done!" diff --git a/install-scripts/secretsdump.ps1 b/install-scripts/secretsdump.ps1 deleted file mode 100644 index 16fb7158ab..0000000000 --- a/install-scripts/secretsdump.ps1 +++ /dev/null @@ -1,106 +0,0 @@ -# Install secretsdump - -$startingDirectory = Get-Location -$tempPath = $env:TEMP - -$pythonInstaller = Join-Path -Path $TempPath -ChildPath "python-3.13.0.exe" - -$repositoryArchive = Join-Path -Path $TempPath -ChildPath "impacket-exe.zip" -$repositoryFolder = Join-Path -Path $TempPath -ChildPath "impacket-exe-master" - -$applicationFolder = "C:\Program Files\secretsdump" - -$machinePythonKey = "HKLM:\Software\Python\PythonCore" -$userPythonKey = "HKCU:\Software\Python\PythonCore" - -$foundPython = $false - -# Check Local Machine Registry -if (Test-Path $machinePythonKey) { - Get-ChildItem $machinePythonKey | ForEach-Object { - $versionInfo = Get-ItemProperty $_.PSPath - if ($_.PSChildName -eq "3.13") { - $foundPython = $true - Write-Host "Python $($_.PSChildName) found in Local Machine: $($versionInfo.InstallPath)" - } - } -} - -# Check Current User Registry -if (Test-Path $userPythonKey) { - Get-ChildItem $userPythonKey | ForEach-Object { - $versionInfo = Get-ItemProperty $_.PSPath - if ($_.PSChildName -eq "3.13") { - $foundPython = $true - Write-Host "Python $($_.PSChildName) found in Current User: $($versionInfo.InstallPath)" - } - } -} - -# Download and install Python -if (-not $foundPython) { - Write-Host "Python 3.13 is not installed, installing now" - Invoke-WebRequest -Uri "https://www.python.org/ftp/python/3.13.0/python-3.13.0-amd64.exe" -OutFile $pythonInstaller - Start-Process $pythonInstaller -ArgumentList "/quiet PrependPath=1 Include_launcher=0" -Wait - - # Refresh PATH - $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") -} - -# Download and unzip repository -Write-Host "Downloading repository" -Invoke-WebRequest -Uri "https://github.com/p0rtL6/impacket-exe/archive/refs/heads/master.zip" -OutFile $repositoryArchive -Expand-Archive -Path $repositoryArchive -DestinationPath $tempPath -Force -Remove-Item $repositoryArchive - -# Begin build process -Write-Host "Beginning build process" -Set-Location -Path $repositoryFolder - -# Create and activate virtual environment -python -m venv .venv -.venv\Scripts\activate.ps1 - -# Setup -pip install -r requirements.txt -python setup.py install - -# Build -pyinstaller --onefile examples\secretsdump.py - -# Prepare destination folder -Write-Host "Copying executable to Program Files" -New-Item -ItemType Directory -Path $applicationFolder -Force - -# Copy built executable into program files -$application = Join-Path -Path $repositoryFolder -ChildPath "dist\secretsdump.exe" -Copy-Item -Path $application -Destination $applicationFolder -Force - -# Clean up -Write-Host "Cleaning up" -deactivate -Set-Location -Path $startingDirectory -Remove-Item -Recurse -Force $repositoryFolder - -if (-not $foundPython) { - Start-Process $pythonInstaller -ArgumentList "/uninstall /quiet PrependPath=1" -Wait -} - -# Get the current PATH environment variable -Write-Host "Updating PATH" -$currentPath = [System.Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::Machine) - -# Check if the path already exists in PATH -if ($currentPath -notlike "*$applicationFolder*") { - # Append the new path to the existing PATH variable - $newPath = $currentPath + ";" + $applicationFolder - - # Set the new PATH variable - [System.Environment]::SetEnvironmentVariable("Path", $newPath, [System.EnvironmentVariableTarget]::Machine) - - Write-Host "Successfully added $applicationFolder to PATH." -} else { - Write-Host "$applicationFolder is already in PATH." -} - -Write-Host "Done!" From e186676367e3039312793a13223a4fc59baa86ca Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Wed, 23 Oct 2024 20:25:35 -0400 Subject: [PATCH 08/30] Update Help message --- impacket-exe-installer.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/impacket-exe-installer.ps1 b/impacket-exe-installer.ps1 index fc0fe3e345..6085cbaf90 100644 --- a/impacket-exe-installer.ps1 +++ b/impacket-exe-installer.ps1 @@ -62,7 +62,7 @@ function Show-HelpMenu { Write-Host '=== Impacket-exe Installer ===' Write-Host 'Downloads, builds, and installs scripts from the Impacket-exe repository' Write-Host '' - Write-Host 'Usage: impacket-exe-installer.ps1 [FLAGS] [OPTIONS] ' + Write-Host 'Usage: impacket-exe-installer.ps1 [FLAGS] [OPTIONS] []' Write-Host '' Write-Host 'Positional Arguments:' Write-Host " $(''.PadRight($HelpMenuPadding)) A space seperated list of scripts you want to install" From b28c5a082f21900b77cc7999ede4c98a96bc1c8b Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Wed, 23 Oct 2024 20:31:30 -0400 Subject: [PATCH 09/30] Add list of available scripts in help message --- impacket-exe-installer.ps1 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/impacket-exe-installer.ps1 b/impacket-exe-installer.ps1 index 6085cbaf90..51848e38b7 100644 --- a/impacket-exe-installer.ps1 +++ b/impacket-exe-installer.ps1 @@ -80,6 +80,11 @@ function Show-HelpMenu { Write-Host " $($FormattedKeywords.PadRight($HelpMenuPadding)) $($Option['Desc']) (default: $($Option['Value']))" } Write-Host '' + Write-Host 'Available Scripts:' + foreach ($AvailableScript in $AvailableScripts) { + Write-Host " $AvailableScript" + } + Write-Host '' } ## PARSING CMD ARGS ## From 13d2e223d831d7eb64249698e4f944df3785fb0c Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Wed, 23 Oct 2024 20:36:39 -0400 Subject: [PATCH 10/30] Fix issue with command description --- impacket-exe-installer.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/impacket-exe-installer.ps1 b/impacket-exe-installer.ps1 index 51848e38b7..bf64269856 100644 --- a/impacket-exe-installer.ps1 +++ b/impacket-exe-installer.ps1 @@ -29,7 +29,7 @@ $Flags['OverridePython'] = @{ } $Flags['LeavePython'] = @{ Name = 'Leave Installed Python' - Desc = 'If installed, do not uninstall Python $PythonVersion from the system' + Desc = "If installed, do not uninstall Python $PythonVersion from the system" Keywords = @('-L', '--leave-python') Value = $False } From 6278ec7f2a1b6d3cc3db5dfc1e560255c70d491c Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Wed, 23 Oct 2024 21:37:21 -0400 Subject: [PATCH 11/30] update readme and install script --- README.md | 1 + impacket-exe-installer.ps1 | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 39f78a6644..69c79f450f 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ Impacket-exe ======== To build a tool into an executable: +* You may have to disable Windows AV EITHER diff --git a/impacket-exe-installer.ps1 b/impacket-exe-installer.ps1 index bf64269856..aa28acf84f 100644 --- a/impacket-exe-installer.ps1 +++ b/impacket-exe-installer.ps1 @@ -5,9 +5,7 @@ $PythonVersion = '3.13.0' $StartingDirectory = Get-Location -$AvailableScripts = New-Object System.Collections.Generic.HashSet[string] -$AvailableScripts.Add('ntlmrelayx') | Out-Null -$AvailableScripts.Add('secretsdump') | Out-Null +$AvailableScripts = [System.Collections.Generic.HashSet[string]] @('DumpNTLMInfo','Get-GPPPassword','GetADComputers','GetADUsers','GetLAPSPassword','GetNPUsers','GetUserSPNs','addcomputer','atexec','changepasswd','dacledit','dcomexec','describeTicket','dpapi','esentutl','exchanger','findDelegation','getArch','getPac','getST','getTGT','goldenPac','karmaSMB','keylistattack','kintercept','lookupsid','machine_role','mimikatz','mqtt_check','mssqlclient','mssqlinstance','net','netview','ntfs-read','ntlmrelayx','owneredit','ping','ping6','psexec','raiseChild','rbcd','rdp_check','reg','registry-read','rpcdump','rpcmap','sambaPipe','samrdump','secretsdump','services','smbclient','smbexec','smbserver','sniff','sniffer','split','ticketConverter','ticketer','tstool','wmiexec','wmipersist','wmiquery') $SelectedScripts = New-Object System.Collections.Generic.HashSet[string] @@ -75,16 +73,12 @@ function Show-HelpMenu { Write-Host '' Write-Host 'Options:' Write-Host " $('-h --help'.PadRight($HelpMenuPadding)) Display this menu" + Write-Host " $('-s --list-scripts'.PadRight($HelpMenuPadding)) List available scripts" foreach ($Option in $Options.Values) { $FormattedKeywords = $Option['Keywords'] -join ' ' Write-Host " $($FormattedKeywords.PadRight($HelpMenuPadding)) $($Option['Desc']) (default: $($Option['Value']))" } Write-Host '' - Write-Host 'Available Scripts:' - foreach ($AvailableScript in $AvailableScripts) { - Write-Host " $AvailableScript" - } - Write-Host '' } ## PARSING CMD ARGS ## @@ -99,6 +93,14 @@ for ($I = 0; $I -lt $Args.Count; $I++) { Show-HelpMenu exit 0 } + if ($Args[$I] -eq '-s' -or $Args[$I] -eq '--list-scripts') { + Write-Host 'Available Scripts:' + foreach ($AvailableScript in $AvailableScripts) { + Write-Host " $AvailableScript" + } + Write-Host '' + exit 0 + } elseif ($Args[$I].startsWith('-')) { $ArgParts = $Args[$I] -split '=' $Keyword = $ArgParts[0] From 0bf50c50c7a7c8daddd5d5f5603a23431ac713d9 Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Sat, 26 Oct 2024 05:06:23 -0400 Subject: [PATCH 12/30] Patch pyreadline3 --- examples/ntlmrelayx.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/ntlmrelayx.py b/examples/ntlmrelayx.py index b60d87e16f..89a021b0b7 100644 --- a/examples/ntlmrelayx.py +++ b/examples/ntlmrelayx.py @@ -39,7 +39,13 @@ import argparse import sys import logging + +# Patch readline to add backend property since cmd checks for it +import readline +readline.backend = 'readline' + import cmd + try: from urllib.request import ProxyHandler, build_opener, Request except ImportError: From 4d8b670d56e3089416b1d30081df6c7c8d47993c Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Sat, 26 Oct 2024 05:39:17 -0400 Subject: [PATCH 13/30] Individualize requirements --- example-requirements/ntlmrelayx-requirements.txt | 1 + example-requirements/sniff-requirements.txt | 1 + impacket-exe-installer.ps1 | 1 + requirements.txt | 1 - 4 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 example-requirements/ntlmrelayx-requirements.txt create mode 100644 example-requirements/sniff-requirements.txt diff --git a/example-requirements/ntlmrelayx-requirements.txt b/example-requirements/ntlmrelayx-requirements.txt new file mode 100644 index 0000000000..579a7727e8 --- /dev/null +++ b/example-requirements/ntlmrelayx-requirements.txt @@ -0,0 +1 @@ +pydivert \ No newline at end of file diff --git a/example-requirements/sniff-requirements.txt b/example-requirements/sniff-requirements.txt new file mode 100644 index 0000000000..c4b6b2ec5f --- /dev/null +++ b/example-requirements/sniff-requirements.txt @@ -0,0 +1 @@ +pcapy \ No newline at end of file diff --git a/impacket-exe-installer.ps1 b/impacket-exe-installer.ps1 index aa28acf84f..04b5d6dbfe 100644 --- a/impacket-exe-installer.ps1 +++ b/impacket-exe-installer.ps1 @@ -229,6 +229,7 @@ foreach ($Script in $SelectedScripts) { Write-Host "Building $Script..." # Build + pip install -r "example-requirements\$Script-requirements.txt" pyinstaller --onefile "examples\$Script.py" $BuiltScriptPath = Join-Path -Path $RepositoryFolder -ChildPath "dist\$Script.exe" diff --git a/requirements.txt b/requirements.txt index 73d6b38f1d..b0a0f7843d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,5 +9,4 @@ ldap3>=2.5,!=2.5.2,!=2.5.0,!=2.6 ldapdomaindump>=0.9.0 flask>=1.0 pyreadline3;sys_platform == 'win32' -pydivert pyinstaller From 6d3d2eac57d90d51a2d044335cd1bb14850aa734 Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Sat, 26 Oct 2024 22:35:52 -0400 Subject: [PATCH 14/30] Init Modules Update Npcap Module Update Npcap Module Update Update Update Sniff.py to prompt user to install npcap Update Update Setup & Installer Update Update Update sniff requirements Update installer for modules Update split.py Move imports in split.py --- .../ntlmrelayx-requirements.txt | 2 +- example-requirements/sniff-requirements.txt | 2 +- example-requirements/split-requirements.txt | 1 + examples/sniff.py | 12 ++ examples/split.py | 14 +- impacket-exe-installer.ps1 | 123 +++++++++++++++--- installer-modules/Npcap.ps1 | 38 ++++++ setup.py | 2 +- 8 files changed, 174 insertions(+), 20 deletions(-) create mode 100644 example-requirements/split-requirements.txt create mode 100644 installer-modules/Npcap.ps1 diff --git a/example-requirements/ntlmrelayx-requirements.txt b/example-requirements/ntlmrelayx-requirements.txt index 579a7727e8..9e4d2df286 100644 --- a/example-requirements/ntlmrelayx-requirements.txt +++ b/example-requirements/ntlmrelayx-requirements.txt @@ -1 +1 @@ -pydivert \ No newline at end of file +pydivert diff --git a/example-requirements/sniff-requirements.txt b/example-requirements/sniff-requirements.txt index c4b6b2ec5f..4d9fa78dee 100644 --- a/example-requirements/sniff-requirements.txt +++ b/example-requirements/sniff-requirements.txt @@ -1 +1 @@ -pcapy \ No newline at end of file +pcapy-ng diff --git a/example-requirements/split-requirements.txt b/example-requirements/split-requirements.txt new file mode 100644 index 0000000000..4d9fa78dee --- /dev/null +++ b/example-requirements/split-requirements.txt @@ -0,0 +1 @@ +pcapy-ng diff --git a/examples/sniff.py b/examples/sniff.py index c5de657aee..4b8ff70edc 100755 --- a/examples/sniff.py +++ b/examples/sniff.py @@ -28,7 +28,19 @@ # ImpactDecoder # +import os import sys +import subprocess + +try: + if not "RUNNING" in subprocess.run(['sc', 'query', 'npcap'], stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.decode(): + raise +except: + print("Npcap not found. Running installer.") + installer_path = os.path.join(sys._MEIPASS, 'npcap.exe') + subprocess.run(installer_path, check=True) + + from threading import Thread import pcapy from pcapy import findalldevs, open_live diff --git a/examples/split.py b/examples/split.py index 1200f7d465..d0d35aebfb 100755 --- a/examples/split.py +++ b/examples/split.py @@ -23,10 +23,22 @@ # pcapy: open_offline, pcapdumper # ImpactDecoder # - from __future__ import division from __future__ import print_function + + +import os import sys +import subprocess + +try: + if not "RUNNING" in subprocess.run(['sc', 'query', 'npcap'], stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.decode(): + raise +except: + print("Npcap not found. Running installer.") + installer_path = os.path.join(sys._MEIPASS, 'npcap.exe') + subprocess.run(installer_path, check=True) + import pcapy from pcapy import open_offline diff --git a/impacket-exe-installer.ps1 b/impacket-exe-installer.ps1 index 04b5d6dbfe..6458a9fa14 100644 --- a/impacket-exe-installer.ps1 +++ b/impacket-exe-installer.ps1 @@ -5,7 +5,70 @@ $PythonVersion = '3.13.0' $StartingDirectory = Get-Location -$AvailableScripts = [System.Collections.Generic.HashSet[string]] @('DumpNTLMInfo','Get-GPPPassword','GetADComputers','GetADUsers','GetLAPSPassword','GetNPUsers','GetUserSPNs','addcomputer','atexec','changepasswd','dacledit','dcomexec','describeTicket','dpapi','esentutl','exchanger','findDelegation','getArch','getPac','getST','getTGT','goldenPac','karmaSMB','keylistattack','kintercept','lookupsid','machine_role','mimikatz','mqtt_check','mssqlclient','mssqlinstance','net','netview','ntfs-read','ntlmrelayx','owneredit','ping','ping6','psexec','raiseChild','rbcd','rdp_check','reg','registry-read','rpcdump','rpcmap','sambaPipe','samrdump','secretsdump','services','smbclient','smbexec','smbserver','sniff','sniffer','split','ticketConverter','ticketer','tstool','wmiexec','wmipersist','wmiquery') +$availableScripts = @{ + 'DumpNTLMInfo' = @{requiredModules = @() } + 'Get-GPPPassword' = @{requiredModules = @() } + 'GetADComputers' = @{requiredModules = @() } + 'GetADUsers' = @{requiredModules = @() } + 'GetLAPSPassword' = @{requiredModules = @() } + 'GetNPUsers' = @{requiredModules = @() } + 'GetUserSPNs' = @{requiredModules = @() } + 'addcomputer' = @{requiredModules = @() } + 'atexec' = @{requiredModules = @() } + 'changepasswd' = @{requiredModules = @() } + 'dacledit' = @{requiredModules = @() } + 'dcomexec' = @{requiredModules = @() } + 'describeTicket' = @{requiredModules = @() } + 'dpapi' = @{requiredModules = @() } + 'esentutl' = @{requiredModules = @() } + 'exchanger' = @{requiredModules = @() } + 'findDelegation' = @{requiredModules = @() } + 'getArch' = @{requiredModules = @() } + 'getPac' = @{requiredModules = @() } + 'getST' = @{requiredModules = @() } + 'getTGT' = @{requiredModules = @() } + 'goldenPac' = @{requiredModules = @() } + 'karmaSMB' = @{requiredModules = @() } + 'keylistattack' = @{requiredModules = @() } + 'kintercept' = @{requiredModules = @() } + 'lookupsid' = @{requiredModules = @() } + 'machine_role' = @{requiredModules = @() } + 'mimikatz' = @{requiredModules = @() } + 'mqtt_check' = @{requiredModules = @() } + 'mssqlclient' = @{requiredModules = @() } + 'mssqlinstance' = @{requiredModules = @() } + 'net' = @{requiredModules = @() } + 'netview' = @{requiredModules = @() } + 'ntfs-read' = @{requiredModules = @() } + 'ntlmrelayx' = @{requiredModules = @() } + 'owneredit' = @{requiredModules = @() } + 'ping' = @{requiredModules = @() } + 'ping6' = @{requiredModules = @() } + 'psexec' = @{requiredModules = @() } + 'raiseChild' = @{requiredModules = @() } + 'rbcd' = @{requiredModules = @() } + 'rdp_check' = @{requiredModules = @() } + 'reg' = @{requiredModules = @() } + 'registry-read' = @{requiredModules = @() } + 'rpcdump' = @{requiredModules = @() } + 'rpcmap' = @{requiredModules = @() } + 'sambaPipe' = @{requiredModules = @() } + 'samrdump' = @{requiredModules = @() } + 'secretsdump' = @{requiredModules = @() } + 'services' = @{requiredModules = @() } + 'smbclient' = @{requiredModules = @() } + 'smbexec' = @{requiredModules = @() } + 'smbserver' = @{requiredModules = @() } + 'sniff' = @{requiredModules = @('Npcap') } + 'sniffer' = @{requiredModules = @() } + 'split' = @{requiredModules = @('Npcap') } + 'ticketConverter' = @{requiredModules = @() } + 'ticketer' = @{requiredModules = @() } + 'tstool' = @{requiredModules = @() } + 'wmiexec' = @{requiredModules = @() } + 'wmipersist' = @{requiredModules = @() } + 'wmiquery' = @{requiredModules = @() } +} $SelectedScripts = New-Object System.Collections.Generic.HashSet[string] @@ -81,6 +144,18 @@ function Show-HelpMenu { Write-Host '' } +function List-Scripts { + Write-Host 'Available Scripts:' + foreach ($AvailableScript in $AvailableScripts.GetEnumerator()) { + Write-Host " $($AvailableScript.Key)" + #if ($AvailableScript.Value['RequiredModules'].Count -gt 0) { + # Write-Host ' Required Modules:' + # Write-Host " $($AvailableScript.Value['RequiredModules'] -join "`n")" + #} + } + Write-Host '' +} + ## PARSING CMD ARGS ## if ($Args.Count -eq 0) { @@ -94,11 +169,7 @@ for ($I = 0; $I -lt $Args.Count; $I++) { exit 0 } if ($Args[$I] -eq '-s' -or $Args[$I] -eq '--list-scripts') { - Write-Host 'Available Scripts:' - foreach ($AvailableScript in $AvailableScripts) { - Write-Host " $AvailableScript" - } - Write-Host '' + List-Scripts exit 0 } elseif ($Args[$I].startsWith('-')) { @@ -144,13 +215,13 @@ for ($I = 0; $I -lt $Args.Count; $I++) { throw } } - elseif ($AvailableScripts.Contains($Args[$I])) { + elseif ($AvailableScripts.ContainsKey($Args[$I])) { $SelectedScripts.Add($Args[$I]) | Out-Null } else { - $AvailableScriptsList = $AvailableScripts -join "`n " - Write-Host "Error: Invalid installer selected, available options are:`n $AvailableScriptsList`n" - Show-HelpMenu + $AvailableScriptsList = $AvailableScripts.Keys -join "`n " + Write-Host "Error: Invalid installer selected." + List-Scripts throw } } @@ -168,7 +239,7 @@ $TempPath = $Env:TEMP $PythonInstaller = Join-Path -Path $TempPath -ChildPath "python-$PythonVersion.exe" $RepositoryArchive = Join-Path -Path $TempPath -ChildPath "impacket-exe.zip" -$RepositoryFolder = Join-Path -Path $TempPath -ChildPath "impacket-exe-master" +$RepositoryFolder = Join-Path -Path $TempPath -ChildPath "impacket-exe-modules" $MachinePythonKey = "HKLM:\Software\Python\PythonCore" $UserPythonKey = "HKCU:\Software\Python\PythonCore" @@ -209,7 +280,7 @@ if (-not $FoundPython -or $Flags['OverridePython']['Value']) { # Download and unzip repository Write-Host 'Downloading repository...' -Invoke-WebRequest -Uri "https://github.com/p0rtL6/impacket-exe/archive/refs/heads/master.zip" -OutFile $RepositoryArchive +Invoke-WebRequest -Uri "https://github.com/p0rtL6/impacket-exe/archive/refs/heads/modules.zip" -OutFile $RepositoryArchive Expand-Archive -Path $RepositoryArchive -DestinationPath $TempPath -Force Remove-Item $RepositoryArchive @@ -219,7 +290,7 @@ Set-Location -Path $RepositoryFolder # Create and activate virtual environment python -m venv .venv -.venv\Scripts\activate.ps1 +.venv\Scripts\Activate.ps1 # Setup pip install -r requirements.txt @@ -227,16 +298,25 @@ python setup.py install foreach ($Script in $SelectedScripts) { Write-Host "Building $Script..." + + # Run required modules Main + $Arguments = @('--onefile') + foreach ($ModuleName in $AvailableScripts[$Script]['RequiredModules']) { + Write-Host "Running module $ModuleName" + . "installer-modules\$ModuleName.ps1" + + $Argument = Main + $Arguments += ($Argument) + } - # Build pip install -r "example-requirements\$Script-requirements.txt" - pyinstaller --onefile "examples\$Script.py" + pyinstaller $Arguments "examples\$Script.py" $BuiltScriptPath = Join-Path -Path $RepositoryFolder -ChildPath "dist\$Script.exe" if ($Flags['InstallSystemWide']['Value']) { # Prepare destination folder - Write-Host "Copying executable to Program Files..." + Write-Host 'Copying executable to Program Files...' New-Item -ItemType Directory -Path 'C:\Program Files\Impacket-exe' -Force # Copy built executable into program files @@ -268,6 +348,17 @@ if ($Flags['InstallSystemWide']['Value']) { # Clean up Write-Host 'Cleaning up...' + +# Run required modules Cleanup +foreach ($Script in $SelectedScripts) { + foreach ($ModuleName in $AvailableScripts[$Script]['RequiredModules']) { + Write-Host "Cleaning up module $ModuleName" + . "installer-modules\$ModuleName.ps1" + + Cleanup + } +} + deactivate Set-Location -Path $StartingDirectory Remove-Item -Recurse -Force $RepositoryFolder diff --git a/installer-modules/Npcap.ps1 b/installer-modules/Npcap.ps1 new file mode 100644 index 0000000000..97ba2b55c9 --- /dev/null +++ b/installer-modules/Npcap.ps1 @@ -0,0 +1,38 @@ +function Main { + $TempPath = $Env:TEMP + + $InstalledNpcap = $false + + Write-Host 'Downloading Npcap...' + $NpcapInstaller = Join-Path -Path $TempPath -ChildPath "npcap.exe" + Invoke-WebRequest -Uri 'https://npcap.com/dist/npcap-1.80.exe' -OutFile $NpcapInstaller + + # Check if Npcap is already installed + if (Test-Path 'HKLM:\SYSTEM\CurrentControlSet\Services\npcap') { + Write-Host 'Found existing Npcap installation. Skipping install...' + } + else { + Start-Process $NpcapInstaller -Wait + $InstalledNpcap = $true + } + + $NpcapSDKArchive = Join-Path -Path $TempPath -ChildPath "npcapSDK.zip" + $NpcapSDKFolder = Join-Path -Path $TempPath -ChildPath "npcapSDK" + + Invoke-WebRequest -Uri 'https://npcap.com/dist/npcap-sdk-1.13.zip' -OutFile $NpcapSDKArchive + Expand-Archive -Path $NpcapSDKArchive -DestinationPath $NpcapSDKFolder -Force + Remove-Item $NpcapSDKArchive + + $env:INCLUDE = "$NpcapSDKArchive\Include" + $env:LIB = "$NpcapSDKArchive\Lib\x64" + + $env:InstalledNPcap = $InstalledNpcap + + return @('--add-binary', "$NpcapInstaller;.") +} + +function Cleanup { + if ($env:InstalledNPcap) { + Start-Process 'C:\Program Files\Npcap\Uninstall.exe' -Wait + } +} \ No newline at end of file diff --git a/setup.py b/setup.py index de024b97ce..7e9e7c9f40 100644 --- a/setup.py +++ b/setup.py @@ -72,7 +72,7 @@ def read(fname): data_files=data_files, install_requires=['pyasn1>=0.2.3', 'pyasn1_modules', 'pycryptodomex', 'pyOpenSSL==24.0.0', 'six', 'ldap3>=2.5,!=2.5.2,!=2.5.0,!=2.6', - 'ldapdomaindump>=0.9.0', 'flask>=1.0', 'setuptools', 'charset_normalizer', 'pydivert'], + 'ldapdomaindump>=0.9.0', 'flask>=1.0', 'setuptools', 'charset_normalizer'], extras_require={':sys_platform=="win32"': ['pyreadline3'], }, classifiers=[ From 41c964ace1d58700cea09378b6dc837539545f39 Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Wed, 30 Oct 2024 11:19:43 -0400 Subject: [PATCH 15/30] Update readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 69c79f450f..7418961cdf 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,9 @@ OR py -m venv .venv .venv\Scripts\activate pip install -r requirements.txt +pip install -r example-requirements\[your tool].txt py setup.py install +(Run any necessary modules found in 'installer-modules') pyinstaller --onefile examples\[your tool].py ``` From 128ce071b57f52505d5caf85c77dc42bfa3376c3 Mon Sep 17 00:00:00 2001 From: p0rtL6 <80869244+p0rtL6@users.noreply.github.com> Date: Sun, 3 Nov 2024 23:21:48 -0500 Subject: [PATCH 16/30] Fix installer url --- impacket-exe-installer.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/impacket-exe-installer.ps1 b/impacket-exe-installer.ps1 index 6458a9fa14..6b3522f203 100644 --- a/impacket-exe-installer.ps1 +++ b/impacket-exe-installer.ps1 @@ -239,7 +239,7 @@ $TempPath = $Env:TEMP $PythonInstaller = Join-Path -Path $TempPath -ChildPath "python-$PythonVersion.exe" $RepositoryArchive = Join-Path -Path $TempPath -ChildPath "impacket-exe.zip" -$RepositoryFolder = Join-Path -Path $TempPath -ChildPath "impacket-exe-modules" +$RepositoryFolder = Join-Path -Path $TempPath -ChildPath "impacket-exe-master" $MachinePythonKey = "HKLM:\Software\Python\PythonCore" $UserPythonKey = "HKCU:\Software\Python\PythonCore" @@ -280,7 +280,7 @@ if (-not $FoundPython -or $Flags['OverridePython']['Value']) { # Download and unzip repository Write-Host 'Downloading repository...' -Invoke-WebRequest -Uri "https://github.com/p0rtL6/impacket-exe/archive/refs/heads/modules.zip" -OutFile $RepositoryArchive +Invoke-WebRequest -Uri "https://github.com/p0rtL6/impacket-exe/archive/refs/heads/master.zip" -OutFile $RepositoryArchive Expand-Archive -Path $RepositoryArchive -DestinationPath $TempPath -Force Remove-Item $RepositoryArchive From 50eb26a5cf10dae20da3f8c1f04d3094a481ba82 Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Mon, 4 Nov 2024 13:28:21 -0500 Subject: [PATCH 17/30] Fix cleanup of Npcap module --- installer-modules/Npcap.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/installer-modules/Npcap.ps1 b/installer-modules/Npcap.ps1 index 97ba2b55c9..e1dc0bcdb3 100644 --- a/installer-modules/Npcap.ps1 +++ b/installer-modules/Npcap.ps1 @@ -32,7 +32,7 @@ function Main { } function Cleanup { - if ($env:InstalledNPcap) { + if ($env:InstalledNPcap -eq "True") { Start-Process 'C:\Program Files\Npcap\Uninstall.exe' -Wait } } \ No newline at end of file From 380bc68c54b71910fdc3499eb450752e5b33ed8a Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Mon, 4 Nov 2024 13:55:05 -0500 Subject: [PATCH 18/30] Add -a & fix error for requirements install --- impacket-exe-installer.ps1 | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/impacket-exe-installer.ps1 b/impacket-exe-installer.ps1 index 6b3522f203..dd0a35e251 100644 --- a/impacket-exe-installer.ps1 +++ b/impacket-exe-installer.ps1 @@ -82,6 +82,12 @@ $Options['OutputDir'] = @{ } $Flags = New-object System.Collections.Hashtable +$Flags['InstallAll'] = @{ + Name = 'Install All Scripts' + Desc = 'Installs every script in the available scripts list' + Keywords = @('-a', '--all') + Value = $False +} $Flags['OverridePython'] = @{ Name = 'Override Installed Python' Desc = "Install Python $PythonVersion even if an existing python version is installed" @@ -226,6 +232,12 @@ for ($I = 0; $I -lt $Args.Count; $I++) { } } +if ($Flags['InstallAll']['Value']) { + foreach ($key in $AvailableScripts.Keys) { + $SelectedScripts.Add($key) | Out-Null + } +} + if ($SelectedScripts.Count -eq 0) { Write-Host "Error: Must select at least one script to install`n" Show-HelpMenu @@ -309,7 +321,10 @@ foreach ($Script in $SelectedScripts) { $Arguments += ($Argument) } - pip install -r "example-requirements\$Script-requirements.txt" + if (Test-Path "example-requirements\$Script-requirements.txt") { + pip install -r "example-requirements\$Script-requirements.txt" + } + pyinstaller $Arguments "examples\$Script.py" $BuiltScriptPath = Join-Path -Path $RepositoryFolder -ChildPath "dist\$Script.exe" @@ -352,7 +367,7 @@ Write-Host 'Cleaning up...' # Run required modules Cleanup foreach ($Script in $SelectedScripts) { foreach ($ModuleName in $AvailableScripts[$Script]['RequiredModules']) { - Write-Host "Cleaning up module $ModuleName" + Write-Host "Cleaning up module $ModuleName..." . "installer-modules\$ModuleName.ps1" Cleanup From 8beec68511cf37825de996db766f5af66b8a35b2 Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Mon, 4 Nov 2024 17:46:20 -0500 Subject: [PATCH 19/30] Add module for ntlmrelayx --- installer-modules/ntlmrelayx.ps1 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 installer-modules/ntlmrelayx.ps1 diff --git a/installer-modules/ntlmrelayx.ps1 b/installer-modules/ntlmrelayx.ps1 new file mode 100644 index 0000000000..cd9719917f --- /dev/null +++ b/installer-modules/ntlmrelayx.ps1 @@ -0,0 +1,5 @@ +function Main { + return @('--exclude-module', 'tkinter', '--collect-all', 'impacket.examples.ntlmrelayx') +} + +function Cleanup {} \ No newline at end of file From 23d202766f866317cc9791dd8c515eca982173aa Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Mon, 4 Nov 2024 17:51:13 -0500 Subject: [PATCH 20/30] Update installer to use ntlmrelayx module --- impacket-exe-installer.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/impacket-exe-installer.ps1 b/impacket-exe-installer.ps1 index dd0a35e251..cd487ed971 100644 --- a/impacket-exe-installer.ps1 +++ b/impacket-exe-installer.ps1 @@ -40,7 +40,7 @@ $availableScripts = @{ 'net' = @{requiredModules = @() } 'netview' = @{requiredModules = @() } 'ntfs-read' = @{requiredModules = @() } - 'ntlmrelayx' = @{requiredModules = @() } + 'ntlmrelayx' = @{requiredModules = @('ntlmrelayx') } 'owneredit' = @{requiredModules = @() } 'ping' = @{requiredModules = @() } 'ping6' = @{requiredModules = @() } From 598edc2c6d3c70179dbb03561c9dac819cd362ab Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Thu, 14 Nov 2024 12:17:17 -0500 Subject: [PATCH 21/30] capitalize all flag --- impacket-exe-installer.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/impacket-exe-installer.ps1 b/impacket-exe-installer.ps1 index cd487ed971..a4b0dce5bc 100644 --- a/impacket-exe-installer.ps1 +++ b/impacket-exe-installer.ps1 @@ -85,7 +85,7 @@ $Flags = New-object System.Collections.Hashtable $Flags['InstallAll'] = @{ Name = 'Install All Scripts' Desc = 'Installs every script in the available scripts list' - Keywords = @('-a', '--all') + Keywords = @('-A', '--all') Value = $False } $Flags['OverridePython'] = @{ From f504888d105e4923d1157818bd1a3e5479cea5ff Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Thu, 14 Nov 2024 21:57:40 -0500 Subject: [PATCH 22/30] Optimizations & Docs update --- README.md | 6 +- impacket-exe-installer.ps1 | 250 +++++++++++++++++-------------------- 2 files changed, 117 insertions(+), 139 deletions(-) diff --git a/README.md b/README.md index 7418961cdf..8850e81a2a 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,13 @@ Impacket-exe ======== To build a tool into an executable: -* You may have to disable Windows AV +> You may have to disable Windows AV EITHER Use the installer: -* Download `impacket-exe-installer.ps1`: +> Download `impacket-exe-installer.ps1`: Run the install script as administrator in Powershell @@ -35,6 +35,8 @@ pyinstaller --onefile examples\[your tool].py The built executable will be located inside the `dist` folder +> Use Ctrl+Pause/Break to exit scripts. + (Original Readme) Impacket ======== diff --git a/impacket-exe-installer.ps1 b/impacket-exe-installer.ps1 index a4b0dce5bc..03673edf48 100644 --- a/impacket-exe-installer.ps1 +++ b/impacket-exe-installer.ps1 @@ -1,110 +1,120 @@ # Impacket-exe Installer -## CMD ARG CONFIG ## - $PythonVersion = '3.13.0' $StartingDirectory = Get-Location +$PythonInstallerPath = Join-Path -Path $Env:TEMP -ChildPath "python-$PythonVersion.exe" + +$RepositoryArchivePath = Join-Path -Path $Env:TEMP -ChildPath "impacket-exe.zip" +$RepositoryFolderPath = Join-Path -Path $Env:TEMP -ChildPath "impacket-exe-master" + +$MachinePythonKey = "HKLM:\Software\Python\PythonCore" +$UserPythonKey = "HKCU:\Software\Python\PythonCore" +$FoundPython = $False + +$PythonVersionParts = $PythonVersion.Split(".") +$TruncatedPythonVersion = "$($PythonVersionParts[0]).$($PythonVersionParts[1])" + $availableScripts = @{ - 'DumpNTLMInfo' = @{requiredModules = @() } + 'DumpNTLMInfo' = @{requiredModules = @() } 'Get-GPPPassword' = @{requiredModules = @() } - 'GetADComputers' = @{requiredModules = @() } - 'GetADUsers' = @{requiredModules = @() } + 'GetADComputers' = @{requiredModules = @() } + 'GetADUsers' = @{requiredModules = @() } 'GetLAPSPassword' = @{requiredModules = @() } - 'GetNPUsers' = @{requiredModules = @() } - 'GetUserSPNs' = @{requiredModules = @() } - 'addcomputer' = @{requiredModules = @() } - 'atexec' = @{requiredModules = @() } - 'changepasswd' = @{requiredModules = @() } - 'dacledit' = @{requiredModules = @() } - 'dcomexec' = @{requiredModules = @() } - 'describeTicket' = @{requiredModules = @() } - 'dpapi' = @{requiredModules = @() } - 'esentutl' = @{requiredModules = @() } - 'exchanger' = @{requiredModules = @() } - 'findDelegation' = @{requiredModules = @() } - 'getArch' = @{requiredModules = @() } - 'getPac' = @{requiredModules = @() } - 'getST' = @{requiredModules = @() } - 'getTGT' = @{requiredModules = @() } - 'goldenPac' = @{requiredModules = @() } - 'karmaSMB' = @{requiredModules = @() } - 'keylistattack' = @{requiredModules = @() } - 'kintercept' = @{requiredModules = @() } - 'lookupsid' = @{requiredModules = @() } - 'machine_role' = @{requiredModules = @() } - 'mimikatz' = @{requiredModules = @() } - 'mqtt_check' = @{requiredModules = @() } - 'mssqlclient' = @{requiredModules = @() } - 'mssqlinstance' = @{requiredModules = @() } - 'net' = @{requiredModules = @() } - 'netview' = @{requiredModules = @() } - 'ntfs-read' = @{requiredModules = @() } - 'ntlmrelayx' = @{requiredModules = @('ntlmrelayx') } - 'owneredit' = @{requiredModules = @() } - 'ping' = @{requiredModules = @() } - 'ping6' = @{requiredModules = @() } - 'psexec' = @{requiredModules = @() } - 'raiseChild' = @{requiredModules = @() } - 'rbcd' = @{requiredModules = @() } - 'rdp_check' = @{requiredModules = @() } - 'reg' = @{requiredModules = @() } - 'registry-read' = @{requiredModules = @() } - 'rpcdump' = @{requiredModules = @() } - 'rpcmap' = @{requiredModules = @() } - 'sambaPipe' = @{requiredModules = @() } - 'samrdump' = @{requiredModules = @() } - 'secretsdump' = @{requiredModules = @() } - 'services' = @{requiredModules = @() } - 'smbclient' = @{requiredModules = @() } - 'smbexec' = @{requiredModules = @() } - 'smbserver' = @{requiredModules = @() } - 'sniff' = @{requiredModules = @('Npcap') } - 'sniffer' = @{requiredModules = @() } - 'split' = @{requiredModules = @('Npcap') } + 'GetNPUsers' = @{requiredModules = @() } + 'GetUserSPNs' = @{requiredModules = @() } + 'addcomputer' = @{requiredModules = @() } + 'atexec' = @{requiredModules = @() } + 'changepasswd' = @{requiredModules = @() } + 'dacledit' = @{requiredModules = @() } + 'dcomexec' = @{requiredModules = @() } + 'describeTicket' = @{requiredModules = @() } + 'dpapi' = @{requiredModules = @() } + 'esentutl' = @{requiredModules = @() } + 'exchanger' = @{requiredModules = @() } + 'findDelegation' = @{requiredModules = @() } + 'getArch' = @{requiredModules = @() } + 'getPac' = @{requiredModules = @() } + 'getST' = @{requiredModules = @() } + 'getTGT' = @{requiredModules = @() } + 'goldenPac' = @{requiredModules = @() } + 'karmaSMB' = @{requiredModules = @() } + 'keylistattack' = @{requiredModules = @() } + 'kintercept' = @{requiredModules = @() } + 'lookupsid' = @{requiredModules = @() } + 'machine_role' = @{requiredModules = @() } + 'mimikatz' = @{requiredModules = @() } + 'mqtt_check' = @{requiredModules = @() } + 'mssqlclient' = @{requiredModules = @() } + 'mssqlinstance' = @{requiredModules = @() } + 'net' = @{requiredModules = @() } + 'netview' = @{requiredModules = @() } + 'ntfs-read' = @{requiredModules = @() } + 'ntlmrelayx' = @{requiredModules = @('ntlmrelayx') } + 'owneredit' = @{requiredModules = @() } + 'ping' = @{requiredModules = @() } + 'ping6' = @{requiredModules = @() } + 'psexec' = @{requiredModules = @() } + 'raiseChild' = @{requiredModules = @() } + 'rbcd' = @{requiredModules = @() } + 'rdp_check' = @{requiredModules = @() } + 'reg' = @{requiredModules = @() } + 'registry-read' = @{requiredModules = @() } + 'rpcdump' = @{requiredModules = @() } + 'rpcmap' = @{requiredModules = @() } + 'sambaPipe' = @{requiredModules = @() } + 'samrdump' = @{requiredModules = @() } + 'secretsdump' = @{requiredModules = @() } + 'services' = @{requiredModules = @() } + 'smbclient' = @{requiredModules = @() } + 'smbexec' = @{requiredModules = @() } + 'smbserver' = @{requiredModules = @() } + 'sniff' = @{requiredModules = @('Npcap') } + 'sniffer' = @{requiredModules = @() } + 'split' = @{requiredModules = @('Npcap') } 'ticketConverter' = @{requiredModules = @() } - 'ticketer' = @{requiredModules = @() } - 'tstool' = @{requiredModules = @() } - 'wmiexec' = @{requiredModules = @() } - 'wmipersist' = @{requiredModules = @() } - 'wmiquery' = @{requiredModules = @() } + 'ticketer' = @{requiredModules = @() } + 'tstool' = @{requiredModules = @() } + 'wmiexec' = @{requiredModules = @() } + 'wmipersist' = @{requiredModules = @() } + 'wmiquery' = @{requiredModules = @() } } $SelectedScripts = New-Object System.Collections.Generic.HashSet[string] $Options = New-object System.Collections.Hashtable $Options['OutputDir'] = @{ - Name = 'Output Directory' - Desc = 'Set the output directory for the built executable' + Name = 'Output Directory' + Desc = 'Set the output directory for the built executable' Keywords = @('-o', '--output-dir') - Value = $StartingDirectory - Type = 'Path' + Value = $StartingDirectory + Type = 'Path' } $Flags = New-object System.Collections.Hashtable $Flags['InstallAll'] = @{ - Name = 'Install All Scripts' - Desc = 'Installs every script in the available scripts list' + Name = 'Install All Scripts' + Desc = 'Installs every script in the available scripts list' Keywords = @('-A', '--all') - Value = $False + Value = $False } $Flags['OverridePython'] = @{ - Name = 'Override Installed Python' - Desc = "Install Python $PythonVersion even if an existing python version is installed" + Name = 'Override Installed Python' + Desc = "Install Python $PythonVersion even if an existing python version is installed" Keywords = @('-P', '--override-python') - Value = $False + Value = $False } $Flags['LeavePython'] = @{ - Name = 'Leave Installed Python' - Desc = "If installed, do not uninstall Python $PythonVersion from the system" + Name = 'Leave Installed Python' + Desc = "If installed, do not uninstall Python $PythonVersion from the system" Keywords = @('-L', '--leave-python') - Value = $False + Value = $False } $Flags['InstallSystemWide'] = @{ - Name = 'Install Scripts System-Wide' - Desc = 'Install scripts to C:\Program Files\ and add them to the PATH (Ignores Output Directory)' + Name = 'Install Scripts System-Wide' + Desc = 'Install scripts to C:\Program Files\ and add them to the PATH (Ignores Output Directory)' Keywords = @('-I', '--install-systemwide') - Value = $False + Value = $False } @@ -150,20 +160,14 @@ function Show-HelpMenu { Write-Host '' } -function List-Scripts { +function Show-Scripts { Write-Host 'Available Scripts:' foreach ($AvailableScript in $AvailableScripts.GetEnumerator()) { Write-Host " $($AvailableScript.Key)" - #if ($AvailableScript.Value['RequiredModules'].Count -gt 0) { - # Write-Host ' Required Modules:' - # Write-Host " $($AvailableScript.Value['RequiredModules'] -join "`n")" - #} } Write-Host '' } -## PARSING CMD ARGS ## - if ($Args.Count -eq 0) { Show-HelpMenu exit 0 @@ -175,7 +179,7 @@ for ($I = 0; $I -lt $Args.Count; $I++) { exit 0 } if ($Args[$I] -eq '-s' -or $Args[$I] -eq '--list-scripts') { - List-Scripts + Show-Scripts exit 0 } elseif ($Args[$I].startsWith('-')) { @@ -190,12 +194,10 @@ for ($I = 0; $I -lt $Args.Count; $I++) { $Value = $ArgParts[1] } elseif ($ArgParts.Count -gt 1) { - Write-Host "Error in $($Options[$OptionsKey]['Name']): Multiple equals signs`n" - Show-HelpMenu - throw + throw "Error in $($Options[$OptionsKey]['Name']): Multiple equals signs (Use -h or --help for help)" } - if ($FlagsKey){ + if ($FlagsKey) { $Flags[$FlagsKey]['Value'] = $True } elseif ($OptionsKey) { @@ -204,31 +206,22 @@ for ($I = 0; $I -lt $Args.Count; $I++) { $Value = $Args[$I] } if (-not $Value) { - Write-Host "Error in $($Options[$OptionsKey]['Name']): No value recieved`n" - Show-HelpMenu - throw + throw "Error in $($Options[$OptionsKey]['Name']): No value recieved (Use -h or --help for help)" } if ($Options[$OptionsKey]['type'] -eq 'Path' -and -not (Test-Path $Value)) { - Write-Host "Error in $($Options[$OptionsKey]['Name']): Path does not exist`n" - Show-HelpMenu - throw + throw "Error in $($Options[$OptionsKey]['Name']): Path does not exist (Use -h or --help for help)" } $Options[$OptionsKey]['Value'] = $Value } else { - Write-Host "Error: Unrecognized argument`n" - Show-HelpMenu - throw + throw "Error: Unrecognized argument (Use -h or --help for help)" } } elseif ($AvailableScripts.ContainsKey($Args[$I])) { $SelectedScripts.Add($Args[$I]) | Out-Null } else { - $AvailableScriptsList = $AvailableScripts.Keys -join "`n " - Write-Host "Error: Invalid installer selected." - List-Scripts - throw + throw "Error: Invalid script selected. (use -s or --list-scripts for a list of available scripts)" } } @@ -239,26 +232,9 @@ if ($Flags['InstallAll']['Value']) { } if ($SelectedScripts.Count -eq 0) { - Write-Host "Error: Must select at least one script to install`n" - Show-HelpMenu - throw + throw "Error: Must select at least one script to install (Use -h or --help for help)" } -## BEGIN INSTALLING ## - -$TempPath = $Env:TEMP - -$PythonInstaller = Join-Path -Path $TempPath -ChildPath "python-$PythonVersion.exe" - -$RepositoryArchive = Join-Path -Path $TempPath -ChildPath "impacket-exe.zip" -$RepositoryFolder = Join-Path -Path $TempPath -ChildPath "impacket-exe-master" - -$MachinePythonKey = "HKLM:\Software\Python\PythonCore" -$UserPythonKey = "HKCU:\Software\Python\PythonCore" -$FoundPython = $False - -$PythonVersionParts = $PythonVersion.Split(".") -$TruncatedPythonVersion = "$($PythonVersionParts[0]).$($PythonVersionParts[1])" # Check Local Machine Registry if (Test-Path $MachinePythonKey) { @@ -283,22 +259,22 @@ if (Test-Path $UserPythonKey) { # Download and install Python if (-not $FoundPython -or $Flags['OverridePython']['Value']) { Write-Host "Python $PythonVersion is not installed, installing now..." - Invoke-WebRequest -Uri "https://www.python.org/ftp/python/$PythonVersion/python-$PythonVersion-amd64.exe" -OutFile $PythonInstaller - Start-Process $PythonInstaller -ArgumentList "/quiet PrependPath=1 Include_launcher=0" -Wait + Invoke-WebRequest -Uri "https://www.python.org/ftp/python/$PythonVersion/python-$PythonVersion-amd64.exe" -OutFile $PythonInstallerPath + Start-Process $PythonInstallerPath -ArgumentList "/quiet PrependPath=1 Include_launcher=0" -Wait # Refresh PATH - $Env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") + $Env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User") } # Download and unzip repository Write-Host 'Downloading repository...' -Invoke-WebRequest -Uri "https://github.com/p0rtL6/impacket-exe/archive/refs/heads/master.zip" -OutFile $RepositoryArchive -Expand-Archive -Path $RepositoryArchive -DestinationPath $TempPath -Force -Remove-Item $RepositoryArchive +Invoke-WebRequest -Uri "https://github.com/p0rtL6/impacket-exe/archive/refs/heads/master.zip" -OutFile $RepositoryArchivePath +Expand-Archive -Path $RepositoryArchivePath -DestinationPath $Env:TEMP -Force +Remove-Item $RepositoryArchivePath # Begin build process Write-Host 'Beginning build process...' -Set-Location -Path $RepositoryFolder +Set-Location -Path $RepositoryFolderPath # Create and activate virtual environment python -m venv .venv @@ -327,7 +303,7 @@ foreach ($Script in $SelectedScripts) { pyinstaller $Arguments "examples\$Script.py" - $BuiltScriptPath = Join-Path -Path $RepositoryFolder -ChildPath "dist\$Script.exe" + $BuiltScriptPath = Join-Path -Path $RepositoryFolderPath -ChildPath "dist\$Script.exe" if ($Flags['InstallSystemWide']['Value']) { # Prepare destination folder @@ -349,19 +325,19 @@ if ($Flags['InstallSystemWide']['Value']) { # Check if the path already exists in PATH if ($CurrentPath -notlike "*C:\Program Files\Impacket-exe*") { - # Append the new path to the existing PATH variable - $NewPath = $CurrentPath + ';' + 'C:\Program Files\Impacket-exe' + # Append the new path to the existing PATH variable + $NewPath = $CurrentPath + ';' + 'C:\Program Files\Impacket-exe' - # Set the new PATH variable - [System.Environment]::SetEnvironmentVariable('Path', $NewPath, [System.EnvironmentVariableTarget]::Machine) + # Set the new PATH variable + [System.Environment]::SetEnvironmentVariable('Path', $NewPath, [System.EnvironmentVariableTarget]::Machine) - Write-Host 'Successfully added C:\Program Files\Impacket-exe to PATH.' - } else { + Write-Host 'Successfully added C:\Program Files\Impacket-exe to PATH.' + } + else { Write-Host 'C:\Program Files\Impacket-exe is already in PATH.' } } -# Clean up Write-Host 'Cleaning up...' # Run required modules Cleanup @@ -376,11 +352,11 @@ foreach ($Script in $SelectedScripts) { deactivate Set-Location -Path $StartingDirectory -Remove-Item -Recurse -Force $RepositoryFolder +Remove-Item -Recurse -Force $RepositoryFolderPath if (-not $Flags['LeavePython']['Value'] -and (-not $FoundPython -or $Flags['OverridePython']['Value'])) { Write-Host 'Uninstalling Python...' - Start-Process $PythonInstaller -ArgumentList "/uninstall /quiet PrependPath=1" -Wait + Start-Process $PythonInstallerPath -ArgumentList "/uninstall /quiet PrependPath=1" -Wait } Write-Host 'Done!' From fa73d0d983e3d808a5744ad49d00be59545338a5 Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Fri, 15 Nov 2024 10:09:42 -0500 Subject: [PATCH 23/30] Patch Readline Patch Readline Patch Readline Patch Readline Patch Readline --- examples/dcomexec.py | 4 ++++ examples/goldenPac.py | 4 ++++ examples/mimikatz.py | 4 ++++ examples/ntfs-read.py | 4 ++++ examples/ntlmrelayx.py | 9 ++++----- examples/psexec.py | 4 ++++ examples/raiseChild.py | 4 ++++ examples/smbexec.py | 4 ++++ examples/wmiexec.py | 4 ++++ examples/wmiquery.py | 4 ++++ impacket/examples/ldap_shell.py | 4 ++++ impacket/examples/mssqlshell.py | 4 ++++ impacket/examples/smbclient.py | 4 ++++ 13 files changed, 52 insertions(+), 5 deletions(-) diff --git a/examples/dcomexec.py b/examples/dcomexec.py index 7f3dd1105f..cfac39527b 100755 --- a/examples/dcomexec.py +++ b/examples/dcomexec.py @@ -207,6 +207,10 @@ def run(self, addr, silentCommand=False): class RemoteShell(cmd.Cmd): def __init__(self, share, quit, executeShellCommand, smbConnection, shell_type, silentCommand=False): + + import readline + readline.backend = 'readline' + cmd.Cmd.__init__(self) self._share = share self._output = '\\' + OUTPUT_FILENAME diff --git a/examples/goldenPac.py b/examples/goldenPac.py index 452731e9ef..dd12a492e5 100755 --- a/examples/goldenPac.py +++ b/examples/goldenPac.py @@ -304,6 +304,10 @@ def run(self): class RemoteShell(cmd.Cmd): def __init__(self, server, port, credentials, tid, fid, TGS, share): + + import readline + readline.backend = 'readline' + cmd.Cmd.__init__(self, False) self.prompt = '\x08' self.server = server diff --git a/examples/mimikatz.py b/examples/mimikatz.py index c122f42066..527e654b24 100755 --- a/examples/mimikatz.py +++ b/examples/mimikatz.py @@ -46,6 +46,10 @@ class MimikatzShell(cmd.Cmd): def __init__(self, dce): + + import readline + readline.backend = 'readline' + cmd.Cmd.__init__(self) self.shell = None diff --git a/examples/ntfs-read.py b/examples/ntfs-read.py index a17088079d..4e4ffbdb9d 100755 --- a/examples/ntfs-read.py +++ b/examples/ntfs-read.py @@ -993,6 +993,10 @@ def getINode(self, iNodeNum): class MiniShell(cmd.Cmd): def __init__(self, volume): + + import readline + readline.backend = 'readline' + cmd.Cmd.__init__(self) self.volumePath = volume self.volume = NTFS(volume) diff --git a/examples/ntlmrelayx.py b/examples/ntlmrelayx.py index 89a021b0b7..374744877a 100644 --- a/examples/ntlmrelayx.py +++ b/examples/ntlmrelayx.py @@ -39,11 +39,6 @@ import argparse import sys import logging - -# Patch readline to add backend property since cmd checks for it -import readline -readline.backend = 'readline' - import cmd try: @@ -69,6 +64,10 @@ class MiniShell(cmd.Cmd): def __init__(self, relayConfig, threads, api_address): + + import readline + readline.backend = 'readline' + cmd.Cmd.__init__(self) self.prompt = 'ntlmrelayx> ' diff --git a/examples/psexec.py b/examples/psexec.py index 8bcd5c5fa9..cc62c45015 100755 --- a/examples/psexec.py +++ b/examples/psexec.py @@ -470,6 +470,10 @@ def run(self): class RemoteShell(cmd.Cmd): def __init__(self, server, port, credentials, tid, fid, share, transport): + + import readline + readline.backend = 'readline' + cmd.Cmd.__init__(self, False) self.prompt = '\x08' self.server = server diff --git a/examples/raiseChild.py b/examples/raiseChild.py index abab970b96..7f121bc248 100755 --- a/examples/raiseChild.py +++ b/examples/raiseChild.py @@ -342,6 +342,10 @@ def run(self): class RemoteShell(cmd.Cmd): def __init__(self, server, port, credentials, tid, fid, TGS, share): + + import readline + readline.backend = 'readline' + cmd.Cmd.__init__(self, False) self.prompt = '\x08' self.server = server diff --git a/examples/smbexec.py b/examples/smbexec.py index 4985e94864..88cb7b32e2 100755 --- a/examples/smbexec.py +++ b/examples/smbexec.py @@ -174,6 +174,10 @@ def run(self, remoteName, remoteHost): class RemoteShell(cmd.Cmd): def __init__(self, share, rpc, mode, serviceName, shell_type): + + import readline + readline.backend = 'readline' + cmd.Cmd.__init__(self) self.__share = share self.__mode = mode diff --git a/examples/wmiexec.py b/examples/wmiexec.py index 52411b55da..18049d68c6 100755 --- a/examples/wmiexec.py +++ b/examples/wmiexec.py @@ -123,6 +123,10 @@ def run(self, addr, silentCommand=False): class RemoteShell(cmd.Cmd): def __init__(self, share, win32Process, smbConnection, shell_type, silentCommand=False): + + import readline + readline.backend = 'readline' + cmd.Cmd.__init__(self) self.__share = share self.__output = '\\' + OUTPUT_FILENAME diff --git a/examples/wmiquery.py b/examples/wmiquery.py index 34527f5391..1ae714bbec 100755 --- a/examples/wmiquery.py +++ b/examples/wmiquery.py @@ -43,6 +43,10 @@ class WMIQUERY(cmd.Cmd): def __init__(self, iWbemServices): + + import readline + readline.backend = 'readline' + cmd.Cmd.__init__(self) self.iWbemServices = iWbemServices self.prompt = 'WQL> ' diff --git a/impacket/examples/ldap_shell.py b/impacket/examples/ldap_shell.py index 8acf7960fc..fae56ac3dc 100755 --- a/impacket/examples/ldap_shell.py +++ b/impacket/examples/ldap_shell.py @@ -34,6 +34,10 @@ class LdapShell(cmd.Cmd): LDAP_MATCHING_RULE_IN_CHAIN = "1.2.840.113556.1.4.1941" def __init__(self, tcp_shell, domain_dumper, client): + + import readline + readline.backend = 'readline' + cmd.Cmd.__init__(self, stdin=tcp_shell.stdin, stdout=tcp_shell.stdout) if PY2: diff --git a/impacket/examples/mssqlshell.py b/impacket/examples/mssqlshell.py index a96fde225c..40083e7721 100644 --- a/impacket/examples/mssqlshell.py +++ b/impacket/examples/mssqlshell.py @@ -31,6 +31,10 @@ class SQLSHELL(cmd.Cmd): def __init__(self, SQL, show_queries=False, tcpShell=None): if tcpShell is not None: + + import readline + readline.backend = 'readline' + cmd.Cmd.__init__(self, stdin=tcpShell.stdin, stdout=tcpShell.stdout) sys.stdout = tcpShell.stdout sys.stdin = tcpShell.stdin diff --git a/impacket/examples/smbclient.py b/impacket/examples/smbclient.py index 21ec0e87a0..52d461902a 100755 --- a/impacket/examples/smbclient.py +++ b/impacket/examples/smbclient.py @@ -42,6 +42,10 @@ def __init__(self, smbClient, tcpShell=None, outputfile=None): #If the tcpShell parameter is passed (used in ntlmrelayx), # all input and output is redirected to a tcp socket # instead of to stdin / stdout + + import readline + readline.backend = 'readline' + if tcpShell is not None: cmd.Cmd.__init__(self, stdin=tcpShell.stdin, stdout=tcpShell.stdout) sys.stdout = tcpShell.stdout From db86eae2cbf0999ba0dd207d905c5c8cf79786fe Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Fri, 17 Jan 2025 20:07:18 -0500 Subject: [PATCH 24/30] Fix packet redirection bug --- examples/ntlmrelayx.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/ntlmrelayx.py b/examples/ntlmrelayx.py index 374744877a..1a14edf3f0 100644 --- a/examples/ntlmrelayx.py +++ b/examples/ntlmrelayx.py @@ -276,9 +276,9 @@ def stop_servers(threads): def redirect_smb_packets(): with pydivert.WinDivert("tcp.DstPort == 445 or tcp.SrcPort == 4445") as w: for packet in w: - if packet.dst_port == 445: + if packet.dst_port == 445 and packet.is_inbound: packet.dst_port = 4445 - if packet.src_port == 4445: + if packet.src_port == 4445 and packet.is_outbound: packet.src_port = 445 w.send(packet) From 428f13d05f32521ca152585f3a66d187a8ac11bf Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Wed, 5 Feb 2025 19:56:26 -0500 Subject: [PATCH 25/30] Fix readline patch for SQLSHELL --- impacket/examples/mssqlshell.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/impacket/examples/mssqlshell.py b/impacket/examples/mssqlshell.py index 40083e7721..bd2b49eb20 100644 --- a/impacket/examples/mssqlshell.py +++ b/impacket/examples/mssqlshell.py @@ -30,11 +30,11 @@ class SQLSHELL(cmd.Cmd): def __init__(self, SQL, show_queries=False, tcpShell=None): + + import readline + readline.backend = 'readline' + if tcpShell is not None: - - import readline - readline.backend = 'readline' - cmd.Cmd.__init__(self, stdin=tcpShell.stdin, stdout=tcpShell.stdout) sys.stdout = tcpShell.stdout sys.stdin = tcpShell.stdin From 7a9f25b437a3241b5ce01a04cc19f53d46441ab6 Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Thu, 13 Feb 2025 13:38:19 -0500 Subject: [PATCH 26/30] Allow installer to pull from different repos/branches as well as build locally --- impacket-exe-installer.ps1 | 54 +++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/impacket-exe-installer.ps1 b/impacket-exe-installer.ps1 index 03673edf48..0ececbd0e8 100644 --- a/impacket-exe-installer.ps1 +++ b/impacket-exe-installer.ps1 @@ -6,7 +6,6 @@ $StartingDirectory = Get-Location $PythonInstallerPath = Join-Path -Path $Env:TEMP -ChildPath "python-$PythonVersion.exe" $RepositoryArchivePath = Join-Path -Path $Env:TEMP -ChildPath "impacket-exe.zip" -$RepositoryFolderPath = Join-Path -Path $Env:TEMP -ChildPath "impacket-exe-master" $MachinePythonKey = "HKLM:\Software\Python\PythonCore" $UserPythonKey = "HKCU:\Software\Python\PythonCore" @@ -90,6 +89,20 @@ $Options['OutputDir'] = @{ Value = $StartingDirectory Type = 'Path' } +$Options['Branch'] = @{ + Name = 'Repository Branch' + Desc = 'Set the branch of the repository to download from' + Keywords = @('-b', '--branch') + Value = 'master' + Type = 'String' +} +$Options['Repository'] = @{ + Name = 'Repository' + Desc = 'The Github repository to download from' + Keywords = @('-r', '--repository') + Value = 'p0rtl6/impacket-exe' + Type = 'String' +} $Flags = New-object System.Collections.Hashtable $Flags['InstallAll'] = @{ @@ -116,7 +129,12 @@ $Flags['InstallSystemWide'] = @{ Keywords = @('-I', '--install-systemwide') Value = $False } - +$Flags['InstallFromCurrentDir'] = @{ + Name = 'Install From Current Directory' + Desc = 'Install scripts from the current directory instead of downloading from a URL' + Keywords = @('-C', '--install-current-dir') + Value = $False +} function GetKeyByKeyword { param ( @@ -235,6 +253,7 @@ if ($SelectedScripts.Count -eq 0) { throw "Error: Must select at least one script to install (Use -h or --help for help)" } +$ProgressPreference = 'SilentlyContinue' # Check Local Machine Registry if (Test-Path $MachinePythonKey) { @@ -266,15 +285,23 @@ if (-not $FoundPython -or $Flags['OverridePython']['Value']) { $Env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User") } -# Download and unzip repository -Write-Host 'Downloading repository...' -Invoke-WebRequest -Uri "https://github.com/p0rtL6/impacket-exe/archive/refs/heads/master.zip" -OutFile $RepositoryArchivePath -Expand-Archive -Path $RepositoryArchivePath -DestinationPath $Env:TEMP -Force -Remove-Item $RepositoryArchivePath - -# Begin build process -Write-Host 'Beginning build process...' -Set-Location -Path $RepositoryFolderPath +if (-not $Flags['InstallFromCurrentDir']['Value']) { + # Set the source + $RepositoryUrl = "https://github.com/$($Options['Repository']['Value'])/archive/refs/heads/$($Options['Branch']['Value']).zip" + $RepositoryFolderPath = Join-Path -Path $Env:TEMP -ChildPath "impacket-exe-$($Options['Branch']['Value'])" + + # Download and unzip repository + Write-Host 'Downloading repository...' + Invoke-WebRequest -Uri $RepositoryUrl -OutFile $RepositoryArchivePath + Expand-Archive -Path $RepositoryArchivePath -DestinationPath $Env:TEMP -Force + Remove-Item $RepositoryArchivePath + + # Begin build process + Write-Host 'Beginning build process...' + Set-Location -Path $RepositoryFolderPath +} else { + $RepositoryFolderPath = Get-Location +} # Create and activate virtual environment python -m venv .venv @@ -352,7 +379,10 @@ foreach ($Script in $SelectedScripts) { deactivate Set-Location -Path $StartingDirectory -Remove-Item -Recurse -Force $RepositoryFolderPath + +if (-not $Flags['InstallFromCurrentDir']['Value']) { + Remove-Item -Recurse -Force $RepositoryFolderPath +} if (-not $Flags['LeavePython']['Value'] -and (-not $FoundPython -or $Flags['OverridePython']['Value'])) { Write-Host 'Uninstalling Python...' From 5d829be2813622b272a714472ae97b97bcf123e3 Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Mon, 17 Feb 2025 16:15:42 -0500 Subject: [PATCH 27/30] Add temp dir and extract dir options --- impacket-exe-installer.ps1 | 42 ++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/impacket-exe-installer.ps1 b/impacket-exe-installer.ps1 index 0ececbd0e8..09f1ec2adc 100644 --- a/impacket-exe-installer.ps1 +++ b/impacket-exe-installer.ps1 @@ -3,10 +3,6 @@ $PythonVersion = '3.13.0' $StartingDirectory = Get-Location -$PythonInstallerPath = Join-Path -Path $Env:TEMP -ChildPath "python-$PythonVersion.exe" - -$RepositoryArchivePath = Join-Path -Path $Env:TEMP -ChildPath "impacket-exe.zip" - $MachinePythonKey = "HKLM:\Software\Python\PythonCore" $UserPythonKey = "HKCU:\Software\Python\PythonCore" $FoundPython = $False @@ -103,6 +99,20 @@ $Options['Repository'] = @{ Value = 'p0rtl6/impacket-exe' Type = 'String' } +$Options['TempDir'] = @{ + Name = 'Temporary Directory' + Desc = 'The temporary directory to download and build in' + Keywords = @('-t', '--temp-dir') + Value = $ENV:Temp + Type = 'Path' +} +$Options['ExtractDir'] = @{ + Name = 'Extraction Directory' + Desc = 'The directory in which binaries extract to during runtime' + Keywords = @('-e', '--extract-dir') + Value = $null + Type = 'Path' +} $Flags = New-object System.Collections.Hashtable $Flags['InstallAll'] = @{ @@ -226,8 +236,11 @@ for ($I = 0; $I -lt $Args.Count; $I++) { if (-not $Value) { throw "Error in $($Options[$OptionsKey]['Name']): No value recieved (Use -h or --help for help)" } - if ($Options[$OptionsKey]['type'] -eq 'Path' -and -not (Test-Path $Value)) { - throw "Error in $($Options[$OptionsKey]['Name']): Path does not exist (Use -h or --help for help)" + if ($Options[$OptionsKey]['type'] -eq 'Path') { + if (-not (Test-Path $Value)) { + throw "Error in $($Options[$OptionsKey]['Name']): Path does not exist (Use -h or --help for help)" + } + $Value = (Resolve-Path $Value).Path } $Options[$OptionsKey]['Value'] = $Value } @@ -275,6 +288,10 @@ if (Test-Path $UserPythonKey) { } } +$PythonInstallerPath = Join-Path -Path $Options['TempDir']['Value'] -ChildPath "python-$PythonVersion.exe" + +$RepositoryArchivePath = Join-Path -Path $Options['TempDir']['Value'] -ChildPath "impacket-exe.zip" + # Download and install Python if (-not $FoundPython -or $Flags['OverridePython']['Value']) { Write-Host "Python $PythonVersion is not installed, installing now..." @@ -288,18 +305,19 @@ if (-not $FoundPython -or $Flags['OverridePython']['Value']) { if (-not $Flags['InstallFromCurrentDir']['Value']) { # Set the source $RepositoryUrl = "https://github.com/$($Options['Repository']['Value'])/archive/refs/heads/$($Options['Branch']['Value']).zip" - $RepositoryFolderPath = Join-Path -Path $Env:TEMP -ChildPath "impacket-exe-$($Options['Branch']['Value'])" + $RepositoryFolderPath = Join-Path -Path $Options['TempDir']['Value'] -ChildPath "impacket-exe-$($Options['Branch']['Value'])" # Download and unzip repository Write-Host 'Downloading repository...' Invoke-WebRequest -Uri $RepositoryUrl -OutFile $RepositoryArchivePath - Expand-Archive -Path $RepositoryArchivePath -DestinationPath $Env:TEMP -Force + Expand-Archive -Path $RepositoryArchivePath -DestinationPath $Options['TempDir']['Value'] -Force Remove-Item $RepositoryArchivePath # Begin build process Write-Host 'Beginning build process...' Set-Location -Path $RepositoryFolderPath -} else { +} +else { $RepositoryFolderPath = Get-Location } @@ -316,6 +334,12 @@ foreach ($Script in $SelectedScripts) { # Run required modules Main $Arguments = @('--onefile') + + if ($Options['ExtractDir']['Value']) { + $Arguments += '--runtime-tmpdir' + $Arguments += $Options['ExtractDir']['Value'] + } + foreach ($ModuleName in $AvailableScripts[$Script]['RequiredModules']) { Write-Host "Running module $ModuleName" . "installer-modules\$ModuleName.ps1" From 346a34b6ad1916824ee5d4d79d2388d550486b3b Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Wed, 19 Feb 2025 19:17:22 -0500 Subject: [PATCH 28/30] Rewrite installer to use Powershell framework --- .../ntlmrelayx-requirements.txt | 1 - example-requirements/sniff-requirements.txt | 1 - example-requirements/split-requirements.txt | 1 - impacket-exe-installer.ps1 | 416 -------- impacket-installer.ps1 | 966 ++++++++++++++++++ installer-modules/Npcap.ps1 | 38 - installer-modules/ntlmrelayx.ps1 | 5 - 7 files changed, 966 insertions(+), 462 deletions(-) delete mode 100644 example-requirements/ntlmrelayx-requirements.txt delete mode 100644 example-requirements/sniff-requirements.txt delete mode 100644 example-requirements/split-requirements.txt delete mode 100644 impacket-exe-installer.ps1 create mode 100644 impacket-installer.ps1 delete mode 100644 installer-modules/Npcap.ps1 delete mode 100644 installer-modules/ntlmrelayx.ps1 diff --git a/example-requirements/ntlmrelayx-requirements.txt b/example-requirements/ntlmrelayx-requirements.txt deleted file mode 100644 index 9e4d2df286..0000000000 --- a/example-requirements/ntlmrelayx-requirements.txt +++ /dev/null @@ -1 +0,0 @@ -pydivert diff --git a/example-requirements/sniff-requirements.txt b/example-requirements/sniff-requirements.txt deleted file mode 100644 index 4d9fa78dee..0000000000 --- a/example-requirements/sniff-requirements.txt +++ /dev/null @@ -1 +0,0 @@ -pcapy-ng diff --git a/example-requirements/split-requirements.txt b/example-requirements/split-requirements.txt deleted file mode 100644 index 4d9fa78dee..0000000000 --- a/example-requirements/split-requirements.txt +++ /dev/null @@ -1 +0,0 @@ -pcapy-ng diff --git a/impacket-exe-installer.ps1 b/impacket-exe-installer.ps1 deleted file mode 100644 index 09f1ec2adc..0000000000 --- a/impacket-exe-installer.ps1 +++ /dev/null @@ -1,416 +0,0 @@ -# Impacket-exe Installer - -$PythonVersion = '3.13.0' -$StartingDirectory = Get-Location - -$MachinePythonKey = "HKLM:\Software\Python\PythonCore" -$UserPythonKey = "HKCU:\Software\Python\PythonCore" -$FoundPython = $False - -$PythonVersionParts = $PythonVersion.Split(".") -$TruncatedPythonVersion = "$($PythonVersionParts[0]).$($PythonVersionParts[1])" - -$availableScripts = @{ - 'DumpNTLMInfo' = @{requiredModules = @() } - 'Get-GPPPassword' = @{requiredModules = @() } - 'GetADComputers' = @{requiredModules = @() } - 'GetADUsers' = @{requiredModules = @() } - 'GetLAPSPassword' = @{requiredModules = @() } - 'GetNPUsers' = @{requiredModules = @() } - 'GetUserSPNs' = @{requiredModules = @() } - 'addcomputer' = @{requiredModules = @() } - 'atexec' = @{requiredModules = @() } - 'changepasswd' = @{requiredModules = @() } - 'dacledit' = @{requiredModules = @() } - 'dcomexec' = @{requiredModules = @() } - 'describeTicket' = @{requiredModules = @() } - 'dpapi' = @{requiredModules = @() } - 'esentutl' = @{requiredModules = @() } - 'exchanger' = @{requiredModules = @() } - 'findDelegation' = @{requiredModules = @() } - 'getArch' = @{requiredModules = @() } - 'getPac' = @{requiredModules = @() } - 'getST' = @{requiredModules = @() } - 'getTGT' = @{requiredModules = @() } - 'goldenPac' = @{requiredModules = @() } - 'karmaSMB' = @{requiredModules = @() } - 'keylistattack' = @{requiredModules = @() } - 'kintercept' = @{requiredModules = @() } - 'lookupsid' = @{requiredModules = @() } - 'machine_role' = @{requiredModules = @() } - 'mimikatz' = @{requiredModules = @() } - 'mqtt_check' = @{requiredModules = @() } - 'mssqlclient' = @{requiredModules = @() } - 'mssqlinstance' = @{requiredModules = @() } - 'net' = @{requiredModules = @() } - 'netview' = @{requiredModules = @() } - 'ntfs-read' = @{requiredModules = @() } - 'ntlmrelayx' = @{requiredModules = @('ntlmrelayx') } - 'owneredit' = @{requiredModules = @() } - 'ping' = @{requiredModules = @() } - 'ping6' = @{requiredModules = @() } - 'psexec' = @{requiredModules = @() } - 'raiseChild' = @{requiredModules = @() } - 'rbcd' = @{requiredModules = @() } - 'rdp_check' = @{requiredModules = @() } - 'reg' = @{requiredModules = @() } - 'registry-read' = @{requiredModules = @() } - 'rpcdump' = @{requiredModules = @() } - 'rpcmap' = @{requiredModules = @() } - 'sambaPipe' = @{requiredModules = @() } - 'samrdump' = @{requiredModules = @() } - 'secretsdump' = @{requiredModules = @() } - 'services' = @{requiredModules = @() } - 'smbclient' = @{requiredModules = @() } - 'smbexec' = @{requiredModules = @() } - 'smbserver' = @{requiredModules = @() } - 'sniff' = @{requiredModules = @('Npcap') } - 'sniffer' = @{requiredModules = @() } - 'split' = @{requiredModules = @('Npcap') } - 'ticketConverter' = @{requiredModules = @() } - 'ticketer' = @{requiredModules = @() } - 'tstool' = @{requiredModules = @() } - 'wmiexec' = @{requiredModules = @() } - 'wmipersist' = @{requiredModules = @() } - 'wmiquery' = @{requiredModules = @() } -} - -$SelectedScripts = New-Object System.Collections.Generic.HashSet[string] - -$Options = New-object System.Collections.Hashtable -$Options['OutputDir'] = @{ - Name = 'Output Directory' - Desc = 'Set the output directory for the built executable' - Keywords = @('-o', '--output-dir') - Value = $StartingDirectory - Type = 'Path' -} -$Options['Branch'] = @{ - Name = 'Repository Branch' - Desc = 'Set the branch of the repository to download from' - Keywords = @('-b', '--branch') - Value = 'master' - Type = 'String' -} -$Options['Repository'] = @{ - Name = 'Repository' - Desc = 'The Github repository to download from' - Keywords = @('-r', '--repository') - Value = 'p0rtl6/impacket-exe' - Type = 'String' -} -$Options['TempDir'] = @{ - Name = 'Temporary Directory' - Desc = 'The temporary directory to download and build in' - Keywords = @('-t', '--temp-dir') - Value = $ENV:Temp - Type = 'Path' -} -$Options['ExtractDir'] = @{ - Name = 'Extraction Directory' - Desc = 'The directory in which binaries extract to during runtime' - Keywords = @('-e', '--extract-dir') - Value = $null - Type = 'Path' -} - -$Flags = New-object System.Collections.Hashtable -$Flags['InstallAll'] = @{ - Name = 'Install All Scripts' - Desc = 'Installs every script in the available scripts list' - Keywords = @('-A', '--all') - Value = $False -} -$Flags['OverridePython'] = @{ - Name = 'Override Installed Python' - Desc = "Install Python $PythonVersion even if an existing python version is installed" - Keywords = @('-P', '--override-python') - Value = $False -} -$Flags['LeavePython'] = @{ - Name = 'Leave Installed Python' - Desc = "If installed, do not uninstall Python $PythonVersion from the system" - Keywords = @('-L', '--leave-python') - Value = $False -} -$Flags['InstallSystemWide'] = @{ - Name = 'Install Scripts System-Wide' - Desc = 'Install scripts to C:\Program Files\ and add them to the PATH (Ignores Output Directory)' - Keywords = @('-I', '--install-systemwide') - Value = $False -} -$Flags['InstallFromCurrentDir'] = @{ - Name = 'Install From Current Directory' - Desc = 'Install scripts from the current directory instead of downloading from a URL' - Keywords = @('-C', '--install-current-dir') - Value = $False -} - -function GetKeyByKeyword { - param ( - [hashtable]$HashTable, - [string]$Keyword - ) - - foreach ($Key in $HashTable.Keys) { - $Item = $HashTable[$Key] - if ($Item.Keywords -contains $Keyword) { - return $Key - } - } - return $Null -} - -$HelpMenuPadding = 25 - -function Show-HelpMenu { - Write-Host '=== Impacket-exe Installer ===' - Write-Host 'Downloads, builds, and installs scripts from the Impacket-exe repository' - Write-Host '' - Write-Host 'Usage: impacket-exe-installer.ps1 [FLAGS] [OPTIONS] []' - Write-Host '' - Write-Host 'Positional Arguments:' - Write-Host " $(''.PadRight($HelpMenuPadding)) A space seperated list of scripts you want to install" - Write-Host '' - Write-Host 'Flags:' - foreach ($Flag in $Flags.Values) { - $FormattedKeywords = $Flag['Keywords'] -join ' ' - Write-Host " $($FormattedKeywords.PadRight($HelpMenuPadding)) $($Flag['Desc']) (default: $($Flag['Value']))" - } - Write-Host '' - Write-Host 'Options:' - Write-Host " $('-h --help'.PadRight($HelpMenuPadding)) Display this menu" - Write-Host " $('-s --list-scripts'.PadRight($HelpMenuPadding)) List available scripts" - foreach ($Option in $Options.Values) { - $FormattedKeywords = $Option['Keywords'] -join ' ' - Write-Host " $($FormattedKeywords.PadRight($HelpMenuPadding)) $($Option['Desc']) (default: $($Option['Value']))" - } - Write-Host '' -} - -function Show-Scripts { - Write-Host 'Available Scripts:' - foreach ($AvailableScript in $AvailableScripts.GetEnumerator()) { - Write-Host " $($AvailableScript.Key)" - } - Write-Host '' -} - -if ($Args.Count -eq 0) { - Show-HelpMenu - exit 0 -} - -for ($I = 0; $I -lt $Args.Count; $I++) { - if ($Args[$I] -eq '-h' -or $Args[$I] -eq '--help') { - Show-HelpMenu - exit 0 - } - if ($Args[$I] -eq '-s' -or $Args[$I] -eq '--list-scripts') { - Show-Scripts - exit 0 - } - elseif ($Args[$I].startsWith('-')) { - $ArgParts = $Args[$I] -split '=' - $Keyword = $ArgParts[0] - $Value = $Null - - $FlagsKey = GetKeyByKeyword -HashTable $Flags -Keyword $Keyword - $OptionsKey = GetKeyByKeyword -HashTable $Options -Keyword $Keyword - - if ($ArgParts.Count -eq 2) { - $Value = $ArgParts[1] - } - elseif ($ArgParts.Count -gt 1) { - throw "Error in $($Options[$OptionsKey]['Name']): Multiple equals signs (Use -h or --help for help)" - } - - if ($FlagsKey) { - $Flags[$FlagsKey]['Value'] = $True - } - elseif ($OptionsKey) { - if (-not $Value) { - $I++ - $Value = $Args[$I] - } - if (-not $Value) { - throw "Error in $($Options[$OptionsKey]['Name']): No value recieved (Use -h or --help for help)" - } - if ($Options[$OptionsKey]['type'] -eq 'Path') { - if (-not (Test-Path $Value)) { - throw "Error in $($Options[$OptionsKey]['Name']): Path does not exist (Use -h or --help for help)" - } - $Value = (Resolve-Path $Value).Path - } - $Options[$OptionsKey]['Value'] = $Value - } - else { - throw "Error: Unrecognized argument (Use -h or --help for help)" - } - } - elseif ($AvailableScripts.ContainsKey($Args[$I])) { - $SelectedScripts.Add($Args[$I]) | Out-Null - } - else { - throw "Error: Invalid script selected. (use -s or --list-scripts for a list of available scripts)" - } -} - -if ($Flags['InstallAll']['Value']) { - foreach ($key in $AvailableScripts.Keys) { - $SelectedScripts.Add($key) | Out-Null - } -} - -if ($SelectedScripts.Count -eq 0) { - throw "Error: Must select at least one script to install (Use -h or --help for help)" -} - -$ProgressPreference = 'SilentlyContinue' - -# Check Local Machine Registry -if (Test-Path $MachinePythonKey) { - Get-ChildItem $MachinePythonKey | ForEach-Object { - if ($_.PSChildName -eq $TruncatedPythonVersion) { - $FoundPython = $True - Write-Host "Python $($_.PSChildName) found in Local Machine" - } - } -} - -# Check Current User Registry -if (Test-Path $UserPythonKey) { - Get-ChildItem $UserPythonKey | ForEach-Object { - if ($_.PSChildName -eq $TruncatedPythonVersion) { - $FoundPython = $True - Write-Host "Python $($_.PSChildName) found in Current User" - } - } -} - -$PythonInstallerPath = Join-Path -Path $Options['TempDir']['Value'] -ChildPath "python-$PythonVersion.exe" - -$RepositoryArchivePath = Join-Path -Path $Options['TempDir']['Value'] -ChildPath "impacket-exe.zip" - -# Download and install Python -if (-not $FoundPython -or $Flags['OverridePython']['Value']) { - Write-Host "Python $PythonVersion is not installed, installing now..." - Invoke-WebRequest -Uri "https://www.python.org/ftp/python/$PythonVersion/python-$PythonVersion-amd64.exe" -OutFile $PythonInstallerPath - Start-Process $PythonInstallerPath -ArgumentList "/quiet PrependPath=1 Include_launcher=0" -Wait - - # Refresh PATH - $Env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User") -} - -if (-not $Flags['InstallFromCurrentDir']['Value']) { - # Set the source - $RepositoryUrl = "https://github.com/$($Options['Repository']['Value'])/archive/refs/heads/$($Options['Branch']['Value']).zip" - $RepositoryFolderPath = Join-Path -Path $Options['TempDir']['Value'] -ChildPath "impacket-exe-$($Options['Branch']['Value'])" - - # Download and unzip repository - Write-Host 'Downloading repository...' - Invoke-WebRequest -Uri $RepositoryUrl -OutFile $RepositoryArchivePath - Expand-Archive -Path $RepositoryArchivePath -DestinationPath $Options['TempDir']['Value'] -Force - Remove-Item $RepositoryArchivePath - - # Begin build process - Write-Host 'Beginning build process...' - Set-Location -Path $RepositoryFolderPath -} -else { - $RepositoryFolderPath = Get-Location -} - -# Create and activate virtual environment -python -m venv .venv -.venv\Scripts\Activate.ps1 - -# Setup -pip install -r requirements.txt -python setup.py install - -foreach ($Script in $SelectedScripts) { - Write-Host "Building $Script..." - - # Run required modules Main - $Arguments = @('--onefile') - - if ($Options['ExtractDir']['Value']) { - $Arguments += '--runtime-tmpdir' - $Arguments += $Options['ExtractDir']['Value'] - } - - foreach ($ModuleName in $AvailableScripts[$Script]['RequiredModules']) { - Write-Host "Running module $ModuleName" - . "installer-modules\$ModuleName.ps1" - - $Argument = Main - $Arguments += ($Argument) - } - - if (Test-Path "example-requirements\$Script-requirements.txt") { - pip install -r "example-requirements\$Script-requirements.txt" - } - - pyinstaller $Arguments "examples\$Script.py" - - $BuiltScriptPath = Join-Path -Path $RepositoryFolderPath -ChildPath "dist\$Script.exe" - - if ($Flags['InstallSystemWide']['Value']) { - # Prepare destination folder - Write-Host 'Copying executable to Program Files...' - New-Item -ItemType Directory -Path 'C:\Program Files\Impacket-exe' -Force - - # Copy built executable into program files - Copy-Item -Path $BuiltScriptPath -Destination 'C:\Program Files\Impacket-exe' -Force - } - else { - Copy-Item -Path $BuiltScriptPath -Destination $Options['OutputDir']['Value'] -Force - } -} - -if ($Flags['InstallSystemWide']['Value']) { - # Get the current PATH environment variable - Write-Host "Updating PATH..." - $CurrentPath = [System.Environment]::GetEnvironmentVariable('Path', [System.EnvironmentVariableTarget]::Machine) - - # Check if the path already exists in PATH - if ($CurrentPath -notlike "*C:\Program Files\Impacket-exe*") { - # Append the new path to the existing PATH variable - $NewPath = $CurrentPath + ';' + 'C:\Program Files\Impacket-exe' - - # Set the new PATH variable - [System.Environment]::SetEnvironmentVariable('Path', $NewPath, [System.EnvironmentVariableTarget]::Machine) - - Write-Host 'Successfully added C:\Program Files\Impacket-exe to PATH.' - } - else { - Write-Host 'C:\Program Files\Impacket-exe is already in PATH.' - } -} - -Write-Host 'Cleaning up...' - -# Run required modules Cleanup -foreach ($Script in $SelectedScripts) { - foreach ($ModuleName in $AvailableScripts[$Script]['RequiredModules']) { - Write-Host "Cleaning up module $ModuleName..." - . "installer-modules\$ModuleName.ps1" - - Cleanup - } -} - -deactivate -Set-Location -Path $StartingDirectory - -if (-not $Flags['InstallFromCurrentDir']['Value']) { - Remove-Item -Recurse -Force $RepositoryFolderPath -} - -if (-not $Flags['LeavePython']['Value'] -and (-not $FoundPython -or $Flags['OverridePython']['Value'])) { - Write-Host 'Uninstalling Python...' - Start-Process $PythonInstallerPath -ArgumentList "/uninstall /quiet PrependPath=1" -Wait -} - -Write-Host 'Done!' diff --git a/impacket-installer.ps1 b/impacket-installer.ps1 new file mode 100644 index 0000000000..a87554bc66 --- /dev/null +++ b/impacket-installer.ps1 @@ -0,0 +1,966 @@ +$scriptTitle = 'Impacket Installer' +$scriptFileName = 'impacket-installer.ps1' +$scriptDesc = 'Builds Impacket to windows compatible binaries' +$version = '1.0.0' + +$commands = @{ + 'install' = @{ + Description = 'Install Impacket' + Order = 0 + Arguments = @{ + 'tools' = @{ + Description = 'A list of tools to install' + Order = 0 + Required = $true + Type = 'TOOL' + CustomType = @{ + ReturnType = [string] + Parser = { + param ( + [System.Object]$Value + ) + + # Validate that the tools are in the list of available tools + + $value = $value.ToLower() + + if ($availableTools -contains $value) { + return $value + } + else { + return $null + } + } + } + List = $true + } + 'output-dir' = @{ + Description = 'The output directory for the binaries' + Order = 1 + Required = $false + Type = 'PATH' + Default = Get-Location + } + 'source' = @{ + Description = 'The source to download from (USER/REPO/BRANCh uses Github)' + Order = 2 + Required = $false + Default = New-Object System.Uri('https://github.com/p0rtL6/impacket/archive/refs/heads/windows.zip') + Type = 'USER/REPO/BRANCH or URL or DIRECTORY' + CustomType = @{ + ReturnType = [Uri] + Parser = { + param ( + [System.Object]$Value + ) + + # This is all just fancy parsing for the different input types, it should guarantee that we have a valid download url + + $parsedUri = $null + $isURL = [Uri]::TryCreate($value, [UriKind]::RelativeOrAbsolute, [ref]$parsedUri) + + if (-not $isURL) { + $parts = $value -split '/' + if ($parts.Length -eq 3) { + $stringUri = "https://github.com/$($parts[0])/$($parts[1])/archive/refs/heads/$($parts[2]).zip" + [Uri]::TryCreate($stringUri, [UriKind]::RelativeOrAbsolute, [ref]$parsedUri) | Out-Null + } + } + else { + if (-not $parsedUri.IsAbsoluteUri) { + if (Test-Path $parsedUri) { + try { + $resolvedPath = (Resolve-Path -Path $value).Path + if (Test-Path -Path $resolvedPath -PathType Container) { + $fileUri = "file://$resolvedPath" + [Uri]::TryCreate($fileUri, [UriKind]::RelativeOrAbsolute, [ref]$parsedUri) | Out-Null + } + else { + $parsedUri = $null + } + } + catch { + $parsedUri = $null + } + } + else { + $parsedUri = $null + } + } + } + + return $parsedUri + } + } + } + 'temp-dir' = @{ + Description = 'The temporary directory that is used for downloading and building' + Order = 3 + Required = $false + Type = 'PATH' + Default = $env:temp + } + 'extract-dir' = @{ + Description = 'The directory in which binaries will extract to during runtime' + Order = 4 + Required = $false + Type = 'PATH' + } + } + Flags = @{ + 'system-wide' = @{ + Description = 'Install system-wide and add to PATH' + Order = 0 + } + } + } + 'list-tools' = @{ + Description = 'Show the list of available tools to install' + Order = 1 + } +} + +# A big list of all the examples in the Impacket repo, if something gets added, this needs to be updated +$availableTools = @( + 'DumpNTLMInfo' + 'Get-GPPPassword' + 'GetADComputers' + 'GetADUsers' + 'GetLAPSPassword' + 'GetNPUsers' + 'GetUserSPNs' + 'addcomputer' + 'atexec' + 'changepasswd' + 'dacledit' + 'dcomexec' + 'describeTicket' + 'dpapi' + 'esentutl' + 'exchanger' + 'findDelegation' + 'getArch' + 'getPac' + 'getST' + 'getTGT' + 'goldenPac' + 'karmaSMB' + 'keylistattack' + 'kintercept' + 'lookupsid' + 'machine_role' + 'mimikatz' + 'mqtt_check' + 'mssqlclient' + 'mssqlinstance' + 'net' + 'netview' + 'ntfs-read' + 'ntlmrelayx' + 'owneredit' + 'ping' + 'ping6' + 'psexec' + 'raiseChild' + 'rbcd' + 'rdp_check' + 'reg' + 'registry-read' + 'rpcdump' + 'rpcmap' + 'sambaPipe' + 'samrdump' + 'secretsdump' + 'services' + 'smbclient' + 'smbexec' + 'smbserver' + 'sniff' + 'sniffer' + 'split' + 'ticketConverter' + 'ticketer' + 'tstool' + 'wmiexec' + 'wmipersist' + 'wmiquery' + 'all' +) + +# Extra code that needs to run conditionally for certain tools +$modules = @{ + 'ntlmrelayx' = @{ + 'install' = { + param ( + [Hashtable]$Arguments, + [Hashtable]$Flags + ) + + # No extra things need to happen here, just more Arguments + # For some reason there is a bug with tkinter being included (?????) + + return @('--exclude-module', 'tkinter', '--collect-all', 'impacket.examples.ntlmrelayx') + } + 'cleanup' = { + param ( + [Hashtable]$Arguments, + [Hashtable]$Flags + ) + } + } + 'npcap' = @{ + 'install' = { + param ( + [Hashtable]$Arguments, + [Hashtable]$Flags + ) + + $tempDir = $arguments['temp-dir'] + $npcapInstaller = Join-Path -Path $tempDir -ChildPath 'npcap.exe' + + # Check if the module has already been run + if (-not $flags['modulesRan'].Contains('npcap')) { + + # We need to make sure build tools are installed for pcapy-ng + $buildToolsUrl = 'https://aka.ms/vs/17/release/vs_BuildTools.exe' + + # Npcap also needs to be bundled with the binaries + $npcapVersion = '1.80' + $npcapSDKVersion = '1.13' + + $npcapUrl = "https://npcap.com/dist/npcap-$npcapVersion.exe" + $npcapSDKUrl = "https://npcap.com/dist/npcap-sdk-$npcapSDKVersion.zip" + + $buildToolsInstaller = Join-Path -Path $tempDir -ChildPath 'buildtools.exe' + Invoke-WebRequest -Uri $buildToolsUrl -OutFile $buildToolsInstaller + + # Skip installation if already on the system + if (Test-Path 'C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools') { + $flags['installedBuildTools'] = $false + } + else { + Write-Host 'Installing VC Build Tools...' + Start-Process $buildToolsInstaller -ArgumentList '--quiet', '--wait', '--add', 'Microsoft.VisualStudio.Workload.VCTools;includeRecommended' -Wait + + $flags['installedBuildTools'] = $true + $arguments['buildToolsInstaller'] = $buildToolsInstaller + } + + Invoke-WebRequest -Uri $npcapUrl -OutFile $npcapInstaller + + # Skip installation if already on the system + if (Test-Path 'HKLM:\SYSTEM\CurrentControlSet\Services\npcap') { + $flags['installedNpcap'] = $false + } + else { + Write-Host 'Installing Npcap...' + Start-Process $npcapInstaller -Wait + + $flags['installedNpcap'] = $true + } + + # The SDK also needs to be installed for pcapy-ng + + $npcapSDKArchive = Join-Path -Path $tempDir -ChildPath 'npcapSDK.zip' + $npcapSDKFolder = Join-Path -Path $tempDir -ChildPath 'npcapSDK' + + Invoke-WebRequest -Uri $npcapSDKUrl -OutFile $npcapSDKArchive + Expand-Archive -Path $npcapSDKArchive -DestinationPath $npcapSDKFolder -Force + Remove-Item $npcapSDKArchive + + # Add required folders to the environment so that pcapy-ng builds correctly + + $env:INCLUDE = "$npcapSDKFolder\Include" + $env:LIB = "$npcapSDKFolder\Lib\x64" + } + + return @('--add-binary', "$npcapInstaller;.") + } + 'cleanup' = { + param ( + [Hashtable]$Arguments, + [Hashtable]$Flags + ) + + if (-not $flags['modulesCleaned'].Contains('npcap')) { + # Check if we installed Npcap during previous step + if ($flags['installedNpcap']) { + Start-Process 'C:\Program Files\Npcap\Uninstall.exe' -Wait + + # Set the flag to false so that on subsequent runs it does not try to uninstall again + $flags['installedNpcap'] = $false + } + + # Check if we installed VC Build Tools during previous step + if ($flags['installedBuildTools']) { + Write-Host 'Uninstalling VC Build Tools...' + Start-Process $arguments['buildToolsInstaller'] -ArgumentList '--quiet', '--wait', '--remove', 'Microsoft.VisualStudio.Workload.VCTools' -Wait + + # Set the flag to false so that on subsequent runs it does not try to uninstall again + $flags['installedBuildTools'] = $false + } + } + } + } +} + +# Define what tools require what modules and packages +$toolExtras = @{ + 'ntlmrelayx' = @{ + Modules = @('ntlmrelayx') + Packages = @('pydivert') + } + 'sniff' = @{ + Modules = @('npcap') + Packages = @('pcapy-ng') + } + 'split' = @{ + Modules = @('npcap') + Packages = @('pcapy-ng') + } +} + +function install { + param ( + [Hashtable]$Arguments, + [Hashtable]$Flags + ) + + try { + + # With the way lists are parsed, this has to be done at runtime + if ($arguments['tools'] -contains 'all') { + $arguments['tools'] = $availableTools + } + + # Create a folder in the specified temp dir, this will be used as the place where everything is downloaded and built in + $tempDir = Join-Path -Path $arguments['temp-dir'] -ChildPath ($scriptTitle -replace ' ', '-').ToLower() + $arguments['temp-dir'] = $tempDir + + # Remove any existing temp dir from a possible previous run + if (Test-Path -Path $tempDir) { + Remove-Item -Path $tempDir -Recurse -Force + } + + New-Item -Path $tempDir -ItemType 'Directory' -Force | Out-Null + + # Save for later to return back to the start + $startingDirectory = Get-Location + + $targetDirectory + + # Check if the source is a local directory, else download from the source url + if ($arguments['source'].IsFile) { + $targetDirectory = $arguments['source'].AbsolutePath + $virtualEnvironmentPath = Join-Path -Path $targetDirectory -ChildPath '.venv' + if (Test-Path -Path $virtualEnvironmentPath) { + Remove-Item -Path $virtualEnvironmentPath -Recurse -Force + } + } + else { + Write-Host 'Downloading source...' + $sourceArchivePath = Join-Path -Path $tempDir -ChildPath 'source.zip' + $sourceFolderPath = Join-Path -Path $tempDir -ChildPath 'source' + + Invoke-WebRequest -Uri $arguments['source'].AbsoluteUri -OutFile $sourceArchivePath + Expand-Archive -Path $sourceArchivePath -DestinationPath $sourceFolderPath + + # Git repo archives tend to be put inside subfolders so this should provide a better way to find the right folder without knowing things like the branch name + # There may be a more ideal file to search for, but this shoudl work for now + $foldersWithPythonFile = Get-ChildItem -Path $sourceFolderPath -Recurse -File -Filter "setup.py" | Select-Object DirectoryName + $targetDirectory = $foldersWithPythonFile.DirectoryName + } + + Set-Location -Path $targetDirectory + + $pythonBinary = Get-Python -TempDir $tempDir + + # Create and activate a Python virtual environment + & $pythonBinary -m venv .venv + .\.venv\Scripts\Activate.ps1 + + # Install the requiements and Pyinstaller + pip install -r requirements.txt + pip install pyinstaller + + # Build the library + python setup.py install + + # Create a base list of arguments for Pyinstaller + $installerArgs = New-Object System.Collections.ArrayList + $installerArgs.Add('--onefile') | Out-Null + + # This changes where the binaries extract their data to during runtime + if ($arguments.ContainsKey('extract-dir')) { + $installerArgs.Add('--runtime-tmpdir') | Out-Null + $installerArgs.Add($arguments['extract-dir']) | Out-Null + } + + # Start a list of modules that have been run so we can skip ones that have already been run + $flags['modulesRan'] = New-Object System.Collections.Generic.HashSet[string] + + foreach ($tool in $arguments['tools']) { + # Create a copy of the base args to be modified for each tool + $toolInstallerArgs = [System.Collections.ArrayList]$installerArgs.Clone() + + # Check if there are extra things we need to do for this tool + if ($toolExtras.ContainsKey($tool)) { + foreach ($module in $toolExtras[$tool]['Modules']) { + # Modules return a list of arguments to be added to Pyinstaller, so we run the module, and append the arguments + Write-Host "Running module $module" + $moduleArguments = & $modules[$module]['install'] -Arguments $arguments -Flags $flags + $toolInstallerArgs.AddRange($moduleArguments) + + ($flags['modulesRan']).Add($module) | Out-Null + } + + # Install extra packages + foreach ($package in $toolExtras[$tool]['Packages']) { + pip install $package + } + } + + # Build the binary + pyinstaller $toolInstallerArgs "examples\$tool.py" + + $binaryPath = Join-Path -Path $targetDirectory -ChildPath "dist\$tool.exe" + + # If the system-wide flag was set, copy the binary to Program Files and add it to the PATH if not already added + if ($flags['system-wide']) { + Write-Host 'Copying binary to Program Files...' + New-Item -ItemType Directory -Path 'C:\Program Files\Impacket' -Force + Copy-Item -Path $binaryPath -Destination 'C:\Program Files\Impacket' + + $currentPath = [System.Environment]::GetEnvironmentVariable('Path', [System.EnvironmentVariableTarget]::Machine) + + if ($currentPath -notlike "*C:\Program Files\Impacket*") { + $newPath = $currentPath + ';' + 'C:\Program Files\Impacket' + + Write-Host "Adding $tool to PATH..." + [System.Environment]::SetEnvironmentVariable('Path', $newPath, [System.EnvironmentVariableTarget]::Machine) + } + else { + Write-Host 'Impacket is already in PATH.' + } + } + else { + # Otherwise just copy it to the output directory + Copy-Item -Path $binaryPath -Destination $arguments['output-dir'] + } + } + } + finally { + # Should run even if the installation failed + Write-Host 'Cleaning up...' + + # Start list of already cleaned up modules, same as above + $flags['modulesCleaned'] = New-Object System.Collections.Generic.HashSet[string] + + # Runs any module cleanup for tools + foreach ($tool in $arguments['tools']) { + if ($toolExtras.ContainsKey($tool)) { + $toolModules = $toolExtras[$tool]['Modules'] + + foreach ($module in $toolModules) { + Write-Host "Cleaning up module $module..." + & $modules[$module]['cleanup'] -Arguments $arguments -Flags $flags + + ($flags['modulesCleaned']).Add($module) | Out-Null + } + } + } + + # Deactivate the Python virtual environment and reset our working directory + deactivate + Set-Location -Path $startingDirectory + + # Remove our Python install + Remove-Python -TempDir $tempDir + + # Remove the temp dir if it still exists + if (Test-Path -Path $tempDir) { + Remove-Item -Path $tempDir -Recurse -Force + } + } +} + +function list-tools { + param ( + [Hashtable]$Arguments, + [Hashtable]$Flags + ) + + Write-Host 'Available tools:' + + foreach ($tool in $availableTools) { + Write-Host "$tool" + } + + Write-Host '' +} + +function Get-Python { + param ( + [string]$TempDir + ) + + $pythonVersion = '3.13.2' + $pythonUrl = "https://www.python.org/ftp/python/$pythonVersion/python-$pythonVersion-amd64.exe" + + # Check if Python is already installed, and if the version matches + $pythonOutput = python --version + if ($pythonOutput -eq "python $pythonVersion") { + return (Get-Command python).Source + } + + # Python needs to be downloaded, do that, and then return the path to the binary since we are not adding it to the PATH + Write-Host 'Downloading Python...' + + $ProgressPreference = 'SilentlyContinue' + $pythonDirectory = Join-Path -Path $TempDir -ChildPath 'python' + + if (Test-Path -Path $pythonDirectory) { + Remove-Item $pythonDirectory -Recurse -Force + } + + New-Item -Path $pythonDirectory -ItemType 'Directory' | Out-Null + $pythonInstallerPath = Join-Path -Path $pythonDirectory -ChildPath 'python-installer.exe' + + Invoke-WebRequest -Uri $pythonUrl -Outfile $pythonInstallerPath + Start-Process $pythonInstallerPath -ArgumentList '/quiet', "TargetDir=$($pythonDirectory -replace ' ', '` ')", 'Shortcuts=0', 'Include_doc=0', 'Include_launcher=0' -Wait -Verb RunAs + + $pythonBinary = Join-Path -Path $pythonDirectory -ChildPath 'python.exe' + return $pythonBinary +} + +function Remove-Python { + param ( + [string]$TempDir + ) + + $pythonDirectory = Join-Path -Path $TempDir -ChildPath 'python' + $pythonInstallerPath = Join-Path -Path $pythonDirectory -ChildPath 'python-installer.exe' + + # Check if the Python installer is still around, if so, uninstall, this should only happen if we did not find an existing install + if (Test-Path $pythonInstallerPath) { + Start-Process $pythonInstallerPath -ArgumentList '/quiet', 'uninstall' -Wait -Verb RunAs + } +} + +# !!! Everything below this point does not need to be changed !!! + +function Get-FlatArguments { + param ( + [string]$CommandName + ) + + $flatArguments = @{} + + if ($commands[$commandName].ContainsKey('Arguments')) { + foreach ($argument in $commands[$commandName]['Arguments'].GetEnumerator()) { + if ($argument.Value.ContainsKey('Group') -and $argument.Value['Group']) { + $group = $argument.Value + if ($group.ContainsKey('Arguments')) { + foreach ($groupArgument in $group['Arguments'].GetEnumerator()) { + $flatArguments[$groupArgument.Key] = $groupArgument.Value + } + } + } + else { + $flatArguments[$argument.Key] = $argument.Value + } + } + } + + return $flatArguments +} + +function Show-Argument { + param ( + [System.Collections.DictionaryEntry]$Argument, + [int]$Padding + ) + + $argumentOutputString = " --$("$($argument.Key) <$($argument.Value['Type'])>".PadRight($padding)) $($argument.Value['Description'])" + if ($argument.Value.ContainsKey('Default')) { + if ($argument.Value['Default'] -is [System.Management.Automation.ScriptBlock]) { + if ($argument.Value.ContainsKey('DefaultDescription')) { + $argumentOutputString = $argumentOutputString + " (default: $($argument.Value['DefaultDescription']))" + } + else { + $argumentOutputString = $argumentOutputString + " (default: )" + } + } + else { + $argumentOutputString = $argumentOutputString + " (default: $($argument.Value['Default']))" + } + } + + Write-Host $argumentOutputString +} + +function Show-HelpMenu { + param ( + [Parameter(Mandatory = $False)] + [string]$SelectedCommand + ) + + Write-Host "=== $scriptTitle ===" + Write-Host $scriptDesc + Write-Host "Version: $version" + Write-Host '' + Write-Host "Usage: $scriptFileName [COMMAND] [ARGUMENTS] [FLAGS]" + Write-Host '' + + $helpMenuCommandPadding = 0 + $helpMenuArgsAndFlagsPadding = 0 + + foreach ($commandName in $commands.Keys) { + if ($commandName.Length -gt $helpMenuCommandPadding) { + $helpMenuCommandPadding = $commandName.Length + } + + $flatArguments = Get-FlatArguments -CommandName $commandName + + foreach ($argument in $flatArguments.GetEnumerator()) { + $fullArgument = $argument.Key + if ($argument.Value.ContainsKey('Type')) { + $fullArgument = "$fullArgument <$($argument.Value['Type'])>" + } + + if ($fullArgument.Length -gt $helpMenuArgsAndFlagsPadding) { + $helpMenuArgsAndFlagsPadding = $fullArgument.Length + } + } + + foreach ($flagName in $commands[$commandName]['Flags'].Keys) { + if ($flagName.Length -gt $helpMenuArgsAndFlagsPadding) { + $helpMenuArgsAndFlagsPadding = $flagName.Length + } + } + } + + $helpMenuCommandPadding += 2 + $helpMenuArgsAndFlagsPadding += 2 + + if (-not $selectedCommand) { + Write-Host '[COMMANDS]' + } + + $sortedCommands = $commands.GetEnumerator() | Sort-Object { $_.Value['Order'] } + foreach ($command in $sortedCommands) { + + if ($selectedCommand -and ($selectedCommand -ne ($command.Key))) { + continue + } + + Write-Host " $($command.Key.PadRight($helpMenuCommandPadding)) $($command.Value['Description'])" + Write-Host '' + + if ($command.Value.ContainsKey('Arguments')) { + Write-Host ' [ARGUMENTS]' + + $arguments = $command.Value['Arguments'] + $sortedArguments = $arguments.GetEnumerator() | Sort-Object { $_.Value['Order'] } + + $lastItemWasGroup = $false + + foreach ($argument in $sortedArguments) { + if ($argument.Value.ContainsKey('Group') -and $argument.Value['Group']) { + $lastItemWasGroup = $true + Write-Host '' + + $group = $argument.Value + + if ($group.ContainsKey('Arguments')) { + $groupTitleString = " {$($argument.Key)}" + if ($group.ContainsKey('Required') -and $group['Required']) { + $groupTitleString += ' (Required)' + } + if ($group.ContainsKey('Exclusive') -and $group['Exclusive']) { + $groupTitleString += ' (Exclusive)' + } + Write-Host $groupTitleString + + $groupArguments = $group['Arguments'].GetEnumerator() | Sort-Object { $_.Value['Order'] } + foreach ($groupArgument in $groupArguments) { + Show-Argument -Argument $groupArgument -Padding $helpMenuArgsAndFlagsPadding + } + } + } + else { + if ($lastItemWasGroup) { + Write-Host '' + } + Show-Argument -Argument $argument -Padding $helpMenuArgsAndFlagsPadding + 2 + } + } + Write-Host '' + } + + if ($command.Value.ContainsKey('Flags')) { + Write-Host ' [FLAGS]' + $flags = $command.Value['Flags'].GetEnumerator() | Sort-Object { $_.Value['Order'] } + foreach ($flagName in $flags.Key) { + $flagValue = $command.Value['Flags'][$flagName] + Write-Host " -$($flagName.PadRight($helpMenuArgsAndFlagsPadding + 1)) $($flagValue['Description'])" + } + Write-Host '' + } + } + Write-Host '' +} + +if ($Args.Count -eq 0 -or $Args[0] -eq '-h' -or $Args[0] -eq '--help') { + Show-HelpMenu + exit 0 +} + +if (-not $commands.ContainsKey($Args[0])) { + throw 'Invalid command selected (Use -h or --help for help)' +} + +$selectedCommand = $null +$flattenedCommandArguments = $null +$selectedArguments = @{} +$selectedFlags = @{} + +for ($i = 0; $i -lt $Args.Count; $i++) { + if ($i -eq 0) { + $selectedCommand = $Args[0] + $flattenedCommandArguments = Get-FlatArguments -CommandName $Args[0] + } + elseif ($Args -contains '-h' -or $Args -contains '--help') { + if ($selectedCommand) { + Show-HelpMenu -SelectedCommand $selectedCommand + } + else { + Show-HelpMenu + } + exit 0 + } + elseif ($Args[$i].StartsWith('--')) { + $arg = $Args[$i].Substring(2) + $argParts = $arg -split '=' + $keyword = $argParts[0] + $value = $null + + if (-not $flattenedCommandArguments.ContainsKey($keyword)) { + throw 'Invalid argument (Use -h or --help for help)' + } + + if ($argParts.Count -eq 2) { + $value = $argParts[1] + } + elseif ($argParts.Count -gt 2 -or $argParts -lt 1) { + throw 'Malformed argument (Use -h or --help for help)' + } + + if (-not $value) { + $i++ + $value = $Args[$i] + } + + if (-not $value) { + throw "No value provided for argument `"$keyword`" (Use -h or --help for help)" + } + + $argumentTypeString = $flattenedCommandArguments[$keyword]['Type'] + + $targetType = [System.Object] + $parser = { param([System.Object]$Value) return $value } + + if ($flattenedCommandArguments[$keyword].ContainsKey('CustomType')) { + if ($flattenedCommandArguments[$keyword].ContainsKey('ReturnType')) { + $targetType = $flattenedCommandArguments[$keyword]['CustomType']['ReturnType'] + } + + $parser = $flattenedCommandArguments[$keyword]['CustomType']['Parser'] + } + else { + switch ($argumentTypeString) { + 'STRING' { + $targetType = [string] + $parser = { param([System.Object]$Value) return $value -as [string] } + } + 'NUMBER' { + $targetType = [int32] + $parser = { param([System.Object]$Value) return $value -as [int32] } + } + 'BOOLEAN' { + $targetType = [bool] + $parser = { param([System.Object]$Value) return $value -as [bool] } + } + 'PATH' { + $targetType = [string] + $parser = { + param( + [System.Object]$Value + ) + + if ((-not ($value -match '\\')) -and (-not ($value -match '/'))) { + $value = Join-Path -Path (Get-Location) -ChildPath $value + } + + $parentDir = Split-Path -Path $value -Parent + + if ((-not $parentDir) -or ($parentDir -and (Test-Path -Path $parentDir))) { + return (Resolve-Path -Path $value).Path -as [string] + } + } + } + } + } + + $targetArrayType = $targetType.MakeArrayType() + $shouldBeList = $flattenedCommandArguments[$keyword].ContainsKey('List') -and $flattenedCommandArguments[$keyword]['List'] + + $parsedValue = $null + + if ($value -is [System.Object[]]) { + if (-not $shouldBeList) { + throw "Argument value for `"$keyword`" cannot be a list (Use -h or --help for help)" + } + + for ($j = 0; $j -lt $value.Length; $j++) { + $parsedListItem = & $parser -Value $value[$j] + if ($null -ne $parsedListItem) { + $value[$j] = $parsedListItem + } + else { + throw "Argument value `"$($value[$j])`" is not a valid $($argumentTypeString.ToLower()) (Use -h or --help for help)" + } + } + + $parsedValue = $value -as $targetArrayType + } + else { + if ($shouldBeList) { + $parsedItem = & $parser -Value $value + if ($null -ne $parsedItem) { + $parsedValue = @($parsedItem) -as $targetArrayType + } + else { + throw "Argument value `"$value`" is not a valid $($argumentTypeString.ToLower()) (Use -h or --help for help)" + } + } + else { + $parsedValue = & $parser -Value $value + } + } + + if ($null -eq $parsedValue) { + if ($shouldBeList) { + throw "Argument value `"$value`" for `"$keyword`" is not a valid $($argumentTypeString.ToLower()) list (Use -h or --help for help)" + } + else { + throw "Argument value `"$value`" for `"$keyword`" is not a valid $($argumentTypeString.ToLower()) (Use -h or --help for help)" + } + } + + $selectedArguments[$keyword] = $parsedValue + } + elseif ($Args[$i].StartsWith('-')) { + $flag = $Args[$i].Substring(1) + if (-not $commands[$selectedCommand]['Flags'].ContainsKey($flag)) { + throw 'Invalid flag (Use -h or --help for help)' + } + + $selectedFlags[$flag] = $True + } + else { + throw 'Invalid input (Use -h or --help for help)' + } +} + +foreach ($flagName in $commands[$selectedCommand]['Flags'].Keys) { + if (-not $selectedFlags.ContainsKey($flagName)) { + $selectedFlags[$flagName] = $False + } +} + +$defaultArguments = @{} +foreach ($argument in $flattenedCommandArguments.GetEnumerator()) { + if ($argument.Value.ContainsKey('Default')) { + if ($argument.Value['Default'] -is [System.Management.Automation.ScriptBlock]) { + $defaultArguments[$argument.Key] = & $argument.Value['Default'] -Arguments $selectedArguments -Flags $selectedFlags + } + else { + $defaultArguments[$argument.Key] = $argument.Value['Default'] + } + } +} + +foreach ($defaultArgument in $defaultArguments.GetEnumerator()) { + if (-not $selectedArguments.ContainsKey($defaultArgument.Key)) { + $selectedArguments[$defaultArgument.Key] = $defaultArgument.Value + } +} + +foreach ($argument in $flattenedCommandArguments.GetEnumerator()) { + if ($argument.Value.ContainsKey('Group') -and $argument.Value['Group']) { + $group = $argument.Value + + if ($group.ContainsKey('Required')) { + if ($group['Required'] -is [bool]) { + $required = $false + if ($group.ContainsKey('Required') -and $group['Required']) { + $required = $true + } + + $exclusive = $false + if ($group.ContainsKey('Exclusive') -and $group['Exclusive']) { + $exclusive = $true + } + + if ($group.ContainsKey('Arguments')) { + $numberOfArgumentsSelected = 0 + foreach ($groupArgument in $group['Arguments'].GetEnumerator()) { + $selectedArguments + if ($selectedArguments.ContainsKey($groupArgument.Key)) { + $numberOfArgumentsSelected++ + } + } + + if (($numberOfArgumentsSelected -eq 0) -and $required) { + throw "Missing required argument for required group `"$($argument.Key)`" (Use -h or --help for help)" + } + + if (($numberOfArgumentsSelected -gt 1) -and $exclusive) { + throw "Multiple arguments specified for exclusive group `"$($argument.Key)`" (Use -h or --help for help)" + } + } + } + elseif ($group['Required'] -is [System.Management.Automation.ScriptBlock]) { + if (-not (& $group['Required'] -Arguments $selectedArguments -Flags $selectedFlags)) { + if ($group.ContainsKey('RequiredDescription')) { + throw "Group `"$($argument.Key)`" did not meet the requirements: $($group['RequiredDescription'])" + } + else { + throw "Group `"$($argument.Key)`" did not meet the requirements, no description was provided." + } + } + } + } + } + else { + if ($argument.Value.ContainsKey('Required')) { + if ($argument.Value['Required'] -is [bool] -and $argument.Value['Required'] -and (-not $selectedArguments.ContainsKey($argument.Key))) { + throw "Missing required argument `"$($argument.Key)`" (Use -h or --help for help)" + } + + if ($argument.Value['Required'] -is [System.Management.Automation.ScriptBlock]) { + if (-not (& $argument.Value['Required'] -Arguments $selectedArguments -Flags $selectedFlags)) { + if ($argument.Value.ContainsKey('RequiredDescription')) { + throw "Argument `"$($argument.Key)`" did not meet the requirements: $($argument.Value['RequiredDescription'])" + } + else { + throw "Argument `"$($argument.Key)`" did not meet the requirements, no description was provided." + } + } + } + } + } +} + +& (Get-Command $selectedCommand) -Arguments $selectedArguments -Flags $selectedFlags \ No newline at end of file diff --git a/installer-modules/Npcap.ps1 b/installer-modules/Npcap.ps1 deleted file mode 100644 index e1dc0bcdb3..0000000000 --- a/installer-modules/Npcap.ps1 +++ /dev/null @@ -1,38 +0,0 @@ -function Main { - $TempPath = $Env:TEMP - - $InstalledNpcap = $false - - Write-Host 'Downloading Npcap...' - $NpcapInstaller = Join-Path -Path $TempPath -ChildPath "npcap.exe" - Invoke-WebRequest -Uri 'https://npcap.com/dist/npcap-1.80.exe' -OutFile $NpcapInstaller - - # Check if Npcap is already installed - if (Test-Path 'HKLM:\SYSTEM\CurrentControlSet\Services\npcap') { - Write-Host 'Found existing Npcap installation. Skipping install...' - } - else { - Start-Process $NpcapInstaller -Wait - $InstalledNpcap = $true - } - - $NpcapSDKArchive = Join-Path -Path $TempPath -ChildPath "npcapSDK.zip" - $NpcapSDKFolder = Join-Path -Path $TempPath -ChildPath "npcapSDK" - - Invoke-WebRequest -Uri 'https://npcap.com/dist/npcap-sdk-1.13.zip' -OutFile $NpcapSDKArchive - Expand-Archive -Path $NpcapSDKArchive -DestinationPath $NpcapSDKFolder -Force - Remove-Item $NpcapSDKArchive - - $env:INCLUDE = "$NpcapSDKArchive\Include" - $env:LIB = "$NpcapSDKArchive\Lib\x64" - - $env:InstalledNPcap = $InstalledNpcap - - return @('--add-binary', "$NpcapInstaller;.") -} - -function Cleanup { - if ($env:InstalledNPcap -eq "True") { - Start-Process 'C:\Program Files\Npcap\Uninstall.exe' -Wait - } -} \ No newline at end of file diff --git a/installer-modules/ntlmrelayx.ps1 b/installer-modules/ntlmrelayx.ps1 deleted file mode 100644 index cd9719917f..0000000000 --- a/installer-modules/ntlmrelayx.ps1 +++ /dev/null @@ -1,5 +0,0 @@ -function Main { - return @('--exclude-module', 'tkinter', '--collect-all', 'impacket.examples.ntlmrelayx') -} - -function Cleanup {} \ No newline at end of file From 696bfc9e6e85b2305847b33335391da009238781 Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Tue, 25 Feb 2025 18:23:13 -0500 Subject: [PATCH 29/30] Update Documentation --- README.md | 41 +++++++++++------------------------------ 1 file changed, 11 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 8850e81a2a..433033212b 100644 --- a/README.md +++ b/README.md @@ -1,45 +1,26 @@ -Impacket-exe +Impacket ======== -To build a tool into an executable: -> You may have to disable Windows AV - -EITHER +Windows Branch +----------------------- -Use the installer: +This branch contains modifications to make impacket examples work on Windows as +well as adding a helpful installer to build examples into standalone binaries. -> Download `impacket-exe-installer.ps1`: +**To build a tool into an executable:** +> You may have to disable Windows AV -Run the install script as administrator in Powershell +Download `impacket-installer.ps1` and run the script as administrator in Powershell. ``` Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process -impacket-exe-installer.ps1 +impacket-exe-installer.ps1 --help ``` -OR - -* Download & install python (Check "Add Python to PATH" during install) -* Download this repository -* Open a terminal as administrator and navigate to this repository -* Run the following commands -``` -py -m venv .venv -.venv\Scripts\activate -pip install -r requirements.txt -pip install -r example-requirements\[your tool].txt -py setup.py install -(Run any necessary modules found in 'installer-modules') -pyinstaller --onefile examples\[your tool].py -``` - -The built executable will be located inside the `dist` folder - > Use Ctrl+Pause/Break to exit scripts. -(Original Readme) -Impacket -======== +Original README +--- [![Latest Version](https://img.shields.io/pypi/v/impacket.svg)](https://pypi.python.org/pypi/impacket/) [![Build and test Impacket](https://github.com/fortra/impacket/actions/workflows/build_and_test.yml/badge.svg)](https://github.com/fortra/impacket/actions/workflows/build_and_test.yml) From c84f3b1441acaeb523f54d90806f123786bf7133 Mon Sep 17 00:00:00 2001 From: p0rtL6 Date: Tue, 25 Feb 2025 19:10:53 -0500 Subject: [PATCH 30/30] remove pyinstaller from requirements --- requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b0a0f7843d..dff4a2f436 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,4 +9,3 @@ ldap3>=2.5,!=2.5.2,!=2.5.0,!=2.6 ldapdomaindump>=0.9.0 flask>=1.0 pyreadline3;sys_platform == 'win32' -pyinstaller