Last active
December 18, 2021 09:03
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
- 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