Download presentation
Presentation is loading. Please wait.
Published byClarence Blair Modified over 9 years ago
1
S ECURE P ROGRAMMING 2. I NTRODUCTION TO S TATIC A NALYSIS Chih Hung Wang Reference: 1. B. Chess and J. West, Secure Programming with Static Analysis, Addison-Wesley, 2007. 2. R. C. Seacord, Secure Coding in C and C++, Addison-Wesley, 2006. 1
2
Capabilities and Limitations of Static Analysis False positives (false alarm) A problem reported but not actually exists False negatives--much worse ! Problem exists but not reported All static analysis tools are guaranteed to produce some false positives or some false negatives. Code quality tool usually attempt to produce a low number of false positives and are more willing to accept false negatives. Security (tool ) is a different story Produce more false positives to minimize false negatives 2
3
Solving Problems with Static Analysis (1) Type checking Eliminates entire categories of programming mistakes Example of false positive 3
4
Solving Problems with Static Analysis (2) Style Checking Enforce a picker and more superficial set of rules than a type checker. Example 4
5
Solving Problems with Static Analysis (3) Program Understanding Reverse Engineering higher-level information from lower-level source Open source: Fujaba tool suit (http://wwwcs.uni- paderborn.de/cs/fujaba) 5 Enables a developer to move back and forth between UML diagrams and Java source code
6
Solving Problems with Static Analysis (4) Program Verification and Property Checking A program verification tool accepts a specification and a body of code and then attempts to prove that the code is a faithful implementation. Many property checking tools focus on temporal safety properties. A temporal safety property specifies an ordered sequence of events that a must not carry out. An example of a temporal safety property is “a memory location should not be read after it is freed”. Most property-checking tools enable programmers to write their own specifications to check program-specific properties. 6
7
Solving Problems with Static Analysis (5) Example of a memory leak 7
8
Solving Problems with Static Analysis (6) An errant counterexample from a property checking tool running against the code in Example 2.6. 8
9
Solving Problems with Static Analysis (7) Bug Finding (FindBugs, http://findbugs.sourceforge.net/) Simply points out places where the program will behave in a way that the programmer did not intend. Most bug finders are easy to use because they come prestocked with a set of bug idioms (rules) that describe patterns in code that often indicate bugs. Example of Double-Checked Locking 9
10
Solving Problems with Static Analysis (8) Bug Finding (FindBugs, http://findbugs.sourceforge.net/) 10
11
Security Review Security-focused static analysis tools use many of the same techniques found in other tools, but their more focused goal (identifying security problems) means that they apply these techniques differently. The second code will result in an overflow if argv[0] points to a very long string. 11
12
A Little Theory, a little Reality Perfectly determining any nontrivial program property is impossible in the general case. Assume is_safe() is safe (and unsafe() is not safe()) If is_safe() determins bother is safe, bother will call unsafe() If is_safe() determines bother is unsafe, bother will not call unsafe() and it is safe 12
13
Trade-offs Analysis scope vs. execution time for the bug finding and security tools discussed in Section 2.1 13
14
Flawfinder A program that examines source code and reports possible security weaknesses (``flaws'') sorted by risk level. It's very useful for quickly finding and removing at least some potential security problems before a program is widely released to the public. http://www.dwheeler.com/flawfinder/ 14
15
Some Security Problems of C/C++ in String (1) Unbounded String Copies Unbounded string copies occur when data is copied from an unbounded source to a fixed length character array (for example, when reading from standard input into a fixed length buffer) The programmer is only expecting the user to enter 8 characters so it is reasonable to assume that the 80- character length will not be exceeded. 15
16
Some Security Problems of C/C++ in String (2) It is also easy to make errors when copying and concatenating strings because the standard strcpy() and strcat() functions perform unbounded copy operations. 16
17
Some Security Problems of C/C++ in String (3) A simple solution is to test the length of the input using strlen() and dynamically allocate the memory. 17
18
Some Security Problems of C/C++ in String (4) Unbounded string copies are not limited to the C programming language. For example, if a user inputs more than 11 characters into the C++ program below: 18
19
Some Security Problems of C/C++ in String (5) The standard object cin is an instantiation of the istream class. The istream class provides member functions to assist in reading and interpreting input from a stream buffer. All formatted input is performed using the extraction operator operator>>. C++ also defines external operator>> overloaded functions that are global functions and not members of istream, including: istream& operator>> (istream& is, char* str); 19
20
Some Security Problems of C/C++ in String (6-1) Off-by-One errors Off-by-one errors are similar to unbounded string copies in that they both involve writing outside the bounds of an array. 20 Null termination problem Off-by-one errors i=11 (error!)
21
Some Security Problems of C/C++ in String (6-2)—Correction code (complete) 21 #include int main(int argc, char* argv[]) { char source[11]; int i; strcpy(source, "0123456789"); char *dest=(char *)malloc(strlen(source)); for(i=0;i<10;i++){ dest[i]=source[i]; } dest[i]='\0'; printf("dest=%s", dest); return 0; } for(i=0;i!=10;i++) or for(i=0;i<strlen(source);i++)
22
Some Security Problems of C/C++ in String (7-1) Null-Termination Errors Null-termination errors, like the other string errors, are difficult to detect and can lie dormant in deployed code until a particular set of inputs causes a failure. 22
23
Some Security Problems of C/C++ in String (7-2) Explanation of the code Lines 2-4 Line 5 Line 6 Line 7 23 abc a 0 1 b \0 c a 0 1 c \0 b 0 1 a 0 1 c 0 1 b 0 1 f \0 Result may be (line 8) ERROR! 0123456789abcdef0123456789abcdef0123456789abcdef In Linux (old version with stack protection)
24
Some Security Problems of C/C++ in String (7-2.1=> another case in MSWindows) Explanation of the code Lines 2-4 Line 5 Line 6 Line 7 Line 8 ? 24 cba cba 0 1 ca \0 1 b 0 1 ca \0 1 b 0 1 Result may be (line 8) ERROR! 0123456789abcdef \0
25
Some Security Problems of C/C++ in String (7-3) – Correction ! 25 #include int main(int argc, char* argv[]) { char a[17]; char b[17]; char c[33]; strcpy(a, "0123456789abcdef"); strcpy(b, "0123456789abcdef"); strcpy(c, a); strcat(c, b); printf("c=%s\n", c); return 0; } Result: 0123456789abcdef0123456789abcdef
26
Some Security Problems of C/C++ in String (8) String Errors Without Functions 26 If the first argument to the program equals or exceeds 128 characters (remember the trailing null character), the program writes outside the bounds
27
Some Security Problems of C/C++ in String (9) String Vulnerability 27 17 }
28
Some Security Problems of C/C++ in String (10) Buffer Overflow Buffer overflows occur when data is written outside of the boundaries of the memory allocated to a particular data structure. C and C++ are susceptible to buffer overflows because (a) define strings as null-terminated arrays of characters (b) do not perform implicit bounds checking; and (c) provide standard library calls for strings that do not enforce bounds checking Dynamic analysis tools can be used to discover buffer overflows as long as the test data precipitates a detectable overflow. 28
29
Some Security Problems of C/C++ in String (11) Writing beyond array bounds 29 How to attack this program?? Waiting… Program crash? Code injection?
30
Buffer Overflow (Introduction) (1) Process Memory Organization Process memory is generally organized into code, data, heap, and stack segments. 30
31
Buffer Overflow (Introduction) (2) Stack Management (1) A stack is well suited for maintaining return address of the function call because it is a dynamic LIFO data structure that can support any level of nesting within memory constraints. When a subroutine is called, the address of the next instruction to execute in the calling routine is pushed onto the stack. When the subroutine returns, this return address is popped from the stack and program execution jumps to the specified location. Information pushed onto the stack as a result of a function call is called a frame. The address of the current frame is stored in the frame or base pointer register. On Intel architectures, the ebp (extended base pointer) register is used for this purpose. 31
32
Stack Frame and Function Call 32
33
Buffer Overflow (Introduction) (3) Stack Management (2) 33 Disassembly of a function call
34
Buffer Overflow (Introduction) (3.1) 34 MyStrPtr (4) ebp MyInt (4) ebp-4 ebp-8 arg:MyStrPtr (4) arg:MyInt (4) Arguments esp Return address (4) Calling ebp main()(4) Low High Top of the Stack
35
Buffer Overflow (Introduction) (4) The function prolog: The push instruction (line 4) pushes the ebp register containing the pointer to the current stack frame onto the stack. The mov instruction (line 5) sets the frame pointer for the function (the ebp register) to the current stack pointer. On line 7, the function allocates a total of 28 bytes of space on the stack for local variables (24 bytes for LocalChar and 4 bytes for LocalInt). 35
36
Buffer Overflow (Introduction) (4.1) 36 MyStrPtr (4) ebp MyInt (4) ebp-4 ebp-8 arg:MyStrPtr (4) arg:MyInt (4) Arguments Return address (4) Calling ebp main()(4) Low High Top of the Stack LocalInt(4) LocalChar(24) esp
37
Buffer Overflow (Introduction) (5) The stack pointer (esp) is restored from the frame pointer (ebp) (line 3). The original ebp is popped from the stack (line 4). The ret instruction pops a return address off the stack and transfers control to that location (line 5). 37
38
Buffer Overflow (Introduction) (5.1) 38 MyStrPtr (4) ebp MyInt (4) ebp-4 ebp-8 arg:MyStrPtr (4) arg:MyInt (4) Arguments Return address (4) Calling ebp main()(4) Low High Top of the Stack LocalInt(4) LocalChar(24) esp +8
39
Buffer Overflow (Introduction) (5.2) In Linux (gcc with stack protoction) Address low -> Address High Integer(4) Ptr(4) Char array[] (small -> large) From low to high Example: int a; char b[7]; char c[5]; int d; char *e; 39 a LowHigh d e cb
40
Buffer Overflow (Introduction) (5.3) 40 In Windows by gcc (or gcc without stack protection in Linux ) Address High -> Address Low Char array[] -> Integer Ptr From high to low Example: int a; char b[7]; char c[5]; int d; char *e; a LowHigh d e c b
41
Buffer Overflow (Introduction) (6) Sample stack frame foo() 41
42
Stack Smashing (1) Stack smashing occurs when a buffer overflow overwrites data in the memory allocated to the execution stack. This can have serious consequences for the reliability and security of a program. A buffer overflow in the stack segment can lead to an attacker executing arbitrary code by overwriting a pointer address to which control is (eventually) transferred. A common example is overwriting the return address (which is also located on the stack). 42
43
Stack Smashing (2) Program stack before call to IsPasswordOkay() 43 ESP
44
Stack Smashing (3) While the program is executing the function IsPasswordOkay(), the stack contains the information shown in the following. Notice that the password is located on the stack with the return address of the caller main(), which is located after the memory that is used to store the password. 44 Program stack during call to IsPasswordOkay()
45
Stack Smashing (4) Program stack after call to IsPasswordOkay() 45
46
Stack Smashing (4)—(a) More explanation about function call (I) 46 during call Push the return address to the stack
47
Stack Smashing (4)—(b) More explanation about function call (II) 47 After call --Return Pop the return address from the stack
48
Stack Smashing (5) This flaw can easily be demonstrated by entering a 20-character password of “12345678901234567890” that causes the program to crash 48
49
Stack Smashing (6) The program crashes because the return address is altered by the buffer overflow and the new address is either invalid, or memory at that address (a) does not contain a valid CPU instruction; (b) does contain a valid instruction, but the CPU registers are not set up for proper execution of the instruction; or (c) is not executable. A carefully crafted input string can make the program produce unexpected results, 49
50
Stack Smashing (7) Program result for a carefully crafted input string 50
51
Stack Smashing (8) Corrupted stack caused by the 20-byte password 51
52
Stack Smashing (9) Circumventing the password validation logic 52
53
Stack Smashing (10) Crafted input string’s effect on the stack 53 Real Demonstration ---Next time!!
54
Summary Practical challenge for static analysis tools: Making sense of the program (building an accurate program model) Making good trade-offs between precision, depth, and scalability Looking for the right set of defects Presenting easy-to-understand results and errors Integrating easily with the build system and integrated development environments 54
55
Summary—Static Analysis Tools 55
56
Use GDB to Observe the Stack (1) GDB GDB, the GNU Project debugger, allows you to see what is going on `inside' another program while it executes -- or what another program was doing at the moment it crashed. GDB can do four main kinds of things (plus other things in support of these) to help you catch bugs in the act: Start your program, specifying anything that might affect its behavior. Make your program stop on specified conditions. Examine what has happened, when your program has stopped. Change things in your program, so you can experiment with correcting the effects of one bug and go on to learn about another. The program being debugged can be written in Ada, C, C++, Objective-C, Pascal (and many other languages). Those programs might be executing on the same machine as GDB (native) or on another machine (remote). GDB can run on most popular UNIX and Microsoft Windows variants. http://www.gnu.org/software/gdb/ 56
57
Use GDB to Observe the Stack (2) Basic Example In Ubuntu (with stack protection) gdb stacktest disass main 57 #include void foo(int, char *); int main(void){ int MyInt=1; char *MyStrPtr="MyString"; foo(MyInt, MyStrPtr); return 0; } void foo(int i, char *name) { char LocalChar[24]="12345678901234567890123"; int LocalInt=3; return; }
58
Use GDB to Observe the Stack (2.1) In Ubuntu break *0x08048465 run x/32wx $esp 58 Arguments Local vars The same as the textbook
59
Use GDB to Observe the Stack (2.2) In Ubuntu disass foo break *0x080484b9 x/32wx $esp 59 The same as the textbook
60
Use GDB to Observe the Stack (2.3) In windows break *0x00401361 Run x/32wx $esp 60 Arguments Local vars Not the same as the textbook
61
Use GDB to Observe the Stack (2.4) In Windows disass foo break *0x00401392 61 Not the same as the textbook
62
Use GDB to Observe the Stack (3) Null Termination (see pp. 22) In windows 62 b c a
63
Use GDB to Observe the Stack (3.1) In Ubuntu Similar to the situation in the Windows (by gcc). 63 Note that the following compiler parameters to perform the buffer overflow attack in Linux system. gcc -o offbyonetest offbyonetest.c -fno-stack-protector
64
Use GDB to Observe the Stack (4) Advanced Example In Ubuntu (with stack protection) gdb stacktest2 64 #include void foo(char *, int); int main(void){ char a[10]="888888888"; int MyInt=1; char *MyStrPtr="MyString"; char *MyS="test"; int My2=2; char b[3]="44"; foo(MyStrPtr, MyInt); return 0; } void foo(char *name, int i) { char LocalChar[24]="12345678901234567890123"; int LocalInt=3; return; }
65
Use GDB to Observe the Stack (4.1) In Ubuntu (without stack protection) Similar to the situation in Windows (by gcc) 65
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.