Skip to content

Commit a8dfb55

Browse files
author
Robby Swartenbroekx
committed
Merge branch 'N-able-master'
2 parents 6407a23 + d1b47d2 commit a8dfb55

1 file changed

Lines changed: 229 additions & 61 deletions

File tree

Vulnerability - CVE-2021-44228 (Log4j)/get-log4jrcevulnerability.ps1

Lines changed: 229 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,108 @@
11
<#
22
Name: get-log4jrcevulnerability.ps1
3-
Version: 0.1.7.2 (14th December 2021)
3+
Version: 0.2.4.1 (21st December 2021)
44
Author: Prejay Shah (Doherty Associates)
5-
Thanks: Christopher Bledsoe (IPM Computers)
6-
Purpose: Detection of jar files vulnerable to log4j RCE vulnerability (CVE-2021-44228)
7-
Utilizing JNDILookup detection method posted to https://gist.github.com/Neo23x0/e4c8b03ff8cdf1fa63b7d15db6e3860b with some slight modifications to make it more RMM friendly
8-
9-
NOTE: Have excluded files within windows\system32\spool\drivers from being scanned due to access denied issues disrupting the output.
5+
Thanks: Christopher Bledsoe (IPM Computers) for some bugfixes,
6+
Robby Swartenbroekx (b-Inside) for some ideas,
7+
Arctic Wolf for coming up with a way to detect patched files
8+
Purpose: Detection of jar files vulnerable to the "Log4Shell" log4j RCE vulnerability (CVE-2021-44228)
9+
Originally Utilizing JNDILookup detection method posted to https://gist.github.com/Neo23x0/e4c8b03ff8cdf1fa63b7d15db6e3860b with some slight modifications to make it more RMM friendly
10+
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
11+
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.
12+
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.
1013
14+
NOTE: Only scans against NTFS File Format
15+
RMM Output optimized for N-Central
16+
Not currently compatible with Powershell 2.0
17+
Have excluded files within windows\system32\spool\drivers from being scanned due to access denied issues disrupting the output.
1118
1219
0.1 Initial Release
13-
0.1.1 Adeed Dedupe to Vulnerable .JAR Listings
20+
0.1.1 Added Dedupe to Vulnerable .JAR Listings
1421
0.1.2 Public Release
1522
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
1623
0.1.4 Experimenting with Unicode/Robocopy to bypass 260 character file path limit / access denied errors
17-
0.1.5 added support for pseverything module
24+
0.1.5 added support for PSEverything module
1825
0.1.5.1 changed detection to be module based rather than command based
1926
0.1.5.2 Cleaned up Output
2027
0.1.6 Have revamped order to PSEverything, Robocopy, GCI
2128
0.1.6.1 Fixed Typo, Modification for N-Central AMP Output of file names when robocopy is utilized
22-
0.1.7 Some bugfixes courtesy of Christopher Bledsoe (IPM Computers). Who knew cinaccessible cloud only JAR files would be a thing?
29+
0.1.7 Some bugfixes courtesy of Christopher Bledsoe (IPM Computers). Who knew inaccessible cloud only JAR files would be an issue?
2330
won't try checking an empty file path
2431
should ignore those "placeholder.jar" files in things like dropbox cache
2532
it uses "|" for the delimiter when reading the CSV/txt file created, so any file paths with "," in them should not get unintentionally split
2633
0.1.7.1 Excluding spool\drivers jar files from being scanned
2734
0.1.7.2 Updated gci to use -filter and -file rather than -include after finding it to be much more performant
35+
0.1.8 Fix for Everything/gci compatibility, Update for Log4j 2.16 update
36+
0.1.8.1 Improved Try/Catch methodology for when Everything search Fails. Thanks to Robby Swartenbroekx (b-Inside) for the assist.
37+
0.1.8.2 Made robocopy window hidden by request
38+
0.1.8.3 Improved Vulnerable File Output for RMM
39+
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)
40+
0.2 Separated detection of Log4j 2.16 Patched and 2.17 Patched States
41+
0.2.1 Adding better output for when Everything fails to scan via RMM PS wrapping
42+
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)
43+
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
44+
0.2.4 Moved Tasks into Functions, Fixed output bug for number counts.
45+
0.2.4.1 Changed robocopy export/csv import encoding to fix issue with display of special characters in file names
2846
#>
2947

30-
$Version = "0.1.7.2" # 14th December 2021
31-
Write-Host "get-log4jrcevulnerability $version" -foregroundcolor Green
48+
$Version = "0.2.4.1" # 21st December 2021
49+
Write-Host "`nget-log4jrcevulnerability $version" -foregroundcolor Green
3250
$robocopycsv = $null
51+
$log4junscanned = $null
52+
$log4jvulnerablefiles = $null
53+
$robocopycsvfile = "$env:temp\log4jfilescan.csv"
3354

3455

35-
if (get-module -listavailable | where-object {$_.name -like 'PSEverything'}) {
36-
Write-Host "The almighty PSEverything module's Search-Everything command was found.`nDoing a new scan because we can..." -ForegroundColor Yellow
37-
$log4jfiles = $null
38-
$log4jfilescan = $null
39-
$Timetaken = (measure-command {$log4jfilescan = search-everything -global -extension jar}).totalseconds
40-
Write-host "See? That only took $timetaken seconds to scan the entire C: Drive for .jar files!" -foregroundcolor Green
41-
$log4jfilenames = $log4jfilescan
42-
}
43-
else {
56+
#region functions
57+
Function Scan-Files {
58+
try {
59+
if (get-module -listavailable | where-object {$_.name -like 'PSEverything'}) {
60+
Write-Host "The almighty PSEverything module's Search-Everything command was found.`nDoing a new scan because we can..." -ForegroundColor Yellow
61+
$log4jfiles = $null
62+
$log4jfilescan = $null
63+
$StopWatch = [system.diagnostics.stopwatch]::startNew()
64+
$log4jfilescan = search-everything -global -extension jar,war,ear
65+
$StopWatch.stop()
66+
$Timetaken = $StopWatch.elapsed.totalseconds
67+
if ($log4jfilescan -ne $null) {
68+
Write-host "See? That only took $([math]::Round($($Timetaken),2)) seconds to scan all Fixed NTFS Drives for .jar/.war/.ear files!" -foregroundcolor Green
69+
$log4jfilenames = $log4jfilescan
70+
}
71+
else {
72+
$StopWatch.stop()
73+
Write-Host $($StopWatch.elapsed.totalseconds) -ForegroundColor Red
74+
Write-Host "Something went wrong with calling PSEverything, lets fallback to the next scan method." -ForegroundColor Yellow
75+
Throw
76+
}
77+
}
78+
else {
79+
# Write-Host "Something went wrong with calling PSEverything, lets fallback to the next scan method." -ForegroundColor Yellow
80+
Throw
81+
}
82+
}
83+
catch {
84+
#Run when PSEverything isn't found or it gave an error
85+
$Drives = ([System.IO.DriveInfo]::getdrives() | Where-Object {$_.DriveType -eq 'Fixed' -and $_.DriveFormat -eq 'NTFS'}).Name
86+
if (test-path $robocopycsvfile) {
87+
remove-item $robocopycsvfile -force
88+
}
4489
try {
45-
Write-Host "Attempting to use Robocopy to scan for JAR files.." -ForegroundColor Yellow
46-
$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
90+
Write-Host "Attempting to use Robocopy to scan for JAR/WAR/EAR files on all Fixed NTFS Drives.." -ForegroundColor Yellow
91+
foreach ($drive in $drives) {
92+
$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
93+
}
4794
if ($? -eq $True) {
4895
$robocopycsv = $true
49-
$log4jfilescan = import-csv "$env:temp\log4jfilescan.csv" -header FilePath -delimiter "|"
96+
$log4jfilescan = import-csv $robocopycsvfile -header FilePath -delimiter "|" -encoding UTF7
5097
$log4jfilenames = $log4jfilescan
5198
}
5299
}
53100
catch {
54101
Write-Host "WARNING: Robocopy Scan failed. Falling back to GCI.." -ForegroundColor Yellow
55-
$log4jfilescan = get-childitem 'C:\' -file -filter *.jar -rec -force -ea 0
102+
foreach ($drive in $drives) {
103+
#multiple filetypes requires -include rather than -filter
104+
$log4jfilescan = get-childitem $drive -file -include *.jar,*.war,*.ear -rec -force -ea 0
105+
}
56106
if ($? -eq $true) {
57107
$log4jfilenames = ($log4jfilescan).fullname
58108
}
@@ -64,56 +114,174 @@ else {
64114
Exit 1
65115
}
66116
}
117+
}
118+
67119
}
68-
if ($log4jfilescan -eq $null) {
69-
$log4jfiles = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') OK - No JAR Files were found on this device"
70-
$log4jvulnerable = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') OK - No JAR Files were found on this device"
71-
$log4jvulnerablefilecount = '0'
72-
Write-Host "$log4jvulnerable" -ForegroundColor Green
120+
121+
Function Process-PotentiallyVulnerableFiles {
122+
if ($robocopycsv -eq $true) {
123+
$log4jpotentiallyvulnerablefiles = $log4jfilescan | foreach-object {
124+
if (($_.FilePath -ne $null) -and ($_.FilePath -ne "")) {
125+
if (($_.FilePath -notmatch "placeholder.jar") -and ($_.FilePath -notmatch "spool\\drivers")) {
126+
#write-host "CHECKING : " $_.FilePath -ForegroundColor Yellow
127+
select-string "JndiLookup.class" "$($_.FilePath)"
128+
if ($? -eq $False) {
129+
Write-Host "ERROR: Unable to scan $($_.FilePath)" -ForegroundColor Red
130+
$log4junscanned = $log4junscanned+"<br>ERROR: Unable to scan $($_.FilePath)"
131+
}
132+
}
133+
}
134+
} | select-object -exp Path | sort-object -unique
135+
}
136+
else {
137+
$log4jpotentiallyvulnerablefiles = $log4jfilescan | foreach-object {
138+
if (($_ -ne $null) -and ($_ -ne "")) {
139+
if ($_ -notmatch "placeholder.jar") {
140+
#write-host "CHECKING : " $_ -ForegroundColor Yellow
141+
select-string "JndiLookup.class" "$_"
142+
if ($? -eq $False) {
143+
Write-Host "ERROR: Unable to scan $_" -ForegroundColor Red
144+
$log4junscanned = $log4junscanned+"<br>ERROR: Unable to scan $_"
145+
}
146+
}
147+
}
148+
} | select-object -exp Path | sort-object -unique
149+
}
73150
}
74-
else {
75-
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
76-
if ($log4jfilescan -eq $null) {
77-
$log4jvulnerablefiles = $null
78-
} elseif ($log4jfilescan -ne $null) {
79-
if ($robocopycsv -eq $true) {
80-
$log4jvulnerablefiles = $log4jfilescan | foreach-object {
81-
if (($_.FilePath -ne $null) -and ($_.FilePath -ne "")) {
82-
if (($_.FilePath -notmatch "placeholder.jar") -and ($_.FilePath -notmatch "spool\\drivers")) {
83-
#write-host "CHECKING : " $_.FilePath -ForegroundColor Yellow
84-
select-string "JndiLookup.class" $_.FilePath
151+
152+
Function Process-VulnerableFiles {
153+
Add-Type -AssemblyName System.IO.Compression.FileSystem
154+
Foreach ($log4jpotentiallyvulnerablefile in $log4jpotentiallyvulnerablefiles) {
155+
$jartoscan = [io.compression.zipfile]::OpenRead($log4jpotentiallyvulnerablefile)
156+
$potentiallyvulnerable = $false
157+
$patchedjar = $false
158+
foreach ($Entry in $jartoscan.Entries) {
159+
if ($Entry.Name -eq "JndiLookup.class") {
160+
$potentiallyvulnerable = $true
161+
}
162+
elseif ($Entry.Name -eq "JndiManager.class") {
163+
try {
164+
$stream = $Entry.Open()
165+
$reader = New-Object IO.StreamReader($stream)
166+
$jarattributes = $reader.ReadToEnd()
167+
# Apache Log4j 2.17 Fix. (Thx to Robby S - b-Inside)
168+
$CVE202145105patchedjar = $jarattributes | Select-String -Pattern "isJndiContextSelectorEnabled" -Quiet
169+
# Apache Log4j 2.15/2.16 Fix
170+
$CVE202144228patchedjar = $jarattributes | Select-String -Pattern "allowedJndiProtocols" -Quiet
171+
172+
}
173+
catch {
174+
Write-Output $_
175+
Write-Output "Result: ERROR"
176+
exit 1
177+
}
178+
finally {
179+
# Need the checks since we don't know where the try statements might fail
180+
if ($reader) {
181+
$reader.Close()
182+
}
183+
if ($stream) {
184+
$stream.Close()
185+
}
186+
if ($jar) {
187+
$jartoscan.Dispose()
85188
}
86189
}
87-
} | select-object -exp Path | sort-object -unique
190+
}
191+
}
192+
if ($potentiallyvulnerable -and $CVE202145105patchedjar) {
193+
$CVE202145105patchedjarfiles += @($log4jpotentiallyvulnerablefile)
194+
Write-Host "$($log4jpotentiallyvulnerablefile | split-path -leaf) has been fully patched to the current standard (Log4J 2.17)" -ForegroundColor Green
88195
}
89196
else {
90-
$log4jvulnerablefiles = $log4jfilescan | foreach-object {
91-
if (($_.FilePath -ne $null) -and ($_.FilePath -ne "")) {
92-
if ($_.FilePath -notmatch "placeholder.jar") {
93-
#write-host "CHECKING : " $_ -ForegroundColor Yellow
94-
select-string "JndiLookup.class" $_
95-
}
96-
}
97-
} | select-object -exp Path | sort-object -unique
197+
$log4jvulnerablefiles += @($log4jpotentiallyvulnerablefile)
198+
# which addresses all 3 known Log4Shell related Vulnerabilities: CVE-2021-44228, CVE-2021-45046, CVE-2021-45105
199+
if ($potentiallyvulnerable -and $CVE202144228patchedjar) {
200+
$CVE202144228patchedjarfiles += @($log4jpotentiallyvulnerablefile)
201+
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
202+
}
98203
}
99-
}
204+
}
205+
206+
$log4jvulnerablefiles = $log4jvulnerablefiles | sort-object -Unique
207+
if (($log4jvulnerablefiles).count -eq $null) {
208+
$log4jvulnerablefilecount = '0'
209+
}
210+
else {
100211
$log4jvulnerablefilecount = ($log4jvulnerablefiles).count
101-
if ($log4jvulnerablefiles -eq $null) {
102-
$log4jvulnerable = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') OK - 0 Vulnerable JAR files were found"
103-
write-host "Log4J CVE-2021-44228 Vulnerable Files:`n$log4jvulnerable" -ForegroundColor Green
104-
} elseif ($log4jvulnerablefiles -ne $null) {
105-
Write-Host "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') WARNING - $log4jvulnerablefilecount Vulnerable JAR file(s) were found" -foregroundcolor Red
106-
write-host "Log4J CVE-2021-44228 Vulnerable Files:`n$log4jvulnerablefiles" -ForegroundColor Red
107-
$log4jvulnerable = $log4jvulnerablefiles -join '<br>'
212+
}
213+
214+
}
215+
216+
Function Process-Output {
217+
if ($log4jvulnerablefilecount -eq '0') {
218+
if ($log4junscanned -eq $null) {
219+
$log4jvulnerable = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') OK - 0 Vulnerable JAR/WAR/EAR files were found"
220+
write-host "$log4jvulnerable" -ForegroundColor Green
108221
}
109-
# Write-Host "Log4j Files found:`n$log4jfiles"
110-
$log4jfiles = $log4jfilenames -join '<br>'
222+
else {
223+
$log4jvulnerablefilecount = '-1'
224+
}
225+
}
226+
227+
if ($log4jvulnerablefilecount -eq '-1') {
228+
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
229+
Write-Host $log4junscanned -ForegroundColor Red
230+
Write-Host "Vulnerable Files: $log4jvulnerablefilecount" -ForegroundColor Red
231+
$log4jvulnerable = $log4junscanned
232+
}
233+
234+
if ([decimal]$log4jvulnerablefilecount -ge '1') {
235+
Write-Host "`n$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') WARNING - $log4jvulnerablefilecount Vulnerable File(s) found:" -foregroundcolor Red
236+
$log4jvulnerablefiles | Foreach-object ({ Write-Host $_ -ForegroundColor Red })
237+
Write-Host "Recommend that these Files be updated to utilize Log4J 2.17 at the earliest opportunity" -ForegroundColor Cyan
238+
$log4jvulnerable = $log4jvulnerablefiles -join '<br>'
239+
if ($log4junscanned -ne $null){
240+
Write-Host $log4junscanned -ForegroundColor Red
241+
$log4jvulnerable = "$log4jvulnerable<br>$log4junscanned"
242+
}
243+
}
244+
}
245+
246+
#endregion
247+
248+
249+
. Scan-Files
250+
251+
if ($log4jfilescan -eq $null) {
252+
$log4jfiles = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') OK - No JAR/WAR/EAR Files were found on this device"
253+
$log4jvulnerable = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') OK - No JAR/WAR/EAR Files were found on this device"
254+
$log4jvulnerablefilecount = '0'
255+
Write-Host "$log4jvulnerable" -ForegroundColor Green
256+
}
257+
else {
258+
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
259+
if ($log4jfilescan -eq $null) {
260+
$log4jpotentiallyvulnerablefiles = $null
261+
}
262+
elseif ($log4jfilescan -ne $null) {
263+
. Process-PotentiallyVulnerableFiles
264+
}
265+
$log4jpotentiallyvulnerablefilecount = ($log4jpotentiallyvulnerablefiles).count
266+
if (($log4jpotentiallyvulnerablefiles -eq $null) -and ($log4junscanned -eq $null)){
267+
$log4jvulnerable = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') OK - 0 Vulnerable JAR/WAR/EAR files were found"
268+
write-host "Log4J CVE-2021-44228 Potentially Vulnerable Files:`n$log4jvulnerable" -ForegroundColor Green
269+
}
270+
elseif ($log4jpotentiallyvulnerablefiles -ne $null) {
271+
Write-Host "$log4jpotentiallyvulnerablefilecount Potentially Vulnerable JAR/WAR/EAR file(s) were found:" -foregroundcolor Red
272+
$log4jpotentiallyvulnerablefiles | Foreach-object ({ Write-Host $_ -ForegroundColor Red })
273+
Write-Host "`nChecking the $($log4jpotentiallyvulnerablefiles.count) potentially vulnerable files for an actual vulnerability now that Log4j 2.17 has been released..." -foregroundcolor Yellow
274+
. Process-VulnerableFiles
275+
}
276+
277+
. Process-Output
278+
111279
}
112280

113281
if ($robocopycsv -eq $true) {
114-
$log4jfiles = get-content "$env:temp\log4jfilescan.csv" -readcount 0 | ForEach-Object{$_ -join '<br>'}
282+
$log4jfiles = get-content $robocopycsvfile -readcount 0 | ForEach-Object{$_ -join '<br>'}
115283
start-sleep 5
116-
#remove-item "$env:temp\log4jfilescan.csv" -force
284+
remove-item $robocopycsvfile -force
117285
}
118286
else {
119287
$log4jfiles = $log4jfilenames -join '<br>'

0 commit comments

Comments
 (0)