Hacker News new | past | comments | ask | show | jobs | submit login

Crap, so if `objdump` is likely vulnerable to overflows, and `ldd` is a simple bash script ripe for abuse¹, is there a safe and easy way to determine dynamic library dependencies in an executable?

¹ http://www.catonmat.net/blog/ldd-arbitrary-code-execution/




There's also readelf:

$ readelf -d /bin/ls

[...] Tag Type Name/Value 0x0000000000000001 (NEEDED) Shared library: [libselinux.so.1] 0x0000000000000001 (NEEDED) Shared library: [libcap.so.2] 0x0000000000000001 (NEEDED) Shared library: [libacl.so.1] 0x0000000000000001 (NEEDED) Shared library: [libc.so.6] [...]

I don't know how careful readelf is with its input validation.


The article mentions readelf as using the same buggy library :(


readelf specifically doesn't use BFD - one of it's majors reasons for existence is to validate libbfd.


Hmm, my mistake. You're completely correct.

From the readelf man page:

      This program performs a similar function to objdump but it goes into
      more detail and it exists independently of the BFD library,
      so if there is a bug in BFD then readelf will not be affected.


For an executable you don't trust? Probably running objdump as an unprivileged user inside a VM, and working on future hardening of libbfd.


You can run ldd safely as a normal user.


ldd actually executes the program being probed; it is not a static analyzer. It's only safe if you trust the program in the first place.

From my /usr/bin/ldd:

    try_trace() (
      output=$(eval $add_env '"$@"' 2>&1; rc=$?; printf 'x'; exit $rc)
      rc=$?
      printf '%s' "${output%x}"
      return $rc
    )
    …
    # If the program exits with exit code 5, it means the process has been
    # invoked with __libc_enable_secure.  Fall back to running it through
    # the dynamic linker.
    try_trace "$file"


It depends, but in general, ldd(1) should be considered unsafe. See under Security: http://man7.org/linux/man-pages/man1/ldd.1.html

This is an insightful bug report: https://bugzilla.redhat.com/show_bug.cgi?id=531160


> ldd actually executes the program being probed;

It's insecure, but it's actually a bit more nuanced. What I'm describing applies to up-to-date glibc, it might have been even more insecure in the past.

ldd first calls the dynamic linker with --verify, i.e.:

    /lib/ld-linux.so.2 --verify $file
This is the system's dynamic linker, which should be considered safe. The --verify parameter tells the dynamic linker to check if the file is a valid dynamically linked file. Assuming that the file exists and it is an ELF file, the dynamic linker exits with status 1 if the file doesn't have a DYNAMIC segment, with 2 if the file doesn't have a INTERP segment or with 0 if it has both (the typical case). Execution is never passed to the file with this flag.

Depending on the exit status of the loader, ldd does different things:

* If it was 0, it calls try_trace "$file", meaning that the file is invoked directly. However, remember that for the status to be 0, the file must have an INTERP segment, meaning that the kernel will call the interpreter, typically the dynamic linker, i.e. /lib/ld-linux.so.2. A well behaved linker doesn't pass control to the file if LD_TRACE_LOADED_OBJECTS is set.

This is the insecure case. The interpreter can be set to any other application (it must be statically linked or it must dynamically link itself). However, if the attacker doesn't control the file system, there typically aren't any files which match this condition and either pass control to the application or do anything harmful when invoked with no arguments. The alternative is to set the interpreter field to be the file itself. The problem with that is the full path to the ELF file must be known by the attacker (or it must be known that the victim will call ldd from the directory in which the file resides). /proc/self/exe will not work because at the time the kernel reads the entry, it will still point to the executable of the calling process, usually bash in this case.

* If the exit status was 1, ldd quits (because it's an invalid file).

* If the exit status was 2 (no INTERP segment), the dynamic loader is invoked directly, i.e.

    try_trace "$RTLD" "$file"
These two latter cases are safe.

A bug which can significantly simplify the attack would be a mismatch between the dynamic loader and the kernel, where the dynamic linker thinks that the ELF file has an INTERP filed and returns 0 for --verify and then the kernel doesn't find the INTERP field and passes control directly to the application. I've poked a bit around and as far as I can tell, there's no such bug in the latest kernel and glibc releases. In addition, the kernel aborts the loading process for any errors related to loading the interpreter.

This 30C3 talk[0] discusses potential security issues arising because of mismatches between the various ELF parsers.

[0] http://www.youtube.com/watch?v=1-tUo6RUzBU




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: