360 likes | 489 Views
FIT3056 Secure and Trusted software systems. Lecture 2 & 3 Computer software problems and security. Why consider security before software design?. Adding security later is wrapping security around existing features, not designing features with security in mind.
E N D
FIT3056 Secure and Trusted software systems Lecture 2 & 3 Computer software problems and security
Why consider security before software design? • Adding security later is wrapping security around existing features, not designing features with security in mind. • Adding security later is expensive and incomplete. • Adding security may change the way you implement application features. This can affect the performance of the application. • Adding security to an application may change the user interface. User interfaces are often built closely with the applications, therefore if an application is wrapped with the security around it, it is likely the associated interface has to be modified.
Categories of Security Flaws • Architectural/design-level flaws: security issues that original design did not consider or solve correctly. • Implementation flaws: errors made in coding the design. • Operational flaws: problems arising from how software is installed or configured.
Architecture/Design Flaws • Race Condition • Application checks access control, then accesses a file as two separate steps, permitting an attacker to race program and substitute the accessible file for one that’s not allowed. • Replay Attack • If an attacker can record a transaction between a client and server at one time, then replay part of the conversation without the application detecting it, a replay attack is possible. Some software protocols have this serious problem. • Sniffing • Software applications for sensitive information transmission using static keys or weak encryption allows attackers to sniff and collect sufficient information to launch attacks.
Implementation Flaws • Buffer overflow • Overwrite data that controls the privileged program execution path and hijack the control of the program to execute the attacker’s code. • Input without validation • It is a general way to exploit privileged to traverse across the system or to gain privileged accessed. • E.g: Applications which don’t check that input has valid format, such as not checking for “../” sequences in pathnames, allowing attackers to traverse up the directory tree to access any file. • E.g; Privileged applications which don’t validate input may allow bad input to change the path of the application execution. • Back door • Programmers write special code to bypass access control system, often for debugging or maintenance purposes. Attackers exploit the code to gain the control of the system.
Implementation Flaws • Denial of service • System does not have enough resources or ability to monitor resources to sustain availability under large number of requests. • E.g: A process may generate too many requests or too many child processes that use up the system resources. • E.g: A poorly-designed server may accept unlimited number of requests. • Poor encryption • Poor key generation or encryption implementation can create vulnerabilities. • Eg: RSA algorithm cannot get large prime numbers with higher probability. • Poor integrity • Poor integrity algorithm implementation (higher collision rate) can provide attackers opportunity to attack on system integrity. • Eg: poor implementation of SHA1 with higher collision rate to lead to slight modification undetected.
Poor implementation of a one-way hash function I, Bob, will pay $1,000 to Alice. I, Bob, will pay $10,000 to Alice. 1010010100 1010010100 Hash value 1 Hash value 2
Operational Flaws • Software installation with default set-up or privilege. • Eg: many software packages are installed with vendors’ default set-up and this can lead to many security problems. • Eg: clients and servers share the same static key. • Software installation and execution with higher privilege • Eg: Web scripts are usefully installed and run with highest privilege and more access. This allows attackers to exploit the vulnerability in the scrips and launch attacks. • Eg: system administrators often make mistake by installing user-space software using root account and this leads to serious security.
Program structure • A program consists of a set of variables which contain data to be processed • A set of procedures/functions or methods to execute subtasks of the main task which is supposed to be performed by the program. • A procedure can call another procedure • Data and procedures can be put together into classes or units that allow better code design and maintenance.
Programs and memory allocation • The set of variables declared in a program can be local or global and the set of procedures/functions (methods) of a program can be global or local. • A program is loaded into memory and executed to perform the task that is designed to do. • Memory needed can be allocated at the compile-time, if the compiler can calculate it, or at the run-time.
Program’s address space • In most cases, a program’s address space contains 4 regions: • stack: contains local variables of functions or methods. it grows downward • heap: dynamic space allocated by calling malloc()as in C, new() as in C++ or Java. It is dynamically resized at run-time and grows upward • static data: variables that can be calculated at compile-time and do not grow or shrink. • code: loaded when program starts, does not change stack High heap staticdata code Low
Program’s address space and function call • When a function or method is invoked, the program needs to know the return address to be able to resume execution. • The return address for a function call is put on the stack. • A function can call another function, hence return addresses are put on the stack on the last-in first-out fashion.
Possible attacks • Some data of the program are stored on the stack. • The return addresses of functions of the program are stored on the stack. • What if the return address is overwritten by some new address which contains a new code written by the attacker? • buffer overflow allows us to change the return address of a function. therefore we can change the flow of execution of the program to execute our code.
Code Injection • Trick some program into executing an attacker’s code by the attacker’s input construction that normally mixes code and data • Mixed code and data input with special characters that trigger a context change between data and code interpretation • The attacker wants to inject meta-characters through some clever way, so supplied data is interpreted as code.
Code injection (e.g) #!/bin/sh #file name : eg.1 X=$1 eval "ls $X" What does this script do? #!/bin/sh #file name: dangerous1 rm -ri * What does this script do?
Code Injection (e.g) • Eg.1 receives the data input and it depends on the input the output can be normal or abnormal (dangerous). • The program can be attacked with malicious input string and it depends on the privilege of the owner of the program the attacker can gain the control of the system.
Stack memory and possible attacks (eg) bo2.c #include <stdio.h> /* pointer to different addresses in memory stack or heap */ void f(int a, int b) { int * p; /* pointer to an address that could be a return address */ p = &b ; p -= 2 ; printf("The current address pointed at by p is %x \n",*p); (*p)+= 10; printf("The new address is %x \n",*p); } main() { int nu; nu = 0; printf(" The value of nu is %d \n",nu); f(1,2); nu = 1; printf(" The new value of nu is now %d \n",nu); }
Output of the program bo2.c • From the output of the program we can see clearly that we can travel the stack and/or heap address space. • This provides the attacker the opportunity to exploit vulnerable programs and load her/his code into the memory for execution. • The attacker’s code is normally loaded into the memory via input. The value of nu is 0 The current address pointed at by p is 804840b The new address is 8048415 The new value of nu is now 0
Buffer overflow code (eg) – bo3.c #include <stdio.h> #include <string.h> void f(char *str) { char buffer[20]; strcpy(buffer,str); printf("%s is required to pay %d dollars", buffer, strlen(buffer)); } main() { char string[20]; printf("Please enter your name \n"); gets(string); f(string); }
Assemble code of bo3.c (compile with gcc –S on beast.csse.monash.edu.au) • .file "bo3.c" • .section .rodata • .align 4 • .LC0: • .string "%s is required to pay %d dollars" • .text • .globl f • .type f, @function • f: • pushl %ebp • movl %esp, %ebp • pushl %edi • subl $36, %esp • subl $8, %esp • pushl 8(%ebp) • leal -24(%ebp), %eax • pushl %eax • call strcpy • addl $16, %esp • leal -24(%ebp), %eax • movl $-1, %ecx • movl %eax, -40(%ebp) • movb $0, %al
Assemble code of bo3.c • cld • movl -40(%ebp), %edi • repnz • scasb • movl %ecx, %eax • notl %eax • decl %eax • subl $4, %esp • pushl %eax • leal -24(%ebp), %eax • pushl %eax • pushl $.LC0 • call printf • addl $16, %esp • movl -4(%ebp), %edi • leave • ret • .size f, .-f • .section .rodata • .LC1: • .string "Please enter your name " • .text • .globl main
Assemble code of bo3.c • .type main, @function • main: • pushl %ebp • movl %esp, %ebp • subl $40, %esp • andl $-16, %esp • movl $0, %eax • addl $15, %eax • addl $15, %eax • shrl $4, %eax • sall $4, %eax • subl %eax, %esp • subl $12, %esp • pushl $.LC1 • call puts • addl $16, %esp
Assemble code of bo3.c • subl $12, %esp • leal -20(%ebp), %eax • pushl %eax • call gets • addl $16, %esp • subl $12, %esp • leal -20(%ebp), %eax • pushl %eax • call f • addl $16, %esp • leave • ret • .size main, .-main • .ident "GCC: (GNU) 4.0.2 20051125 (Red Hat 4.0.2-8)" • .section .note.GNU-stack,"",@progbits
Compiling and executing bo3.c • gcc or some smart compilers will give warning message with the gets() function. • The program will run normally with input of the right size (not greater than the declared size). • The program will crash when the input is more than the declared size. Normally you will get “segmentation fault error”.
Stack memory and possible attacks • The above program demonstrates that we can explore the stack memory. • Dynamic data can be written into memory stack. • Mixed of dynamic data and instruction to change the program execution can then be put in the stack memory target. • Attacker’s written program gets executed by the exploited program or the exploited program will transfer the control to the attacker’s program.
Possible way of overflow attack • Find a code which has buffer overflow vulnerability, let’s call bov. • Compute the number of bytes to overwrite the return address. • Calculate the address for the alternative code. • Write a code to do the damage, let’s call damage. • Execute the program (bov) with buffer overflow vulnerability with the input containing the address of the damage’s code .
Programs with system calls invite attackers int main(int argc, char *argv[], char **envp) { char buf [100]; buf[0] = '\0'; strcpy(buf,argv[1]); printf(“\n The output of your command is \n”); system(buf); exit(0); }
Programs with system calls invite attackers • Any program which invokes system calls uses lower level of system programs. Those lower level programs are written with efficiency in mind rather than security • E.g; most system functions in most OSs are written in C, C++ and assembly language. • The attacker will then exploit the security holes in those programs.
Code Injection (con’t) • Many applications allow generic input with or without validation. The reason is to make the applications more useful and adaptable to the future extensibility. • Applications written in programming languages such as SQL or PHP often do not have strong features for validation. • This allows attackers to exploit the code injection techniques to inject code which explores the system further and gains higher privileges. • The consequences are injected code can take the control of the system or at least do some damages to the system.
Reading on code injection • You are advised to read code injection techniques further to understand how attackers can exploit vulnerable SQL, PHP, and XML code with their input and launch attacks. • Attackers can use code injection techniques to attack programs written in most programming languages.
Solutions to buffer overflow attacks • Use safer programming languages, e.g., Java • This is not always feasible if you have to deal with performance or efficiency. • Black-box testing with long strings • Not all programmers listen to the right things. • Mark stack as non-executable • It is not always possible in some programming languages. • Randomize stack location or encrypt return address on stack by XORing with random string • Attacker won’t know what address to use in her/his string, however there is performance penalty. • Run-time checking of array and buffer bounds • Use tools such as StackGuard, libsafe to defend (helpful but not 100% a good choice) • Static analysis of source code to find overflows • You need to know software security before design and implement the software.
Non-Executable Stack Technique • Code patches marking stack segment as non-executable exist for some OS such as Linux, Solaris, OpenBSD • However, some applications still need executable stack: e.g • LISP interpreters (functional interpreter language) • This technique does not defend against system library function exploits • Therefore, overwriting return address with the address of an existing library function can still be harmful. • It also does not defend against heap and function pointer overflows.
Run-Time Checking: StackGuard (e.g) • Embed “canaries” in stack frames and verify their integrity prior to function return Buf (for local vars) canary sfp ret addr Frame of the calling function Pointer to previous frame Return execution to this address • Choose and insert a random canary string every time the program starts. • Terminate canary with “\0”, newline, linefeed, etc. • (s tring functions like strcpy() won’t copy beyond “\0” but still works fine) • Attackers can’t guess what the value of canary will be.
Using encryption to deter buffer overflow attacks • encrypt all pointers while in memory • Generate a random key when program is executed • Each pointer is XORed with this key when loaded from memory to registers or stored back into memory (pointers cannot be overflown while in registers) • Attackers cannot predict the target program’s key (even if a pointer is overwritten) because after XORing with key the pointer will dereference. It is a random memory address.
Buffer Overflow Defence Techniques : advantages and Disadvantages • Although the above buffer overflow defence techniques are useful. They have some disadvantages: • Buffer-overflow defence with encryption: • Encryption must be very fast and storing and retrieving key can slow down the program. • Pointers have to be encrypted and this makes it difficult to design efficient and optimal compilers. • Random insertion: • Run time defence techniques can be expensive and have performance penalty.
Conclusion • Buffer overflow defence techniques are useful but attackers have found new ways to attack. • Code recompilation and modification are real problems when fixing existing code. • It is difficult to find which technique is more robust than others. • The system need to be redesigned and reconstructed rather than patched. However, redesign and reconstruction of many parts of a system is a huge task.