|[Home] [Credit Search] [Category Browser] [Staff Roll Call]||The LINUX.COM Article Archive|
|Originally Published: Monday, 8 January 2001||Author: Marius Aamodt Eriksen|
|Published to: enchance_articles_security/Advanced Security Articles||Page: 1/1 - [Std View]|
Introduction to snoopy
We've asked Marius to share his thoughts on Snoopy Logger, a program using shared libraries to record system activity. Marius is coauthor of the program and has some interesting insight on security and shared libraries, click the link to read on.
In modern UNIX operating systems, two core components come to mind; the kernel and the c library (libc). Together, they help perform the most important tasks of the operating system. The c library, through its system call wrappers and other functions act as a front end to many functions that reside in the kernel. For example, printing something on screen can be done via the c library call printf(). In this case, printf() is the interface provided by the c library, which in turn formats the string to be printed and tells the kernel, via system calls, to perform the actual printing on the screen since it is the kernel that ultimately has control over the hardware (since modern UNIX kernels run in protected mode).
Most executables, for a number of reasons, are linked dynamically. That is to say, functionality in the common libraries such as libc aren't compiled in to the executables. That functionality is rather referred to shared libraries present in a system. These libraries, called shared libraries, are common to most incarnations of the operating systems. Shared libraries are also often available as separate pieces of software.
The component of the UNIX operating systems that make this possible is the dynamic linker and loader (commonly called "ld.so"). It is responsible for the determination of which shared libraries are needed as well as the loading of those libraries and referencing them to virtual addresses addresseable by the executable itself. This way, one can build more compact executables, and equally importantly, one can the functions provided by these libraries as up to date as possible without having to recompile every executable on a system. This is particularly important for security reasons, for example if a security hole is fixed in a library, a simple fix to the library is sufficient, whereas if all executables where statically linked, one would have to recompile everything in a system before the fix has completely propagated. There are other important issues why one would want to use shared libraries like for example memory usage; only one copy of a shared library is needed to be in memory for its functions to be accessed by all other running executables needing that functiontlity. If they were statically linked, the functionality formely provided by the shared library would be loaded in memory by each executable image.
-enter the threat-
Although shared libraries present many advantages, they also have their disadvantages. One obvious point of failure of the system would be if the shared libraries are exploitable. Hence, the shared libraries must be trusted. If they are not, the system's security if fully up to that of the shared library. For example, consider an untrusted or exploited version of the c library. It has a version of the commonly used 'printf' function that not only carries out the tasks of the real printf, but in addition has a go at the filesystem, doing something similar to 'rm -rf /' when it is being called as root. This can be potentially disastrous. The first root user to come along could potentially ruin the system.
Another real threat is that of preloaded shared libraries. A preloaded shared library is a shared library that is loaded before any other shared library when a dynamically linked executable is called. One can easily overload functions that belong to the real shared libraries in these preloaded libraries. Doing this allows for the modification of any function. With the GNU dynamic linker, one can deal with preloads in two ways
One scenario in which this would be a sizeable threat to a system:
Joe Linux user downloads the latest RPM of Netscape from some ftp site that he doesn't necessarily know of as a trusted ftp site (not that most ftp sites, are, or indeed can be verified easily for Joe Linux user). He 'su's' to root in order to install this new version of Netscape and starts the install. After installing the real Netscape binaries, the RPM installation script goes onto installing a malicious library and enters it in the /etc/ld.so.preload file. The library modifies the 'scanf' and 'getc' functions allowing it to snatch Joe Linux user's passwords as they are typed in. Joe Linux user is now clearly compromised.It is quite obvious that any untrusted binary can do any extent of damage. The same is true of unchecked, untrusted source code. Any untrusted piece of source code would have to be audited before its executable version is let loose on the system. The issue of preloads surpasses this, however; even in a completely trusted environment (where all running executables have been audited/checked) a malicious preload would make the trusted executables behave in a bad manner. So preloads are an important issue for several reasons: