Abstract
Even well administered networks are vulnerable to attacks due to the security ramifications of offering a variety of combined services. That is, services that are secure when offered in isolation nonetheless provide an attacker with a vulnerability to exploit when offered simultaneously. Many current tools address vulnerabilities in the context of a single host. In this paper we address vulnerabilities due to the configuration of various hosts in a network.
In a different line of research, formal methods are often useful for generating test cases, and model checkers are particularly adept at this task due to their ability to generate counterexamples. In this paper, we address the network vulnerability problem with test cases, which amount to attack scenarios, generated by a model checker. We encode the vulnerabilities in a state machine description suitable for a model checker and then assert that an attacker cannot acquire a given privilege on a given host. The model checker either offers assurance that the assertion is true on the actual network or provides a counterexample detailing each step of a successful attack.
1. Introduction
Even well administered networks have difficulty defending against network attacks. One underlying reason is the problem of determining the security ramifications of offering combined services. Many services are perfectly secure when offered in isolation, but when combined with other services result in an exploitable vulnerability. A simple example would be file transfer protocol (ftp) services and hypertext transfer protocol (http) services hosted on the same machine. If the attacker can use the ftp service to write data to a directory that the web server can read, it may be possible for the attacker to cause the web server to execute a program written by the attacker.
There are many tools available to help locate individual vulnerabilities in a host. Programs such as Computer Oracle and Password System (COPS) [7], System Scanner by ISS [9], and CyberCop by Network Associates [12] scan hosts to attempt to discover vulnerabilities in the host’s configuration. However, they do not attempt to identify how combinations of configurations on the same host or between hosts on the same network can contribute to the vulnerabilities of a network.
A comprehensive view of the overall security of a network requires analysis not only of the vulnerabilities on a single host, but also must take into account the relationship between hosts on a network. Previous work in NetKuang [15] demonstrates the power of extending beyond host- only vulnerability assessment. They accomplished this by developing a distributed version of the rule-based expert system Kuang [2] and extending Kuang’s ruleset to include certain specific Unix network security issues. NetKuang is able to successfully discover security problems that are undetectable when searching a single host. NetKuang used a tailor-made search algorithm to accomplish the identification of vulnerabilities; here we employ a more general and more expressive technique based upon model checking.
In this paper we describe a modeling based approach that can be used to analyze the overall security of a network based on the interactions of vulnerabilities within a single host and within a network of hosts. We apply model checking tools to perform this analysis. We present a model that can be used to describe a network’s overall vulnerability to attack based on the individual configuration of each host, then demonstrate how model checking can be used to analyze the resulting model to determine the true vulnerability of the system, including how combined services affect the security of the network. We also show how a model checker’s ability to produce counterexamples can be used to generate attack scenarios for a vulnerable network.
Using Model Checking to Analyze Network Vulnerabilities
Ronald W. Ritchey
Paul Ammann *
National Security Team
Information and Software Engineering Department
Booz Allen & Hamilton
George Mason University
Falls Church, Virginia
Fairfax, Virginia
[email protected]
[email protected]
*Supported in part by the National Science Foundation under grant CCR-99-01030.
2. Network exploitation methods
This section presents the network intrusion methodology that we used to develop the model presented in this paper. 2.1. Vulnerability
Breaking into a computer network requires that vulnerabilities exist in the network and that exploits for the vulnerabilities are known. Any network that an attacker has connectivity with will have some level of vulnerability. The goal of network security is to try to limit vulnerability while still allowing the network to fulfill its purpose.
Network vulnerability is impossible to entirely eliminate. This is due to several factors. For a network to be useful it must offer services. These services are implemented in software and it is difficult to guarantee that any complex piece of software does not contain some flaws [3]. These flaws frequently translate into security vulnerabilities. If exploitable flaws exist in a service, even if the flaws have not been discovered, they still represent a potential for network intrusion. New security bugs are frequently discovered in server software. The worst possible situation for the security of a network is for an attacker to know about a security flaw in the software that the network relies on that is unknown to the network administrators.
Sometimes, even when a security flaw is known, the operational need to offer a service with the vulnerability supercedes the need for the network to be totally secure. These types of decisions are normally presented as risk versus reward arguments. If the risk of a network intrusion is judged small and the reward or convenience of offering a service is high many sites may choose to implement services that contain known security flaws.
A network may also contain hosts that are misconfigured. Given the large number of hosts on some networks, it is not surprising that some of them may not be set up to maximize their defenses. Many hosts are administered by the primary user of the system, who may lack the proper training to configure a secure computer system.
2.2. Exploitation
Before an attacker can attempt to break into a computer system several conditions must be met. To start with the attacker must know a technique (referred to throughout this paper as an exploit) that can be used to attempt the attack. However, knowing the exploit is not enough. Before an exploit can be used its preconditions must be met. These preconditions include the set of vulnerabilities that the exploit relies on, sufficient user rights on the target, sufficient user rights on the attacking host, and basic
connectivity. The result of a successful exploit is not necessarily a compromised system; most exploits simply cause an increase in the vulnerability of the network. Results of a successful exploit could include discovering valuable information about the network, elevating user rights, defeating filters, and adding trust relationships among other possible effects. Most successful attacks consist of a series of exploits that gradually increase the vulnerability of the network until the prerequisites of the final exploit are met.
As an example, take the case of a public web server that is (1) using the phf common gateway interface (CGI) program to offer a white pages directory service, (2) does not use a password shadow file, and (3) allows telnet access. A version of phf was distributed with several versions of the NCSA and Apache web servers that allowed an attacker to execute arbitrary commands on the host running the web server at the http daemon’s privilege level. With the presence of the vulnerable version of phf, the attacker can execute programs at the http daemon’s privilege level. With httpd level access, the attacker can capture the password file for the system. Since no password shadow file is being used, the password file will contain the password hashes. With the password hashes, a password cracking utility can be run by the attacker to potentially reveal the unencrypted passwords for each user on the system including the root user. With the root password and the ability to log into the system using telnet, the attacker is able to become the root user on the system. Figure 1 shows a state chart illustrating how this would be modeled.
Figure 1. Example network security analysis for a single host
Network attackers normally start their work by searching for vulnerabilities on the hosts they can communicate with on the target’s network. When a vulnerability is discovered they use it to increase the vulnerability level of the host. Once a host is compromised to the point that the attacker has some remote control of it, the host can be used to launch attacks further into the network. This will more than likely
httpd PHF cgi telnetd no shadow file none httpd PHF cgi telnetd no shadow file httpd PHF change access level to httpd httpd PHF cgi telnetd no shadow file pwd hashes known httpd Capture password hashes add pwd hashes known httpd PHF cgi telnetd no shadow file pwd hashes known root pwd known root Brute Force Cracker Program Passwords root pwd known httpd PHF cgi telnetd no shadow file pwd hashes known root pwd known httpd telnet login as root change access level to root
include hosts that the attacker can not reach directly. The attacker will use this new point of view to extend the number of hosts that can be searched for vulnerabilities; perhaps discovering new hosts that can eventually be taken over. This process can be continued until the network is fully compromised, the attacker can no longer find additional vulnerabilities to exploit, or the attacker’s goals are met.
3. A motivating example
Suppose a small organization has a web server that they use to provide information to their customers. Because this effort has a small budget, public domain software is used to reduce costs. The web server they have chosen to use is the widely used Apache web server [1]. They have installed the web server using the copy that was included on an old RedHat Linux [13] distribution. The version of the Apache server is 1.04. They have also decided to implement a white pages directory services on the web server using the phf program included with the Apache distribution. Because they are a small company they only maintain one network segment so the web server gets placed on the same segment as their file server. This network structure is shown in figure 2.
Figure 2. Example network diagram
To protect this private server from the Internet they have installed packet filtering rules on their border router. These rules allow hosts on the Internet to connect to the web server, but not with the private server. Table 1 shows the filtering
rules that are being enforced at the border router.
Table 1. Border filtering rules
External users use web browsers to communicate with the public web server but they are not supposed to have any other access to the network. Private users rely on the private file server to hold their home directories that often contain company proprietary data. These directories are shared with the users of the network using Network File Service (NFS). They also occasionally use a custom database application located on the file server that they access by remotely logging in to the server using the rlogin command from their workstations. We use this example to illustrate our technique throughout the remainder of the paper, but first we must discuss model checking in the context of network security.
4. Model checking network security
A model checking specification consists of two parts. One part is the model: a state machine defined in terms of variables, initial values for the variables, and a description of the conditions under which variables may change value. The second part is temporal logic constraints over states and execution paths. Conceptually, a model checker visits all reachable states and verifies that the temporal logic properties are satisfied over each possible path, that is, the model checker determines if the state machine is a model for the temporal logic formula. Model checkers exploit clever ways of avoiding brute force exploration of the state space, for example, see [4]. If a property is not satisfied, the model checker attempts to generate a counterexample in the form of a trace or sequence of states. For some temporal logic properties, no counterexample is possible. For example, if the property states that at least one possible execution path leads to a certain state and in fact no execution path leads to that state, there is no counterexample to exhibit.
The model checking approach to formal methods has received considerable attention in the literature, and readily available tools such as SMV, SPIN, and Murø are capable of handling the state spaces associated with realistic problems [6]. We use the SMV model checker, which is
s s e r d d A e c r u o SourceAddress SourceAddress SourceAddress SSourceAddress DDDDDeeeeessssstttttiiiiinnnnnaaaaatttttiiiiiooooonnnnnAAAAAddddddddddrrrrreeeeessssssssss AAAAAccccctttttiiiiiooooonnnnn y n A 192.168.1.4 Allow 4 2 / 0 . 1 . 8 6 1 . 2 9 1 Not192.168.1.4 Allow y n A Any Deny
Internet
Attacker Border Router Public Web Server 192.168.1.4 Private File Server 192.168.1.100 192.168.1.0/24 Private Workstationsfreely available from Carnegie Mellon University and elsewhere. Although model checking began as a method for verifying hardware designs, there is growing evidence that model checking can be applied with considerable automation to specifications for relatively large software systems, such as TCAS II [5]. Model checking has been successfully applied to a wide variety of practical problems. These include hardware design, protocol analysis, operating systems, reactive system analysis, fault tolerance, and security [8]. The chief advantage of model checking over the competing approach of theorem proving is complete automation. Human interaction is generally required to prove all but the most trivial theorems.
The increasing usefulness of model checkers for software systems makes model checkers attractive targets for use in aspects of software development other than pure analysis, which is their primary role today. Model checkers are desirable tools to incorporate because they are explicitly designed to handle large state spaces and they generate counterexamples efficiently. Thus they provide a mechanism to avoid custom building these same capabilities into special purpose tools. For these reasons, in this paper we encode the security of a computer network in a finite state description and then write assertions in the temporal logic to the effect that “an attacker can never acquire certain rights on a given host.” We then use the model checker to verify that the claim holds in the model or to generate an attack scenario against the network that shows how the attacker penetrates the system.
There are several advantages to using a model checker over custom built analysis engines for the search problem at the heart of this paper. First, although it is possible in theory to repeat the implementation of a model checker in a security analysis engine, such an approach would require a significant investment of resources and this investment is typically not done [10][15]. As a result, custom analysis methods tend to be more limited, both in the size of the state space that can be handled and in the types of queries that can be posed. With respect to the latter, we argue that the temporal logics supported by model checkers offer a rich language for specifying security requirements. Put another way, the requirements of a security policy, such a “a certain class of machines should only be accessible by the following types of users” have relatively straight forward translations into temporal logics.
4.1. Description of the model
There are four major elements that make up our network security model.
· Hosts on the network including their vulnerabilities · Connectivity of the hosts
· Current point of view of the attacker
· Exploits that can be used to change the state of the model.
Host Descriptions
Hosts are described by their starting set of vulnerabilities and the current access level of the attacker within the host. In our model, a vulnerability is any feature of a system that could possible be a factor in any exploit attempt. This includes obvious security problems, such as running an outdated version of sendmail. It also includes general configuration information about the host, such as operating system type and version, type of authentication, maximum length of passwords, and network services by software type and version.
It is worth reiterating that our definition of vulnerability is quite broad. For our model, vulnerability is any observable system attribute that could possibly be used as a prerequisite for an exploit. Therefore, the domain of the set of vulnerabilities can be defined by the total set of all vulnerabilities that exist in the union of all prerequisites for all exploits known by the model.
Access level is used to determine whether an attacker has the right to execute programs on a host. This can be equated to user group membership. There are two special access levels, none and root. Access level none means the attacker has no ability to execute programs on the host. Access level root means the attacker can execute any program on the host. If access level is not none, the attacker can execute programs with whatever user rights are granted by the current access level. Though we have not shown it in our example, access level can also be used to model denial of service attacks. This would require a third special case that would reflect a state different from none, but still deny an attacker the ability to attack from the host’s point of view.
Connectivity
Connectivity is defined as a host’s ability to communicate with other hosts in the model. Because a key security technique is network layer filtering, it is important for the model to be able to represent the connectivity between hosts that remains after all filters that exist between the hosts have been examined. Unlike vulnerabilities and access level, connectivity can not change during the analysis. Instead attacker point of view is used to allow changes in the filtering that may occur upon a successful exploit by an attacker.
Attacker Point of View
Attacker point of view is defined as the host within the model that the attacker is currently attacking from. If an attacker can gain sufficient access to a host, it is possible
for the attacker to use the host to launch exploits. This new launch point for the attack may allow the attacker to circumvent network filters. Any host with an access level higher than none may potentially be used to launch an exploit.
Exploits
Exploits are defined by the set of vulnerabilities, source access level, target access level, and connectivity they require, plus the results they have on the state of the model if they are successful. Exploits are used by the model to affect changes to the security of the hosts under analysis. The quality and quantity of exploits encoded in the model have a direct relationship with the quality of the analysis that can be performed with the model.
4.2. Initialization of the model
Four main efforts need to be undertaken to populate our model. · Exploit description · Host initialization · Connectivity description · Failure definition. Exploit Description
Each exploit included in the analysis must be described in terms of its required prerequisite vulnerabilities, required access levels on the host being used to launch the attack, required access level on the target of the attack, and results of the attack if the exploit is successful. The prerequisites, source access level, and target access level are converted into a boolean statement that is used to test a host under attack. If the statement is true and the attacker has connectivity to the host, the exploit will succeed and the results for the exploit will be applied to the host. The possible changes to the host include additional vulnerabilities being added to the host and changes to the attacker’s current access level on the host. Table 2 shows a sample using the phf exploit.
Table 2. Sample exploit
Host Initialization
The second initialization step for the model is determining which vulnerabilities should be assigned to the hosts that make up the network. This is done by carefully
reviewing the configuration of each host. For our example we have conducted this review manually. It is entirely feasible though to produce tools that would search for the vulnerabilities automatically. Tools that perform host security scanning such as COPS, or Internet Security System’s System Scanner are good examples of this type of capability. The tool would need to be customized to search for the set of vulnerabilities currently defined by the prerequisites of the model’s set of exploits. As new exploits are encoded into the model, the tool would need to be extended to search for any new prerequisites required by the new exploits. Table 3 shows a sample initialization for a typical host.
Table 3. Sample host -- PublicWebServer
In addition to the vulnerability list, the initial current access level for each host must be assigned. One of the useful features of our technique is the ability to model different attacker scenarios by modifying the starting values of current access level. For an external attack, access level would normally be set to none for all hosts on the network. If we are trying to model an attack by an employee or other trusted individual, we may want to start the attacker with higher access privileges on some hosts.
Connectivity Description
The third step during the initialization is to decide which hosts can communicate with which hosts. As with host initialization, this step can be automated. There are many network discovery tools available that could be scripted to execute from each host that is to be included in the model. The results could be tabulated to create the network connectivity matrix. A more interesting approach is presented in FANG [10]. Their method builds a model of the network connectivity by analyzing the configuration of each network filtering device that exist on the network.
In our SMV example we have modeled connectivity with a boolean matrix that has the distinct disadvantage of not allowing our model to describe partial connectivity. This choice was made to simplify our example. It would be an easy task to add a richer connectivity description to our method that includes common network connectivity details such as port numbers. Table 4 shows the connectivity matrix for our example network.
s e t i s i u q e r e r Prerequisites Prerequisites Prerequisites Prerequisites P SSSSSooooouuuuurrrrrccccceeeee l e v e L s s e c c A t e g r a Target Target Target Target T l e v e L s s e c c A RRRRReeeeesssssuuuuullllltttttsssss 4 . 0 . 1 o t p u s n o i s r e v e h c a p A ( ) a 5 . 1 o t p u s n o i s r e v A S C N R O m a r g o r p f h p D N A Y N A ANY l e v e l s s e c c A o t d e g n a h c d p t t h s e i t i l i b a r e n l u Vulnerabilities Vulnerabilities Vulnerabilities Vulnerabilities V CCCCCuuuuurrrrrrrrrreeeeennnnntttttAAAAAcccccccccceeeeessssssssssLLLLLeeeeevvvvveeeeelllll 1 . 5 . 2 n o i s r e v s i r a l o S 4 0 . 1 n o i s r e v e h c a p A i g c .t n u o c i g c .f h p d t e n l e t d p t f r e h t a g p p a t d e n o N
Table 4. Connectivity matrix
Failure Definition
To allow the model checker to know when it has discovered a state worth reporting, the model must include statements that indicate a security failure. These are written as invariant statements in the model checker’s temporal logic formula language. In SMV’s specification language AG designates a statement that should be true in every state, i.e. an invariant. If we want SMV to verify that an external attacker could never gain access to the file server we would write the following specification statement.
AG PrivateFileServer.Access = None
If the model checker can reach any state where this statement is false then we know that it is possible for an external attacker to gain some level of access to the private server.
4.3. Analyses method
To perform the analysis, a search is conducted from the initial point of view of the attacker for a host that the attacker can communicate with and that includes all the prerequisite vulnerabilities for one of the exploits known to the model. If these requirements are met, then the model can change state based on the rules defined for the exploit. This could result in additional vulnerabilities being added to the target host’s set of vulnerabilities, or changes to the attacker’s current access level on the host.
If a host exists on the network with an access level above none, the model can also change the attacker’s current point of view to the host. In most cases this will change the set of hosts that the attacker can reach.
Each of these results represent a change to the state of the model and a general reduction in the security of the network. These changes may allow other exploits to be employed further reducing the security of the network. Eventually a state will be reached where one of our invariant statements has been violated or no more exploits can be employed.
4.4. Counterexamples
When a model checker is able to prove one of the specification statements untrue, it produces a report detailing the order of states that was required to reach the state that disproves the specification statement. Since every state change in our model is the result of an exploit, the counterexample represents the series of exploits that need to be run to achieve the level of network break-in defined by the security invariant that has been violated. This represents an attacker scenario for the network (see figure 3).
Figure 3. Counter example generation
Taking the example from figure 1, if the security invariant was
AG ! host.access = root
then the last state in the figure would prove the invariant false. The counterexample produced by the model checker in this case would duplicate the state list and order that is shown in figure 1.
5. Encoding the example model in SMV
This section will describe how we translated our network model into the SMV [14] model checking language. It is important to note that most of this translation is mechanical; i.e. it is entirely feasible to automate this translation. Indeed this would be required before this technique would be practical for the analysis of real networks.
Our technique should be applicable to several model checking tools including SPIN [8] and Murø [11]. We chose to use SMV because of our previous familiarity with the tool. r e k c a t t Attacker Attacker Attacker Attacker A BBBBBooooorrrrrdddddeeeeerrrrr r e t u o R b e W c i l b u PublicWeb PublicWeb PublicWeb PublicWeb P r e v r e S e l i F e t a v i r PrivateFile PrivateFile PrivateFile PrivateFile P r e v r e S r e k c a t t Attacker Attacker Attacker AAttacker N/A Yes Yes No r e t u o R r e d r o BorderRouter BorderRouter BorderRouter BBorderRouter Yes N/A Yes Yes b e W c i l b u PublicWeb PublicWeb PublicWeb PPublicWeb r e v r e S Yes Yes N/A Yes e l i F e t a v i r PrivateFile PrivateFile PrivateFile PPrivateFile r e v r e S No Yes Yes N/A
5.1. Hosts
As described earlier, hosts are described by their vulnerabilities and the current access level of the attacker on the host. In addition to these we needed to add the exploits that have been used successfully against the host and a host id used to index into the connection matrix.
The exploit set is used to allow the model to remember what exploits have been used against a host. Our model uses separate attack and result modules. When an attack is successful, it is recorded in the exploit set. The result module reads this array to determine when the affects of an exploit should be applied to a host.
Here is the host module that we used in our example.
MODULE machine VAR
access : { none, user, root }; — records - current attacker access level on this - host
exploit : array 1..6 of boolean; — records - which of the six exploits in the model — have been used against the host
hostid : { 1, 2, 3, 4}; — used to index into - the row and column of the connection - table
vulnerability : array 1..15 of boolean; - records which of the 15 vulnerabilities - in the model that the host currently has
SMV does not support a set variable so we have represented the host’s vulnerability set as a boolean array. Each vulnerability known to the system is assigned a unique, sequentially assigned ID that is used to index into the host’s vulnerability array. The host’s exploit set is similarly implemented.
Each variable in the host must be given specific starting values. Exploits are initialized by setting each value in the array to zero. init(exploit[1]) := 0; init(exploit[2]) := 0; init(exploit[3]) := 0; init(exploit[4]) := 0; init(exploit[5]) := 0; init(exploit[6]) := 0;
Hostid is sequentially assigned to each host and is used to index into the row and column of the connectivity matrix. The attacker is assigned hostid one, so the hostid numbering starts at two. Since hostid does not change once it is assigned, we must assign both an initial value and a next value in SMV to prevent the model checker from changing the value. init(BorderRouter.hostid) := 2; next(BorderRouter.hostid) := 2; init(PublicWebServer.hostid) := 3; next(PublicWebServer.hostid) := 3; init(PrivateFileServer.hostid) := 4; next(PrivateFileServer.hostid) := 4;
Vulnerabilities are assigned by examining the total set of vulnerabilities in the model to determine the vulnerabilities that exist for a particular host. Here is a partial initialization for the PublicWebServer’s vulnerability set.
init(PublicWebServer.vulnerability[1]) := 1; — Apache/1.04
init(PublicWebServer.vulnerability[2]) := 0; — home directories exported rw (ALL) init(PublicWebServer.vulnerability[3]) := 0; — ftpd init(PublicWebServer.vulnerability[4]) := 0; — nfsd init(PublicWebServer.vulnerability[5]) := 1; — No shadow file
It is important to note that the host exploit and vulnerability arrays are sized based on the total number of exploits and vulnerabilities that are described in the model. If the model must represent a large number of vulnerabilities and exploits these arrays will also be large. Since the addition of vulnerabilities and exploits is a large part of how this model reasons, the size of these arrays has a direct impact on the size of the state space.
Access is set to the appropriate access level for the scenario that is being modeled. For an external attack, access level is normally set to none for all hosts on the network.
init(PublicWebServer.access) := none; 5.2. Connectivity matrix
The connectivity matrix is used to determine whether a host can communicate with another host. The matrix is represented by an array of an array of boolean values. The host ids for the source and destination hosts are used to index into the row and column of the matrix to determine if communication is possible. This example shows the attacker’s connectivity being initialized.
init(Connect[1][1]) := 1; next(Connect[1][1]) := 1; — Attacker to Attacker init(Connect[1][2]) := 1; next(Connect[1][2]) := 1; — Attacker to BorderRouter
init(Connect[1][3]) := 1; next(Connect[1][3]) := 1; — Attacker to PublicWebServer init(Connect[1][4]) := 0; next(Connect[1][4]) := 0; — Attacker to PrivateFileServer 5.3. Exploits
Exploits are implemented in two modules of the model, attack and result.
Attack Module
In the attack module, an exploit is described by a case statement that determines whether all of the prerequisites for the exploit have been met. If they are met, the case statement adds the exploit to the host’s exploit set.
Here is an example of the phf vulnerability exploit’s implementation in the attack module.
next(m.exploit[4]) := — PHF.cgi case
— Make sure that we are attempting the - current exploit
a = 4 &
— Check that we have sufficient - connectivity for this exploit (
(src = 1 & m.hostid = 1 & conn[1][1]) | (src = 1 & m.hostid = 2 & conn[1][2]) | (src = 1 & m.hostid = 3 & conn[1][3]) | (src = 1 & m.hostid = 4 & conn[1][4]) | (src = 2 & m.hostid = 1 & conn[2][1]) | (src = 2 & m.hostid = 2 & conn[2][2]) | (src = 2 & m.hostid = 3 & conn[2][3]) | (src = 2 & m.hostid = 4 & conn[2][4]) | (src = 3 & m.hostid = 1 & conn[3][1]) | (src = 3 & m.hostid = 2 & conn[3][2]) | (src = 3 & m.hostid = 3 & conn[3][3]) | (src = 3 & m.hostid = 4 & conn[3][4]) | (src = 4 & m.hostid = 1 & conn[4][1]) | (src = 4 & m.hostid = 2 & conn[4][2]) | (src = 4 & m.hostid = 3 & conn[4][3]) | (src = 4 & m.hostid = 4 & conn[4][4]) ) &
— Check for required prerequisite - vulnerabilities
m.vulnerability[1] & — Apache/1.04 m.vulnerability[6] — PHF.cgi : 1; — Exploit successful 1 : m.exploit[4]; — Exploit failed esac;
The a variable tested at the top of the case statement is set at the top of the attack module. It is used to prevent SMV from applying more than one exploit at a time. Before each attack a is nondeterministically assigned a value from
1 to the total number of exploits. This number is used to determine the exploit that the model will attempt next.
The next series of statements checks for sufficient connectivity. The nested nature of the check is required because SMV requires that terms on the left hand side of a case statement be static. A statement of the form conn[src][dst] is not allowed because src and dst are variables.
The last check is for the exploit’s prerequisites. In the case of the PHF exploit, these are a vulnerable version of the Apache web server and a copy of the PHF.cgi program located in the web server’s cgi-bin directory.
Result Module
The result module uses the host’s exploit array to determine whether to add vulnerabilities to the host and whether to change the attacker’s access level on the host.
Each vulnerability that may change has a case statement associated with it that checks to see if any exploit that would add the vulnerability has been set on the host.
For example, the following code is used to check if the “password hashes known” vulnerability should be added to the host.
next(m.vulnerability[7]) := — Password Hashes Known case
m.exploit[3] : 1;
— Capture Password Hashes
1 : m.vulnerability[7];
esac;
Access level is set by checking for each exploit that causes an access level change.
next(m.access) := case
m.exploit[4] | — PHF.cgi OR
m.exploit[6] — shell login as user : user;
m.exploit[5] : root; — shell login as root 1 : m.access;
esac;
5.4. Example results
The example network described in Section 3 was translated into our model and presented to SMV. We used the invariant AG !(PrivateFileServer = root).
The following is the counterexample produced that shows how the PrivateFileServer might be taken over from an external attacker.
State 2.1:
— many lines of initialization omitted — source = 1
state 2.2:
AttackPublicWebServer.a = 4
[executing process AttackPublicWebServer] state 2.3:
PublicWebServer.exploit[4] = 1 AttackPublicWebServer.a = 6
[executing process ResultPublicWebServer] state 2.4:
PublicWebServer.access = user AttackPublicWebServer.a = 3
[executing process AttackPublicWebServer] state 2.5:
PublicWebServer.exploit[3] = 1 PublicWebServer.exploit[4] = 0 AttackPublicWebServer.a = 6
[executing process ResultPublicWebServer] state 2.6:
PublicWebServer.vulnerability[7] = 1 AttackPublicWebServer.a = 2
[executing process AttackPublicWebServer] state 2.7:
PublicWebServer.exploit[2] = 1 PublicWebServer.exploit[3] = 0 AttackPublicWebServer.a = 6
[executing process ResultPublicWebServer] state 2.8:
PublicWebServer.vulnerability[9] = 1 AttackPublicWebServer.a = 5
[executing process AttackPublicWebServer] state 2.9:
PublicWebServer.exploit[2] = 0 PublicWebServer.exploit[5] = 1 AttackPublicWebServer.a = 6
[executing process ResultPublicWebServer] state 2.10: PublicWebServer.access = root PublicWebServer.vulnerability[15] = 1 [stuttering] state 2.11: source = 3 AttackPrivateFileServer.a = 5
[executing process AttackPrivateFileServer] state 2.12:
PrivateFileServer.exploit[5] = 1 AttackPrivateFileServer.a = 6
[executing process ResultPrivateFileServer] state 2.13:
PrivateFileServer.access = root
PrivateFileServer.vulnerability[15] = 1 [stuttering]
After the initialization state 2.1, the model will start to alternate between running the attack and result modules for the host that is currently under attack. This counterexample starts off attacking the PublicWebServer from the point of view of the external attacker. This can be determined by noting that in state 2.1, source is set to 1 (the attacker) and in state 2.2, the PublicWebServerAttack module is being executed. From states 2.2 though 2.10 the attack and result modules for PublicWebServer are executed one after the other. You can determine which exploit is being attempted in each attack by looking at the value of the a variable. In the result module executions, you can see any resulting change of access or addition of vulnerability applied to the host.
The following table illustrates the complete exploit scenario as derived from the counterexample.
Table 5. Counterexample result for the example network
It is interesting to note that when we created this example we had intended that the attacker be forced to use the overly permissive nfs share to add a trust relationship between the PublicWebServer and the PrivateFileServer. We had forgotten that during implementation of the model we had decided that it would be likely that these servers would have BSD trusts set up between them. When we ran the analysis we were a bit surprised when the model checker (correctly) omitted the “Add BSD trust relationship” exploit from its counterexample. e c r u o Source Source Source SSource TTTTTaaaaarrrrrgggggeeeeettttt EEEEExxxxxpppppllllloooootititititi RRRRReeeeesssssuuuuutltltltltl r e k c a H PubilcWebServer phf UseraccessonPubilcWebServer r e k c a H PubilcWebServer Capturepwdhashes PubilcWebServe'rspassword r e k c a h o t n w o n k s e h s a h r e k c a H PubilcWebServer BruteForcePasswords HroaoctkpearsksnwoowrdsPubilcWebServe'rs r e k c a H PubilcWebServer Shellloginasroot HPuabckilceW'rsebacSceervsserlecvhealnognedtoroot r e v r e S b e W c il b u P PrivateFlieServer Shellloginasroot HPraivcakteeF'rslieaScceervsserlecvhealnognedtoroot
6. Conclusion
There two key features of our analysis technique that we believe provide substantial benefit to the analysis of network security. First, the technique automatically explores the total security ramification of a vulnerability that is accessible to an attacker. Using this technique it is easy to demonstrate why defense in depth is important in the design of network security. Second, the technique allows multiple attack scenarios to be tested using the same model description. Once the model has been set up it is a trivial modification to show what access can be gained by allowing the attacker to start with different levels of access into the system. To model an inside attack requires that the host the insider would start on have its access level changed to the level appropriate to the user (frequently this would grant root access on this host to the attacker). It may also be interesting to see what level of access an external attacker would have if they already have gained a foothold on one of the network’s public servers. This is useful to model the results of a new vulnerability being discovered in one of the public services the network offers to external users.
Acknowledgements
The authors are grateful to several people for assistance with the creation of this paper. We would like to specifically thank Brian O’Berry and Scott Bisker for reviewing the paper and making suggestions concerning the example exploits we should include. We would also like to thank Sharon Ritchey for editing the drafts and providing support throughout the duration of this effort.
7. References
[1] Apache Web Server information and software on the web at <http://www.apache.com>.
[2] R. Baldwin, Kuang: Rule-based security checking. Information at <ftp://ftp.cert.org/pub/tools/cops/ 1.04/cops.104.tar>.
[3] B. Beizer, Software Testing Techniques, 2nd edition,
Thomson Computer Press, 1990.
[4] J. Birch, E. Clarke, K. McMillan, D. Dill, and L.J. Hwang, Symbolic Model Checking: 1020 States and
Beyond, Proceedings of the ACM/SIGDA
International Workshop in Formal Methods in VLSI Design, January 1991.
[5] W. Chan, R. Anderson, P. Beame, S. Burns, F. Modugno, and D. Notkin, “Model Checking Large Software Specifications”, IEEE Transactions on Software Engineering, 24(7):498-520, July 1998.
[6] E. Clarke, O. Grumberg, and D. Peled, Model Checking, Cambridge, MA: MIT Press, 2000. [7] Computer Oracle and Password System (COPS)
information and software on the web at <ftp.cert.org/pub/tools/cops>.
[8] G. Holzmann, “The Model Checker SPIN”, IEEE Transactions on Software Engineering, 23(5):279-295, May 1997.
[9] Internet Security Systems, System Scanner information on the web at <http://www.iss.net>. [10] A. Mayer, A. Wool, E. Ziskind. Fang: A Firewall
Analysis Engine, In Proceedings of the IEEE Symposium on Security and Privacy, Oakland, CA, May 2000.
[11] J.C. Mitchell, M. Mitchell, and U. Stern, Automated analysis of cryptographic protocols using Murø, In Proceedings of the IEEE Symposium on Security and Privacy, 141-151, Oakland, CA, May 1997. [12] Network Associates, CyberCop Scanner information
on the web at <http://www.nai.com/asp_set/ products/tns/ccscanner_intro.asp>.
[13]RedHat Linux information and software on the web at <http://www.redhat.com>.
[14]SMV information and software on the web at <http:// www.cs.cmu.edu/~modelcheck>.
[15] D. Zerkle, K. Levitt, NetKuang – A Multi-Host Configuration Vulnerability Checker, In Proceedings of the Sixth USENIX Unix Security Symposium, San Jose, CA, 1996.