A Guide to Kernel Exploitation Attacking the Core [Paperback]
465 pág.

A Guide to Kernel Exploitation Attacking the Core [Paperback]

DisciplinaLinux716 materiais1.853 seguidores
Pré-visualização50 páginas
setsockopt(udev_monitor->sock, SOL_SOCKET, [4]
SO_PASSCRED, &on, sizeof(on));
struct udev_device *udev_monitor_receive_device(struct udev_monitor
42 CHAPTER 2 A Taxonomy of Kernel Vulnerabilities
if (udev_monitor->sun.sun_family != 0) { [5]
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&smsg);
struct ucred *cred = (struct ucred *)CMSG_DATA (cmsg);
if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
info(udev_monitor->udev, "no sender credentials received,
message ignored");
return NULL;
if (cred->uid != 0) {
info(udev_monitor->udev, "sender uid=%d, message
ignored", cred->uid);
return NULL;
udev_device = device_new(udev_monitor->udev); [6]
if (udev_device == NULL) {
return NULL;
Actually, more than one issue was found with the udevd code, but we will focus
on the most interesting one: a faulty architectural design. As shown at [1], [2], and [3]
in the preceding code, the udevd daemon can receive sockets of type AF_NETLINK
and AF_UNIX (the local UNIX socket, also used for IPC but only at the user-to-user
level). The function udev_monitor_enable_receiving() sets up the receiving end of
the socket. As you can see at [4], for the AF_UNIX type of socket [3], the code enables
the receipt of sender credentials, to later check, in [5], if root is sending a message.
On the other hand, for AF_NETLINK sockets [3], no such credential-checking system
is put in place. In other words, whatever message arrives on that socket would be
implicitly trusted by the application, and whatever command is inside that message
will be parsed and executed (as we show, for example, at [6]).
Unfortunately, it turned out that it was not very complicated to send a mes-
sage, as a regular user, to the udevd netlink socket. Whereas multicast (one-to-
many) sockets are reserved for root only, unicast (one-to-one) sockets are not. The
only thing that is required is the correct destination, which, for this type of socket,
is the pid of the process. Although ps might have been enough to find it, that pid
is actually stored in /proc/net/netlink, making the job of the exploit developer
even easier. This vulnerability was exploited in a variety of ways and allowed an
immediate root on nearly all the major Linux distributions, almost bypassing all
kernel security patches that were in place.
This vulnerability is a classic example of the design flaws we mentioned at the
beginning of this chapter. It does not (and would not) matter if the daemon is
(was) written in C++, Python, or Java instead of plain C. The vulnerability would
still be there. In other words, the flaw stays at a higher level; it is incidental to
the architecture.
Logic Bugs (a.k.a. the Bug Grab Bag) 43
In this chapter, we discussed various different vulnerability classes that may affect
an operating system. We took a bottom-up approach, starting with vulnerabilities
related to the dereferencing of an uninitialized, trashed, or improperly sanitized
pointer. This kind of issue can, and usually does, lead directly to a successful
exploitation, as you will see in Chapter 3. We also discussed memory corruption
vulnerabilities, which we divided into two major categories: stack corruption and
heap corruption. In most cases, a memory corruption will lead to a corrupted
pointer that will then be dereferenced.
Next, we discussed integer issues, a group of vulnerabilities that depend on incor-
rect use of or operations on numbers. This kind of vulnerability can be pretty subtle
and has extensively plagued nearly all versions of modern operating systems today.
Integer issues are not exploitable per se, but integers are generally used in memory
operations. Again, our issue will generate another issue (memory corruption, most
likely) and yet again we are down to a wrong dereference or memory usage.
Integer issues are the last vulnerability class that is relatively easy to model.
After we discussed integer issues, we talked about logic bugs and race conditions.
The basic idea behind race conditions is that a correct kernel path can lead to
incorrect/exploitable results whenever more than one thread gets to execute it at
the same time. In other words, race conditions expose a flaw in the locking/
synchronization design of specific code. The key point in race conditions is the
size of the raceable window, which puts a constraint on how easily the race condi-
tion can be triggered. For that reason, some race conditions can be exploited only
on SMP systems.
Despite the fact that they are widespread, race conditions are not the only exam-
ple of logic bugs. Nearly any other bug that we were not able to successfully
include in any of the presented classes ends up being part of the logic bug category.
In this chapter, we discussed three examples: reference counter overflows, physical-
device-generated bugs, and the particularly interesting category of kernel-generated
user-land helper vulnerabilities which, given today\u2019s trend of offloading increasingly
more duties from kernel-land to user-land applications, might be particularly hot in
the coming years.
1. Van Sprundel I, 2005. Bluetooth, http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-
2. ISO/IEC 9899:TC2. 2005. Committee draft, www.open-std.org/JTC1/SC22/wg14/www/
docs/n1124.pdf [accessed 06.05.05].
3. FreeBSD uninitialized pointer usage, 2009. www.jp.freebsd.org/cgi/query-pr.cgi?
4. Purczynski W, 2008. Linux vmsplice vulnerability, www.isec.pl/vulnerabilities/isec-
44 CHAPTER 2 A Taxonomy of Kernel Vulnerabilities
5. Bonwick J, 1994. The slab allocator: an object-caching kernel memory allocator, www.
6. Klein T, 2009. Sun Solaris aio_suspend() kernel integer overflow vulnerability,
7. Balestra F, Branco RR, 2009. FreeBSD/NetBSD/TrustedBSD*/DragonFlyBSD/
MidnightBSD all versions FireWire IOCTL kernel integer overflow information dis-
clousure, www.kernelhacking.com/bsdadv1.txt [accessed 15.11.06].
8. Seacord RC, 2008. The CERT C secure coding standard. Addison-Wesley.
9. Starzetz P, 2005. Linux kernel uselib() privilege elevation, www.isec.pl/vulnerabil-
ities/isec-0021-uselib.txt [accessed 07.01.05].
10. Starzetz P, 2005. Linux kernel i386 SMP page fault handler privilege escalation, www.
isec.pl/vulnerabilities/isec-0022-pagefault.txt [accessed 12.01.05].
11. Alexander V, 2005. Linux kernel sendmsg local buffer overflow, www.securityfocus.
12. Sun Microsystems. Solaris dynamic tracing guide, http://docs.sun.com/app/docs/doc/
13. Pol J, 2003. File descriptor leak in fpathconf, http://security.freebsd.org/advisories/
FreeBSD-SA-02:44.filedesc.asc [accessed 07.01.03].
14. Krahmer S, 2009. Linux udev trickery, http://c-skills.blogspot.com/2009/04/udev-trickery-
Endnotes 45
This page intentionally left blank
3Stairway to SuccessfulKernel Exploitation
\u2022 A Look at the Architecture Level
\u2022 The Execution Step
\u2022 The Triggering Step
\u2022 The Information-Gathering Step
In Chapter 2, we said a bug becomes a security issue as soon as someone figures
out how to take advantage of it. That\u2019s what we\u2019ll focus on in this chapter: how
to develop a successful exploit. Demonstrating that a vulnerability exists (e.g., via
proof-of-concept code) is only a first step in kernel exploitation. The exploit has
to work. A piece of code that gives you full privileges and then immediately
panics the machine is clearly of no use.
To develop a good exploit, you must understand the vulnerability you are
targeting, the kernel subsystems involved, and the techniques you are using.
A properly written