Paranoid Penguin: Taking a Risk-Based Approach to Linux Security

Risk is inevitable. Be pessimistic about individual programs failing, make plans for handling and containing problems, and you'll keep your system as a whole secure.

Since I started writing this column four years ago,
the nature of Linux software vulnerabilities and
threats hasn't changed that much. Buffer overflows,
bad configurations (including file permissions)
and inadequate input validation still form the lion's
share of Linux vulnerabilities. If the same kinds of
vulnerabilities keep cropping up, is the whole patch
rat race futile? Or, is there a broader approach to
Linux security that we can adopt?

This month, I discuss Linux security from
a risk-based perspective and illustrate how by
using the risk-based approach we can mitigate not
only the Linux vulnerabilities we know about, but the ones
nobody's discovered or publicized yet.

The Risk-Based Approach to Security

You may be wondering, what do I mean by a
risk-based approach? Isn't all information
security about risks? Indeed it is, but this term is
actually short for risk management-based approach.

There are only a few ways to handle a given
information security risk. We can avoid it by not
doing anything that exposes us to that risk. We can
eliminate it by addressing its root cause (which
is, in practice, seldom within our control). We can
mitigate it—that is, do something that lessens the
impact of the risk in some way. Or, we can accept it.

One school of thought, now thankfully obsolete,
holds that security is a binary equation: things
either are secure or stupid, and if one judges a
given activity or tool as not being secure, one
simply should not do that thing or use that tool. In other
words, in this school of thought, risk avoidance is
the preferred approach to security.

As most of us acknowledge nowadays, however,
absolute security does not exist. No magic combination
of software choices, software/system configuration
or network topology can make us invulnerable to
security breaches. No combination, that is, that you
actually can do any work with. Risk in some quantity
or another is inevitable in networked computing.

The risk management-based approach to security
acknowledges the need to seek balance between
risk avoidance, risk mitigation and risk acceptance,
by prioritizing risks based on their likelihood
and potential impact. Risks that are both likely to
occur and expensive to recover from are tagged as being
the most important risks either to mitigate or avoid.
Risks that either are highly unlikely or extremely
cheap to recover from become reasonable candidates
for risk acceptance. By the way, when I talk of the
cost or impact of a risk occurring, I mean not
only monetary cost but also lost time, reputation
and productivity.

Figure 1 shows the general relationship
between a risk's likelihood, its cost and its
acceptability. The precise shape of the curve that
defines the acceptable risk and unacceptable risk
zones will vary from organization to organization. A
financial institution, for example, will tend to
have a much bigger red zone than a university
network.

Figure 1. Risk Thresholds

Thus, to take a risk-based approach to security is to
acknowledge that not all risks are created equal, and therefore,
you must choose your fights. To do so
effectively, however, requires you to be creative
and honest in identifying and assessing the risks in
a given undertaking. Denying a risk exists is far more
dangerous than acknowledging and accepting that risk
and making recovery plans should the worst occur.

This brings up another important aspect of the
risk-based approach: risk acceptance should not mean
complacency. Any risk that can't be avoided or
mitigated must at least be taken into consideration in
business continuation and recovery plans. Furthermore,
very few information security risks can't be mitigated
in some way or another; many types of risks
can't be eliminated but can nonetheless
be contained or attenuated.

Vulnerabilities and Threats

Okay, so Linux security is best handled with a
risk-based outlook. What does that look like?
Step one is to think about known and potential
vulnerabilities in your Linux system. Most of Linux's
application and system vulnerabilities fall into one
of these categories:

Buffer-overflow vulnerabilities (inadequate
bounds checking).

Poor input validation.

Inappropriate file permissions.

Inappropriate system privileges (avoidable use of root).

Sloppy configuration.

Insecure use of temporary files.

Predictable or known default passwords.

Administrative back doors (test or debug
accounts).

The first vulnerability in this list,
buffer overflows, is arguably the scariest.
Buffer overflows frequently lead directly to
remote root compromises. Like buffer-overflow
conditions, many of these vulnerabilities are the
direct result of programming errors such as insecure use of
temporary files and administrative back doors. Others
are more typically user-inflicted by predictable
passwords or sloppy configuration.

No vulnerability, however, actually constitutes a
threat unless someone attempts to exploit it. In
other words, a threat equals a vulnerability plus
an attacker.

Step two is to think about ways that these
vulnerabilities might be exploited. Although Linux
vulnerabilities haven't changed much over the years,
the actors who attempt to exploit them have. They've
become both more effective and dumber. The scary
truth is, easy availability of exploit code and
scripts has made it increasingly easy for unskilled
attackers to conduct increasingly sophisticated
attacks.

For example, traditionally, conducting a
buffer-overflow attack has required considerable
programming skill—besides being able to determine
where in memory the overflowed data will end up,
the attacker must write or procure exploit code, or shellcode
written in assembler code specific
to the target system's architecture, such as i386 or SPARC.
Shellcode is the code that gets overflowed
and executed, resulting in a shell, ideally with root
privileges, on the target system.

In olden times, the difficulty of identifying
offsets and writing working shellcode narrowed
the field of potential buffer-overflow attackers
considerably. Nowadays, however, if you
want to exploit a well-known buffer-overflow
vulnerability, all you need to do is perform the
right type of Google search to obtain exploit tools,
each complete with shellcode for a variety of target
systems.

People who write exploit scripts and publish them on
the Internet are a big enough problem. But they're
not the only actors in the threat equation; if you're
the kind of person who enjoys arming script kiddies,
it's only a little more work to automate the exploit
completely and package it up into a worm or virus.

Viruses, of course, can't propagate themselves;
they're always embedded within something else, for
example, e-mail attachments or executable files. Worms,
which propagate themselves, are much scarier—they're
essentially viruses with wings. In fact, if you
were to watch your log files during a worm attack,
you'd have a hard time distinguishing it from an
attack conducted by a human being. A worm is sort of
an attack robot.

Thus, attackers either can be humans or pieces of
software. The good news is, because they exploit
exactly the same sorts of vulnerabilities, the
defenses are the same for each. The bad news is,
attack scripts, worms and viruses have
shortened exponentially the amount of time you've got between the
time a vulnerability is discovered and publicized
and the time your system probably will be probed
for that vulnerability by an attacker.