├── .gitignore ├── CIS-Controls ├── CIS-Controls.ps1 └── README.md ├── README.md └── emotet-trickbot-finder ├── README.md └── emotet-trickbot-finder.ps1 /.gitignore: -------------------------------------------------------------------------------- 1 | ### macOS ### 2 | *.DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | 6 | # Icon must end with two \r 7 | Icon 8 | 9 | # Thumbnails 10 | ._* 11 | 12 | # Files that might appear in the root of a volume 13 | .DocumentRevisions-V100 14 | .fseventsd 15 | .Spotlight-V100 16 | .TemporaryItems 17 | .Trashes 18 | .VolumeIcon.icns 19 | .com.apple.timemachine.donotpresent 20 | 21 | # Directories potentially created on remote AFP share 22 | .AppleDB 23 | .AppleDesktop 24 | Network Trash Folder 25 | Temporary Items 26 | .apdisk 27 | -------------------------------------------------------------------------------- /CIS-Controls/CIS-Controls.ps1: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020 Huntress Labs, Inc. 2 | # All rights reserved. 3 | # 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are met: 6 | # * Redistributions of source code must retain the above copyright 7 | # notice, this list of conditions and the following disclaimer. 8 | # * Redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution. 11 | # * Neither the name of the Huntress Labs nor the names of its contributors 12 | # may be used to endorse or promote products derived from this software 13 | # without specific prior written permission. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | # DISCLAIMED. IN NO EVENT SHALL HUNTRESS LABS BE LIABLE FOR ANY DIRECT, INDIRECT, 19 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 21 | # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 22 | # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24 | # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | # This script will enable various controls from the CIS Top 20. 27 | 28 | $ScriptVersion = "2020 September 17; beta 1" 29 | 30 | # Find poorly written code faster with the most stringent setting. 31 | Set-StrictMode -Version Latest 32 | 33 | # log file for troubleshooting 34 | $DebugLog = Join-Path $Env:TMP CIS_Controls.log 35 | 36 | function Get-TimeStamp { 37 | return "[{0:yyyy/MM/dd} {0:HH:mm:ss}]" -f (Get-Date) 38 | } 39 | 40 | function LogMessage ($msg) { 41 | Add-Content $DebugLog "$(Get-TimeStamp) $msg" 42 | Write-Host "$(Get-TimeStamp) $msg" 43 | } 44 | 45 | function SetDWordValue ($regKey, $regValue, $valueData) { 46 | if ( !(New-ItemProperty -Path $regKey -Name $regValue -Value $valueData -PropertyType DWORD -Force) ) 47 | { 48 | LogMessage($error[0]) 49 | } 50 | } 51 | 52 | ## Main 53 | LogMessage "Log written to '$DebugLog'" 54 | LogMessage "Script version: '$ScriptVersion'" 55 | 56 | ############################################################################## 57 | ## 6.1 - Network - Detect - Activate Audit Logging 58 | LogMessage "Enabling logon/logoff event auditing" 59 | Auditpol /set /category:"Account Logon" /Success:enable /Failure:enable 60 | Auditpol /set /category:"Logon/Logoff" /Success:enable /Failure:enable 61 | 62 | ############################################################################## 63 | ## 8.6 - Devices - Protect - Configure Devices to Not Auto-Run Content 64 | # Disable removable media autorun 65 | # https://support.microsoft.com/en-us/help/967715/how-to-disable-the-autorun-functionality-in-windows 66 | LogMessage "Disabling removable media autorun" 67 | $PoliciesExplorerKey = "HKLM:Software\Microsoft\Windows\CurrentVersion\Policies\Explorer" 68 | SetDWordValue $PoliciesExplorerKey "NoDriveTypeAutorun" 0xFF 69 | 70 | ############################################################################## 71 | ## 8.8 - Devices - Detect - Enable Command-Line Audit Logging 72 | # Log the content of all PowserShell script blocks. 73 | # https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_logging_windows?view=powershell-7 74 | # LogMessage "Enabling PowerShell script block logging" 75 | # $ScriptBlockLoggingKey = "HKLM:Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" 76 | # if ( ! (Test-Path $ScriptBlockLoggingKey) ) 77 | # { 78 | # New-Item -Path "HKLM:Software\Policies\Microsoft\Windows\PowerShell" -Name "ScriptBlockLogging" 79 | # } 80 | # SetDWordValue $ScriptBlockLoggingKey "EnableScriptBlockLogging" 1 81 | # SetDWordValue $ScriptBlockLoggingKey "EnableScriptBlockInvocationLogging" 1 82 | 83 | # Command line audit processing 84 | # https://docs.microsoft.com/en-us/windows-server/identity/ad-ds/manage/component-updates/command-line-process-auditing 85 | LogMessage "Enabling command line audit processing" 86 | $AuditKey = "HKLM:Software\Microsoft\Windows\CurrentVersion\Policies\System\Audit" 87 | SetDWordValue $AuditKey "ProcessCreationIncludeCmdLine_Enabled" 1 88 | 89 | ############################################################################## 90 | ## 16: Account Monitoring and Control 91 | # https://support.microsoft.com/en-us/help/2871997/microsoft-security-advisory-update-to-improve-credentials-protection-a 92 | # Clear any credentials of logged off users after delay 93 | # $LsaKey = "HKLM:SYSTEM\CurrentControlSet\Control\Lsa" 94 | # SetDWordValue $LsaKey "TokenLeakDetectDelaySecs" 30 95 | 96 | # Prevent WDigest credentials from being stored in memory 97 | # LogMessage "Preventing WDigest credentials from being stored in memory" 98 | # $WDigestKey = "HKLM:SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest" 99 | # SetDWordValue $WDigestKey "UseLogonCredential" 0 100 | -------------------------------------------------------------------------------- /CIS-Controls/README.md: -------------------------------------------------------------------------------- 1 | This PowerShell script will enable settings related to the 20 CIS controls. It was intended for environments with an RMM tool which can be used to run the script. 2 | 3 | See https://www.cisecurity.org/controls/cis-controls-list/ for details. 4 | 5 | This is considered beta and is provided as is. 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # free-tools -------------------------------------------------------------------------------- /emotet-trickbot-finder/README.md: -------------------------------------------------------------------------------- 1 | ## PowerShell script for finding and removing Emotet and Trickbot footholds 2 | 3 | This [PowerShell script](https://raw.githubusercontent.com/huntresslabs/free-tools/master/emotet-trickbot-finder/emotet-trickbot-finder.ps1) is designed to identify (and optionally remove) common Emotet and Trickbot footholds (services, scheduled tasks, etc.). The script can be modified to include new footholds you may encounter. 4 | 5 | _Many thanks to the Bytes Computer & Network Solutions team, this script is based on their work._ 6 | 7 | **The script is unsupported and is provided as-is.** 8 | 9 | ### Notes 10 | * The script must be run with **administrative privileges**. 11 | * By default, the script will only display the services, tasks, and files it finds. There is no output if it finds nothing. 12 | * The script uses `schtasks.exe` to get a list of scheduled tasks. If the Task Scheduler service is not running, `schtasks.exe` will diplay `ERROR: The network address is invalid.` 13 | 14 | ### Usage 15 | 16 | ``` 17 | C:\> powershell -executionpolicy bypass -f c:\users\user\downloads\emotet_trickbot_finder.ps1 18 | [*] Looking for process by name: mssvca 19 | [*] Process: mssvca.exe (mssvca) - c:\windows\mssvca.exe 20 | 21 | Name Used (GB) Free (GB) Provider Root CurrentLocation 22 | ---- --------- --------- -------- ---- --------------- 23 | HKU Registry HKEY_USERS 24 | [*] Found registry value: mttvca 25 | [*] Service: 12345678 (12345678) - c:\12345678.exe 26 | [*] Service: yxyxzeea (NewService1) - c:\NewService1.bat 27 | [*] Task: msnEtcs - c:\task2.bat 28 | [*] Task: msntcs - c:\task1.bat 29 | ``` 30 | 31 | Run with the **remove** argument to have the script remove the services/tasks/files. 32 | 33 | ``` 34 | C:\> powershell -executionpolicy bypass -f c:\users\user\downloads\emotet_trickbot_finder.ps1 remove 35 | [*] Looking for process by name: mssvca 36 | [*] Process: mssvca.exe (mssvca) - c:\windows\mssvca.exe 37 | VERBOSE: Performing operation "Stop-Process" on Target "mssvca (3320)". 38 | [!] Removing c:\windows\mssvca.exe... 39 | VERBOSE: Performing operation "Remove File" on Target "C:\windows\mssvca.exe". 40 | 41 | Name Used (GB) Free (GB) Provider Root CurrentLocation 42 | ---- --------- --------- -------- ---- --------------- 43 | HKU Registry HKEY_USERS 44 | [*] Found registry value: mttvca 45 | [!] Removing registry value: mttvca 46 | VERBOSE: Performing operation "Remove Property" on Target "Item: 47 | HKEY_USERS\S-1-5-18\software\Microsoft\Windows\CurrentVersion\Run Property: mttvca". 48 | [*] Attempting to terminate process based on file path: 'c:\stsvc.exe'... 49 | VERBOSE: Performing operation "Stop-Process" on Target "stsvc (892)". 50 | [!] Removing c:\stsvc.exe... 51 | VERBOSE: Performing operation "Remove File" on Target "C:\stsvc.exe". 52 | [*] Service: 12345678 (12345678) - c:\12345678.exe 53 | VERBOSE: Performing operation "Stop-Service" on Target "12345678 (12345678)". 54 | [*] Attempting to terminate process based on file path: 'c:\12345678.exe'... 55 | VERBOSE: Performing operation "Stop-Process" on Target "12345678 (3884)". 56 | [!] Removing c:\12345678.exe... 57 | VERBOSE: Performing operation "Remove File" on Target "C:\12345678.exe". 58 | [!] Deleting service: 12345678 59 | [SC] DeleteService SUCCESS 60 | [*] Service: yxyxzeea (NewService1) - c:\NewService1.bat 61 | VERBOSE: Performing operation "Stop-Service" on Target "NewService1 (yxyxzeea)". 62 | [*] Attempting to terminate process based on file path: 'c:\NewService1.bat'... 63 | [!] Removing c:\NewService1.bat... 64 | VERBOSE: Performing operation "Remove File" on Target "C:\NewService1.bat". 65 | [!] Deleting service: yxyxzeea 66 | [SC] DeleteService SUCCESS 67 | [*] Task: msnEtcs - c:\task2.bat 68 | [*] Attempting to terminate process based on file path: 'c:\task2.bat'... 69 | [!] Removing c:\task2.bat... 70 | VERBOSE: Performing operation "Remove File" on Target "C:\task2.bat". 71 | [!] Deleting scheduled task: msnEtcs 72 | SUCCESS: The scheduled task "msnEtcs" was successfully deleted. 73 | [*] Task: msntcs - c:\task1.bat 74 | [*] Attempting to terminate process based on file path: 'c:\task1.bat'... 75 | [!] Removing c:\task1.bat... 76 | VERBOSE: Performing operation "Remove File" on Target "C:\task1.bat". 77 | [!] Deleting scheduled task: msntcs 78 | SUCCESS: The scheduled task "msntcs" was successfully deleted. 79 | ``` 80 | -------------------------------------------------------------------------------- /emotet-trickbot-finder/emotet-trickbot-finder.ps1: -------------------------------------------------------------------------------- 1 | # Powershell script to remove Emotet and Trickbot services and scheduled 2 | # tasks. 3 | 4 | # If you have an active Emotet/Trickbot infection, you'll want to stop 5 | # the spread before running this script. 6 | 7 | # This script is based on the work of the Bytes Computer & Network Solutions team. 8 | 9 | # This is free and unencumbered software released into the public domain. 10 | 11 | # Anyone is free to copy, modify, publish, use, compile, sell, or 12 | # distribute this software, either in source code form or as a compiled 13 | # binary, for any purpose, commercial or non-commercial, and by any 14 | # means. 15 | 16 | # In jurisdictions that recognize copyright laws, the author or authors 17 | # of this software dedicate any and all copyright interest in the 18 | # software to the public domain. We make this dedication for the benefit 19 | # of the public at large and to the detriment of our heirs and 20 | # successors. We intend this dedication to be an overt act of 21 | # relinquishment in perpetuity of all present and future rights to this 22 | # software under copyright law. 23 | 24 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 27 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 28 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 29 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 30 | # OTHER DEALINGS IN THE SOFTWARE. 31 | 32 | # For more information, please refer to 33 | 34 | # By default, the script will display the service and tasks it finds. 35 | # Run with the "remove" argument to remove the services/tasks/files. 36 | 37 | # C:\Users\admin> powershell -executionpolicy bypass -f emotet_trickbot_finder.ps1 38 | # Service: 12345678 (12345678) - c:\12345678.bat 39 | # Service: yxyxzeea (NewService1) - c:\NewService1.bat 40 | # Task: msnEtcs - c:\task2.bat 41 | # Task: msntcs - c:\task1.bat 42 | 43 | # C:\Users\admin> powershell -executionpolicy bypass -f emotet_trickbot_finder.ps1 remove 44 | # Service: 12345678 (12345678) - c:\12345678.bat 45 | # VERBOSE: Performing operation "Stop-Service" on Target "12345678 (12345678)". 46 | # Attempting to stop c:\12345678.bat... 47 | # Removing c:\12345678.bat... 48 | # VERBOSE: Performing operation "Remove File" on Target "C:\12345678.bat". 49 | # [SC] DeleteService SUCCESS 50 | # ... 51 | # Task: msntcs - c:\task1.bat 52 | # Removing c:\task1.bat... 53 | # VERBOSE: Performing operation "Remove File" on Target "C:\task1.bat". 54 | # SUCCESS: The scheduled task "msntcs" was successfully deleted. 55 | 56 | # command line argument for removing the services/tasks/files 57 | Param([String]$remove) 58 | 59 | # simplistic versioning 60 | $revisionDate = '21 September 2019' 61 | 62 | ############################################################################## 63 | ## Add known Emotet/Trickbot files, services, scheduled tasks, etc. below 64 | 65 | # Known Trickbot file names to remove 66 | $filesToRemove = @( 67 | 'c:\stsvc.exe', 68 | 'c:\mswvc.exe', 69 | 'c:\mtwvc.exe', 70 | 'c:\smver.exe', 71 | 'c:\wines.exe' 72 | ) 73 | 74 | # Run Key values to remove, string matching 75 | $valueNameMatches = @( 76 | 'mttvca' 77 | ) 78 | 79 | # services to remove, initialize array 80 | $badServices = @() 81 | 82 | # Add Emotet numbered services 83 | $badServices += Get-Service | ? { $_.name -match '^[0-9]{6,20}$' } 84 | 85 | # Add Trickbot services, match the display name 86 | $badServices += Get-Service | ? { $_.DisplayName -match '^AdvanceMService' } 87 | $badServices += Get-Service | ? { $_.DisplayName -match '^ControlServiceW' } 88 | $badServices += Get-Service | ? { $_.DisplayName -match '^ControlServiceWall' } 89 | $badServices += Get-Service | ? { $_.DisplayName -match '^ControlSysWallService' } 90 | $badServices += Get-Service | ? { $_.DisplayName -match '^NControlService' } 91 | $badServices += Get-Service | ? { $_.DisplayName -match '^NewService' } 92 | $badServices += Get-Service | ? { $_.DisplayName -match '^NService' } 93 | $badServices += Get-Service | ? { $_.DisplayName -match '^Service-Log' } 94 | $badServices += Get-Service | ? { $_.DisplayName -match '^ServiceTechnoMS' } 95 | $badServices += Get-Service | ? { $_.DisplayName -match '^SystemVsService' } 96 | $badServices += Get-Service | ? { $_.DisplayName -match '^TopVsSystemService' } 97 | $badServices += Get-Service | ? { $_.DisplayName -match '^VsTechniceService' } 98 | $badServices += Get-Service | ? { $_.DisplayName -match '^ControlServiceXQ' } 99 | $badServices += Get-Service | ? { $_.DisplayName -match '^ControlServiceXc' } 100 | $badServices += Get-Service | ? { $_.DisplayName -match '^ControlSystemXQService' } 101 | $badServices += Get-Service | ? { $_.DisplayName -match '^QeControlService' } 102 | 103 | # processes to terminate, initialize array 104 | $badProcesses = @() 105 | 106 | # add known Emotet/Trickbot processes 107 | $badProcesses += Get-Process | ? { $_.Path -match '\\mttvca\.exe' } 108 | $badProcesses += Get-Process | ? { $_.Path -match '\\mssvca\.exe' } 109 | $badProcesses += Get-Process | ? { $_.Path -match '\\mswvc\.exe' } 110 | $badProcesses += Get-Process | ? { $_.Path -match '\\mtwvc\.exe' } 111 | 112 | # Trickbot scheduled task names regex 113 | $badTasks = 'msnetcs|msntcs|sysnetsf|MsSystemWatcher|netsys|WinDotNet|CleanMemoryWinTask|DefragWinSysTask|WinNetworkTask|ApplicationNetwork|Ms Dll libraries|Ms Cloud Lan|iCloud Free Disk' 114 | 115 | ############################################################################## 116 | ## helper functions 117 | 118 | function deleteFile ($file) { 119 | # only delete files 120 | if (Test-Path -PathType Leaf $file) { 121 | Write-Output "[!] Removing file '$file'..." 122 | Remove-Item $file -Force -Confirm:$false -Verbose -ErrorAction SilentlyContinue 123 | } 124 | } 125 | 126 | # terminate the process associated with the specified file 127 | function terminateProcess ($file) { 128 | if (($file -ne $null) -and (Test-Path -PathType Leaf $file)) { 129 | Write-Output "[*] Attempting to terminate process based on file path: '$file'..." 130 | Get-Process | ? { $_.Path -eq $file } | Stop-Process -Force -Confirm:$false -Verbose 131 | } 132 | } 133 | 134 | function removeRegistryValues() { 135 | New-PSDrive -PSProvider Registry -Name HKU -Root HKEY_USERS 136 | foreach ($v in $valueNameMatches) { 137 | $value = (Get-item HKU:\S-1-5-18\software\microsoft\windows\currentversion\run).property | ? { $_ -match $v } 138 | if ($value -ne $null) { 139 | Write-Output "[*] Found registry value: $value" 140 | if ($remove -eq "remove") { 141 | Write-Output "[!] Removing registry value: $value" 142 | Remove-ItemProperty HKU:\S-1-5-18\software\Microsoft\Windows\CurrentVersion\Run -Name $value -Verbose -Force -Confirm:$false 143 | } 144 | } 145 | } 146 | } 147 | 148 | function removeFiles(){ 149 | foreach ($f in $filesToRemove) { 150 | if ($remove -eq "remove") { 151 | terminateProcess $f 152 | deleteFile $f 153 | } 154 | } 155 | } 156 | 157 | function removeServices() { 158 | foreach ($bSvc in $badServices) { 159 | if ($bSvc -eq $null) { continue } 160 | 161 | # get Win32_Service object matching on the service name 162 | $svcWmiObj = gwmi Win32_Service | ? { $_.name -eq $bSvc.name } 163 | 164 | if ($svcWmiObj -ne $null ) { 165 | $svcPath = $svcWmiObj | select -expand pathname -ErrorAction SilentlyContinue 166 | # $svcPath = $($svcWmiObj.PathName) 167 | 168 | Write-Output "[*] Service: $($bSvc.Name) ($($bSvc.DisplayName)) - file: '$svcPath'" 169 | 170 | if ($remove -eq "remove") { 171 | $bSvc | Stop-Service -Force -Verbose -ErrorAction SilentlyContinue 172 | Start-Sleep 1 173 | 174 | if ($svcPath -ne $null) { 175 | terminateProcess $svcPath 176 | 177 | Start-Sleep -Seconds 2 178 | 179 | deleteFile $svcPath 180 | remove-variable svcPath 181 | } 182 | 183 | Write-Output "[!] Deleting service: $($bSvc.Name)" 184 | cmd.exe /C sc.exe delete $bSvc.name 185 | } # end "remove" 186 | 187 | remove-variable svcWmiObj 188 | } 189 | } # end foreach 190 | } 191 | 192 | function removeTasks() { 193 | $AllSchedTasks = schtasks.exe /QUERY /V /FO CSV | ConvertFrom-CSV | ? { $_.TaskName -match $badTasks } 194 | foreach ($stask in $AllSchedTasks) { 195 | if ($stask -eq $null) { continue } 196 | 197 | $binToDel = $stask.'Task To Run'.Trim() 198 | 199 | Write-Output "[*] Task: $($stask.taskname.split('\')[-1]) - $binToDel" 200 | 201 | if ($remove -eq "remove") { 202 | if ($binToDel -ne $null) { 203 | terminateProcess $binToDel 204 | 205 | deleteFile $binToDel 206 | } 207 | 208 | Write-Output "[!] Deleting scheduled task: $($stask.taskname.split('\')[-1])" 209 | schtasks.exe /DELETE /TN $stask.taskname.split('\')[-1] /F 210 | } 211 | } 212 | } 213 | 214 | function removeProcesses() { 215 | foreach($bProc in $badProcesses) { 216 | if ($bProc -eq $null) { continue } 217 | 218 | Write-Output "[*] Looking for process by name: $($bProc.ProcessName)" 219 | 220 | # get Win32_Process object matching on the process name 221 | $procWmiObj = gwmi Win32_Process | ? { $_.Name -match $bProc.ProcessName } 222 | if ($procWmiObj -ne $null ) { 223 | Write-Output "[*] Process: $($procWmiObj.Name) ($($bProc.ProcessName)) - $($procWmiObj.ExecutablePath)" 224 | 225 | if ($remove -eq "remove") { 226 | $bProc | Stop-Process -Force -Verbose -ErrorAction SilentlyContinue 227 | Start-Sleep 1 228 | 229 | if ($procWmiObj.ExecutablePath -ne $null) { 230 | deleteFile $procWmiObj.ExecutablePath 231 | } 232 | 233 | remove-variable procWmiObj 234 | } 235 | } 236 | } 237 | } 238 | 239 | ############################################################################## 240 | ## MAIN 241 | 242 | Write-Output "Hostname: $env:computername" 243 | Write-Output "Script revision: $revisionDate" 244 | 245 | removeProcesses 246 | removeRegistryValues 247 | removeFiles 248 | removeServices 249 | removeTasks 250 | Write-Output "Done!" 251 | --------------------------------------------------------------------------------