Skip to content

Commit

Permalink
Merge branch 'N-able-master'
Browse files Browse the repository at this point in the history
  • Loading branch information
Robby Swartenbroekx committed Dec 23, 2021
2 parents 6407a23 + d1b47d2 commit a8dfb55
Showing 1 changed file with 229 additions and 61 deletions.
290 changes: 229 additions & 61 deletions Vulnerability - CVE-2021-44228 (Log4j)/get-log4jrcevulnerability.ps1
Original file line number Diff line number Diff line change
@@ -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
}
Expand All @@ -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+"<br>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+"<br>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 '<br>'
}

}

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 '<br>'
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 '<br>'
if ($log4junscanned -ne $null){
Write-Host $log4junscanned -ForegroundColor Red
$log4jvulnerable = "$log4jvulnerable<br>$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 '<br>'}
$log4jfiles = get-content $robocopycsvfile -readcount 0 | ForEach-Object{$_ -join '<br>'}
start-sleep 5
#remove-item "$env:temp\log4jfilescan.csv" -force
remove-item $robocopycsvfile -force
}
else {
$log4jfiles = $log4jfilenames -join '<br>'
Expand Down

0 comments on commit a8dfb55

Please sign in to comment.