Inhaltsverzeichnis
Nach Log4j Jars auf dem Betriebsystem suchen
Zwar ist jetzt (01.2021) die ganz große Aufregung rund um log4j https://logging.apache.org/log4j/2.x/ schon wieder etwas abgeklungen, aber es wird trotzdem wichtig bleiben regelmäßig zu prüfen welche Log4J Versionen so auf den Server installiert und evtl. im Einsatz sind.
Wichtige Node von Oracle dazu ⇒MOS Article: “Impact of December 2021 Apache Log4j Vulnerabilities on Oracle Products and Services (CVE-2021-44228, CVE-2021-45046)” (Doc ID 2827611.1).
Und es müssen sobald wie möglich die Oracle Critical Patchs January 2022 (siehe ⇒ https://www.oracle.com/security-alerts/cpujan2022.html ) eingespielt werden!
Auch sollten die User Verzeichnisse / PC's im Unternehmen mit durchsucht werden, viele Client Applikationen wie der Oracle SQL Developer verwenden noch angreifbare Versionen, vor allem dann wenn die Software älter als 11.2021 ist.
Nach dem Auffinden lässt sich das Problem auch dadurch beheben, das die Jar Dateien (falls Version 2 » ) mit der neuesten Version ( Upgrade to Log4j 2.3.2 (for Java 6), 2.12.4 (for Java 7), or 2.17.1 (for Java 8 and later) ) https://logging.apache.org/log4j/2.x/download.html ausgetauscht werden , falls noch kein Update für die Software zur Verfügung steht.
Die genaue Version ermitteln
Normalerweise steht die Version auch im Dateinamen, aber nicht immer!
Auch besteht die Gefahr das die Datei umbenannt wurde!
Unter Java ist es normalerweise üblich die Version in der Manifest Datei des Jars zu hinterlegen, das ist zwar auch keine Garantie das das am Ende auch stimmt, aber besser als nichts.
Daher ist ein Ansatz alle Laufwerke nach Log4j zu durchsuchen und in den Jars zu prüfen welche Version das nun sein könnte.
Im besten Fall findet sich die Version im Manifest der Jar Datei:
Windows
Unter Windows bietet sich die Powershell an, nach den Jars zu suchen, aus diesen die Manifest Datei zu extrahieren und dort die Version auszulesen.
Das Ergebnis wird dann in einer CSV Datei gespeichert und kann ausgewertet werden.
Suchen über die Powershell:
- checkJarVersion.ps1
#============================================================================== # Author: Gunther Pippèrr ( http://www.pipperr.de ) # Desc: Search for Jar and show the version # Date: Jan 2021 # Site: https://github.com/gpipperr/OraPowerShell # The code is based on an answers at https://stackoverflow.com/a/37561878/101151 # Check if the version is inside the Jar! # & "C:\Program Files\Java\jdk1.8.0_191\bin\jar.exe" xvf junit-4.10.jar META-INF/MANIFEST.MF # get-content .\META-INF\MANIFEST.MF # #============================================================================== <# Security: (see http://www.pipperr.de/dokuwiki/doku.php?id=windows:powershell_script_aufrufen ) To switch it off (as administrator) get-Executionpolicy -list set-ExecutionPolicy -scope CurrentUser RemoteSigned .NOTES Created: 01.2021 : Gunther Pippèrr (c) http://www.pipperr.de .SYNOPSIS Search for Jar Files and read version .DESCRIPTION Search for Jar Files and read version over the manifest information .COMPONENT Oracle GPI Script Lib .EXAMPLE Backup the Database .\checkJarVersion.ps1. log4j-core-2.9.1.jar #> param( [Parameter(Mandatory=$true)][string]$startDirectory ) Add-Type -assembly "system.io.compression.filesystem" $Invocation = (Get-Variable MyInvocation -Scope 0).Value $scriptpath=Split-Path $Invocation.MyCommand.Path $starttime=get-date #Output File $logfile_name=$scriptpath+"\search_jar_result_"+$env:COMPUTERNAME+".csv" function searchVersion{ param ( [String] $jarfile , [String] $jardir , [String] $jarname ) try { if (![System.IO.File]::Exists($jarfile)) { $version=-1 throw "Jar file ""$jarfile"" not found." } $jar = [io.compression.zipfile]::OpenRead($jarfile) $file = $jar.Entries | where-object { $_.Name -eq "MANIFEST.MF"} if ($file) { $stream = $file.Open() $reader = New-Object IO.StreamReader($stream) $text = $reader.ReadToEnd() $stream.Close() $lines =$text -split "`r`n" $version_line=$lines | Select-String -InputObject {$_} -Pattern 'Implementation-Version' $version = $version_line -split "`r`n" $version = $version -replace "Implementation-Version:",""; } else { $version=-1 } echo "$jardir $jarname $version" } catch { echo "$jardir $jarname -1" } finally { if ($reader) { $reader.Dispose() } if ($jar) { $jar.Dispose() } } } # check if \ is missing if ($startDirectory -notmatch '\\$') { $startDirectory += '\' } $dir_param="$startDirectory"+"log4*.jar"+" /a-d /-c /s /b" # Search over the directory echo "--------------------------------------------------------------" echo "Start to search for Log4J Jars at $starttime" echo "" echo "Parameter startDirectory : $startDirectory" echo "Use cmd file search to speed : $dir_param " echo "" echo "Write results to : $logfile_name" echo "--------------------------------------------------------------" # to slow need 7min to 1 min with cmd #$files=Get-ChildItem -Path $startDirectory -Include log4*.jar -File -Recurse -ErrorAction SilentlyContinue #https://dmfrsecurity.com/2021/08/23/get-childitem-performance/ # much better performance $files=(cmd /c "dir $dir_param" ) #init logfile echo "Directory JarName Version"> $logfile_name $file_count=0 $searchtime=get-date $duration = [System.Math]::Round(($searchtime- $starttime).TotalMinutes,2) echo "Start to check Jars at $searchtime - need for search :: $duration Minutes" echo "--------------------------------------------------------------" #check jahrs foreach ( $file in $files ) { if ($file) { $fpath = Split-Path $file $fName = Split-Path $file -Leaf echo "Start to check $fName at directory $fpath" searchVersion -jarfile $file -jardir $fpath -jarname $fName >> $logfile_name $file_count=$file_count+1 } else { echo "$file is empty" } } echo "--------------------------------------------------------------" $endtime=get-date $duration = [System.Math]::Round(($endtime- $starttime).TotalMinutes,2) echo "Finish Search $file_count Jars from $starttime until $endtime - Duration:: $duration Minutes" echo "Check $logfile_name for results" echo "-----------------------Finish-------------------------------"
Sollten sich noch Log4J in Wars verstecken, muss hier das ganze nochmal erweitert werden.
Linux
Unter Linux ist das ganze etwas einfacher, auch lässt sich hier das Suche mit „ansible“ ( Mehr zu Ansible siehe Eine Oracle Umgebung mit Ansible warten über alle Linux Server automatisch durchführen.
Suche die Version über die Manifest Datei:
Falls zipgrep verfügbar:
find . -name "YOUR_JAR_FILE.jar" -exec zipgrep "Implementation-Version:" '{}' \;|awk -F ': ' '{print $2}'
Finde log4j jars in wars
Finde alle vorkommen von log4j aus bekannten Anlass in allen Wars auf der aktuellen Maschine
files=`find /. -name "*.war"` for f in $files do echo "$HOSTNAME:$f: " unzip -l $f | grep -i log4j | awk -v host="$HOSTNAME" -v war=$f 'BEGIN { OFS = ":" }{ print host, war, $4 }' done
Ansible Playbook
Einfache Suche nach dem Jar Dateien mit „ansible.builtin.find“ , ermittelte Facts als lokale CSV speichern:
--- - name : Create List of all Log4J Findings hosts: all vars: log_file : "/tmp/find_jars.log" tasks: - name: check if logfile exits ansible.builtin.stat: path: "{{ log_file }}" register: file_exits_check delegate_to: localhost - name: Remove file (delete file) ansible.builtin.file: path: "{{ log_file }}" state: absent when: file_exits_check.stat.exists delegate_to: localhost - name: create the file if not extis ansible.builtin.file: path: "{{ log_file }}" state: touch when: not file_exits_check.stat.exists delegate_to: localhost - name: search for all jars with this name become: yes become_user: root ansible.builtin.find: file_type : file paths : "/" patterns : "*log4j*" recurse: yes register: jar_files - name: write to local log ansible.builtin.lineinfile: path: "{{ log_file }}" line: "{{ inventory_hostname }}:{{ item.path }}" insertafter: EOF with_items: "{{ jar_files.files }}" delegate_to: localhost