Last active
July 31, 2019 11:59
-
-
Save Darkbat91/66eecb8d24b256a0ade811da49f1bd7c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
Blocks USB devices from being used by registering a WMI event, Not entirely secure as base64 encoded secret is stored in WMI | |
Approved devices are by default stored in the root of the C drive should be moved to another directory or registry? | |
#> | |
function Get-Base64 { | |
param($string) | |
$Bytes = [System.Text.Encoding]::Unicode.GetBytes($string) | |
$EncodedText = [Convert]::ToBase64String($Bytes) | |
return $EncodedText | |
} | |
$encodedsecret = Get-Base64 -string "YOurSpecialOneTimeSharedSecret" | |
#Original USB from Xavier Mertens <[email protected]> | |
# Remove handler if already exists | |
Unregister-Event -SourceIdentifier RemovableDiskDetection | |
$query = "SELECT * FROM __InstanceOperationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_LogicalDisk' AND TargetInstance.DriveType=2" | |
Register-WmiEvent -Query $query -SourceIdentifier RemovableDiskDetection -Action { | |
#region OTP | |
# $SHAREDSECRET must be base64 encoded | |
$SHAREDSECRET = $encodedsecret | |
function New-Otp($SHAREDSECRET) { | |
#Base function borrowed from https://warroom.securestate.com/generating-time-based-one-time-passwords-powershell/ | |
$COUNTERCURSOR = 7 | |
$EPOCH = Get-Date -Year 1970 -Month 1 -Day 1 -Hour 0 -Minute 0 -Second 0 | |
$INTERVAL = 30 | |
$OTPLENGTH = 6 | |
#CB | |
# calculate seconds since epoch (UNIX time) | |
$span = New-TimeSpan -Start $EPOCH -End (Get-Date).ToUniversalTime() | |
$seconds = [math]::floor($span.TotalSeconds) | |
$counter = [math]::floor($seconds / $INTERVAL) | |
$counter = [Convert]::ToInt32($seconds / $INTERVAL) | |
# calculate the counter bytes | |
$counterBytes = New-Object Byte[] 8 | |
while (($counter -gt 0) -and ($COUNTERCURSOR -ge 0)) { | |
$counterBytes[$COUNTERCURSOR] = ($counter -band 0xff) | |
$counter = [math]::floor($counter / [math]::pow(2, 8)) | |
$COUNTERCURSOR -= 1 | |
} | |
# generate SHA1 HMAC from $counterBytes using $SHAREDSECRET as the key | |
$enc = [System.Text.Encoding]::UTF8 | |
$hmac = New-Object -TypeName System.Security.Cryptography.HMACSHA1 | |
$hmac.key = [System.Convert]::FromBase64String($SHAREDSECRET) | |
$randHash = $hmac.ComputeHash($counterBytes) | |
# create an OTP compatable with http://tools.ietf.org/html/rfc4226#section-5.3 | |
$offset = $randhash[19] -band 0xf | |
$fullOTP = ($randhash[$offset] -band 0x7f) * [math]::pow(2, 24) | |
$fullOTP += ($randHash[$offset + 1] -band 0xff) * [math]::pow(2, 16) | |
$fullOTP += ($randHash[$offset + 2] -band 0xff) * [math]::pow(2, 8) | |
$fullOTP += ($randHash[$offset + 3] -band 0xff) | |
$modNumber = [math]::pow(10, $OTPLENGTH) | |
$otp = $fullOTP % $modNumber | |
# zero pad to $OTPLENGTH digits | |
$otp = $otp.ToString("0" * $OTPLENGTH) | |
return $otp | |
} | |
function Test-OTP { | |
param([string]$enteredcode | |
) | |
if ($enteredcode -eq (New-Otp)) { | |
return $true | |
} | |
else { | |
return $false | |
} | |
} | |
function Get-OTP { | |
param([switch]$Attempt2) | |
$SCRIPT:return = $false | |
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") | |
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | |
$objForm = New-Object System.Windows.Forms.Form | |
$objForm.Text = "Provide Access Code" | |
$objForm.Size = New-Object System.Drawing.Size(300, 200) | |
$objForm.StartPosition = "CenterScreen" | |
$objForm.KeyPreview = $True | |
$objForm.Add_KeyDown( {if ($_.KeyCode -eq "Enter") | |
{$SCRIPT:return = Test-OTP $objTextBox.Text; $objForm.Close()}}) | |
$objForm.Add_KeyDown( {if ($_.KeyCode -eq "Escape") | |
{$objForm.Close()}}) | |
$OKButton = New-Object System.Windows.Forms.Button | |
$OKButton.Location = New-Object System.Drawing.Size(75, 120) | |
$OKButton.Size = New-Object System.Drawing.Size(75, 23) | |
$OKButton.Text = "OK" | |
$OKButton.Add_Click( {$SCRIPT:return = Test-OTP $objTextBox.Text; $objForm.Close()}) | |
$objForm.Controls.Add($OKButton) | |
$CancelButton = New-Object System.Windows.Forms.Button | |
$CancelButton.Location = New-Object System.Drawing.Size(150, 120) | |
$CancelButton.Size = New-Object System.Drawing.Size(75, 23) | |
$CancelButton.Text = "Cancel" | |
$CancelButton.Add_Click( {$objForm.Close()}) | |
$objForm.Controls.Add($CancelButton) | |
$objLabel = New-Object System.Windows.Forms.Label | |
$objLabel.Location = New-Object System.Drawing.Size(10, 20) | |
$objLabel.Size = New-Object System.Drawing.Size(280, 20) | |
$objLabel.Text = "Please enter acces Code provided by IT:" | |
if ($Attempt2.IsPresent) { | |
$objLabel.Text = "ERROR: Please Ask for next code:" | |
} | |
$objForm.Controls.Add($objLabel) | |
$objTextBox = New-Object System.Windows.Forms.TextBox | |
$objTextBox.Location = New-Object System.Drawing.Size(10, 40) | |
$objTextBox.Size = New-Object System.Drawing.Size(260, 20) | |
$objForm.Controls.Add($objTextBox) | |
$objForm.Topmost = $True | |
$objForm.Add_Shown( {$objForm.Activate()}) | |
[void] $objForm.ShowDialog() | |
return $SCRIPT:return | |
} | |
#endregion | |
$approveddevicelocation = "C:\ApprovedDevices.log" | |
$Approved = Get-Content $approveddevicelocation | |
$log = 'C:\USBMon.log' | |
$class = $eventArgs.NewEvent.__CLASS | |
$device = $eventArgs.NewEvent.TargetInstance.DeviceID | |
$serialNumber = $eventArgs.NewEvent.TargetInstance.VolumeSerialNumber | |
switch ($class) { | |
__InstanceCreationEvent { | |
#Add-Content -Value "Inserted, device id: $device " -Path $log | |
$ok = $false | |
if ($Approved -contains $serialNumber) { | |
$ok = $true | |
Add-Content -Value "Device $device Good inserted by $env:USERNAME SN: $serialNumber" -path $log | |
} | |
else { | |
Add-Content -Value "Device $device BAD inserted by $env:USERNAME SN: $serialNumber" -Path $log | |
} | |
# File not found | |
if (!$ok) { | |
$driveEject = New-Object -comObject Shell.Application | |
$driveEject.Namespace(17).ParseName($device).InvokeVerb("Eject") | |
Add-Content "The USB stick is considered NOT SAFE. REquesting passcode" -path $log | |
if (Get-OTP) { | |
Add-Content -Value $serialNumber -Path $approveddevicelocation | |
(new-object -ComObject wscript.shell).Popup("The USB stick is Allowed, please re-insert!", 0, "USB Monitor", 0x0) | |
} | |
elseif (Get-OTP -Attempt2) { | |
Add-Content -Value $serialNumber -Path $approveddevicelocation | |
(new-object -ComObject wscript.shell).Popup("The USB stick is Allowed, please re-insert!", 0, "USB Monitor", 0x0) | |
} | |
else { | |
(new-object -ComObject wscript.shell).Popup("The USB stick is considered NOT SAFE. Get authorization from IT Before insertion!", 0, "USB Monitor", 0x0) | |
} | |
} | |
} | |
__InstanceDeletionEvent { | |
Add-Content "Removed, device id: $device " -path $log | |
} | |
} | |
} | |
# |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment