Skip to content

Instantly share code, notes, and snippets.

@FlorianHeigl
Last active December 13, 2021 16:26
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 FlorianHeigl/4f5fc401d9867786f0cd9d4e5da9f9e5 to your computer and use it in GitHub Desktop.
Save FlorianHeigl/4f5fc401d9867786f0cd9d4e5da9f9e5 to your computer and use it in GitHub Desktop.
log4j / log4shell uebersicht (from mindforger, screenshots not incl)
setup_ipset() {
# this only needs to be run once
if ! type ipset 2>/dev/null ; then
ipset create log4j_attackers nethash
iptables -I INPUT -m set --match-set log4j_attackers src -j DROP
iptables -I OUTPUT -m set --match-set log4j_attackers dst -j DROP
}
get_list() {
# this needs to run periodically, it will get the newest attacker host list off github.
set -e
set -o pipefail
wget -Olog4j.txt.unsort https://raw.githubusercontent.com/CriticalPathSecurity/Public-Intelligence-Feeds/master/log4j.txt
strings log4j.txt.unsort | sort -u > log4j.txt.u > log4j.txt
# safeguards here
# list not tiny?
# list only contains ip format entries
}
load_list() {
# load the list, without intelligene
while read ip ; do
ipset add log4j_attackers $ip
done < log4j.txt
}
main() {
setup_ipset
get_list &&
load_list
}
main

log4j / log4shell

An overview of tools, information, helpful stuff and distractions.

Mostly still untested.

blocking

Linux: block using ipsets

an ipset collects a list of ips/networks into a named object which can be accessed at runtime by iptables. (similar to how it's done in BSD's pf firewall)

Pro

  • Very linux-native method, no non-kernel dependencies except the frontend utility, thus working anywhere with a kernel from the last ~7 years.
  • Simple, easy to maintain
  • no reloads or similar needed

Con

The settings made this way are not persistent across reboots. You'll need to reload the ipset and rules, whenever the system is restarted You should also periodically update it as new hostile hosts are detected on the internet.

Howto

Install the ipset command to manage ipsets that will later be referenced from iptables

# apt install ipset

fetch the blocklist from github

wget -O log4j.txt.u https://raw.githubusercontent.com/CriticalPathSecurity/Public-Intelligence-Feeds/master/log4j.txt
sort -u log4j.txt.u > log4j.txt

create an ipset and load the blocklist contents into it

# ipset create log4j_attackers nethash
# while read ip ; do ipset add log4j_attackers $ip ; done < log4j.txt 

insert a DROP rule in the INPUT and OUPTUT changes of iptables.

# iptables -I INPUT -m set --match-set log4j_attackers src -j DROP
# iptables -I OUTPUT -m set --match-set log4j_attackers dst -j DROP

verify the ipset contents match up with the input

# wc -l log4j.txt
891
# ipset list log4j_attackers | wc -l
890

Fail2ban: inject block table entries

set <JAIL> banip <IP> ... <IP> manually Ban for

i.e.:

# fail2ban-client set \
zimbra-webmail banip 45.155.205.233

You could also create a new jail that directly reads in a file with the iplist, but generally fail2ban is made to read log files that are appended. I don't know if it would go perfectly well, but the approach in general would be very pretty / useful. If you go that route, just don't forget to do a multiport ban, not just a single service.

JunOS: block using dynamic lists

A dynamic list is a list of network addresses (not address book entries that can be used in policy. The OS can be easily configured to periodically refresh them.

Pro

  • Simple method that uses JunOS builtins
  • Will produce proper log events

Con

  • Seems to not be supported on very old OS.

Howto

I foun one on reddit Loading Custom dynamic lists from your own

It didn't work on a SRX running very outdated JunOS 12, and my JunOS 21 NFX is offline due to a move at the moment. Yet, the method looks fine.

It should be possible to point this right at the GitHub URL of CriticalPathSecurity's log4j.txt feed. Notably, the example used a .gz file format.

Further docs

JunOS documentation: show security dynamic-address

pfSense: block using pfBlocker

On pfSense the generally best choice is using pfBlockerNG, for purposes of blocking log4j attackers it can handle all the automatic updates by itself.

Pro

  • Automatic
  • Interoperable with other blocklists
  • quick to set up if already using pfBlockerNG

Con

  • pfBlockerNG is not a very stable package
  • Firewall event viewing is not a strong point of pfSense
  • pfblockerNG ad-hoc setup is involved process
  • differenes between -dev and non-dev versions

Howto

We're on pfSense 2.5.2-RELEASE (most recent)

The pfblocker package is also current: image

In pfblocker, you need the "IPv4" menu item to add an IP-based blocklist. (of course there could also be attacks via v6 but i've not yet seen any recorded) image

As you can see in this menu, I've added an entry for log4j to allow individually tracking hits on these rules.

Here are all the settings from this rule image

Zimbra

https://forums.zimbra.org/viewtopic.php?f=15&t=70240&start=20

Testing

A callback tester

https://log4shell.huntress.com/

A good log pattern to look for

This will apparently allow to not just look at log files showing http requests, but also allow you to see if jndi did a connect.

Check your #log4shell #log4j instance for this log line: ”Starting JndiManager http://org.apache.logging.log4j.core.net.JndiManager” That line means someone triggered jndi and you need to make an investigation.

source

Finding vulnerable instances

A log4j search tool (also in java) that can look inside WAR files and similar. This should be the right thing if you want to search all your infra. https://twitter.com/myfear/status/1470129332274225159

A simpler starting point is to look for the log4j.properties config file.

Patching

A hot-patch solution for running JVMs (actually, two of them)

https://twitter.com/karianna/status/1470066728004632580

Overviews

https://mogwailabs.de/en/blog/2021/12/vulnerability-notes-log4shell/

https://unit42.paloaltonetworks.com/apache-log4j-vulnerability-cve-2021-44228/

vuln list

https://gist.github.com/SwitHak/b66db3a06c2955a9cb71a8718970c592?s=09

log4j v1

laut devs nicht affected und unsupported. realitaet ist evtl. nicht ganz so.

apache/logging-log4j2#608 (comment) <- affected, wenn irgendwas enabled ist, risk much lower. damit bleibt meine empfehlung unveraendert, zimbra soll sagen ob zimbra in der jew. Version davon betroffen ist.

apache/logging-log4j2#608 (comment)

hardening options

there's not a lot to do, so far. I've especially looked at the mailserver cases, where you have a lot of outgoing and incoming (legitimate) communications. There's also simpler cases where you can at least restrict the communications.

Measures in general

disrupting execution

simpler attacks will download code, but also often work with helper scripts that are first stored to world-writeable directories and then executed.

The most basic thing is to make your run-time /tmp directories non-executable. This is still needed, even though it's become a bit less simple over the last years.

An entry as the following can be made to disallow running things downloaded to /tmp

tmpfs                   /tmp                    tmpfs   size=512m,noexec,nodev,nosuid,mode=1777      0 0

Sprinkle as needed, meaning, also consider doing the same for /dev/shm and also look at /var/tmp. The latter can be potentially a bit more troublesome, just like /run. I can't do anything about that, but at least /dev/shm should also be fine.

More efficient measures can include not having this as a world-writeable directory in the first place, by setting a mode like 1770 and only allowing certain groups to write there. (that will at least stop anon users like webservers)

Purpose-build HTTP replies

gzip bombing

Sending back a large compressed file to anyone who tries to detect/exploit this. (Will also reply to security companies scanning...)

nginx

https://twitter.com/shipilev/status/1469417410214125569

https://gist.github.com/shipilev/92e709a868f3d328b6636e1bfc21cf09

Apache:

https://twitter.com/KainsRache/status/1470170919658311684/photo/1

Blocking Requests for jndi URLs

will not work against many obfuscated urls, but is still the most basic measure you could apply

nginx

if ($http_user_agent ~* (jndi) ) {
   return 403;
}
location ~* jndi {
   return 403;
}

outgoing rules

if your application's purpose allows, you can easily restrict what kind of outbound communication it can have.

please note that for a normal web server behind a load balancer you DO NOT NEED a DNS or default gateway to be configured for it to simply answer http requests.


if you don't have a db backend, the strongest thing to do is to use selinux to remove the can_network_connect priviledge. That should(!) kill all attempts of outbound connections.

if you have some hosts you connect to, you can use iptables to allow only connecting to those (along with the ports needed. this is basically host based firewall stuff, allowing only communication that you actually want)

dns can maybe still be a troublesome thing, i don't know how jndi does DNS.

if you want to restrict a single application to only what it's supposed to be able to do, you can use iptables, too. It can have rules per-user, so if you deny something for your confluece user's uid, it'll affect all processes running with that user id.

updates

if you're the application owner, simply go and update log4j2 to the current version that has the security fix and redeploy/restart.

if you're in a less privileged position there is not so much that you can do.

you still need to make sure that you have the most recent JDK version for it, in hope of having some secondary security effects, i.e. per default network lookups can be disabled.

Jokes

finally some little jokes since this whole thing is so utterly depressing.


No one.

Absolutely no one.

Me on Monday morning: So, Java nice weekend? (@ravici)


as a pen tester my recommendation is GET THE FUCK OFF THE INTERNET AND RUN UNDER A DESK THIS SHIT IS EVERYWHERE (@_hpy3ri0n)

@FlorianHeigl
Copy link
Author

FlorianHeigl commented Dec 13, 2021

Padding issues and completely wrong entries.

ipset v6.34: Syntax error: cannot parse 001.248.832.956: resolving to IPv4 address failed
ipset v6.34: Syntax error: cannot parse 02.05.09.09: resolving to IPv4 address failed
ipset v6.34: Syntax error: cannot parse 05.06.09.06: resolving to IPv4 address failed
ipset v6.34: Syntax error: cannot parse 05.39.08.45: resolving to IPv4 address failed
ipset v6.34: Syntax error: cannot parse 09.08.17.17: resolving to IPv4 address failed
ipset v6.34: Syntax error: cannot parse 09.09.17.17: resolving to IPv4 address failed
ipset v6.34: Syntax error: cannot parse 11.08.19.17: resolving to IPv4 address failed
ipset v6.34: Syntax error: cannot parse 17.08.17.17: resolving to IPv4 address failed
ipset v6.34: Syntax error: cannot parse 19.08.19.17: resolving to IPv4 address failed
ipset v6.34: Syntax error: cannot parse 553.087.738.225: resolving to IPv4 address failed
ipset v6.34: Syntax error: cannot parse 692.661.75.75: resolving to IPv4 address failed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment