Code Monkey home page Code Monkey logo

log4jscanlinux's Introduction

License
THIS SCRIPT IS PROVIDED TO YOU "AS IS." TO THE EXTENT PERMITTED BY LAW, QUALYS HEREBY DISCLAIMS ALL WARRANTIES AND LIABILITY FOR THE PROVISION OR USE OF THIS SCRIPT. 
IN NO EVENT SHALL THESE SCRIPTS BE DEEMED TO BE CLOUD SERVICES AS PROVIDED BY QUALYS

Log4j Vulnerability Scanner Shell Script:

Description:
This shell script intends to collect necessary details and help detect CVE-2021-44228 and CVE-2021-45046 vulnerabilities reported in Log4j.
The script will scan the entire filesystem, including archives for the Java class that indicates the Java application contains a vulnerable Log4j library.
Once Log4j QID is introduced in Qualys VM signatures, the output file generated by this script will serve as a data point to assess and report the QID during agent VM scan.

Usage: 
Supported platforms: Linux(RHEL, CentOS, Ubuntu, Debian, Amazon Linux, and OEL), MacOS, AIX, and Solaris
Supported architectures: x64, ARM(Linux)

How to run the script? 
1) Create and save a script (.sh) file using any text editor.
2) Execute the script file using shell script. Use the following commands:

LINUX: (detects WARs, EARs, ZIPs, and nested JARs, located under linux folder) 
sh <script-name>.sh [base_dir] [network_filesystem_scan<true/false>]
Here, <script-name> is actual script name.
(default: [base_dir]=/ [network_filesystem_scan]=false)
For example: sh ./log4j_findings.sh /home false

MacOS/AIX/Solaris: (Beta version, detects JARs only, located under unix folder) 
sh <script-name>.sh [base_dir]
Here, <script-name> is actual script name.
(default: [base_dir]=/ )
For example: sh ./log4j_findings_unix.sh /home

The script’s standard output will be redirected to:
Linux: /usr/local/qualys/cloud-agent/log4j_findings.stdout
MacOS: /Library/Application\ Support/QualysCloudAgent/Data/log4j_findings.stdout
AIX/Solaris: /opt/qualys/cloud-agent/log4j_findings.stdout

Any error occurring during its execution is redirected to:
Linux: /usr/local/qualys/cloud-agent/log4j_findings.stderr
MacOS: /Library/Application\ Support/QualysCloudAgent/Data/log4j_findings.stderr
AIX/Solaris: /opt/qualys/cloud-agent/log4j_findings.stderr 
(This file will also contain command execution start time and status on completing the run)

If the agent is not installed, the script will create the following directory and dump the standard output and error in files within it. 
However, no status information will be written in the error file if its execution is aborted.
LINUX: /usr/local/qualys/cloud-agent/ 
MACOS: /Library/Application\ Support/QualysCloudAgent/Data/  
AIX/Solaris: /opt/qualys/cloud-agent/ 

The following details are shown in the output: 
Source: Path of pom.xml within a jar file
JNDI class found or not found status
Path of the jar
log4j version

Sample output:(/usr/local/qualys/cloud-agent/log4j_findings.stdout) 
Source: META-INF/maven/org.slf4j/slf4j-log4j12/pom.xml META-INF/maven/log4j/log4j/pom.xml
JNDI-Class: JNDI Class Not Found
Path= /root/TestFiles_log4j/TestFiles/kafka-producer-intellij.jar
log4j Unknown
------------------------------------------------------------------------
Source: META-INF/maven/org.apache.logging.log4j/log4j-api/pom.xml META-INF/maven/org.apache.logging.log4j/log4j-core/pom.xml
JNDI-Class: JNDI Class Found
Path= /root/TestFiles_log4j/TestFiles/ProjWithVulLog4j-1.0-SNAPSHOT-jar-with-dependencies.jar
log4j 2.13.0
------------------------------------------------------------------------
Source: META-INF/maven/log4j/log4j/pom.xml
JNDI-Class: JNDI Class Not Found
Path= /usr/share/java/log4j.jar
log4j Unknown
------------------------------------------------------------------------

Sample error file: (/usr/local/qualys/cloud-agent/log4j_findings.stderr)
scanning started for log4j jar
Thu Dec 16 17:47:36 IST 2021
Run status : Success

log4jscanlinux's People

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

Watchers

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

log4jscanlinux's Issues

Duplicate files will cause halting the script execution (User will not see the popup and Script wait for user responses)

started running the script early this morning. 8 hours later it was still running. The script does not take
into account if there are duplicate files in a zip file. So it seems to hanging. The line where it is hanging is

            unzip -d /tmp/log4j_for_extract/ $war_file > /dev/null

This should be

            unzip -o -d /tmp/log4j_for_extract/ $war_file > /dev/null

So that duplicate files in the archive will overwrite by default instead of hanging at a user prompt for input, since stdout is redirected to /dev/null it is difficult to tell if it is hanging because it is waiting for a prompt answer or actually running.

Script doesn't handle files with spaces in the path

Example:
path: /home/user/my project.jar

Symptom:

unzip:  cannot find or open /home/user/my, /home/user/my.zip or /home/user/my.ZIP.
unzip:  cannot find or open project.jar, project.jar.zip or project.jar.ZIP.

Password-Protected Compressed Files Cause Script to Hang

When the script encounters a password-protected compressed file (ZIP), it hangs upon waiting for user input and outputs the password prompt to stderr. Expected behavior would be to skip the password-protected file and issue a warning to stdout and/or stderr.

Example (stderr):

error: -fn or any combination of -c, -l, -p, -t, -u and -v options invalid
unzip: cannot find or open /hadoop-yar, /hadoop-yar.zip or /hadoop-yar.ZIP.
unzip: cannot find or open /hadoop-yar, /hadoop-yar.zip or /hadoop-yar.ZIP.
Enter password:

The final line is the only indication that a password protected file was encountered and there are no further logs beyond it after the script hangs.

Functionality Request

We would like an option for the scanner to read the std.out file and then only scan files listed in the signature file AND create a new std.out file.

Another option that would help instead is if the script would accept multiple arguments to the command line. For example:
sh ./log4j_findings.sh /dir1/file1 /dir2/file2 /dir3/file3

Unreadable one-liner source code

*** NOBODY SHOULD EVER RUN UNTRUSTED CODE ***

So it's beyond obvious that you should write your code clearly, with comments, and make it readable - so everyone using this can see what it is doing in order to trust it.

Zip and unzip packages

The qualys linux shell script requires the zip and unzip packages installed and fails silently if one isn't there.... and even worse it reports in the log that it was okay.

Add detection for CVE-2021-4104?

Can coverage for CVE-2021-4104 be added to this script? That would force a detection for old 1.x log4j versions which weren't vulnerable to the previous CVEs I suppose there should technically be a different QID issued for that too, but one hasn't yet been announced...

False positives detected for files with multiple extensions.

We are still working to confirm, but it appears files with multiple extensions are being detected as vulnerable .jars by this script. One such example was a file called "log4j-core 2.11.2.jar.sha1" was being detected as "log4j-core 2.11.2.jar" by the scan utility.

Is there any code or suggestions that can be added to ignore files that have an extension after ".jar"?

Script asking to replace file.

During a run, getting:

[root@lvnprod029619 cloud-agent]# cat log4j_findings.stderr
replace /tmp/log4j_for_extract/importlib/__init__.pyc? [y]es, [n]o, [A]ll, [N]one, [r]ename:

comes from archive have the same file twice. it however stops the entire scan.
Currently, circumvented on my system by using this diff:

diff --git a/log4j_findings.sh b/log4j_findings.sh
index 02fe7cb..791ce38 100644
--- a/log4j_findings.sh
+++ b/log4j_findings.sh
@@ -29,9 +29,9 @@ handle_war_ear_zip()
 {
        war_file=$1
        if jar1=`unzip -l $war_file | awk '{print $NF}'| grep -i ".jar" 2> /dev/null `;then
-               rm -rf /tmp/log4j_for_extract/
+               rm -rf /tmp/log4j_for_extract
                mkdir /tmp/log4j_for_extract;
-               unzip -d /tmp/log4j_for_extract/ $war_file > /dev/null
+               unzip -do /tmp/log4j_for_extract/ $war_file > /dev/null
        fi;
        jars=`find /tmp/log4j_for_extract -type f -regextype posix-egrep -iregex ".+\.(jar)$"  2> /dev/null`; 
        for i in $jars; do

Dunno if it is the right way to do it though... but the unzip version I have running on my system works with that. Colleague of mine does not need it.

This will scan entire of ONE file system only

Per readme, "The script will scan the entire filesystem, including archives (and nested JARs) for the Java class..." It would be more accurate to state This script will scan the entire of ONE file system only"
This will give false result for most Linux systems that built with multiple file systems mount under root. "find / -xdev..." This also makes the rest of parameter at command line useless as it is for root only, it wont be nfs wont be cifs etc.
Also why not scan vxfs? I dont see any justification for that. most of important app would be installed on more robustic vxfs

Pls review and fix this...

AIX Scan

Hello,

Does the Log4jscanlinux work for AIX?

Thank you

Regards
Fabrice

macOS grep does not have -P

The macOS grep command (BSD based) does not have a -P flag (perl regexp), so this part of the script (

ve=`unzip -p $jar_file $test 2> /dev/null | grep -Pzo "<artifactId>log4j</artifactId>\s*<version>.+?</version>"| cut -d ">" -f 2 | cut -d "<" -f 1 | head -2|awk 'ORS=NR%3?FS:RS'`;
) fails on macOS.

script doesn't scan NFS filesystems

The script doesn't scan NFS filesystems. This should be allowed via an option. We have large numbers of these filesystems, which are mounted from NetApp filers, and would otherwise go unscanned.

unzip command is waiting for user intervention during log4j_findings.sh execution

When unzip command is extracting the zip file, it's prompting to enter the option and waiting for the user intervention. It's not moving further.
Error Log :
Scanning started..
Fri Feb 18 14:38:41 GMT 2022
[y]es, [n]o, [A]ll, [N]one, [r]ename:

Please can you explain the below error whether the file is scanned and vulnerable.

unzip: cannot find zipfile directory in one of .jar or
.jar.zip, and cannot find .jar.ZIP, period.
End-of-central-directory signature not found. Either this file is not
a zipfile, or it constitutes one disk of a multi-part archive. In the
latter case the central directory and zipfile comment will be found on
the last disk(s) of this archive.

Verify jar/zip/unzip availability

If zip/unzip and jar programs are not found, output log to the user. Neither are found on a server and 'log4j_findings.stderr' gave the output saying it succeeded, which is false, and no output in 'log4j_findings.stdout'.

I recommend trying to do a lookup for the jar, zip and unzip binaries for execution, and if either is not found, output to the log file. Currently it is assuming these are installed and does not provide output to the user if not found.

NFS filesystems not properly excluded

The code to exclude NFS and other filesystems does not work properly on CentOS 7 (at least), and will still traverse those filesystems, slowing down the detection process

find / -type f -regextype posix-egrep -iregex .+\.(jar|war|ear|zip)$ ! -fstype nfs ! -fstype nfs4 ! -fstype cifs ! -fstype smbfs ! -fstype gfs ! -fstype gfs2 ! -fstype safenetfs ! -fstype secfs ! -fstype gpfs ! -fstype smb2 ! -fstype vxfs ! -fstype vxodmfs ! -fstype afs -print

a faster version would be

find / -fstype nfs -prune -o -fstype nfs4 -prune -o -fstype cifs -prune -o -fstype smbfs -prune -o -fstype gfs -prune -o -fstype gfs2 -prune -o -fstype safenetfs -prune -o -fstype secfs -prune -o -fstype gpfs -prune -o -fstype smb2 -prune -o -fstype vxfs -prune -o -fstype vxodmfs -prune -o -fstype afs -prune -o -type f -regextype posix-egrep -iregex '.+\.(jar|war|ear|zip)$' -print

This change brought my search time down from over 3 hours to less than a minute!

xdev in find causing issues

Hi,

First of all thank you for this script! Being in bash it makes it really easy to run on different servers.

On some of the Linux installs that I tried the script on, I noticed the scan was too quick and did not find the expected vulnerable files. Looking at the script, I noticed that you are using "find / -xdev -name "*.jar" -type f " to find files.

This is problematic on a lot of our servers because the best practice in Linux dictates that at the very least "home" folders should be in a separate partition. In our case we have "/boot", "/home", "/opt", "/var" ...etc. on separate partitions which does not get scanned because of this flag.

The script reports success without actually scanning all partitions which can provide a false sense of security.
Can we please consider removing "xdev" flag or put some more complex logic to handle separate partitions?

ps: I personally prefer to get false positives vs false negatives just in case.

Thanks!
Ali

Output error

I executed the script on my host but not getting the desired output as mentioned in the sample. I was wondering if Qualys agent has to be installed on the host for the script to work correctly?
image

.war files containing duplicate entries will cause wait for user input before proceeding

I found the scanner hung when processing a .war file that contained duplicate .jar files, this causes the unzip to hang waiting for user confirmation
e.g.

  inflating: /tmp/log4j_for_extract/WEB-INF/lib/commons-dbcp-1.4.jar
  inflating: /tmp/log4j_for_extract/WEB-INF/lib/commons-digester-1.8.jar
replace /tmp/log4j_for_extract/WEB-INF/lib/log4j-api-2.16.0.jar? [y]es, [n]o, [A]ll, [N]one, [r]ename: ^C

[08:53|root@gbjhccy01:/opt/vconsole/lib]# unzip -tv webui.war | grep log4j-api-2.16.0.jar
    testing: WEB-INF/lib/log4j-api-2.16.0.jar   OK
    testing: WEB-INF/lib/log4j-api-2.16.0.jar   OK
[08:53|root@host:/opt/vconsole/lib]#

My solution

@@ -31,7 +31,7 @@ handle_war_ear_zip()
        if jar1=`unzip -l $war_file | awk '{print $NF}'| grep -i ".jar" 2> /dev/null `;then
                rm -rf /tmp/log4j_for_extract/
                mkdir /tmp/log4j_for_extract;
-               unzip -d /tmp/log4j_for_extract/ $war_file > /dev/null
+               unzip -o -d /tmp/log4j_for_extract/ $war_file > /dev/null
        fi;
        jars=`find /tmp/log4j_for_extract -type f -regextype posix-egrep -iregex ".+\.(jar)$"  2> /dev/null`;
        for i in $jars; do

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.