免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2622 | 回复: 2
打印 上一主题 下一主题

stack操作原理 [复制链接]

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2004-01-17 13:03 |只看该作者 |倒序浏览
感觉这篇文章讲得不错,贴出来共享

--------------------------------------------------------------------------------

Buffer overflows in user input dependent buffers have become one of the biggest security hazards on the internet and to modern computing in general. This is because such an error can easily be made at programming level, and while invisible for the user who does not understand or cannot acquire the source code, many of those errors are easy to exploit.

What is Stack Smashing? For us to understand what Stack Smashing is, we need to understand some basic terminologies involved. Exploit: is a program designed to exploit a problem another program may have. The exploit will allow us to run arbitrary code that will allow us to do something we shouldn't.

Stack: is what a program uses to store temporary information such as our return address from a function that the program called, or a local variable.

SFP: Stack Frame Pointer. This is the start address of the stack.

RET: Return address. This is when a function was called, and the system saved where it was called. So when the function ends, it will read the return address and let the program return to where is left off. Now if we were to change the return address, we could point it to another address to execute something else.

How stacks work?

A stack is a contiguous block of memory containing data. A register called the stack pointer (SP) points to the top of the stack. The bottom of the stack is at a fixed address. It is to be noted that stack works with LIFO (Last In First Out) as the working principle.

The stack consists of logical stack frames that are pushed when calling a function and popped when returning. A stack frame contains the parameters to a function, its local variables, and the data necessary to recover the previous stack frame, including the value of the instruction pointer at the time of the function call.

Depending on the implementation, the stack will either grow down (towards lower memory addresses) or up. The stack pointer (SP) is also implementation dependent. It may point to the last address on the stack, or to the next free available address after the stack.

In addition to the stack pointer, which points to the top of the stack (lowest numerical address), it is often convenient to have a frame pointer (FP) which points to a fixed location within a frame. Some texts also refer to it as a local base pointer (LB). In principle, local variables could be referenced by giving their offsets from SP. However, as words are pushed onto the stack and popped from the stack, these offsets change. Although in some cases the compiler can keep track of the number of words on the stack and thus correct the offsets, in some cases it cannot, and in all cases considerable administration is required. Furthermore, on some machines, such as Intel-based processors, accessing a variable at a known distance from SP requires multiple instructions.

Consequently, many compilers use a second register, FP, for referencing both local variables and parameters because their distances from FP do not change with PUSHes and POPs. On Intel CPUs, BP (EBP) is used for this purpose. On the Motorola CPUs, any address register except A7 (the stack pointer) will do. Because the way our stack grows, actual parameters have positive offsets and local variables have negative offsets from FP. The first thing a procedure must do when called is save the previous FP (so it can be restored at procedure exit). Then it copies SP into FP to create the new FP, and advances SP to reserve space for the local variables. This code is called the procedure prolog. Upon procedure exit, the stack must be cleaned up again, something called the procedure epilog. The Intel ENTER and LEAVE instructions and the Motorola LINK and UNLINK instructions, have been provided to do most of the procedure prolog and epilog work efficiently.

What is Buffer Over Flow?

A buffer overflow is the result of putting to much data into a buffer than it can handle. So this may lead to us executing arbitrary code if a certain memory pointer is overwritten.

Buffer overflow attacks exploit a lack of bounds checking on the size of input being stored in a buffer array. By writing data past the end of an allocated array, the attacker can make arbitrary changes to program state stored adjacent to the array. By far, the most common data structure to corrupt in this fashion is the stack, called a ``stack smashing attack,'' which I briefly describe here.

There are two well-known types of buffer overflows. One based on the stack, the other on the heap. The most common of the two is the stack based overflow.

The following explanation tells what a Stack Smashing is.

To comprehend how stack smashing occurs, we first need to understand a little bit about buffers and instruction pointers. For example, say a program requires input from the user that is programmed to be a maximum of 256 bytes. There is a spot reserved in the computer's memory (a buffer) to store these 256 bytes or less. If the user inputs more than 256 bytes and the program does not check that this amount has been exceeded, he or she has overflowed the buffer. Since the computer needs a place to put these extra bytes, it generally puts them in a neighboring spot, overwriting what was already there.

There is another buffer in the computer's memory that stores the memory address of the next command to execute. This is called the instruction pointer. Continuing our example above, after reading the user's input, the next statement might be to print it to the screen. The instruction pointer would have as it's contents the memory address of this print statement. The computer gets the input from the user, stores it in the buffer, checks the instruction pointer to find what to execute next, finds the memory address of the print statement, retrieves the contents of the input buffer, and finally prints the user's input to the screen.

Now, putting the two together, if an attacker were able to overflow the buffer so that it modified the return address of the instruction pointer in such a way that it pointed to the attacker's code, they could do some clever things. And that is exactly what happens. The attacker overflows the buffer so that the memory address for the instruction pointer is the memory address of, in most cases, the function to execute /bin/sh. When the program finishes the part of the program that overflowed the buffer, it finds the address for /bin/sh in the instruction pointer and executes it. As long as the program is running with root privilege the attacker now has a root shell and has complete control of your system.

The most general form of security attack achieves two goals:

Inject the attack code, which is typically a small sequence of instructions that spawns a shell, into a running process.

Change the execution path of the running process to execute the attack code. It is important to note that these two goals are mutually dependent on each other: injecting attack code without the ability to execute it is not necessarily a security vulnerability.

Programs written in C have always been plagued with buffer overflows. Two reasons contribute to this problem. First, the C programming language does not automatically bounds-check array and pointer references. Second, and more importantly, many of the functions provided by the standard C library are unsafe, such as those listed in Table 1. Therefore, it is up to the programmers to check explicitly that the use of these functions cannot overflow buffers. However, programmers often omit these checks. Consequently, many programs are plagued with buffer overflows and are therefore vulnerable to security attacks.

Function prototype  Potential problem  
   
strcpy(char *dest, const char *src)  May overflow the dest buffer.  
strcat(char *dest, const char *src)  May overflow the dest buffer.  
getwd(char *buf)  May overflow the buff buffer.  
gets(char *s)  May overflow the s buffer.  
fscanf(FILE *stream, const char *format, ...)  May overflow its arguments.  
scanf(const char *format, ...)  May overflow its arguments.  
realpath(char *path, char resolved_path[])  May overflow the path buffer.  
sprintf(char *str, const char *format, ...)  May overflow the str buffer.  

Table 1: Partial List of Unsafe Functions in the Standard C Library

Some Sample code(s) that can smash a stack The Following code is an example of stack smash.

#include stdio.h

char shellcode[] = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/bin/sh";

char large_string[128];

int i; long *long_ptr;

int main()

{ char buffer[96];

long_ptr = (long *)large_string;

for (i=0; i<32; i++)

*(long_ptr+i) = (int)buffer;

for (i=0; i<(int)strlen(shellcode); i++) large_string = shellcode;

strcpy(buffer, large_string); return 0; }

   





Figure 1: A Process Undergoing a Stack Smashing Attack

Care to prevent getting smashed??

Get with the program!! (no pun intended) Write programs that do bounds checking.
Review legacy software code for security problems.
Avoid functions in C that do no bounds checking. Instead, use their bounds checking substitutes. The following is a recommendation is from "A Lab engineers checklist for writing secure Unix code."
Instead Of:  Use :
gets()  fgets()  
strcpy()  strncpy()  
sprintf() bcopy()  
strcat()  strncat()  
scanf()  bzero()  
sscanf()  memcpy(), memset()  

Be careful when using for and while loops that copy data from one variable to another. Make sure the bounds are checked.
Be especially careful programming and/or installing setuid root programs and programs that run as root. These are the programs that allow an attacker to acquire a root shell.
There is a compiler called "StackGuard" which if used to compile code will protect against stack smashes. It's "implemented as a small patch to the gcc code generator". It "seeks not to prevent stack smashing attacks from occurring at all, but rather to prevent the victim program from executing the attacker's injected code. StackGuard does this by detecting that the return address has been altered before the function returns" .
Another compiler, called "StackShield" is a stack smashing protection tool for Linux. It "integrates with GCC and basically adds a little bit of code that checks the return address of a function and makes sure it is within the correct limits, if it isn't you can have the program exit." [4]
There is an operating system called "Immunix OS". The Web site for it says that "Immunix OS 6.2 is based on Red Hat 6.2, but with all C source-available programs re-compiled with the StackGuard compiler. The result is a system that is fundamentally compatible with Red Hat Linux, but is secured against a majority of all Internet security attacks. "
There is another version of linux designed to be more secure called "Bastille Linux." According to information on the Bastille Linux web site, "The Bastille Hardening System attempts to 'harden' or 'tighten' the Linux operating system. It currently supports Red Hat and Mandrake systems." It also says that it "draws from every available major reputable source on Linux Security."
Links that provide more information on stack smashing:

The following websites provide us with detail explaining Stack Smash From basics

论坛徽章:
0
2 [报告]
发表于 2004-01-17 13:08 |只看该作者

stack操作原理

哪为老大给翻译成中文。

论坛徽章:
0
3 [报告]
发表于 2004-01-17 16:48 |只看该作者

stack操作原理

老大,你给翻译一下吧,要不我只能看懂一半。。。:)
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP