6 ms·
Can anyone ELI5 how the exploit works?
by anonymousDan 5y ago
Can anyone ELI5 how the exploit works?
- detaro 5y agothe library parses logged messages for commands, which include a command which can be used for "connect to this server, download code from there, run it". To exploit it, put such a command into any place the app will write to log.
- layer8 5y agoActually, the command is "download this serialized Java object", and the server serving the object can add "by the way, you will need these classes for deserializing the object", and the client "ok, I’ll download those as well then", and upon deserializing the object, code from the downloaded classes is run (the actual RCE) in order to initialize the class and deserialize the instance.
- kadoban 5y agoA specially formatted log entry can cause the logging library to fetch and run remote code. So if you're printing something a user provides into your logs, you're decently likely to be screwed.
- x0x0 5y agoMore amazingly, this is intentional. If you didn't want log4j to trivially exec remote code, you were expected to add a properties file telling it not to.
- hn_throwaway_99 5y agoThis part is really beyond baffling to me. I could understand pre-configured format strings being allowed to do some crazy shit, but I can't for the life of me understand why log4j would opt to allow any logged string to be given access to a powerful lookup/configuration language, even beyond the specific JNDI issue at hand.
- x0x0 5y agowith this capability enabled by default
- zionic 5y agoHow does this garbage make it into production code?
- jerf 5y agoI would suggest at least two important mechanisms at work. First, template libraries have a fundamental drive towards power. A lot of people will talk big about separating the data from the template, but my gosh it's convenient to put for loops in your template, and be able to resolve properties, and before you know it, one feature at a time, your template code is basically as powerful as your local reflection capabilities. Sometimes, as may have happened here, even the people implementing these powerful features do not know how powerful they are. So there's this powerful pull on template libraries to become more and more powerful. But they're usually written from an assumption of the user of the template having full control over the contents and that nobody is maliciously feeding content to it. It's an assumption that template libraries often start with, as an unspoken and unexamined assumption. Unbeknownst to the template library author, someone out in the world turns out to want templates, because they're so useful and convenient, and the person picking the template library may never consider whether or not the template library they are using matches the security profile they need, because quite often literally nobody at any point of this process is really thinking about that. So it's really easy for someone to grab a templating library that is way too powerful. They're likely to even consider "way too powerful" as a feature. Second, there is a common mistake made in reflection-type APIs shared by many dynamic languages (dynamic languages have their "reflection-type APIs" simply built in, static languages usually have a library/module/package), and also in this case, Java, whereby there is some API to take some sort of string that identifies a class, and get an instance of it, or whatever the local equivalent is. Unfortunately, this turns anything that can invoke this functionality into arbitrary function execution, and "arbitrary function execution" is often leveragable into "arbitrary code execution" with only a bit more work. Again, this is done because it's really convenient and powerful, but it also means there's this Magic Portal in your language where if something can reach out to that functionality, then it can reach anything in the runtime, or possibly beyond if code can be loaded (which it usually can). These two things, when combined, create devastating security bugs. Relatedly, overaggressive deserializers can also serve as your gateway into reflection ("my gosh it's convenient to be able to name arbitrary classes and deserialize into instance of them"), which is what Ruby had with its YAML arbitrary code execution a few years back. The combination of "some way into the reflection system" and "a reflection system that allows access to all classes in the system" is deadly. Taking it one "why" further down, I think developers do not in general understand the interplay between "power" and "restrictions". There's a lot of developers who, given the choice, will always choose power, but in a multi-user world, that means you lose out on some very useful restrictions. A "power programmer" may chafe if they have to work in Go or C or C++ or some other language that doesn't have the built-in "name a class with a string, get an instance" functionality, but having that restriction around turns out to be very useful. When you add more "power" to anything, you should always flip the question around and consider it from the dual perspective of "what restrictions am I losing in order to obtain this power?" Sometimes it will be nothing you care about, and in that case, go for the power by all means. But sometimes, deliberately putting down the "power" to simply name a class and get an instance means you're putting in a very, very useful guard rail. (If you think about it, there's almost never a situation where you need to name an arbitrary class. You can almost always instead force some sort of manual registry of such things. Even cases you might think otherwise like "interpreters" you could probably still force manual registration of allowed classes. Only a very privileged interpreter that is very trusted could be allowed to have that power and lose that restriction.) It is really easy to lose track, in all these moving pieces, of the fact that you've given away too much power.
- oldcigarette 5y agoIs there a more generous perspective than this? I've been reading but from what I can tell this was just a terrible idea. Hindsight is 20/20 and all - but really?
- IiydAbITMvJkqKf 5y agoI think the "generous" perspective is that there was a JRE update once which disabled the remote code execution feature by default. Note, this was a JRE update, not a log4j update.
- hn_throwaway_99 5y agoNote, as others have commented, the JRE change prevented the fully open-ended RCE where you could download classfiles from an external server and run them. However, the log4j bug does still allow posting of environment variables to external servers, even with the JRE changes, which could be just as catastrophic. That was my understanding anyway, someone correct me if I'm wrong.
- x0x0 5y agoNo, the log4j devs really seem to have thought it was a good idea to have this (1) built, and (2) enabled by default. One of them was on twitter whinging that they needed it for backcompat. I just can't.
- astura 5y agoI'm no expert but shouldn't servers be behind some sort of firewall so they won't download code (or anything else) from random remote machines? Why would a server need unfettered access to the outside internet during standard operations?
- duozerk 5y agoThey should, but they often aren't. Also, even if they are, this can be exploited with a port number the attacker picks. So unless you specifically whitelisted what outbound hosts your machine can reach and only those (which is rarely done and not always possible), it isn't likely to help.
- more_corn 5y agoUpdates.
- peterkelly 5y agoMaybe that server needs to talk to other servers on the internet.
- jffry 5y agoShortest version: log4j has a helpful "feature" where if you log a specifically formatted string as a value, it can trigger things like DNS lookup or remote code execution. If you use a vulnerable log4j version to log any user-controlled value (such as a User-Agent header), it's a bad time. Evidently Minecraft used log4j to log user chat messages, allowing a player on a server to leak other players IP addresses.
- CuriousCosmic 5y agoSo far people have been showing off RCE "hello world" for both minecraft clients and servers on twitter. In terms of actual threat this exploit could be easily abused to rapidly spread ransomware, cryptominer malware, botnet slave code, and other nasties extremely easily. You could (devs on twitter have been playing with this) build a script that connects to random servers listed on Shodan and send a message with a payload in it. This payload then executes on both the clients and the server infecting them. Then those clients can have their credentials and server lists used to infect other servers and clients. Considering how many Minecraft servers are just thrown up on old windows machines by people with little to no IT knowledge, I can see this getting out of hand very quickly.
- coolbreezetft 5y agoHow does the downloaded java class get executed though? I get that you can get the logger to download from a server but what needs to be on the server? e.g. how does it trigger the malicious java class? Does it need to contain certain methods/interface?
- layer8 5y agoA serialized instance of the class is downloaded and deserialized. That the class itself is also downloaded (based on server-provided auxiliary download locations) is a secondary feature. The downloaded instance is then deserialized, which may run a custom deserialization method of the class, which in turn would contain the malicious code.
- coolbreezetft 5y agoSo the attacking server sends back a serialized object during the jndi request and then deserialized method is called on that object?
- layer8 5y agoThe serialized object doesn’t contain any code. But the client needs the code of object’s class to deserialize it. Instead of providing the object directly, the server can provide a JNDI object reference, which (among other things) contains a `classFactoryLocation` attribute specifying an URL where the bytecode of the class of the serialized object can be downloaded. If the class isn’t already present in the client’s codebase, the client proceeds to download it, in order to then be able to deserialize the actual object of interest. This only works over LDAP, with the intended use-case that enterprises store and organize their code repository as part of their LDAP directory.