> StackGuard: Automatic Detection and Prevention of Buffer-Overflow Attacks >From the online paper: > StackGuard detects and defeats stack smashing attacks by protecting the > return address on the stack from being altered. StackGuard has two > mechanisms to protect the return address: one provides greater assurance, > and the other provides greater performance. You are only protecting the return address. This means many programs will still be vulnerable to overflow attacks. In particular you don't protect the overflow of locals in a procedure, nor the overflow of globals in the data segment or heap. While it does stop the "cookbook" stack overflow attacks, it does not really put an end to the problem. Consider for example the following (contrived but not entirely fictional) examples: int save_uid; char buf[10]; save_uid = getuid(); setuid(0); fp = fopen("input", "r"); fscanf(fp, "%s", buf); setuid(save_uid); overflowing the buffer will allow the user to increase his priveledge for the duration of the program execution, which may be a very bad thing. int x, *ptr; char buf[10]; ptr = get_some_pointer(); x = compute_some_value(); strcpy(buf, getenv("SOME_ENV")); *ptr = x; overflowing the buffer allows the user to overwrite any 4 bytes in the entire program. Clearly not good. char cmdbuf[100], username[10]; cmdbuf[0] = 0; strcat(cmdbuf, "/bin/cat "); strcat(cmdbuf, filename); getusername(username); if(strcmp(username, "foobar") == 0) return; system(cmdbuf); overflowing the username buffer allows an attacker to overwrite the buffer that gets past to system(). Not good. These are just examples of attacks involving locals. Attackers can also overwrite globals that are in the data and bss segments as well as globals allocated dynamically on the heap. The end result is that an attacker can overwrite data in a security critical program that was never intended to be user changeable. This changes the entire security dynamics of the program. The program may still be secure after the change, or it may not be. The attackers job is then to find out how to manipulate the program given the constraints of the buffer he can overflow. Further in the paper you discuss two techniques that can be used: > The higher performance StackGuard mechanism is to instrument the stack > frame with a "canary" word laid right next to the return address on > the stack. If an attacker attempts to smash the stack and change the > return address, the attacker will necessarily overwrite the canary word as > well. The code emitted by the compiler to do function returns is enhanced > to check the integrity of the stack by looking for the canary word: if > the canary word has been changed, the program aborts instead of yielding > control to the attacker. The canary word is selected at random when > the process starts, to make it difficult for the attacker to guess the > canary value. Obviously this technique is not totally secure (which you note by calling the second technique "high assurance"). By adjusting the size of the "canary" you can probably reduce the chances of effective guessing of the canary pretty low (assuming you have a good source of true randomness). Obviously if the canary is a small value of say 16 bits, an attacker can trivially brute force it (setting off alarms along the way.. but hey, he can clean up afterwards). I assume you picked an integer value that fits nicely on the stack or a 64 bit quantity for extra assurance. A clever attacker may be able to trick the program into disclosing the canary value though. For example if he has more than one overflow, or an overflow that is repeated several times with different input. In this case he can overflow the buffer right up to the value before the canary, watch the resulting behavior of the program to infer the canary, and then construct a second overflow with the proper canary value in it. As an example: char filename[100], username[10]; strcpy(filename, queuename); strcat(filename, ".dat"); getusername(username); if(!authorized_user(userlist, username)) return 0; fd = open(filename, O_READ); if(fd == -1) { perror(filename); return -1; } An attacker can cause "filename" to extend right up to the canary value (and then continue running till the next nul byte on the stack) to get the canary value. > The higher assurance StackGuard mechanism utilizes a tool from the > Synthetix project called MemGuard. MemGuard provides fine-grained > memory protection, down to the size of a single word. The MemGuard > variant of StackGuard applies MemGuard's protect() to the return > address when a function starts, and releases the protection of the return > address when the function finishes. If any part of the program ever tries > to alter the return address (which is not normal behavior) then the MemGuard > memory protection mechanism detects the write to protected > data, and aborts the program. A much safer technique than the canary technique, but it comes at a considerable performance penalty. I may be willing to let some small utilities on my system run with this loss of performance. I doubt many people would make all the security critical programs on their system run with this degraded performance, especially large performance critical daemons like sendmail and httpd. So in summary: You reduced, but did not eliminate, the number of buffer overflow problems that allow a user to hijack the program. The first of your techniques does not eliminate as many of these problems as the second technique, but the second technique is unattractive due to its performance impact. Even with the best of these techniques implemented, there will still be a number of security problems left in the system due to buffer overflows. Comments: If you fix the root of the problem, you can eliminate all the problems. If you make a fix that combats one of the common attacks against a problem, you may make quicker progress, but you cannot address the entire problem. In addition you may affect performance (memory protection) or functionality (allowing execution of code on the stack). My personal feelings on the recent proposals for fixing "the overflow problem" is that I don't like them. They all seem hacky to me, and all claim to be a silver bullet to finally put an end to the problem. I much rather see the original problems fixed, a solution that is much more aesthetically pleasing to me. On the other hand the proposals do reduce the number of attacks, and buy time until attackers get more sophisticated in their exploits. > Crispin Cowan, Research Assistant Professor of Computer Science > PO Box 91000 | digital: crispinat_private Tim N.
This archive was generated by hypermail 2b30 : Fri Apr 13 2001 - 13:37:02 PDT