Live data from Hacker News

Log4j RCE Found

lunasec.io

441–450 of 531 posts

Re: Log4j RCE Found

#441

Earlier quoted context omitted.

I don’t understand these Java protocols enough to understand why was loading arbitrary bytecode from URLs even considered a feature, but I guess it was the 90s and Objects were all the rage

A lot of libs for logging have similar convenient ways for getting usernames and so on. The error here seems to be that even though you use the lib correctly a bug was introduced that made the injected parameters a part of the layout, at least that is what people are claiming. The example from the article though is an incorrect use of the lib and one can expect the same type of issues in a lot of libs when dealing wi…

I understand that. I don’t understand JDNI, LDAP and why it ever downloads and runs remote bytecode and why was that ever considered a good feature.

Re: Log4j RCE Found

#442
post #175

To folks wondering what the issue is about, I'll give a short summary that I myself needed. Typically a logging library has one job to do: swallow the string as if it's some black box and spit it elsewhere as per provided configurations. Log4j though, doesn't treat strings as black boxes. It inspects its contents and checks if it contains any "variables" that need to be resolved before spitting out. Now there's a bun…

These "special" strings that Log4j parse must be in the formatting string though, right? External Strings should normally be logged as parameters, not included in the format String. For example: // this is ok log.debug("user-agent={}", userAgent); // this is bad log.debug("user-agent=" + userAgent); Does this vulnerability still work on the first case? EDIT: the answer is yes, just tried it myself.

Trying to put my head around, why is this log.debug("user-agent=" + userAgent); bad?

Re: Log4j RCE Found

#443
post #442
post #175

Earlier quoted context omitted.

These "special" strings that Log4j parse must be in the formatting string though, right? External Strings should normally be logged as parameters, not included in the format String. For example: // this is ok log.debug("user-agent={}", userAgent); // this is bad log.debug("user-agent=" + userAgent); Does this vulnerability still work on the first case? EDIT: the answer is yes, just tried it myself.

Trying to put my head around, why is this log.debug("user-agent=" + userAgent); bad?

Generally, most logging frameworks have two parts, the format string, and the parameters. A good logging library will also avoid calling str()/toString() if the log isn't emitted (for example, if it's a debug log but minimum level is info).

You have something similar when building database queries, generally you should have a base template into which you insert arguments. The library generally should take care of escaping things and also preventing things like SQL injections.

Re: Log4j RCE Found

#444
post #375

I’m amazed at the reaction here. Lots of comments ITT about how this library is horrible and logging should be a solved problem from a security perspective. Similar commentary was here recently regarding some unsafe docker default. Developers always want abstractions to make programming easier, but they never consider the cost of using those abstractions. It’s so convenient to place all the burden on library authors…

> Put a regex whitelist on your inputs wherever there’s a trust boundary. No. That's a horrible idea because it requires you to think about security in multiple places and get it right every time. Instead I am going to wrap the horrible logging library that does not automatically escape control characters within arguments in a wrapper that does. Now it's impossible for me to mess up. Or... you know. One could have de…

You should still use input validation for many other reasons besides log injection.

Re: Log4j RCE Found

#447
post #424

Earlier quoted context omitted.

Does this affect SL4j wrappers over log4j as well ?

Yes. I managed to reproduce the issue with slf4j + log4j2.

can you please share code sample? and what versions you used? i am unable to replicate with log4j 1.2.12, slf4j 1.7.6, java8-151

Re: Log4j RCE Found

#448
post #289

Earlier quoted context omitted.

The point is that the first argument is the format string. debug.log("{}", stuffIGotFromPeer) should generally be safe (this bug is an example of when it isn't, though)

The fact that the first argument is interpreted as a format string even when you aren't supplying format arguments is a violation of 'principle of least surprise'. The availability of format parameters that can access environment data - let alone remotely loaded code - is a feature most people won't discover unless they go looking for it.

How are varargs implemented in the JVM ABI? Is the called function even aware of how many parameters were actually passed, or does it have to rely on the format string for that?

Re: Log4j RCE Found

#449

Earlier quoted context omitted.

The question isn't about the purpose of the feature. The question is why it's implemented with string parsing. In C, it's unsafe to do printf(string_variable); because variable will get parsed as a format string. The way to solve the vulnerability is printf("%s", string_variable); Is that the same in Java logging libraries? Is it well-known that the logged value will be parsed? What's the safe way to log a value in J…

The RCE isn't in the parsing. What gets parsed is a string that tells the server to make a request to another server. If you use a weird protocol for that, like jndi:ldap, you can then return a class which will be automatically loaded. So the code injection happens as the response to the remote request. The part the logger plays is that you can initiate that remote request by having the logger log some special string…

I think there are 2 problems:

1. Attacker-controlled data is being parsed as code (format code, not Java code). I'm not sure to what degree this is the logging library's fault vs programmer error passing attacker-controlled data as a format string. I know in Go, the standard libraries take care to help programmers avoid this problem by making sure to have the character "f" in the function name to indicate the function parameter is a format string. log.Print() takes data, log.Printf() takes a format string, log.Fatal() takes data, log.Fatalf() takes a format string.

2. The format string syntax contains significantly exploitable features if an attacker can control it. This is the same as in C, because in C, printf() contains exploitable features. This is not the case in Go, because the worst the attacker can do in Go is cause the formatting to be strange or the .String() or .Error() methods to be called on the other inputs.

Note that even without 2, 1 is still a correctness problem. If I want to log attacker-controlled data, I want it to display accurately. If the attacker's User-Agent header contains weird characters, I want those to be logged exactly, not inadvertently transformed into something strange by my library.

Re: Log4j RCE Found

#450
post #215

Earlier quoted context omitted.

This is just stupid. Logging should not do any side effects except writing to the log.

I'm not defending Log4j, but this error can really happen to many logging libraries. All logging libraries contain some kind of template engine as a performance optimization, in order to avoid actually generating the output string (can be costly) if logging is disabled. And template engines have always been a major source of vulnerabilities.

Apparently, from recent posts on this page, the problem is not solely caused by the fact that log4j perform some substitutions from a preset map, but that it performs substitution recursively, thus interpreting again the data injected into the string, with apparently no way to escape it, which I think very few logging libraries are doing.

Imagine, you write SQL commands using the proper parametric form, such as:

> exec("select * where id=${1}", user_provided_login);

You would be right to expect the DB library to escape the string so that no SQL injection is possible. After all, isn't that the whole point of parameters over a mere

> exec('select * where id=' + user_provided_login);

?

Well, apparently log4j is doing the equivalent of treating 'user_provided_login' as legit SQL.

This is especially problematic because not only will it substitute some '${variables}' again at remote user discretion, but some '${special.forms}' can actually instruct log4j to connect anywhere, download some code, execute it, then print the output. Because that was deamed convenient to someone in the past who complained that feature was missing and submitted a patch which, because of stellar unit tests, passed the code review.

The only context I can think of where this behavior regarding recursive substitution is acceptable is text templating, away from possibly adversarial input. I believe it goes opposite to expectations when logging.

Post reply on HN