Giter VIP home page Giter VIP logo

log4j-finder's Introduction

log4j-finder

A Python3 script to scan the filesystem to find Log4j2 that is vulnerable to Log4Shell (CVE-2021-44228 & CVE-2021-45046 & CVE-2021-45105). It scans recursively both on disk and inside (nested) Java Archive files (JARs).

log4j-finder results

How it works

log4j-finder identifies log4j2 libraries on your filesystem using a list of known bad and known good MD5 hashes of specific files (currently only JndiManager.class) present in log4j2-core-* packages; the main package that is affected by log4shell. It searches for these files inside Java Archive files and on the filesystem. The log4j2 version is then identified based on the MD5 hash of this file.

To optimize scanning speed, it searches the filesystem and processes ONLY the following filenames:

  • All files with Java ARchive file extensions in the filename (also nested in these archives):
    • *.jar, *.war, *.ear
  • Filenames that we have known bad and good hashes for (also inside above archives, and nested):
    • JndiManager.class

If the file matches one of the extensions mentioned above, it will check inside these archives (all in memory, nothing is unpacked) to search for the filenames that the script has known hashes for. It also looks inside nested archives, for example, a JAR file in a WAR file.

The script does NOT scan other archive file extensions such as 7z, RAR, TAR, BZ2, etc. So, for example, if a JAR file is inside a 7z file, the script will not find it. The rationale is that Java can only load Java ARchive formats so we only scan those.

Unknown MD5 hashes are shown as UNKNOWN; this could happen if a non log4j2 Java package uses the same filename that this script searches for. It's most likely not log4j2 if the identified file path does not contain references to org/apache/logging/log4j. However, manual verification is still recommended.

Downloading and running

You can install log4j-finder using one of the following methods:

Using the release binary

You can download the correct binary for your Operating System:

  • Windows latest (signed): log4j-finder-signed.exe
    • Non signed binaries are also available but can trigger your AntiVirus due to it being a PyInstaller executable. You can also generate the executable yourself, see "Generating log4j-finder executables" on how to do this.
  • Linux x86_64 latest: log4j-finder

If you are on Linux you can also download the latest release and run using one of the following ways:

curl -L https://github.com/fox-it/log4j-finder/releases/latest/download/log4j-finder -o log4j-finder
chmod +x log4j-finder
sudo ./log4j-finder
wget https://github.com/fox-it/log4j-finder/releases/latest/download/log4j-finder -O log4j-finder
chmod +x log4j-finder
sudo ./log4j-finder

Using Python 3

For distribution with Python 3.6+ installed, one following methods also work:

curl -L https://github.com/fox-it/log4j-finder/raw/main/log4j-finder.py -o log4j-finder.py
sudo python3 log4j-finder.py
wget https://github.com/fox-it/log4j-finder/raw/main/log4j-finder.py
sudo python3 log4j-finder.py
git clone https://github.com/fox-it/log4j-finder
cd log4j-finder
sudo python3 log4j-finder.py

Generating log4j-finder executables

Auto generated executables

There is a GitHub Action in the repository that automatically generates a Windows and Linux binary of the log4j-finder.py script using PyInstaller on every commit. The build artifacts of these workflow runs are used to attach to the Releases page.

We are aware that some Anti Virus vendors don't like the Windows binaries, in that case we recommend using generating the executable yourself using the following steps (note that we now also provide signed binaries).

Generating the Windows executable

  1. If you don't have Python 3.6 or higher installed, download it first from https://www.python.org/downloads/

  2. Open a command prompt and use pip to install the pyinstaller package:

    pip install pyinstaller
    
    # In the output you will see where pyinstaller is installed, for example:
    # C:\Users\User\AppData\Roaming\Python\Python310\Scripts
    #
    # Verify using --version
    C:\Users\User\AppData\Roaming\Python\Python310\Scripts\pyinstaller.exe --version
    4.7
  3. Optionally install the colorama package to add support for colors:

    pip install colorama
  4. Download the latest version of the log4j-finder.py script and then run PyInstaller:

pyinstaller --onefile --hidden-import colorama log4j-finder.py

The Windows executable is then in the dist directory: dist\log4j-finder.exe

Generating the Linux executable

Example given for Debian 11:

# Install PyInstaller using pip3
sudo apt update
sudo apt install python3-pip git
pip3 install --user pyinstaller

# Git clone and build using PyInstaller
git clone https://github.com/fox-it/log4j-finder
cd log4j-finder
~/.local/bin/pyinstaller --onefile log4j-finder.spec

# Verify that the binary works
./dist/log4j-finder --help

Usage

Example usage to scan a path (defaults to /):

$ python3 log4j-finder.py /path/to/scan

Or directly a JAR file:

$ python3 log4j-finder.py /path/to/jarfile.jar

Or multiple directories and or files:

$ python3 log4j-finder.py /path/to/dir1 /path/to/dir2 /path/to/jarfile.jar

Exclude files or directories:

$ python3 log4j-finder.py / --exclude "/*/.dontgohere" --exclude "/home/user/*.war"

Note that on Windows it only scans the root c:\ drive if you don't give any extra arguments. We recommend specifying the drives you need to scan on the commandline such as (drives that don't exist are skipped):

log4j-finder.exe c:\ d:\ e:\ f:\

Files or directories that cannot be accessed (Permission denied errors) are not printed.

If you want to see more output, you can give the -v flag for verbose, or -vv for debug mode (only recommended for debugging purposes).

Application arguments:

positional arguments:
  PATH                  Directory or file(s) to scan (recursively) (default:
                        ['/'])

optional arguments:
  -h, --help            show this help message and exit
  -v, --verbose         verbose output (-v is info, -vv is debug) (default: 0)
  -n, --no-color        disable color output (default: False)
  -q, --quiet           be more quiet, disables banner and summary (default:
                        False)
  -b, --no-banner       disable banner (default: False)
  -V, --version         show program's version number and exit
  -e PATTERN, --exclude PATTERN
                        exclude files/directories by pattern (can be used
                        multiple times) (default: None)

Files are scanned recursively, both on disk and in (nested) Java Archive Files

log4j-finder's People

Contributors

dariux avatar erottier avatar grmt avatar krisjanssen avatar lmorg avatar mjsalmi avatar taufderl avatar yunzheng avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

log4j-finder's Issues

Perhaps mention you need python 3.8.10 to support win7

Because when created with 3.9 or 3.10 the binary will not work, and result in "api-ms-win-core-path-l1-1-0.dll is missing"

It says so on the download page of python.org, but it can't hurt to mention it.

(lower is obviously also possible, but 3.8.10 is easiest to use in this case)

Signed Windows Binary Out-Of-Date

Hello,

Thank you so much for providing the python script and binary.
Are you able to release a new binary and signed version since the log4j version 2.17.1 is not recognized as clean ?

Thank you !

Trojan-Downloader.Win32.Bitser infection found in log4j-finder.exe

Kaspersky Anti-Virus found this on .exe file

Type: Cheval de Troie
Nom: Trojan-Downloader.Win32.Bitser.cue
Exactitude: Exactement
Niveau de menace: Élevé
Type d'objet: Fichier
Nom de l'objet: log4j-finder.exe
Chemin de l'objet: ***********
MD5: 0E08555A17CA3E08D02DBD4CFB87C1AA
Raison: Consigné dans le rapport

Kind regards.
Jipi69

Missing -V option ?

This tool will be popular and live for a long time.
Please add -V to report version information(with cool banner) only.
or may just add version info from --help output but it doesn't have cool banner.

Scanning issue very large zip files

I would like to report an issue on Windows, regarding the scanning of very large zip files.
This seems to be problematic for very large zip files with sizes around 2-4GB containing a large amount of files and/or a very large jar file.
The tools seems to be scanning for a couple of hours (on this zip file alone), after which I manually abort.
When extracted the tool does not have a problem with scanning the jar file(s).
All the zips are oracle related software.
As a workaround I use the -e (exclude) option to exclude these very large zip files.
I just wanted to tip you on this issue.
Perhaps you can add an option: do not scan zip files and/or disable the scanning of very large zip files.
I appreciate all the good work you guys have done.

Not working for log4j-1.x where JMSAppender.class exists

We are using logpresso scanner and it seems to be flagging a lot more files with potential vulnerability after log4j 1.x was added to the CVEs.
log4j-finder is however skipping those files entirely and not flagging anything.

I am curious as to which one is reliable and why is it that log4j-finder thinks that this one is not potentially vulnerable.

Attaching a file for reference
log4j.jar.zip
.

One-Click Windows Version (cmd stays open after execution)

Hi,
would it be possible to let the cmd stay open if users just double-click the exe? It will be usefull for non IT-people just to click, instead of open a cmd and start the *.exe form there :).

Like here:
vercel/pkg#644

We would link this (fantastic tool) and gave that link to our end users for home use. Most of them are non IT-people.

cheers
Niko

Catching log4j 1.x also ?

Hi
I found following string not reported by log4j-finder.

... /xxx/lib/log4j-1.2.15.jar

please consider to catch log4j 1.x jar also.

Thanks

redhat linux 6 glibc_2.14 not found error

on RHEL6 I see:

[22407] Error loading Python lib '/tmp/_MEI7VUFgo/libpython3.7m.so.1.0': dlopen: /lib64/libc.so.6: version 'GLIBC_2.14' not found (required by /tmp/_MEI7VUFgo/libpython3.7m.so.1.0)

When I compile and install glibc-2.14 manually and export as an env variable, I get:

export LD_LIBRARY_PATH=/var/opt/glibc-2.14/lib && /tmp/log4j-finder -b
Traceback (most recent call last):
  File "log4j-finder.py", line 29, in <module>
  File "/root/.pyenv/versions/3.7.5/lib/python3.7/site-packages/PyInstaller/loader/pyimod03_importers.py", line 623, in exec_module
  File "platform.py", line 116, in <module>
  File "/root/.pyenv/versions/3.7.5/lib/python3.7/site-packages/PyInstaller/loader/pyimod03_importers.py", line 623, in exec_module
  File "subprocess.py", line 153, in <module>
ImportError: /var//opt/glibc-2.14/lib/libc.so.6: version `GLIBC_2.15' not found (required by /tmp/_MEIWmgHt6/select.cpython-37m-x86_64-linux-gnu.so)

You guessed it, so I build and compiled glibc-2.15 too, and then it gives again the first error.

What I don't understand is that seemingly it's not using these glibc versions:

objdump -T /tmp/log4j-finder

/tmp/log4j-finder:     file format elf64-x86-64

DYNAMIC SYMBOL TABLE:
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.3.4 __strcat_chk
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 getenv
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.3.4 __snprintf_chk
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 raise
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 free
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.3.4 __vfprintf_chk
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 unlink
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 strncpy
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 strncmp
0000000000000000  w   D  *UND*  0000000000000000              _ITM_deregisterTMCloneTable
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 strcpy
0000000000000000      DF *UND*  0000000000000000              inflate
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 mkdir
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 ferror
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 fread
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 mbstowcs
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 setenv
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 getpid
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 fclose
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 opendir
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 stpcpy
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 rmdir
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 strlen
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 setbuf
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 strchr
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 dirname
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 memset
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 strnlen
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 strncat
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.4   __realpath_chk
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 closedir
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 __strdup
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 __libc_start_main
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 wcsncpy
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 calloc
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 strcmp
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 signal
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 ftell
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 feof
0000000000000000  w   D  *UND*  0000000000000000              __gmon_start__
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 clearerr
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.3   realpath
0000000000000000      DF *UND*  0000000000000000              inflateEnd
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 kill
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 __xpg_basename
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 fileno
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.3.4 __stpcpy_chk
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 __xstat
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 readdir
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 dlopen
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 malloc
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 fflush
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 nl_langinfo
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 fseek
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.3.4 __vsnprintf_chk
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.3.4 __strncpy_chk
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.3.4 __strcpy_chk
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 mkdtemp
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 setlocale
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 fchmod
0000000000000000      DF *UND*  0000000000000000              inflateInit_
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 waitpid
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 fopen
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 perror
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 strtok
0000000000000000  w   D  *UND*  0000000000000000              _Jv_RegisterClasses
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 unsetenv
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 execvp
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 strcat
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 fwrite
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.3.4 __fprintf_chk
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.3.4 __strncat_chk
0000000000000000  w   D  *UND*  0000000000000000              _ITM_registerTMCloneTable
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 dlsym
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 fork
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 dlerror
0000000000607a40 g    DO .bss   0000000000000008  GLIBC_2.2.5 stdout
0000000000607a48 g    DO .bss   0000000000000008  GLIBC_2.2.5 stdin
0000000000607a50 g    DO .bss   0000000000000008  GLIBC_2.2.5 stderr

Could you compile the binary also for older versions of glibc, like 2.12? Or perhaps there's some option that does something dynamic, I'm no expert.

Errors on one certain server - too long filename perhaps?

Hi,

One of my servers spits out an error.
I've replaced the servername and username.

My first wild guess is that the path is too long and the application can't handle that. But that's just a wild guess on the first glance at the path.
Do note that the broken lines is copied as-is from the output I got.

Traceback (most recent call last):
    + CategoryInfo          : NotSpecified: (Traceback (most recent call last)::String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError
    + PSComputerName        : _<servername>_
Traceback (most recent call last):
    + CategoryInfo          : NotSpecified: (Traceback (most recent call last)::String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError
    + PSComputerName        : _<servername>_

  File "log4j-finder.py", line 298, in <module>
  File "log4j-finder.py", line 298, in <module>

  File "log4j-finder.py", line 264, in main
  File "log4j-finder.py", line 264, in main

  File "pathlib.py", line 1193, in open
  File "pathlib.py", line 1193, in open

  File "pathlib.py", line 1046, in _opener
  File "pathlib.py", line 1046, in _opener

FileNotFoundError
FileNotFoundError
:
:
[Errno 2] No such file or directory: 'C:\\Documents and Settings\\_<username>_\\AppData\\Local\\Application Data\\Application
 Data\\Application Data\\Application Data\\Application Data\\Application Data\\Application Data\\Application Data\\Appli
cation Data\\Temp\\tmphc250ssu\\org\\apache\\logging\\log4j\\core\\net\\JndiManager.class'
[Errno 2] No such file or directory: 'C:\\Documents and Settings\\_<username>_\\AppData\\Local\\Application Data\\Application Data\\Application Data\\Application Data\\App
lication Data\\Application Data\\Application Data\\Application Data\\Application Data\\Temp\\tmphc250ssu\\org\\apache\\logging\\log4j\\core\\net\\JndiManager.class'
NotSpecified: (:) [], RemoteException
NotSpecified: (:) [], RemoteException
[
[
3189
3189
7
7
2] Failed
2] Failed
NotSpecified: (:) [], RemoteException
NotSpecified: (:) [], RemoteException
to execute
to execute
NotSpecified: (:) [], RemoteException
NotSpecified: (:) [], RemoteException
script l
script l
o
o
g4j-finder
g4j-finder

Windows - Export results to a file

Looking to somehow run this EXE on all our Windows systems remotely and then somehow aggregate all the results and parse looking for findings.. Any work on possibly implementing this? Thanks for all the hard work!

Readme is still incorrect?

It mentions log2j-finder.py, while only log4j-finder.py is present.

Greetings from Primevision across the road

Very strange security issues from running the Log4j-finder.exe on a Windows 10 machine?

While I appreciate your team's efforts, thought I'd pass on our feedback. When we ran the Log4j-finer.exe on a Windows 10 machine, first we noticed that windows smart screen filter warning popped up waring me even though the app is supposed to be signed? Then the app went into scanning mode for about 5 minutes, then Dropbox suddenly just opened up by itself, and stated that it was syncing, and then downloading a file, again, all by itself? This has never happened before on this machine. I forgot that dropbox was even on this machine. I went and killed the Log4j-finder.exe and the 3 spawned Dropbox instances that are not setup to start with the OS. Hoping nothing jumped the shark here that could affect our network. Thanks...Howie

Adding -q option ?

  • WHAT ?
    One-liner output for each discovered log4j-core-2.x.jar file.
[me@rocky8t01 log4j-finder]$ sudo ./dist/log4j-finder -bq  /tmp
$HOSTNAME [shorter timestamp ] VULNERABLE: /tmp/apache-log4j-2.8-bin/log4j-core-2.8.jar -> org/apache/logging/log4j/core/net/JndiManager.class [415c13e7c8505fb056d540eac29b72fa: log4j 2.7 - 2.8.1]
[me@rocky8t01 log4j-finder]$
  • WHY ?
    So that it is better used with CM tool like saltstack/ansible tools.
    -b option to exclude banner is still too much verbose for me.
[me@rocky8t01 log4j-finder]$ sudo ./dist/log4j-finder -bq  /tmp
usage: log4j-finder [-h] [-v] [-n] [-b] [PATH ...]
log4j-finder: error: argument -b/--no-banner: ignored explicit argument 'q'
[me@rocky8t01 log4j-finder]$ sudo ./dist/log4j-finder -b  /tmp
[2021-12-16 20:55:05.573146] Scanning: /tmp
[2021-12-16 20:55:05.596662] VULNERABLE: /tmp/apache-log4j-2.8-bin/log4j-core-2.8.jar -> org/apache/logging/log4j/core/net/JndiManager.class [415c13e7c8505fb056d540eac29b72fa: log4j 2.7 - 2.8.1]
[2021-12-16 20:55:05.679576] Finished scan, elapsed time: 0.11 seconds

Summary:
 Processed 291 files and 23 directories
 Scanned 44 files
  Found 1 vulnerable files

Elapsed time: 0.11 seconds
[me@rocky8t01 log4j-finder]$

Access Denied even after elevating cmd

Hello Team,

Thanks for developing this tool. I was trying to run it on my PC(windows), just installed python and ran it as explained by you, however, I am seeing a lot of access denied(even after opening cmd as admin and running if from there).

Is there a way to give it privilges?

Documentation should explicitly mention that other archive file types are NOT scanned

I think the documentation should explicitly mention that only JAR, EAR and WAR files are scanned.

For example, often a rolled out software comes in the form of a ZIP file or RAR, TAR, TAR.GZ (TGZ), TAR.BZ2 or platform-specific files types like an extractable EXE or MSI files.

Other programming languages use ZIP the file format but with a different suffix as an archive format as well, e.g. Python uses the WHL suffix.

Such archive files might contain Java classes as well, probably wrapped in *.JAR archives inside the outer archive.

These file types will not be scanned and I think this should be mentioned.

Critical issue on Windows

@yunzheng : you use standard path libraries for the lookups of files in zip files: this approach is incorrect.

image

On windows the Exception will always be hit becasue the path for lookup of the class gets passed in the wrong format:

'org\\apache\\logging\\log4j\\core\\lookup\\JndiLookup.class'

rather than

'org/apache/logging/log4j/core/lookup/JndiLookup.class'

And since you have defaulted to setting has_lookup = False, VULNERABLE jars are being labeled PATCHED.

This is very bad if people using windows are to rely on your tool...

The behavior is inconsistent across your codebase... this is OK:

image

Furtheron it is not OK:

image

Renamed class extensions are not found

I found out that repackaging JAR files and renaming them is a thing in Java land. For example the following elasticsearch APM package is vulnerable but not picked up by log4j-finder:

Advisory: https://discuss.elastic.co/t/apache-log4j2-remote-code-execution-rce-vulnerability-cve-2021-44228-esa-2021-31/291476
Package file: https://github.com/elastic/apm-agent-java/releases/v1.28.0/

When looking into this Zip file (which log4j-finder now supports btw), we can find the following file:

  • JndiManager.esclazz

Because the extension is esclazz instead of class, this file is not checked. However the MD5 is also not known, most likely because everything was recompiled from source so it doesn't match anything from known good or bad.

There are several things I want to tackle in this issue:

  • How to detect renamed class files.
  • How to detect the version if we do not have a known MD5 hash, or how do we even know it's log4j..

How to detect renamed class files

With the assumption that the filename (without extension) should always stay the same as the Java class name, we can just check for "JndiManager.*", or any other ClassNames we want to check for that matter. So basically ignore the file extension.

This is not difficult to achieve, we could change FILENAMES to have glob patterns, like JndiManager.* or maybe even better just change FILENAMES to CLASS_NAMES, and only contain the class name(s), such as JndiManager. My preference would be the latter.

It then shows up as:

[2021-12-18 21:14:27] Scanning: apm
[2021-12-18 21:15:03] UNKNOWN: elastic-apm-java-aws-lambda-layer-1.28.0.zip -> elastic-apm-agent-1.28.0.jar -> agent/org/apache/logging/log4j/core/net/JndiManager.esclazz [fbe4c72a5c9e17b3728f62e64778c2ac: Unknown MD5]
[2021-12-18 21:14:27] UNKNOWN: apm/elastic-apm-agent-1.28.0.jar -> agent/org/apache/logging/log4j/core/net/JndiManager.esclazz [fbe4c72a5c9e17b3728f62e64778c2ac: Unknown MD5]
[2021-12-18 21:14:27] Finished scan, elapsed time: 0.12 seconds

I will probably refactor the code soon to just look for ClassNames in the filename (so file extension agnostic)

How to detect log4j version of unknown MD5 hashes

log4j-finder could maybe also read and parse pom.xml and METADATA.MF files when it finds them, to determine versions used in the Jar file.
If have checked how most packages return their versions, and they seem to all get from that metadata files instead of returning a string from their own codebase itself.

This might be a bit more work and would get a bit messy with the current code base so a refactor of some functions might be better to suit this functionality.

zipfile.Path is 3.8+ only

Your doco says python 3.6+ but you're using zipfile.Path that wasn't introduced until 3.8. Just FYI. So this can't be used on any RHEL boxes without custom python installs.

does not scan .nar files

Apache Nifi uses a proprietary format to package their jar/war files, and decided to call this .nar.
Please include in scannable file extensions.

script (binary) requires executable option on /tmp mount

[root@host tmp]# mount | grep /tmp
/dev/mapper/VolGroup01-tmp on /tmp type xfs (rw,nosuid,nodev,noexec,relatime,seclabel,attr2,inode64,noquota)
[root@host tmp]# /srv/log4j-finder 
/srv/log4j-finder: error while loading shared libraries: libz.so.1: failed to map segment from shared object: Operation not permitted
[root@host tmp]# mount /tmp -o remount,exec
[root@host tmp]# mount | grep /tmp
/dev/mapper/VolGroup01-tmp on /tmp type xfs (rw,nosuid,nodev,relatime,seclabel,attr2,inode64,noquota)
[root@host tmp]# /srv/log4j-finder 
 __               _____  __         ___ __           __
|  |.-----.-----.|  |  ||__|______.'  _|__|.-----.--|  |.-----.----.
|  ||  _  |  _  ||__    |  |______|   _|  ||     |  _  ||  -__|   _|
|__||_____|___  |   |__||  |      |__| |__||__|__|_____||_____|__|
          |_____|      |___| v1.2.0 https://github.com/fox-it/log4j-finder

[2021-12-30 15:29:02] host Scanning: /
^C
Aborted!

this is not expected, especially not from a security scan utility, as noexec is set with a reason on /tmp mount point. It would be nice to provide a different tmp dir for the binary.

Remote scan

Can we somehow use this to remotely scan (internal) servers? Like foreach server in .txt or from an AD filter?

Possibility to exclude directories

Hi, is there a possibility to exclude certain directories from the search? Is it possible to start the tool via an exclude directive?

regards

Michael

log4j-finder will change acces time of a jar file

I know that acces time of a file only gives a mere indication but ik could help a little bit. On linux (and aix) you could use the touch command to save the timestamp in a temporary file. And restore it afterwards.
like:

save_command = "touch -r '{}' /tmp/timestamp.save"
rest_command = "touch -r /tmp/timestamp.save '{}'"

run(save_command.format(<jar_file>))
<do the check>
run(rest_command.format(<jar_file>))

I tried to patch the code with this but I can't. And I don't really now if it is a good idea to do that anyway
FYI i wrote a run function in python.

2.15 update

can you create a new binary for Linux with the update that 2.15 is vulnerable (newly found CVE)? Should only be 2.16 and up now

Error with a ZIP file

Hello,
I have this message :

DEBUG Got <ZipInfo filename='js-sources/tinymce_3.5.9.zip' compress_type=deflate filemode='-rw-rw-r--' file_size=1449915 compress_size=646119>: Bad magic number for central directory, falling back to BytesIO
Traceback (most recent call last):
File "log4j-finder.py", line 371, in <module>
File "log4j-finder.py", line 345, in main
File "log4j-finder.py", line 173, in iter_jarfile
File "log4j-finder.py", line 173, in iter_jarfile
File "log4j-finder.py", line 158, in iter_jarfile
File "zipfile.py", line 1225, in __init__
File "zipfile.py", line 1310, in _RealGetContents
ValueError: negative seek value -27762772
[9308] Failed to execute script log4j-finder

I tried to exclude the directory or file but nothing works.

tinymce_3.5.9.zip

option to remove problematic classes?

Given that the removal of problematic Java classes from files is trivial, it would very much improve this software if it added an option to do so.

zip -q -d $myfile org/apache/logging/log4j/core/net/JndiLookup.class
zip -q -d $myfile org/apache/logging/log4j/core/net/JndiManager.class

How to use

Hi,

It would be nice if you include instructions on how to download the file, for example with wget.

Also, when I run the file, I see at the end "Summary:" and nothing after it. Maybe there should be some indication that no files were found.

Thanks,
Uri.

Missing 'known bad' hash for versions <2.1?

Unless I have misunderstood, this vulnerability affects all versions of log4j from 2.0-beta9 to 2.14.1. I have scanned a directory that contains 2.0.2 and it didn't show up, presumably as there isn't a hash for it. I can supply a hash or a PR if needed.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.