diff --git a/Vulnerability - CVE-2021-44228 (Log4j)/get-log4jrcevulnerability.ps1 b/Vulnerability - CVE-2021-44228 (Log4j)/get-log4jrcevulnerability.ps1
index 98cb001..aaa9bb8 100644
--- a/Vulnerability - CVE-2021-44228 (Log4j)/get-log4jrcevulnerability.ps1
+++ b/Vulnerability - CVE-2021-44228 (Log4j)/get-log4jrcevulnerability.ps1
@@ -1,58 +1,108 @@
<#
Name: get-log4jrcevulnerability.ps1
-Version: 0.1.7.2 (14th December 2021)
+Version: 0.2.4.1 (21st December 2021)
Author: Prejay Shah (Doherty Associates)
-Thanks: Christopher Bledsoe (IPM Computers)
-Purpose: Detection of jar files vulnerable to log4j RCE vulnerability (CVE-2021-44228)
-Utilizing JNDILookup detection method posted to https://gist.github.com/Neo23x0/e4c8b03ff8cdf1fa63b7d15db6e3860b with some slight modifications to make it more RMM friendly
-
-NOTE: Have excluded files within windows\system32\spool\drivers from being scanned due to access denied issues disrupting the output.
+Thanks: Christopher Bledsoe (IPM Computers) for some bugfixes,
+ Robby Swartenbroekx (b-Inside) for some ideas,
+ Arctic Wolf for coming up with a way to detect patched files
+Purpose: Detection of jar files vulnerable to the "Log4Shell" log4j RCE vulnerability (CVE-2021-44228)
+Originally Utilizing JNDILookup detection method posted to https://gist.github.com/Neo23x0/e4c8b03ff8cdf1fa63b7d15db6e3860b with some slight modifications to make it more RMM friendly
+Log4J 2.15 fixed the original Log4Shell CVE, but was suspectable to CVE-2021-44228 which was elevated to an RCE vulnerability and fixed in Log4J 2.16
+I then adopted a method presented to me on behalf of ArcticWolf (https://github.com/rtkwlf/wolf-tools/blob/main/log4shell/log4shell_deep_scan.ps1) of extracting the JAR/WAR/EAR file to corroborate whether the Log4J 2.16 changes have been applied to a JAR file.
+Robby S then suggested an amendment to be able to track the updated fix in 2.17 for CVE-2021-45105 that was introduced in Log4J 2.16.
+NOTE: Only scans against NTFS File Format
+ RMM Output optimized for N-Central
+ Not currently compatible with Powershell 2.0
+ Have excluded files within windows\system32\spool\drivers from being scanned due to access denied issues disrupting the output.
0.1 Initial Release
-0.1.1 Adeed Dedupe to Vulnerable .JAR Listings
+0.1.1 Added Dedupe to Vulnerable .JAR Listings
0.1.2 Public Release
0.1.3 Found that use of -force isn't working for all scans. Have added a non forced mode to see what outputs can be obtained
0.1.4 Experimenting with Unicode/Robocopy to bypass 260 character file path limit / access denied errors
-0.1.5 added support for pseverything module
+0.1.5 added support for PSEverything module
0.1.5.1 changed detection to be module based rather than command based
0.1.5.2 Cleaned up Output
0.1.6 Have revamped order to PSEverything, Robocopy, GCI
0.1.6.1 Fixed Typo, Modification for N-Central AMP Output of file names when robocopy is utilized
-0.1.7 Some bugfixes courtesy of Christopher Bledsoe (IPM Computers). Who knew cinaccessible cloud only JAR files would be a thing?
+0.1.7 Some bugfixes courtesy of Christopher Bledsoe (IPM Computers). Who knew inaccessible cloud only JAR files would be an issue?
won't try checking an empty file path
should ignore those "placeholder.jar" files in things like dropbox cache
it uses "|" for the delimiter when reading the CSV/txt file created, so any file paths with "," in them should not get unintentionally split
0.1.7.1 Excluding spool\drivers jar files from being scanned
0.1.7.2 Updated gci to use -filter and -file rather than -include after finding it to be much more performant
+0.1.8 Fix for Everything/gci compatibility, Update for Log4j 2.16 update
+0.1.8.1 Improved Try/Catch methodology for when Everything search Fails. Thanks to Robby Swartenbroekx (b-Inside) for the assist.
+0.1.8.2 Made robocopy window hidden by request
+0.1.8.3 Improved Vulnerable File Output for RMM
+0.1.9 Expanded Search Criteria to all fixed drives on a device, and added update for Log4j 2.17 Compatibility (Thx to Robby S)
+0.2 Separated detection of Log4j 2.16 Patched and 2.17 Patched States
+0.2.1 Adding better output for when Everything fails to scan via RMM PS wrapping
+0.2.2 Expanded search to cover .jar/.war/.ear files, and partial fix for oddity with scanning certain file names (Thx to Robby S)
+0.2.3 Adding more error logging to RMM output in order to surface files that aren't being scanned, amended query to exclude drives that aren't formatted to NTFS
+0.2.4 Moved Tasks into Functions, Fixed output bug for number counts.
+0.2.4.1 Changed robocopy export/csv import encoding to fix issue with display of special characters in file names
#>
-$Version = "0.1.7.2" # 14th December 2021
-Write-Host "get-log4jrcevulnerability $version" -foregroundcolor Green
+$Version = "0.2.4.1" # 21st December 2021
+Write-Host "`nget-log4jrcevulnerability $version" -foregroundcolor Green
$robocopycsv = $null
+$log4junscanned = $null
+$log4jvulnerablefiles = $null
+$robocopycsvfile = "$env:temp\log4jfilescan.csv"
-if (get-module -listavailable | where-object {$_.name -like 'PSEverything'}) {
- Write-Host "The almighty PSEverything module's Search-Everything command was found.`nDoing a new scan because we can..." -ForegroundColor Yellow
- $log4jfiles = $null
- $log4jfilescan = $null
- $Timetaken = (measure-command {$log4jfilescan = search-everything -global -extension jar}).totalseconds
- Write-host "See? That only took $timetaken seconds to scan the entire C: Drive for .jar files!" -foregroundcolor Green
- $log4jfilenames = $log4jfilescan
-}
-else {
+#region functions
+Function Scan-Files {
+ try {
+ if (get-module -listavailable | where-object {$_.name -like 'PSEverything'}) {
+ Write-Host "The almighty PSEverything module's Search-Everything command was found.`nDoing a new scan because we can..." -ForegroundColor Yellow
+ $log4jfiles = $null
+ $log4jfilescan = $null
+ $StopWatch = [system.diagnostics.stopwatch]::startNew()
+ $log4jfilescan = search-everything -global -extension jar,war,ear
+ $StopWatch.stop()
+ $Timetaken = $StopWatch.elapsed.totalseconds
+ if ($log4jfilescan -ne $null) {
+ Write-host "See? That only took $([math]::Round($($Timetaken),2)) seconds to scan all Fixed NTFS Drives for .jar/.war/.ear files!" -foregroundcolor Green
+ $log4jfilenames = $log4jfilescan
+ }
+ else {
+ $StopWatch.stop()
+ Write-Host $($StopWatch.elapsed.totalseconds) -ForegroundColor Red
+ Write-Host "Something went wrong with calling PSEverything, lets fallback to the next scan method." -ForegroundColor Yellow
+ Throw
+ }
+ }
+ else {
+ # Write-Host "Something went wrong with calling PSEverything, lets fallback to the next scan method." -ForegroundColor Yellow
+ Throw
+ }
+ }
+ catch {
+ #Run when PSEverything isn't found or it gave an error
+ $Drives = ([System.IO.DriveInfo]::getdrives() | Where-Object {$_.DriveType -eq 'Fixed' -and $_.DriveFormat -eq 'NTFS'}).Name
+ if (test-path $robocopycsvfile) {
+ remove-item $robocopycsvfile -force
+ }
try {
- Write-Host "Attempting to use Robocopy to scan for JAR files.." -ForegroundColor Yellow
- $robocopyexitcode = (start-process robocopy -argumentlist "c:\ c:\DOESNOTEXIST *.jar /S /XJ /L /FP /NS /NC /NDL /NJH /NJS /r:0 /w:0 /LOG:$env:temp\log4jfilescan.csv" -wait).exitcode
+ Write-Host "Attempting to use Robocopy to scan for JAR/WAR/EAR files on all Fixed NTFS Drives.." -ForegroundColor Yellow
+ foreach ($drive in $drives) {
+ $robocopyexitcode = (start-process robocopy -argumentlist "$drive c:\DOESNOTEXIST *.jar *.war *.ear /S /XJ /L /FP /NS /NC /NDL /NJH /NJS /r:0 /w:0 /UNILOG+:$env:temp\log4jfilescan.csv" -WindowStyle hidden -wait).exitcode
+ }
if ($? -eq $True) {
$robocopycsv = $true
- $log4jfilescan = import-csv "$env:temp\log4jfilescan.csv" -header FilePath -delimiter "|"
+ $log4jfilescan = import-csv $robocopycsvfile -header FilePath -delimiter "|" -encoding UTF7
$log4jfilenames = $log4jfilescan
}
}
catch {
Write-Host "WARNING: Robocopy Scan failed. Falling back to GCI.." -ForegroundColor Yellow
- $log4jfilescan = get-childitem 'C:\' -file -filter *.jar -rec -force -ea 0
+ foreach ($drive in $drives) {
+ #multiple filetypes requires -include rather than -filter
+ $log4jfilescan = get-childitem $drive -file -include *.jar,*.war,*.ear -rec -force -ea 0
+ }
if ($? -eq $true) {
$log4jfilenames = ($log4jfilescan).fullname
}
@@ -64,56 +114,174 @@ else {
Exit 1
}
}
+ }
+
}
-if ($log4jfilescan -eq $null) {
- $log4jfiles = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') OK - No JAR Files were found on this device"
- $log4jvulnerable = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') OK - No JAR Files were found on this device"
- $log4jvulnerablefilecount = '0'
- Write-Host "$log4jvulnerable" -ForegroundColor Green
+
+Function Process-PotentiallyVulnerableFiles {
+ if ($robocopycsv -eq $true) {
+ $log4jpotentiallyvulnerablefiles = $log4jfilescan | foreach-object {
+ if (($_.FilePath -ne $null) -and ($_.FilePath -ne "")) {
+ if (($_.FilePath -notmatch "placeholder.jar") -and ($_.FilePath -notmatch "spool\\drivers")) {
+ #write-host "CHECKING : " $_.FilePath -ForegroundColor Yellow
+ select-string "JndiLookup.class" "$($_.FilePath)"
+ if ($? -eq $False) {
+ Write-Host "ERROR: Unable to scan $($_.FilePath)" -ForegroundColor Red
+ $log4junscanned = $log4junscanned+"
ERROR: Unable to scan $($_.FilePath)"
+ }
+ }
+ }
+ } | select-object -exp Path | sort-object -unique
+ }
+ else {
+ $log4jpotentiallyvulnerablefiles = $log4jfilescan | foreach-object {
+ if (($_ -ne $null) -and ($_ -ne "")) {
+ if ($_ -notmatch "placeholder.jar") {
+ #write-host "CHECKING : " $_ -ForegroundColor Yellow
+ select-string "JndiLookup.class" "$_"
+ if ($? -eq $False) {
+ Write-Host "ERROR: Unable to scan $_" -ForegroundColor Red
+ $log4junscanned = $log4junscanned+"
ERROR: Unable to scan $_"
+ }
+ }
+ }
+ } | select-object -exp Path | sort-object -unique
+ }
}
-else {
- Write-Host "Determining whether any of the $(($log4jfilenames).count) found .jar files are vulnerable to CVE-2021-44228 due to being capable of JNDI lookups..." -ForegroundColor Yellow
- if ($log4jfilescan -eq $null) {
- $log4jvulnerablefiles = $null
- } elseif ($log4jfilescan -ne $null) {
- if ($robocopycsv -eq $true) {
- $log4jvulnerablefiles = $log4jfilescan | foreach-object {
- if (($_.FilePath -ne $null) -and ($_.FilePath -ne "")) {
- if (($_.FilePath -notmatch "placeholder.jar") -and ($_.FilePath -notmatch "spool\\drivers")) {
- #write-host "CHECKING : " $_.FilePath -ForegroundColor Yellow
- select-string "JndiLookup.class" $_.FilePath
+
+Function Process-VulnerableFiles {
+ Add-Type -AssemblyName System.IO.Compression.FileSystem
+ Foreach ($log4jpotentiallyvulnerablefile in $log4jpotentiallyvulnerablefiles) {
+ $jartoscan = [io.compression.zipfile]::OpenRead($log4jpotentiallyvulnerablefile)
+ $potentiallyvulnerable = $false
+ $patchedjar = $false
+ foreach ($Entry in $jartoscan.Entries) {
+ if ($Entry.Name -eq "JndiLookup.class") {
+ $potentiallyvulnerable = $true
+ }
+ elseif ($Entry.Name -eq "JndiManager.class") {
+ try {
+ $stream = $Entry.Open()
+ $reader = New-Object IO.StreamReader($stream)
+ $jarattributes = $reader.ReadToEnd()
+ # Apache Log4j 2.17 Fix. (Thx to Robby S - b-Inside)
+ $CVE202145105patchedjar = $jarattributes | Select-String -Pattern "isJndiContextSelectorEnabled" -Quiet
+ # Apache Log4j 2.15/2.16 Fix
+ $CVE202144228patchedjar = $jarattributes | Select-String -Pattern "allowedJndiProtocols" -Quiet
+
+ }
+ catch {
+ Write-Output $_
+ Write-Output "Result: ERROR"
+ exit 1
+ }
+ finally {
+ # Need the checks since we don't know where the try statements might fail
+ if ($reader) {
+ $reader.Close()
+ }
+ if ($stream) {
+ $stream.Close()
+ }
+ if ($jar) {
+ $jartoscan.Dispose()
}
}
- } | select-object -exp Path | sort-object -unique
+ }
+ }
+ if ($potentiallyvulnerable -and $CVE202145105patchedjar) {
+ $CVE202145105patchedjarfiles += @($log4jpotentiallyvulnerablefile)
+ Write-Host "$($log4jpotentiallyvulnerablefile | split-path -leaf) has been fully patched to the current standard (Log4J 2.17)" -ForegroundColor Green
}
else {
- $log4jvulnerablefiles = $log4jfilescan | foreach-object {
- if (($_.FilePath -ne $null) -and ($_.FilePath -ne "")) {
- if ($_.FilePath -notmatch "placeholder.jar") {
- #write-host "CHECKING : " $_ -ForegroundColor Yellow
- select-string "JndiLookup.class" $_
- }
- }
- } | select-object -exp Path | sort-object -unique
+ $log4jvulnerablefiles += @($log4jpotentiallyvulnerablefile)
+ # which addresses all 3 known Log4Shell related Vulnerabilities: CVE-2021-44228, CVE-2021-45046, CVE-2021-45105
+ if ($potentiallyvulnerable -and $CVE202144228patchedjar) {
+ $CVE202144228patchedjarfiles += @($log4jpotentiallyvulnerablefile)
+ Write-Host "$($log4jpotentiallyvulnerablefile | split-path -leaf) has been patched to Log4j 2.15/2.16 which addresses `Log4Shell` (CVE-2021-44228), however is still vulnerable to CVE-2021-45105" -ForegroundColor Red
+ }
}
- }
+ }
+
+$log4jvulnerablefiles = $log4jvulnerablefiles | sort-object -Unique
+ if (($log4jvulnerablefiles).count -eq $null) {
+ $log4jvulnerablefilecount = '0'
+ }
+ else {
$log4jvulnerablefilecount = ($log4jvulnerablefiles).count
- if ($log4jvulnerablefiles -eq $null) {
- $log4jvulnerable = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') OK - 0 Vulnerable JAR files were found"
- write-host "Log4J CVE-2021-44228 Vulnerable Files:`n$log4jvulnerable" -ForegroundColor Green
- } elseif ($log4jvulnerablefiles -ne $null) {
- Write-Host "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') WARNING - $log4jvulnerablefilecount Vulnerable JAR file(s) were found" -foregroundcolor Red
- write-host "Log4J CVE-2021-44228 Vulnerable Files:`n$log4jvulnerablefiles" -ForegroundColor Red
- $log4jvulnerable = $log4jvulnerablefiles -join '
'
+ }
+
+}
+
+Function Process-Output {
+ if ($log4jvulnerablefilecount -eq '0') {
+ if ($log4junscanned -eq $null) {
+ $log4jvulnerable = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') OK - 0 Vulnerable JAR/WAR/EAR files were found"
+ write-host "$log4jvulnerable" -ForegroundColor Green
}
- # Write-Host "Log4j Files found:`n$log4jfiles"
- $log4jfiles = $log4jfilenames -join '
'
+ else {
+ $log4jvulnerablefilecount = '-1'
+ }
+ }
+
+ if ($log4jvulnerablefilecount -eq '-1') {
+ Write-Host "`n$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') WARNING - Certain Files were unable to be scanned and will require further inspection" -ForegroundColor Yellow
+ Write-Host $log4junscanned -ForegroundColor Red
+ Write-Host "Vulnerable Files: $log4jvulnerablefilecount" -ForegroundColor Red
+ $log4jvulnerable = $log4junscanned
+ }
+
+ if ([decimal]$log4jvulnerablefilecount -ge '1') {
+ Write-Host "`n$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') WARNING - $log4jvulnerablefilecount Vulnerable File(s) found:" -foregroundcolor Red
+ $log4jvulnerablefiles | Foreach-object ({ Write-Host $_ -ForegroundColor Red })
+ Write-Host "Recommend that these Files be updated to utilize Log4J 2.17 at the earliest opportunity" -ForegroundColor Cyan
+ $log4jvulnerable = $log4jvulnerablefiles -join '
'
+ if ($log4junscanned -ne $null){
+ Write-Host $log4junscanned -ForegroundColor Red
+ $log4jvulnerable = "$log4jvulnerable
$log4junscanned"
+ }
+ }
+}
+
+#endregion
+
+
+. Scan-Files
+
+if ($log4jfilescan -eq $null) {
+ $log4jfiles = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') OK - No JAR/WAR/EAR Files were found on this device"
+ $log4jvulnerable = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') OK - No JAR/WAR/EAR Files were found on this device"
+ $log4jvulnerablefilecount = '0'
+ Write-Host "$log4jvulnerable" -ForegroundColor Green
+}
+else {
+ Write-Host "Determining whether any of the $(($log4jfilenames).count) jar/war/ear files found are potentially vulnerable to CVE-2021-44228 (Log4Shell) due to being capable of JNDI lookups..." -ForegroundColor Yellow
+ if ($log4jfilescan -eq $null) {
+ $log4jpotentiallyvulnerablefiles = $null
+ }
+ elseif ($log4jfilescan -ne $null) {
+ . Process-PotentiallyVulnerableFiles
+ }
+ $log4jpotentiallyvulnerablefilecount = ($log4jpotentiallyvulnerablefiles).count
+ if (($log4jpotentiallyvulnerablefiles -eq $null) -and ($log4junscanned -eq $null)){
+ $log4jvulnerable = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') OK - 0 Vulnerable JAR/WAR/EAR files were found"
+ write-host "Log4J CVE-2021-44228 Potentially Vulnerable Files:`n$log4jvulnerable" -ForegroundColor Green
+ }
+ elseif ($log4jpotentiallyvulnerablefiles -ne $null) {
+ Write-Host "$log4jpotentiallyvulnerablefilecount Potentially Vulnerable JAR/WAR/EAR file(s) were found:" -foregroundcolor Red
+ $log4jpotentiallyvulnerablefiles | Foreach-object ({ Write-Host $_ -ForegroundColor Red })
+ Write-Host "`nChecking the $($log4jpotentiallyvulnerablefiles.count) potentially vulnerable files for an actual vulnerability now that Log4j 2.17 has been released..." -foregroundcolor Yellow
+ . Process-VulnerableFiles
+ }
+
+ . Process-Output
+
}
if ($robocopycsv -eq $true) {
- $log4jfiles = get-content "$env:temp\log4jfilescan.csv" -readcount 0 | ForEach-Object{$_ -join '
'}
+ $log4jfiles = get-content $robocopycsvfile -readcount 0 | ForEach-Object{$_ -join '
'}
start-sleep 5
- #remove-item "$env:temp\log4jfilescan.csv" -force
+ remove-item $robocopycsvfile -force
}
else {
$log4jfiles = $log4jfilenames -join '
'