Skip to content

Instantly share code, notes, and snippets.

@nicka101
Last active December 18, 2021 09:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nicka101/813f423dfc3e6c8dbfbe7a7b8774d47c to your computer and use it in GitHub Desktop.
Save nicka101/813f423dfc3e6c8dbfbe7a7b8774d47c to your computer and use it in GitHub Desktop.
Simple ansible playbook to patch log4j and remove JNDI lookup from discovered JARs, mitigating CVE-2021-44228. The playbook is intended for use against Debian targets (due to the use of apt and debian package names), but with minor modifications should work against other OSes.
---
- name: Patch log4shell
hosts: all
remote_user: root
tasks:
- name: Ensure find, lsof, kill, zip, unzip, coreutils and gawk are installed
apt:
name: "{{ packages }}"
state: present
vars:
packages:
- findutils
- lsof
- procps
- zip
- unzip
- coreutils
- gawk
- name: Discover log4j2 instances
find:
paths:
- /usr
- /root
- /var
- /lib
- /lib64
- /opt
- /bin
- /home
file_type: file
recurse: yes
patterns:
- log4j-core-*.jar
register: log4j_instances
- name: Find all in-use Jars with the log4j JndiLookup in them
shell: ls -l /proc/*/fd/ | awk '$11 ~ /.jar$/ { print $11 }' | sort | uniq | awk '{ "unzip -l " $0 " | grep org/apache/logging/log4j/core/lookup/JndiLookup.class" | getline $2; if ($2 != "") print $1 }'
changed_when: false
register: running_affected_jars
- name: Combine discovered instances with in-use Jars with JndiLookup
set_fact:
jars_to_process: "{{ log4j_jars + running_affected_jars.stdout_lines |unique }}"
vars:
log4j_jars: "{{ log4j_instances.files|map(attribute='path') }}"
# We need to know because zip will change the owner to the login user
- name: Establish owners of Jars we intend to patch
shell: ls -l {{ item }} | awk '{ print $3 ":" $4 }'
changed_when: false
with_items: "{{ jars_to_process }}"
register: jar_owners
- name: Patch CVE-2021-44228 (RCE in log4j2) by removing JNDI lookup from Jars
shell: zip -q -d {{ item.key }} org/apache/logging/log4j/core/lookup/JndiLookup.class && chown {{ item.value }} {{ item.key }}
with_dict: "{{ jar_owners_dict }}"
vars:
jar_owners_real: "{{ jar_owners.results|map(attribute='stdout') }}"
jar_owners_dict: "{{ dict(jars_to_process|zip(jar_owners_real)) }}"
register: log4j_patch
changed_when: log4j_patch.rc == 0
# Zip returns exit code 12 when it has nothing to do
failed_when: log4j_patch.rc != 0 and log4j_patch.rc != 12
# If you're running software that downloads and patches its own Jars (like say, PaperMC), you may want to run with "--skip-tags kill"
# If you don't, you'll be fine (probably), but the instances will restart, triggering PaperMC to redownload and repatch any of its Jars we changed
- name: Find processes running pre-patch Jars
#Column 2 of lsof output is PID
shell: lsof | awk '$12 == "(deleted)" && $11 ~ /.jar$/ { print $2 }' | sort | uniq
changed_when: false
register: unpatched_pids
tags:
- kill
- name: Send SIGHUP to processes running pre-patch Jars so they restart
command: kill -HUP {{ item }}
with_items: "{{ unpatched_pids.stdout_lines }}"
tags:
- kill
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment