Advertisements
Home > Information Technology, Science, Security > Security I: Exercise 1

Security I: Exercise 1

Problem 1: Real and eff ective user ID (5 points)

Every Unix process is associated with a real user ID (RUID) as well as an effective user ID (EUID).

(a) (1 point) Which of them is used by the OS to determine whether aprocess has the right to access a resource or not?

(b) (1 point)What happens to the RUID and EUID when a process spawns a new child process using fork? What RUID and EUID will the child process have?

(c) (1 point) What happens to the RUID and EUID when a process activates an executable file (e.g. by calling exec) whose setuid bit is not set.

(d) (1 point) What happens to the RUID and EUID when a process activates an executable file whose setuid bit is set.

(e) (1 point) In most flavors of Unix the setuid family of functions allows setting the EUID of a process to its RUID. Can you think of a reason to do this in a process running as root (EUID=0)?

Solution

(a) The EUID.

(b) The RUID and EUID of the parent process stay unchanged. The RUID of the child process is copied from the RUID of the parent. Similarly,the EUID of the child process is copied from the EUID of the parent.

(c) They stay unchanged.

(d) The EUID changes to the UID of the user owning the executable file.

(e) Setting the EUID to the RUID allows the process to drop the root privileges. Depending on the details of the specific setuid call and of the operating system, root privileges can be dropped temporarily or permanently when they are no longer needed.

A good reason to drop privileges permanently is in order to limit the impact of security vulnerabilities. A programming error in a program executed as root (EUID=0) may allow an adversary to obtain the root privilege and compromise the security of the whole system. The principle of least privilege states that: every program and every user should operate using the least amount of privilege necessary to complete the job. If one wants to respect this principle one should permanently drop root privileges when they are no longer needed. Dropping privileges temporarily is useful when a process wants to perform certain operations with the permissions of the invoking user (the RUID), but afterwards wants to restore its root privileges. For instance, in Unix is notoriously difficult for a process running as root (EUID=0) to determine whether the invoking user (the RUID) has permissions to open a fi le. The naive way to do this would be to use the access function whose very purpose is to check whether the RUID has permissions to access the fi le and if this is indeed the case then open the fi le (as root this will always work).

if (access(file, R_OK) != 0)

exit(1);

fd = open(file, O_RDONLY);

However, this leads to a TOCTTOU race condition. The vulnerability is very similar to the one in Problem 2, and can be exploited in the same way. One way to avoid this vulnerability is to temporarily drop root privileges, open the file with the privileges of the user, and then restore root privileges.

Problem 2: Race condition (4 points + 2 bonus)

Consider the following code snippet:

if (!stat(“./file.txt”, buf)) return; // Abort if file exists.

sleep(10); // Sleep for 10 seconds.

fp = fopen(“./file.txt”, “w” );

fprintf(fp, “Hello world” );

close(fp);

Unix function stat returns 0 if ./file.txt already exists, while sleep(10) suspends execution for a minimum of 10 seconds. The call fopen(“./file.txt”,”w”) creates a fi le for writing.

(a) (2 points) Suppose this code is compiled to an executable that is owned by root and has the setuid bit set. Explain how this can lead to unexpected behavior that causes a security vulnerability. (Hint: try using symbolic links.)

Program (root) Attacker
(* ./file.txt does not exist *)
stat(“./file.txt”, buf) 

(* stat returns -1 *)

sleep(10);

ln -s /etc/shadow ./file.txt 

(* creates symbolic link *)

fopen(“./file.txt”, “w” ) 

(* empties /etc/shadow *)

(b) (2 points) Suppose that sleep(10) is removed from the code above. Could the vulnerability you identi ed in part (a) still occur? Please explain why or why not.
(c) (2 bonus points) How would you x the code to prevent the vulnerability from part (a)? (Note: Your solution can be operating system dependent.)

Solution

(a) Since checking whether ./file.txt already exists using stat and opening a fi le named ./file.txt are not performed as an atomic transaction, an attacker can create a fi le named ./file.txt after the check but before the call to fopen. Instead of creating a new fi le as intended, the fopen is going to overwrite the fi le the attacker has created(fopen with a “w” argument immediately truncates the fi le to zero length). If at the right time the attacker creates a symbolic link to an important system fi le and names it ./file.txt the program is going to overwrite the contents of the system fi le. Since the program is running as root this will not be prohibited by the operating system, and constitutes a very severe security vulnerability. Because the program is sleeping for 10 seconds the attacker does not need any special mechanism to enforce it gets scheduled at the right time. Figure 1 illustrates this. Such “time of check to time of use” (TOCTTOU) race conditions are common programming errors, in particular for file systems with weak consistency semantics where mapping between fi le names and fi le objects(e.g. inodes) is mutable by design, and can change between a status check and a subsequent operation. Normal Unix and Windows fi le systems fall into this category, and poorly designed OS APIs (e. g. the access function in Unix) make the situation only worse.

(b) Removing sleep(10) from the code does not fix the vulnerability. It only makes it slightly harder to exploit, since the attacker now needs to ensure that it gets scheduled between stat and fopen. It is not too hard for an attacker though to force since the stat takes a very long time to execute, so that he can very reliably win this race (probability  1).There are many ways to do this, but we will use the idea introduced by Borisov et. al. in a paper named “Fixing Races for Fun and Pro fit”.In order to force stat to take very long (but still to fail in the end and return -1) we can create from the start a fi le named ./file.txt that is a symbolic link to a very long path such as: chain/d/d/d/d/d/…/d/.Since on most systems the length of the path cannot exceed a certain length (4K is a typical value) Borisov et. al. propose to chain many such paths into a structure they call a “fi le system maze”. As illustrated in Figure 2, the attacker connects chains by placing a symbolic link at the bottom of chain i+1 that points to chain i. Unix systems impose a limit on the total number of symbolic links that a single file name lookup can traverse (e.g., Linux 2.6 limits this number to 40). Still, even with this limit, a fi le system maze can be composed of nearly 80000 directories which may require loading about 300MB from the disk, just to resolve the associated name. In our case the exit from the maze can be a broken symbolic link, so that in the end stat returns -1, which will be interpreted by the victim program as ./file.txt not existing. Before this happens however, while the victim is still in the maze, the attacker can change ./file.txt so that it points to an important system fi le. Once the victim exits the maze it will open the system file and overwrite it. Figure 3 illustrates this. Another way for an attacker to slow down stat is by creating many files in the parent directory so that name resolution takes a long time. Because of caching this attack technique is not as reliable as the one using fi le system mazes, still it could allow an attacker to win the race with high enough probability. Another simple (but probably not very reliable) way an attacker could try to exploit this is by running a very time consuming process, that considerably slows down the whole system. He can at the same time repeatedly call the vulnerable program and right away create the symlink. After each failed attempt the attacker can delete the symlink, and try again until he wins the race.

(c) The best way to fix this problem is to eliminate the race by performing the check and the open atomically. This cannot be done in a portable way in C however, and requires support from the operating system. On Unix systems that conform to POSIX, the open function accepts the O_CREAT and O_EXCL ags. When used together, these ags instruct the open function to fail if the fi le to be opened already exists.

fd = open(“./file.txt”, O_CREAT | O_EXCL | O_WRONLY);

if (fd != -1) {fp = fdopen(fd, “w”); // convert descriptor to FILE*

if (fp != NULL) {

fprintf(fp, “Hello world” );

close(fp);

}

}

An equivalent solution if you use the GNU C library is to add the`x’ character when opening the fi le with fopen. This guarantees that opening fails if the fi le exists.

fp = fopen(“./file.txt”, “wx”);

if (fp != NULL) {

fprintf(fp, “Hello world” );

close(fp);

}

On systems that support directory locking, another solution is to lock the directory containing file.txt and its parents before the check and only unlock it after the open. This way no other process is able to create a new fi le (e.g. the symbolic link to the important system fi le) or modify a fi le in this directory between the test and the creation. Note that locking file.txt itself (assuming it exists in the rst place, which makes no sense for this example) does not help fix the vulnerability: if the attacker has access to the parent directory he can simply remove the locked fi le and create a new one. Also note that here we are talking about mandatory locking that is enforced for all processes (e.g. using fcntl on a recent Linux version for a fi le-system that was mounted with the MS_MANDLOCK flag), not about advisory locks that are used for synchronization between cooperating processes (so the BSD flock function won’t work here). Finally, note that mandatory locking is not supported by most Unix systems. None of the solutions above is portable. Recently Tsafrir et. al. have proposed to portably solve TOCTTOU races using hardness ampli fication as found in cryptography. In a nutshell, if an adversary has probability p < 1 to win a race, then the probability pK to win K consecutive races can be made negligible by choosing K big enough. In theory at least. In practice things are a lot more complicated, as the lesystem maze attacks can force p to be extremely close to 1 if the hardness ampli cation defense is not properly implemented (the original defense described by Dean and Hu was completely broken by Borisov et. al. using mazes).

 

Problem 3: Virus detection mechanisms (6 points)

Please discuss whether the following techniques are useful detection mechanisms for polymorphic and metamorphic viruses, respectively:

(a) (2 points) Static pattern matching of the virus code: The virus scanner performs a pattern matching with the virus code (or parts of it) on the analyzed files.

(b) (2 points) Pattern matching during emulation: The virus scanner emulates a normal execution and checks at runtime (of the emulation) whether it can detect the virus code (or parts of it) via pattern matching.

(c) (2 points) Suspicious behaviour detection: The virus scanner tries to detect infected programs by checking whether a program behaves suspiciously. For our purposes assume that the virus scanner checks whether a program accesses sensitive fi les (such as the registry), performs a test whether another fi le is an executable, or performs a long sequence of eff ectless instructions (e.g., NOPs).

Hint: The paper Hunting for Metamorphic (by Peter Szor and Peter Ferrie) might contain useful information.

Solution

(a) Static pattern matching does not help for for metamorphic viruses. Metamorphic viruses change their code from generation to generation. Polymorphic viruses need to have some routine for unveiling the obfuscated code. This code might be always the same, in which case the virus is detectable by static pattern matching. If this code changes static pattern matching routines are not able to detect this piece of code.

(b) Pattern matching during emulation helps detecting polymorphic viruses that do not realize that they are being emulated. Metamorphic viruses are not vulnerable to pattern matching as they alter their code. However,even sophisticated polymorphic viruses are hard to detect as an undetectable emulation is so complex that it is practicably impossible.

(c) Both polymorphic and metamorphic viruses are vulnerable to suspicious behaviour detection. However, a virus could imitate the behaviour of an honest systems process that also accesses sensitive fi les, performs a test whether another fi le is executable or performs a long sequence of e ffectless instruction (e.g. Skype). Therefore, such a detection mechanism might cause an allergy such that the anti virus scanner detects honest behaviour as suspicious as well, making the system unable to work properly.

Prof. Michael Backes & Dr. Matteo Ma ei

Advertisements
  1. BruceV
    August 6, 2015 at 3:10 am

    Hi knowledgejunk.net admin, i see you need some fresh content. Daily updates will rank your blog in google higher, content is king nowadays. There is must have tool for every content writer, just search in google for:
    Ightsero’s Essential Tool

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s

%d bloggers like this: