├── Log4JDetection.ps1 └── README.md /Log4JDetection.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Log4j Vulnerability (CVE-2021-44228) file scanner [windows] :: build 8b/seagull 3 | Uses Florian Roth and Jai Minton's research (thank you!) 4 | RELEASED PUBLICLY for all MSPs, originally a Datto RMM ComStore Component. 5 | If you use code from this script, please credit Datto & seagull. 6 | 7 | User Variable Options: 8 | usrScanscope (1/2/3): just home drive / all fixed drives / all drives 9 | usrMitigate (Y/N/X): ternary option to enable/disable 2.10+ mitigation (or do nothing). https://twitter.com/CyberRaiju/status/1469505680138661890 10 | #> 11 | 12 | #########User variables######### 13 | ##Application Variable 14 | $env:usrScanScope = 2 15 | $env:usrMitigate = "Y" 16 | ##E-mail Variable 17 | $User = "Log4@email.com" 18 | $PWord = ConvertTo-SecureString -String "THEPASSWORD" -AsPlainText -Force 19 | $SendTo = "Poorsoul@InIT.com" 20 | $SMTPServer = "smtp.office365.com" 21 | ##Logging Location Variable 22 | $LogTo = "$env:PROGRAMDATA\log4j" 23 | ################################ 24 | 25 | 26 | 27 | #Update Scanning Definitions 28 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 29 | Add-Type -assembly "system.io.compression.filesystem" 30 | Invoke-WebRequest -Uri https://github.com/VirusTotal/yara/releases/download/v4.1.3/yara-v4.1.3-1755-win32.zip -OutFile .\yara32.zip 31 | Invoke-WebRequest -Uri https://github.com/VirusTotal/yara/releases/download/v4.1.3/yara-v4.1.3-1755-win64.zip -OutFile .\yara64.zip 32 | Invoke-WebRequest -Uri https://raw.githubusercontent.com/Neo23x0/signature-base/master/yara/expl_log4j_cve_2021_44228.yar -OutFile .\expl_log4j_cve_2021_44228.yar 33 | [io.compression.zipfile]::ExtractToDirectory("$PSScriptRoot\yara32.zip", "$PSScriptRoot\") 34 | [io.compression.zipfile]::ExtractToDirectory("$PSScriptRoot\yara64.zip", "$PSScriptRoot\") 35 | 36 | #Logging Setup 37 | If(!(test-path $LogTo)) 38 | { 39 | New-Item -ItemType Directory -Force -Path $LogTo 40 | } 41 | 42 | 43 | 44 | [string]$varch=[intPtr]::Size*8 45 | $script:varDetection=0 46 | $varEpoch=[int][double]::Parse((Get-Date -UFormat %s)) 47 | 48 | write-host "Log4j/Log4Shell CVE-2021-44228 Scanning/Mitigation Tool (seagull/Datto)" 49 | write-host "=======================================================================" 50 | if ($env:CS_CC_HOST) { 51 | write-host "Set up a File/Folder Size Monitor against devices" 52 | write-host "(File/s named $LogTo\L4Jdetections.txt : is over : 0MB)" 53 | write-host "to alert proactively if this Component reports signs of infection." 54 | write-host "=======================================================================" 55 | } 56 | 57 | #is there already a detections.txt file? 58 | if (test-path "$LogTo\L4Jdetections.txt" -ErrorAction SilentlyContinue) { 59 | write-host "- An existing L4JDetections.txt file was found. It has been renamed to:" 60 | write-host " $varEpoch-L4JDetections.txt" 61 | Rename-Item -Path "$LogTo\L4Jdetections.txt" "$LogTo\$varEpoch-L4Jdetections.txt" -Force 62 | } 63 | 64 | #did the user turn NOLOOKUPS (2.10+ mitigation) on? 65 | switch ($env:usrMitigate) { 66 | 'Y' { 67 | if ([System.Environment]::GetEnvironmentVariable('LOG4J_FORMAT_MSG_NO_LOOKUPS','machine') -eq 'true') { 68 | write-host "- Log4j 2.10+ exploit mitigation (LOG4J_FORMAT_MSG_NO_LOOKUPS) already set." 69 | } else { 70 | write-host "- Enabling Log4j 2.10+ exploit mitigation: Enable LOG4J_FORMAT_MSG_NO_LOOKUPS" 71 | [Environment]::SetEnvironmentVariable("LOG4J_FORMAT_MSG_NO_LOOKUPS","true","Machine") 72 | } 73 | } 'N' { 74 | write-host "- Reversing Log4j 2.10+ explot mitigation (enable LOG4J_FORMAT_MSG_NO_LOOKUPS)" 75 | write-host " (NOTE: This potentially makes a secure system vulnerable again! Use with caution!)" 76 | [Environment]::SetEnvironmentVariable("LOG4J_FORMAT_MSG_NO_LOOKUPS","false","Machine") 77 | } 'X' { 78 | write-host "- Not adjusting existing LOG4J_FORMAT_MSG_NO_LOOKUPS setting." 79 | } 80 | } 81 | 82 | #map input variable usrScanScope to an actual value 83 | switch ($env:usrScanScope) { 84 | 1 { 85 | write-host "- Scan scope: Home Drive" 86 | $script:varDrives=@($env:HomeDrive) 87 | } 2 { 88 | write-host "- Scan scope: Fixed & Removable Drives" 89 | $script:varDrives=Get-WmiObject -Class Win32_logicaldisk | ? {$_.DriveType -eq 2 -or $_.DriveType -eq 3} | ? {$_.FreeSpace} | % {$_.DeviceID} 90 | } 3 { 91 | write-host "- Scan scope: All drives, including Network" 92 | $script:varDrives=Get-WmiObject -Class Win32_logicaldisk | ? {$_.FreeSpace} | % {$_.DeviceID} 93 | } default { 94 | write-host "! ERROR: Unable to map scan scope variable to a value. (This should never happen!)" 95 | write-host " The acceptable values for env:usrScanScope are:" 96 | write-host " 1: Scan files on Home Drive" 97 | write-host " 2: Scan files on fixed and removable drives" 98 | write-host " 3: Scan files on all detected drives, even network drives" 99 | exit 1 100 | } 101 | } 102 | 103 | #if user opted to update yara rules, do that 104 | if ($env:usrUpdateDefs -match 'true') { 105 | [Net.ServicePointManager]::SecurityProtocol = [Enum]::ToObject([Net.SecurityProtocolType], 3072) 106 | $varYaraNew=(new-object System.Net.WebClient).DownloadString('https://github.com/Neo23x0/signature-base/raw/master/yara/expl_log4j_cve_2021_44228.yar') 107 | #quick verification check 108 | if ($varYaraNew -match 'TomcatBypass') { 109 | Set-Content -Value $varYaraNew -Path yara.yar -Force 110 | write-host "- New YARA definitions downloaded." 111 | } else { 112 | write-host "! ERROR: New YARA definition download failed." 113 | write-host " Falling back to built-in definitions." 114 | copy-item -Path expl_log4j_cve_2021_44228.yar -Destination yara.yar -Force 115 | } 116 | } else { 117 | copy-item -Path expl_log4j_cve_2021_44228.yar -Destination yara.yar -Force 118 | write-host "- Not downloading new YARA definitions." 119 | } 120 | 121 | #check yara32 and yara64 are there and that they'll run 122 | foreach ($iteration in ('yara32.exe','yara64.exe')) { 123 | if (!(test-path $iteration)) { 124 | write-host "! ERROR: $iteration not found. It needs to be in the same directory as the script." 125 | write-host " Download Yara from https://github.com/virustotal/yara/releases/latest and place them here." 126 | exit 1 127 | } else { 128 | write-host "- Verified presence of $iteration." 129 | } 130 | 131 | cmd /c "$iteration -v >nul 2>&1" 132 | if ($LASTEXITCODE -ne 0) { 133 | write-host "! ERROR: YARA was unable to run on this device." 134 | write-host " The Visual C++ Redistributable is required in order to use YARA." 135 | if ($env:CS_CC_HOST) { 136 | write-host " An installer Component is available from the ComStore." 137 | } 138 | exit 1 139 | } 140 | } 141 | 142 | #start a logfile 143 | $host.ui.WriteErrorLine("`r`nPlease expect some permissions errors as some locations are forbidden from traversal.`r`n=====================================================`r`n") 144 | set-content -Path "log.txt" -Force -Value "Files scanned:" 145 | Add-Content "log.txt" -Value "=====================================================" 146 | Add-Content "log.txt" -Value " :: Scan Started: $(get-date) ::" 147 | 148 | 149 | #get a list of all files-of-interest on the device (depending on scope) :: GCI is broken; permissions errors when traversing root dirs cause aborts (!!!) 150 | $arrFiles=@() 151 | foreach ($drive in $varDrives) { 152 | gci "$drive\" -force | ? {$_.PSIsContainer} | % { 153 | gci -path "$drive\$_\" -rec -force -include *.jar,*.log,*.txt -ErrorAction 0 | % { 154 | $arrFiles+=$_.FullName 155 | } 156 | } 157 | } 158 | 159 | #scan i: JARs containing vulnerable Log4j code 160 | write-host "=====================================================" 161 | write-host "- Scanning for JAR files containing potentially insecure Log4j code..." 162 | $arrFiles | ? {$_ -match '\.jar$'} | % { 163 | if (select-string -Quiet -Path $_ "JndiLookup.class") { 164 | write-host "! ALERT: Potentially vulnerable file at $($_)!" 165 | if (!(test-path "$LogTo\L4Jdetections.txt" -ErrorAction SilentlyContinue)) {set-content -path "$LogTo\L4Jdetections.txt" -Value "! CAUTION !`r`n$(get-date)"} 166 | Add-Content "$LogTo\L4Jdetections.txt" -Value "POTENTIALLY VULNERABLE JAR: $($_)" 167 | $script:varDetection=1 168 | } 169 | } 170 | 171 | #scan ii: YARA for logfiles & JARs 172 | write-host "=====================================================" 173 | write-host "- Scanning LOGs, TXTs and JARs for common attack strings via YARA scan......" 174 | foreach ($file in $arrFiles) { 175 | if ($file -match 'log4j' -or $file -match 'L4Jdetections\.txt') { 176 | #do nothing -- this isn't a security threat; we're looking at the pathname of the log, not the contents 177 | } else { 178 | #add it to the logfile, with a pause for handling 179 | try { 180 | Add-Content "log.txt" -Value $file -ErrorAction Stop 181 | } catch { 182 | Start-Sleep -Seconds 1 183 | Add-Content "log.txt" -Value $file -ErrorAction SilentlyContinue 184 | } 185 | 186 | #scan it 187 | clear-variable yaResult -ErrorAction SilentlyContinue 188 | $yaResult=cmd /c "yara$varch.exe `"yara.yar`" `"$file`" -s" 189 | if ($yaResult) { 190 | #sound an alarm 191 | write-host "=====================================================" 192 | $script:varDetection=1 193 | write-host "! DETECTION:" 194 | write-host $yaResult 195 | #write to a file 196 | if (!(test-path "$LogTo\L4Jdetections.txt" -ErrorAction SilentlyContinue)) {set-content -path "$LogTo\L4Jdetections.txt" -Value "! INFECTION DETECTION !`r`n$(get-date)"} 197 | Add-Content "$LogTo\L4Jdetections.txt" -Value $yaResult 198 | } 199 | } 200 | } 201 | 202 | Add-Content "log.txt" -Value " :: Scan Finished: $(get-date) ::" 203 | 204 | #Output of Positive or Negative results 205 | 206 | if ($script:varDetection -eq 1) { 207 | #Positive Results 208 | write-host "=====================================================" 209 | write-host "! Evidence of one or more Log4Shell attack attempts has been found on the system." 210 | write-host " The location of the files demonstrating this are noted in the following log:" 211 | write-host " $LogTo\L4Jdetections.txt" 212 | 213 | # Emailthe Log file 214 | $credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, $PWord 215 | $servername = Get-WmiObject -Class Win32_ComputerSystem | select -ExpandProperty "Name" 216 | $serverdomain = Get-WmiObject -Class Win32_ComputerSystem | select -ExpandProperty "Domain" 217 | Send-MailMessage -To $SendTo -From $User -Subject "Server $servername Domin $serverdomain" -Body "The $servername has L4J Detections on the $serverdomain domain" -Credential $credential -SmtpServer $SMTPServer -Port 587 -UseSsl -Attachments $LogTo\L4Jdetections.txt 218 | 219 | 220 | } else { 221 | #Negative Results 222 | write-host "- There is no indication that this system has received Log4Shell attack attempts ." 223 | $credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, $PWord 224 | $servername = Get-WmiObject -Class Win32_ComputerSystem | select -ExpandProperty "Name" 225 | $serverdomain = Get-WmiObject -Class Win32_ComputerSystem | select -ExpandProperty "Domain" 226 | Send-MailMessage -To $SendTo -From $User -Subject "Server $servername Domin $serverdomain" -Body "The $servername has no detections for the Log4J threat on the $serverdomain domain" -Credential $credential -SmtpServer $SMTPServer -Port 587 -UseSsl 227 | } 228 | 229 | write-host `r 230 | write-host "Datto recommends that you follow best practices with your systems by implementing WAF rules," 231 | write-host "mitigation and remediation recommendations from your vendors. For more information on Datto's" 232 | write-host "response to the log4j vulnerabilty, please refer to https://www.datto.com/blog/dattos-response-to-log4shell." 233 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Log4Shell-Automated 2 | This is an automated script to scan for Log4J vulnerabilities. This is based off of the Datto script. 3 | 4 | The Datto script is here: https://github.com/datto/log4shell-tool 5 | 6 | I have simply made the script automated where you only need to run the powershell script itself. It does the heavy lifting. You can also have each server email you if it finds anything. 7 | 8 | All the user variables are at the top. The email portion is setup to use AppPassword however should you want to use the secure application model you can do so. Though you need to do your own leg work. 9 | --------------------------------------------------------------------------------