diff --git a/BadUSB-Detect-and-Protect/main.ps1 b/BadUSB-Detect-and-Protect/main.ps1 index 68c7d9b..d39edd0 100644 --- a/BadUSB-Detect-and-Protect/main.ps1 +++ b/BadUSB-Detect-and-Protect/main.ps1 @@ -6,17 +6,36 @@ When a new USB device is connected to the machine this script monitors keypresse If there are 13 or more keypresses detected within 200 milliseconds it will pause all input for 10 seconds and attempt to disable the most recently connected USB device USAGE -1. Run the script and follow instructions +1. Edit Options below (optional) and Run the script 2. A pop up will appear when monitoring is active and if a 'BadUSB' device is detected 3. logs are found in 'usblogs' folder in the temp directory. +4. Re-enable any devices with the Re-enable option below. +5. Close the monitor in the system tray REQUIREMENTS -Admin privlages are required for removing any suspected devices (you can re-enable devices too) +Admin privlages are required for removing any suspected devices #> -Add-Type -AssemblyName System.Drawing +# Hide the console after monitor starts +$hidden = 'y' + +# Enable all devices +$enable = 'n' + +# Disable Detected Devices +$DisableOnDetect = 'n' + +$Host.UI.RawUI.BackgroundColor = "Black" +Clear-Host +[Console]::SetWindowSize(80, 35) +[Console]::Title = "BadUSB Detection Setup" + Add-Type -AssemblyName System.Windows.Forms +Add-Type -AssemblyName System.Drawing +Add-Type -AssemblyName Microsoft.VisualBasic +[System.Windows.Forms.Application]::EnableVisualStyles() + Write-Host "Checking User Permissions.." -ForegroundColor DarkGray If (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]'Administrator')) { Write-Host "Admin privileges needed for this script..." -ForegroundColor Red @@ -29,39 +48,27 @@ else{ Write-Host "This script is running as Admin!" -ForegroundColor Green New-Item -ItemType Directory -Path "$env:TEMP\usblogs\" cls - $enable = Read-Host "Re-enable All Devices? [y/n] " - $hidden = Read-Host "Hide This Window [y/n] " - $DisableOnDetect = Read-Host "Disable detected devices (input will still be blocked) [y/n] " } - -If ($hidden -eq 'y'){ - Write-Host "Hiding the Window.." -ForegroundColor Red - sleep 1 - $Async = '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);' - $Type = Add-Type -MemberDefinition $Async -name Win32ShowWindowAsync -namespace Win32Functions -PassThru - $hwnd = (Get-Process -PID $pid).MainWindowHandle - if($hwnd -ne [System.IntPtr]::Zero){ - $Type::ShowWindowAsync($hwnd, 0) - } - else{ - $Host.UI.RawUI.WindowTitle = 'hideme' - $Proc = (Get-Process | Where-Object { $_.MainWindowTitle -eq 'hideme' }) - $hwnd = $Proc.MainWindowHandle - $Type::ShowWindowAsync($hwnd, 0) +Function HideConsole{ + If ($hidden -eq 'y'){ + Write-Host "Hiding the Window.." -ForegroundColor Red + sleep 1 + $Async = '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);' + $Type = Add-Type -MemberDefinition $Async -name Win32ShowWindowAsync -namespace Win32Functions -PassThru + $hwnd = (Get-Process -PID $pid).MainWindowHandle + if($hwnd -ne [System.IntPtr]::Zero){ + $Type::ShowWindowAsync($hwnd, 0) + } + else{ + $Host.UI.RawUI.WindowTitle = 'hideme' + $Proc = (Get-Process | Where-Object { $_.MainWindowTitle -eq 'hideme' }) + $hwnd = $Proc.MainWindowHandle + $Type::ShowWindowAsync($hwnd, 0) + } } } -$usbDevices = Get-WmiObject -Query "SELECT * FROM Win32_PnPEntity WHERE PNPDeviceID LIKE 'USB%'" -$currentUSBDevices = @() -$newUSBDevices = @() -foreach ($device in $usbDevices) { - $deviceID = $device.DeviceID - $newUSBDevices += $deviceID -} -$currentUSBDevices = $newUSBDevices - - function EnableDevices { param ( [string[]]$deviceIDs @@ -97,16 +104,28 @@ if ($enable -eq 'y'){ else{ "" | Out-File -FilePath "$env:TEMP\usblogs\ids.log" "" | Out-File -FilePath "$env:TEMP\usblogs\monon.log" - Write-Host "Monitoring for devices.." -ForegroundColor Green sleep 1 } +$DeviceMonitor = { -$monitor = { - -Add-Type -AssemblyName System.Drawing -Add-Type -AssemblyName System.Windows.Forms - + Add-Type -AssemblyName System.Windows.Forms + Add-Type -AssemblyName System.Drawing + + $usbDevices = Get-WmiObject -Query "SELECT * FROM Win32_PnPEntity WHERE PNPDeviceID LIKE 'USB%'" + $currentUSBDevices = @() + $newUSBDevices = @() + foreach ($device in $usbDevices) { + $deviceID = $device.DeviceID + $newUSBDevices += $deviceID + } + $currentUSBDevices = $newUSBDevices + + $monitor = { + + Add-Type -AssemblyName System.Drawing + Add-Type -AssemblyName System.Windows.Forms + $API = @' [DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true)] public static extern short GetAsyncKeyState(int virtualKeyCode); @@ -117,118 +136,171 @@ public static extern int MapVirtualKey(uint uCode, int uMapType); [DllImport("user32.dll", CharSet=CharSet.Auto)] public static extern int ToUnicode(uint wVirtKey, uint wScanCode, byte[] lpkeystate, System.Text.StringBuilder pwszBuff, int cchBuff, uint wFlags); '@ -$API = Add-Type -MemberDefinition $API -Name 'Win32' -Namespace API -PassThru - - -$balloon = { -Add-Type -AssemblyName System.Drawing -Add-Type -AssemblyName System.Windows.Forms -$notify = New-Object System.Windows.Forms.NotifyIcon -$notify.Icon = [System.Drawing.SystemIcons]::Warning -$notify.Visible = $true -$balloonTipTitle = "WARNING" -$balloonTipText = "Bad USB Device Intercepted!" -$notify.ShowBalloonTip(30000, $balloonTipTitle, $balloonTipText, [System.Windows.Forms.ToolTipIcon]::WARNING) -} - -$pausejob = { -$s='[DllImport("user32.dll")][return: MarshalAs(UnmanagedType.Bool)]public static extern bool BlockInput(bool fBlockIt);' -Add-Type -MemberDefinition $s -Name U -Namespace W -[W.U]::BlockInput($true) -sleep 10 -[W.U]::BlockInput($false) -} - -function DisableDevices { - param ([string[]]$deviceIDs) - foreach ($deviceID in $deviceIDs) { - try { - "Attempting to disable device with ID: $deviceID" | Out-File -FilePath "$env:TEMP\usblogs\log.log" -Append - $pnpDevice = Get-PnpDevice -InstanceId $deviceID -ErrorAction Stop - if ($pnpDevice.Status -eq 'OK') { - Disable-PnpDevice -InstanceId $deviceID -Confirm:$false -ErrorAction Stop - "Successfully disabled device with ID: $deviceID" | Out-File -FilePath "$env:TEMP\usblogs\log.log" -Append - } else { - "Device with ID: $deviceID is not in an 'OK' state and cannot be disabled." | Out-File -FilePath "$env:TEMP\usblogs\log.log" -Append - } - } catch { - "Error disabling device with ID: $deviceID. $_" | Out-File -FilePath "$env:TEMP\usblogs\log.log" -Append + $API = Add-Type -MemberDefinition $API -Name 'Win32' -Namespace API -PassThru + + $balloon = { + Add-Type -AssemblyName System.Drawing + Add-Type -AssemblyName System.Windows.Forms + $notify = New-Object System.Windows.Forms.NotifyIcon + $notify.Icon = [System.Drawing.SystemIcons]::Warning + $notify.Visible = $true + $balloonTipTitle = "WARNING" + $balloonTipText = "Bad USB Device Intercepted!" + $notify.ShowBalloonTip(30000, $balloonTipTitle, $balloonTipText, [System.Windows.Forms.ToolTipIcon]::WARNING) } - } -} - -function MonitorKeys { - $startTime = $null - $keypressCount = 0 - $initTime = Get-Date - while ($MonitorTime -lt $initTime.AddSeconds(30)) { - $stopjob = Get-Content "$env:TEMP\usblogs\monon.log" - if ($stopjob -eq 'true'){"killed monitoring for: $deviceID" | Out-File -FilePath "$env:TEMP\usblogs\log.log" -Append ;exit} - $MonitorTime = Get-Date - Start-Sleep -Milliseconds 10 - for ($i = 8; $i -lt 256; $i++) { - $keyState = $API::GetAsyncKeyState($i) - if ($keyState -eq -32767) { - if (-not $startTime) { - $startTime = Get-Date - } - $keypressCount++ - } - } - if ($startTime -and (New-TimeSpan -Start $startTime).TotalMilliseconds -ge 200) { - if ($keypressCount -gt 12) { - $script:newUSBDeviceIDs = Get-Content "$env:TEMP\usblogs\ids.log" - Start-Job -ScriptBlock $pausejob -Name PauseInput - Start-Job -ScriptBlock $balloon -Name BallonIcon - if ($DisableOnDetect -eq 'y'){ - DisableDevices -deviceIDs $script:newUSBDeviceIDs + + $pausejob = { + $s='[DllImport("user32.dll")][return: MarshalAs(UnmanagedType.Bool)]public static extern bool BlockInput(bool fBlockIt);' + Add-Type -MemberDefinition $s -Name U -Namespace W + [W.U]::BlockInput($true) + sleep 10 + [W.U]::BlockInput($false) + } + + function DisableDevices { + param ([string[]]$deviceIDs) + foreach ($deviceID in $deviceIDs) { + try { + "Attempting to disable device with ID: $deviceID" | Out-File -FilePath "$env:TEMP\usblogs\log.log" -Append + $pnpDevice = Get-PnpDevice -InstanceId $deviceID -ErrorAction Stop + if ($pnpDevice.Status -eq 'OK') { + Disable-PnpDevice -InstanceId $deviceID -Confirm:$false -ErrorAction Stop + "Successfully disabled device with ID: $deviceID" | Out-File -FilePath "$env:TEMP\usblogs\log.log" -Append + } else { + "Device with ID: $deviceID is not in an 'OK' state and cannot be disabled." | Out-File -FilePath "$env:TEMP\usblogs\log.log" -Append + } + } catch { + "Error disabling device with ID: $deviceID. $_" | Out-File -FilePath "$env:TEMP\usblogs\log.log" -Append } } + } + + function MonitorKeys { $startTime = $null - $keypressCount = 0 - } - } -} -MonitorKeys -} - -function CheckNew { - $usbDevices = Get-WmiObject -Query "SELECT * FROM Win32_PnPEntity WHERE PNPDeviceID LIKE 'USB%'" - $newUSBDevices = @() - $newUSBDeviceIDs = @() - foreach ($device in $usbDevices) { - $deviceID = $device.DeviceID - $newUSBDevices += $deviceID - if ($currentUSBDevices -notcontains $deviceID) { - Write-Host "New USB device added: $($device.Name) ID: $($deviceID)" - $script:match = $true - $newUSBDeviceIDs += $deviceID -split "," | Out-File -FilePath "$env:TEMP\usblogs\ids.log" -Append + $keypressCount = 0 + $initTime = Get-Date + while ($MonitorTime -lt $initTime.AddSeconds(30)) { + $stopjob = Get-Content "$env:TEMP\usblogs\monon.log" + if ($stopjob -eq 'true'){"killed monitoring for: $deviceID" | Out-File -FilePath "$env:TEMP\usblogs\log.log" -Append ;exit} + $MonitorTime = Get-Date + Start-Sleep -Milliseconds 10 + for ($i = 8; $i -lt 256; $i++) { + $keyState = $API::GetAsyncKeyState($i) + if ($keyState -eq -32767) { + if (-not $startTime) { + $startTime = Get-Date + } + $keypressCount++ + } + } + if ($startTime -and (New-TimeSpan -Start $startTime).TotalMilliseconds -ge 200) { + if ($keypressCount -gt 12) { + $script:newUSBDeviceIDs = Get-Content "$env:TEMP\usblogs\ids.log" + Start-Job -ScriptBlock $pausejob -Name PauseInput + Start-Job -ScriptBlock $balloon -Name BallonIcon + if ($DisableOnDetect -eq 'y'){ + DisableDevices -deviceIDs $script:newUSBDeviceIDs + } + } + $startTime = $null + $keypressCount = 0 + } + } } + MonitorKeys } - $global:currentUSBDevices = $newUSBDevices - $global:newUSBDeviceIDs = $newUSBDeviceIDs -} - -$notify = New-Object System.Windows.Forms.NotifyIcon -$notify.Icon = [System.Drawing.SystemIcons]::Shield -$notify.Visible = $true -$balloonTipTitle = "USB Monitoring" -$balloonTipText = "BadUSB Monitoring Active.." -$notify.ShowBalloonTip(30000, $balloonTipTitle, $balloonTipText, [System.Windows.Forms.ToolTipIcon]::Info) - -while ($true) { - - CheckNew - if ($match){ - Write-Host "Monitoring Keys" - $jobon = Get-Job -Name Monitor - if ($jobon){ - "true" | Out-File -FilePath "$env:TEMP\usblogs\monon.log" - sleep -Milliseconds 500 + + function CheckNew { + $usbDevices = Get-WmiObject -Query "SELECT * FROM Win32_PnPEntity WHERE PNPDeviceID LIKE 'USB%'" + $newUSBDevices = @() + $newUSBDeviceIDs = @() + foreach ($device in $usbDevices) { + $deviceID = $device.DeviceID + $newUSBDevices += $deviceID + if ($currentUSBDevices -notcontains $deviceID) { + Write-Host "New USB device added: $($device.Name) ID: $($deviceID)" + $script:match = $true + $newUSBDeviceIDs += $deviceID -split "," | Out-File -FilePath "$env:TEMP\usblogs\ids.log" -Append + } } - $script:match = $false - "false" | Out-File -FilePath "$env:TEMP\usblogs\monon.log" - Start-Job -ScriptBlock $monitor -Name Monitor + $global:currentUSBDevices = $newUSBDevices + $global:newUSBDeviceIDs = $newUSBDeviceIDs } - sleep -Milliseconds 500 + + $notify = New-Object System.Windows.Forms.NotifyIcon + $notify.Icon = [System.Drawing.SystemIcons]::Shield + $notify.Visible = $true + $balloonTipTitle = "USB Monitoring" + $balloonTipText = "BadUSB Monitoring Active.." + $notify.ShowBalloonTip(3000, $balloonTipTitle, $balloonTipText, [System.Windows.Forms.ToolTipIcon]::Info) + + while ($true) { + CheckNew + $global:CurrentStatus = 'Waiting For Devices' + if ($match){ + Write-Host "Monitoring Keys" + $global:CurrentStatus = 'Monitoring Inputs..' + $jobon = Get-Job -Name Monitor + if ($jobon){ + "true" | Out-File -FilePath "$env:TEMP\usblogs\monon.log" + sleep -Milliseconds 500 + } + $script:match = $false + "false" | Out-File -FilePath "$env:TEMP\usblogs\monon.log" + Start-Job -ScriptBlock $monitor -Name Monitor + } + sleep -Milliseconds 500 + } + } + +cls +Write-Host "Monitor Started!" -ForegroundColor Green +sleep 1 +Write-Host "Setting Window To Background.." +Write-Host " +=================================================== +**YOU CAN CLOSE THE MONITOR FROM THE SYSTEM TRAY** +===================================================" -ForegroundColor Blue +sleep 2 +HideConsole +Start-Job -ScriptBlock $DeviceMonitor -Name DeviceMonitor + +$Systray_Tool_Icon = New-Object System.Windows.Forms.NotifyIcon +$Systray_Tool_Icon.Text = "BadUSB Monitor" +$Systray_Tool_Icon.Icon = [System.Drawing.SystemIcons]::Shield +$Systray_Tool_Icon.Visible = $true + +$contextmenu = New-Object System.Windows.Forms.ContextMenuStrip +$traytitle = $contextmenu.Items.Add("BadUSB Detection"); + +$Menu_Exit = $contextmenu.Items.Add("Close Monitor"); +$Menu_Exit_Picture =[System.Drawing.Icon]::ExtractAssociatedIcon("C:\Windows\System32\DFDWiz.exe") +$Menu_Exit.Image = $Menu_Exit_Picture + +$Systray_Tool_Icon.ContextMenuStrip = $contextmenu +$appContext = New-Object System.Windows.Forms.ApplicationContext + +$traytitle.add_Click({ + + Start-Process msedge.exe 'https://github.com/beigeworm' + +}) + +$Menu_Exit.add_Click({ + + $notify = New-Object System.Windows.Forms.NotifyIcon + $notify.Icon = [System.Drawing.SystemIcons]::Shield + $notify.Visible = $true + $balloonTipTitle = "USB Monitoring" + $balloonTipText = "BadUSB Monitor Stopped" + $notify.ShowBalloonTip(3000, $balloonTipTitle, $balloonTipText, [System.Windows.Forms.ToolTipIcon]::Error) + + Stop-Job -Name DeviceMonitor + $Systray_Tool_Icon.Visible = $false + $appContext.ExitThread() + exit + +}) + +[void][System.Windows.Forms.Application]::Run($appContext)