Resident Crimeware: The Sending Component
Chapter 2. A Taxonomy of Coding Errors [*]
2.1. The Trinity of Trouble
Complex devices, by their very nature, introduce the risk that malicious functionality may be added (either during creation or afterward) that extends the original device past its primary intended design. An unfortunate side effect of inherent complexity is that it allows malicious subsystems to remain invisible to unsuspecting users until it is too late. Some of the earliest malicious functionality, for example, was associated with complicated copy machines.[1] Extensible systems, including computers, are particularly susceptible to the
malicious functionality problem. When extending a system is as easy as writing and installing a program, the risk of intentional introduction of malicious behavior increases drastically.
[1] Copy machines were an early target for espionage and, according to tradecraft lore, were easy to compromise owing to their complexity.
Any computing system is susceptible to malicious code. Rogue programmers may modify systems software that is initially installed on the machine. Users may unwittingly propagate a virus by installing new programs or software updates from the Internet. In a multiuser system, a hostile user may install a trojan horse to collect other users' passwords. These attack vectors have been well known since the dawn of computing, so why is malicious code a bigger problem now than in the past? Three major trends—connectivity, complexity, and extensibility—have had a large influence on the recent widespread propagation of malicious code.
2.1.1. Connectivity
The growing connectivity of computers through the Internet has increased both the number of attack vectors and the ease with which an attack can be launched. More and more computers—ranging from home PCs to SCADA systems that control critical infrastructures (e.g., the power grid)—are being connected to the Internet. Furthermore, people, businesses, and governments alike increasingly depend on network-enabled
communication such as email and web pages provided by information systems. Unfortunately, when these systems are connected to the Internet, they become vulnerable to attacks from distant sources. Put simply, it is no longer the case that an attacker needs physical access to a system to install or propagate malicious code. Because access through a network does not require human intervention, launching automated attacks from the comfort of one's own living room is relatively easy. Indeed, the recent rise of botnets to carry out distributed denial-of-service attacks is an advance that takes advantage of a number of (previously compromised) hosts to flood targeted Internet hosts with bogus traffic. The ubiquity of networking means that there are more systems to attack, more attacks, and greater risks from malicious code than in the past.
Directly related to the connectivity trend is the rise of massive distributed systems. These systems, sometimes built according to classic client/server architectures, have grown increasingly larger through the years.
Massively multiplayer online role-playing games (MMORPGs) such as Blizzard Entertainment's World of Warcraft are among the largest distributed systems, with millions of subscribers and literally hundreds of thousands of simultaneous users. MMORPGs have become a serious target for malicious hackers, as explained in Exploiting
Online Games [179]. Similarly crafted SOA systems[2] and Web 2.0 software are susceptible to time and state
attacks. Malicious code that takes advantage of overly complicated trust models involved in these massively distributed systems is just around the corner.
[2] SOA is an acronym for "service-oriented architecture" and has become part of the corporate software lexicon as web services architectures
have pushed past the web realm into other kinds of software. See the darkreading article "The Ultimate Insider" at
http://www.darkreading.com/document.asp?doc_id=131477 for more about the relationship between MMORPG security and SOA security.
2.1.2. Complexity
A second trend that has supported the widespread propagation of malicious code is the growing size and complexity of modern information systems. A desktop system running Windows Vista and associated
applications depends on the proper functioning of both the kernel and the applications to ensure that malicious code cannot corrupt the system. However, Vista itself consists of more than 80 million lines of code, and
applications are becoming equally, if not more, complex. When systems reach this size, bugs cannot be avoided. The problem is exacerbated by the use of unsafe programming languages (e.g., C or C++) that do not protect against simple kinds of attacks, such as buffer overflows.
Even if the systems and applications code were bug free, their improper configuration by retailers,
administrators, or users can open the door to malicious code. In addition to providing more avenues for attack, complex systems make it easier to hide or mask malicious code. In theory, one could analyze and prove that a small program was free of malicious code. In reality, this task is impossible for even the simplest desktop systems today, much less the enterprise-wide systems used by businesses or governments.
2.1.3. Extensibility
A third trend enabling malicious code is the degree to which systems have become extensible. An extensible host accepts updates or extensions, sometimes referred to as mobile code, so that the functionality of the system can evolve in an incremental fashion. For example, the JavaScript plug-in architecture of web browsers makes it possible to run client-side AJAX code, extending the capability of the browser. Today's operating systems support extensibility through dynamically loadable device drivers and modules. Today's applications, such as word processors, email clients, spreadsheets, and web browsers, support extensibility through scripting, controls, components, and applets. From an economic standpoint, extensible systems are attractive because they provide flexible interfaces that can be adapted through the inclusion of new components. In today's marketplace, it is crucial that software be deployed as rapidly as possible in order to gain market share. Yet the marketplace also demands that applications provide new features with each release. An extensible architecture makes it easy to satisfy both demands by allowing the base application code to be shipped early and feature extensions shipped later as needed.
Unfortunately, the very nature of extensible systems makes it hard to prevent malicious code from slipping in as an unwanted extension. As a classic example, the Melissa virus took advantage of the scripting extensions of
Microsoft's Outlook email client to propagate itself. The virus was coded as a script contained in what appeared to users as an innocuous mail message. When the message was opened, the script was executed; it proceeded to obtain email addresses from the user's contacts database, and then sent copies of itself to those addresses. Together, connectivity, complexity, and extensibility have made the challenge inherent in writing code that cannot be subverted even more difficult over the years. As a result, today's systems are riddled with coding errors. Understanding these errors is one of the first steps in eradicating them and ridding ourselves of the burden of malicious code. For that reason, describing and discussing a taxonomy of coding errors is a useful exercise.
Chapter 2. A Taxonomy of Coding Errors
[*]
[*] Partsofthis chapter appeared in [424] and parts have been adapted from Software Security (chapter 12) by Gary McGraw © 2006 Pearson Education, Inc., and are reproduced by permission of Pearson Education, Inc.
Gary McGraw
In May 2000, Computer Science Professor Greg Morrisett and I wrote a report for the Infosec Research Council Science and Technology Study Group (ISTSG) focused on malicious code. The purpose of the Malicious Code ISTSG was to develop a national research agenda to address the accelerating threat posed in malicious code. The final report was published in IEEE Software [250].
In the course of our work, we identified what has come to be known as the Trinity of Trouble—three factors responsible for the growth of malicious code. The Trinity of Trouble has since been expanded and discussed in
Exploiting Software [178] and in Software Security [249], but it bears repeating here.
The three trends in the Trinity of Trouble are collectively responsible for the increasing number of software vulnerabilities that are exploited by malicious code. Literally thousands of particular coding errors have been identified over the years. Together with Brian Chess and Katerina Tsipenyuk (both of Fortify software), I developed a taxonomy of coding errors called the Seven Pernicious Kingdoms. After a brief foray into the underpinnings of the Trinity of Trouble, this chapter introduces the Seven Pernicious Kingdoms.
2.1. The Trinity of Trouble
Complex devices, by their very nature, introduce the risk that malicious functionality may be added (either during creation or afterward) that extends the original device past its primary intended design. An unfortunate side effect of inherent complexity is that it allows malicious subsystems to remain invisible to unsuspecting users until it is too late. Some of the earliest malicious functionality, for example, was associated with complicated copy machines.[1] Extensible systems, including computers, are particularly susceptible to the
malicious functionality problem. When extending a system is as easy as writing and installing a program, the risk of intentional introduction of malicious behavior increases drastically.
[1] Copy machines were an early target for espionage and, according to tradecraft lore, were easy to compromise owing to their complexity.
Any computing system is susceptible to malicious code. Rogue programmers may modify systems software that is initially installed on the machine. Users may unwittingly propagate a virus by installing new programs or software updates from the Internet. In a multiuser system, a hostile user may install a trojan horse to collect other users' passwords. These attack vectors have been well known since the dawn of computing, so why is malicious code a bigger problem now than in the past? Three major trends—connectivity, complexity, and extensibility—have had a large influence on the recent widespread propagation of malicious code.
2.1.1. Connectivity
The growing connectivity of computers through the Internet has increased both the number of attack vectors and the ease with which an attack can be launched. More and more computers—ranging from home PCs to SCADA systems that control critical infrastructures (e.g., the power grid)—are being connected to the Internet. Furthermore, people, businesses, and governments alike increasingly depend on network-enabled
communication such as email and web pages provided by information systems. Unfortunately, when these systems are connected to the Internet, they become vulnerable to attacks from distant sources. Put simply, it is no longer the case that an attacker needs physical access to a system to install or propagate malicious code. Because access through a network does not require human intervention, launching automated attacks from the comfort of one's own living room is relatively easy. Indeed, the recent rise of botnets to carry out distributed denial-of-service attacks is an advance that takes advantage of a number of (previously compromised) hosts to flood targeted Internet hosts with bogus traffic. The ubiquity of networking means that there are more systems to attack, more attacks, and greater risks from malicious code than in the past.
Directly related to the connectivity trend is the rise of massive distributed systems. These systems, sometimes built according to classic client/server architectures, have grown increasingly larger through the years.
Massively multiplayer online role-playing games (MMORPGs) such as Blizzard Entertainment's World of Warcraft are among the largest distributed systems, with millions of subscribers and literally hundreds of thousands of simultaneous users. MMORPGs have become a serious target for malicious hackers, as explained in Exploiting
Online Games [179]. Similarly crafted SOA systems[2] and Web 2.0 software are susceptible to time and state
attacks. Malicious code that takes advantage of overly complicated trust models involved in these massively distributed systems is just around the corner.
[2] SOA is an acronym for "service-oriented architecture" and has become part of the corporate software lexicon as web services architectures
have pushed past the web realm into other kinds of software. See the darkreading article "The Ultimate Insider" at
http://www.darkreading.com/document.asp?doc_id=131477 for more about the relationship between MMORPG security and SOA security.
2.1.2. Complexity
A second trend that has supported the widespread propagation of malicious code is the growing size and complexity of modern information systems. A desktop system running Windows Vista and associated
applications depends on the proper functioning of both the kernel and the applications to ensure that malicious code cannot corrupt the system. However, Vista itself consists of more than 80 million lines of code, and
applications are becoming equally, if not more, complex. When systems reach this size, bugs cannot be avoided. The problem is exacerbated by the use of unsafe programming languages (e.g., C or C++) that do not protect against simple kinds of attacks, such as buffer overflows.
Even if the systems and applications code were bug free, their improper configuration by retailers,
administrators, or users can open the door to malicious code. In addition to providing more avenues for attack, complex systems make it easier to hide or mask malicious code. In theory, one could analyze and prove that a small program was free of malicious code. In reality, this task is impossible for even the simplest desktop systems today, much less the enterprise-wide systems used by businesses or governments.
2.1.3. Extensibility
A third trend enabling malicious code is the degree to which systems have become extensible. An extensible host accepts updates or extensions, sometimes referred to as mobile code, so that the functionality of the system can evolve in an incremental fashion. For example, the JavaScript plug-in architecture of web browsers makes it possible to run client-side AJAX code, extending the capability of the browser. Today's operating systems support extensibility through dynamically loadable device drivers and modules. Today's applications, such as word processors, email clients, spreadsheets, and web browsers, support extensibility through scripting, controls, components, and applets. From an economic standpoint, extensible systems are attractive because they provide flexible interfaces that can be adapted through the inclusion of new components. In today's marketplace, it is crucial that software be deployed as rapidly as possible in order to gain market share. Yet the marketplace also demands that applications provide new features with each release. An extensible architecture makes it easy to satisfy both demands by allowing the base application code to be shipped early and feature extensions shipped later as needed.
Unfortunately, the very nature of extensible systems makes it hard to prevent malicious code from slipping in as an unwanted extension. As a classic example, the Melissa virus took advantage of the scripting extensions of
Microsoft's Outlook email client to propagate itself. The virus was coded as a script contained in what appeared to users as an innocuous mail message. When the message was opened, the script was executed; it proceeded to obtain email addresses from the user's contacts database, and then sent copies of itself to those addresses. Together, connectivity, complexity, and extensibility have made the challenge inherent in writing code that cannot be subverted even more difficult over the years. As a result, today's systems are riddled with coding errors. Understanding these errors is one of the first steps in eradicating them and ridding ourselves of the burden of malicious code. For that reason, describing and discussing a taxonomy of coding errors is a useful exercise.