The ldd attempts to display a list of dynamic linkages by executing the target binary with an "magic environment" setting. For a normal binary that's been compiled and linked with glibc and the normal GNU linker this will be adequate. However, crafted sources linked against an alternative library and linker can execute arbitrary code in lieu (or in addition to) this. Because most sysadmins are not aware of this behavior they will have the (reasonable) expectation that ldd is inspecting the target's headers (as data) rather than EXECUTING them. This makes ldd an ideal mechanism for social engineering exploits by users against sysadmins or site developers. Detailed explanation and sample code has been found on: http://www.catonmat.net/blog/ldd-arbitrary-code-execution/
This is just nonsense. There are a gazillion other ways to introduce code if people are downloading arbitrary binaries and install them in appropriate directories or set LD_LIBRARY_PATH etc. Just don't do that.
Created attachment 476574 [details] local-ldd.diff ldd patch from the Debian eglibc packages. It avoids this issue by ensuring that ldd always does: LD_TRACE_LOADED_OBJECTS=1 /lib/ld-linux.so.2 /path/to/ELF-lib-or-binary rather than: LD_TRACE_LOADED_OBJECTS=1 /path/to/ELF-lib-or-binary This change is not part of upstream glibc. I don't seem to be able to find any reference to this change on sourceware.org, so I'm not sure if it was ever proposed upstream. Does it this change break any expected use to explain why this fix should not make it upstream?
(In reply to comment #2) > ldd patch from the Debian eglibc packages. It avoids this issue by ensuring > that ldd always does: > > LD_TRACE_LOADED_OBJECTS=1 /lib/ld-linux.so.2 /path/to/ELF-lib-or-binary > > rather than: > > LD_TRACE_LOADED_OBJECTS=1 /path/to/ELF-lib-or-binary Apparently, Owl / ALT Linux is using the similar approach for a quite some time too: http://thread.gmane.org/gmane.comp.security.oss.general/4427/focus=4428 http://cvsweb.openwall.com/cgi/cvsweb.cgi/~checkout~/Owl/packages/glibc/glibc-2.3.6-owl-alt-ldd.diff http://git.altlinux.org/gears/g/glibc.git?p=glibc.git;a=commitdiff;h=788577027d2950e9508a434475e04c3af864d169
I think this bug should be re-opened. The current DISA STIG officially recommends the ldd program be disabled on our OS. Because this is now the DISA STIG recommendation, there will be a lot of calls to support about this one. <Rule id="SV-28909r1_rule" severity="medium"> <version>GEN007960</version> <title>The 'ldd' command must be disabled unless it protects against the execution of untrusted files.</title> All it would take is adding some option like --force to preserve the old behavior and disallow untrusted linkers by default.
Reopening for the above reasons. (systemtap's --ldd option uses ldd in this vulnerable capacity too.)
Another relevant link with some information: http://reverse.lostrealm.com/protect/ldd.html
The original behaviour of ldd was safe: it always ran ${RTLD} (ld.so) EXECUTABLE instead. This was changed in 1997, as per glibc git commit #2f6d1f1be 1997-02-22 11:30 Andreas Schwab <schwab.uni-dortmund.de> * elf/ldd.bash.in: Run the program directly, not as argument to the dynamic linker, if it contains an interpreter segment. * elf/ldd.sh.in: Likewise. IMO this should be reverted, or made non-default, or something like that, in order to make ldd safe to run on untrusted binaries.
Created attachment 485102 [details] Another suggested patch glibc is also an approved component for RHEL6.1. Is there a separate bug for RHEL6? Can we go ahead and fix it there so that customers do not have to delete ldd from the system per DISA STIG requirements? Preserving the old behavior while protecting against the default usage can be done with a patch like this:
Steve, are you sure that patch helps? The eu-readelf|grep is vulnerable to other mischievous data in the executable. It does not check the putative interpreter against a list of standard ones. It still runs "try_trace $file", which is the source of insecurity. I agree though that the bug should be cloned for RHEL6. My understanding is that this try_trace $file mechanism was put there so that executables without "r" permissions could still be subjected to ldd. (Without read privilege on EXECUTABLE, the safer mode env TRACESTUFF=... /lib/ld.so.FOO EXECUTABLE wouldn't be able to work. It seems to me that ldd should print an error for this case and abort, and only try the unsafe invocation with a --force option. env TRACESTUFF=.... EXECUTABLE
(In reply to comment #9) > Created attachment 485102 [details] > Another suggested patch $ ./ldd /bin/true Non-standard dynamic linker is requested: /lib64/ld-linux-x86-64.so.2 I guess that's not what you expect.
(In reply to comment #10) > My understanding is that this try_trace $file mechanism was put there so that > executables without "r" permissions could still be subjected to ldd. Current ldd version check if file is readable and errors with 'you do not have read permission for ...' anyway. If that was original intention for executing command directly, it does not seem valid any more.
Created attachment 485521 [details] another candidate patch This one just takes away the 1997 option of executing the program directly.
(Please excuse my reinvention of the wheel - the same proposed solution was in the first attachment.)
(In reply to comment #12) > (In reply to comment #10) > > My understanding is that this try_trace $file mechanism was put there so that > > executables without "r" permissions could still be subjected to ldd. > > Current ldd version check if file is readable and errors with 'you do not have > read permission for ...' anyway. If that was original intention for executing > command directly, it does not seem valid any more. ldd version at that time did have 'test -r "$file"' test too. It seems the reason for the change was to use whatever interpreter is noted in the file, assuming it will do the expected thing when LD_TRACE_LOADED_OBJECTS is set.
This fix was added to the fedora branch in upstream git (Andreas, thank you!): http://sourceware.org/git/?p=glibc.git;a=commitdiff;h=83e5edd390eabe8f8e8e0d051f929b77a30c0767 It's on in the glibc master branch yet.
The change has not made it to non-Fedora glibc master, are we going to keep this as Fedora/RHEL specific patch?
This request was evaluated by Red Hat Product Management for inclusion in a Red Hat Enterprise Linux maintenance release. Product Management has requested further review of this request by Red Hat Engineering, for potential inclusion in a Red Hat Enterprise Linux Update release for currently deployed products. This request is not yet committed for inclusion in an Update release.
Since the problem described in this bug report should be resolved in a recent advisory, it has been closed with a resolution of ERRATA. For information on the advisory, and where to find the updated files, follow the link below. If the solution does not work for you, open a new bug report. http://rhn.redhat.com/errata/RHBA-2012-0260.html