Low-level security or C and the infamous buffer overflow
Bài đăng này đã không được cập nhật trong 3 năm
Buffer overflow
A buffer overflow is a bug that affects low-level code, typically in C and C++, with significant security implications. Normally, a program with this bug will simply crash. But an attacker can alter the situations that cause the program to do much worse.
- Steal private information (e.g., Heartbleed)
- Corrupt valuable information
- Run code of the attacker’s choice
Buffer overflows are still relevant today. C and C++ are still popular. Buffer overflows still occur with regularity. They have a long history. Many different approaches developed to defend against them, and bugs like them. C and C++ still very popular
Critical systems in C/C++ Most OS kernels and utilities
- Windows
- Linux
- shell Many high-performance servers
- Microsoft IIS, Apache httpd, nginx
- Microsoft SQL server, MySQL, redis, memcached Many embedded systems
- Mars rover, industrial control systems, automobiles
I use the term buffer overflow to mean any access of a buffer outside of its allotted bounds
- Could be an over-read, or an over-write
- Could be during iteration (“running off the end”) or by direct access (e.g., by pointer arithmetic)
- Out-of-bounds access could be to addresses that precede or follow the buffer
Benign outcome
void func(char *arg1) { char buffer[4]; strcpy(buffer, arg1); ... } int main() { char *mystr = “AuthMe!”; func(mystr); ... }
Upon return, sets %ebp to 0x0021654d strcpy() copy arg1 over %ebp
strcpy() will let you write as much as you want (til a ‘\0’)
On hacker's hand
Hacker set %eip to 0xbdf. Function will jump to malicious code when return.
Secure coding in C
Since the language provides few guarantees, developers must use discipline.
Design vs. Implementation
In general, we strive to follow principles and rules
- A principle is a design goal with many possible manifestations.
- A rule is a specific practice that is consonant with sound design principles.
- The difference between these can sometimes be fuzzy
Here we look at rules for good C coding
- In particular, to avoid implementation errors that could result in violations of memory safety
In a future course module we consider principles and rules more broadly
Rule: Enforce input compliance
len = MIN(len,strlen(buf));
Rule: Enforce input compliance
char digit_to_char(int i) { char convert[] = “0123456789”; if(i < 0 || i > 9) return convert[i]; }
General Principle: Robust coding
- Like defensive driving
- Avoid depending on anyone else around you
- If someone does something unexpected, you won’t crash (or worse)
- It’s about minimizing trust
- Each module pessimistically checks its assumed preconditions (on outside callers)
- Even if you “know” clients will not send a NULL pointer
- … Better to throw an exception (or even exit) than run malicious code
Rule: Use safe string functions
Replacements
… for string-oriented functions
- strcat ⟹ strlcat
- strcpy ⟹ strlcpy
- strncat ⟹ strlcat
- strncpy ⟹ strlcpy
- sprintf ⟹ snprintf
- vsprintf ⟹ vsnprintf
- gets ⟹ fgets
Microsoft versions different
- strcpy_s, strcat_s, …
Rule: Don’t forget NUL terminator
char str[3]; strlcpy(str,”bye”,3); // blocked int x = strlen(str); // returns 2
**Rule: Understand pointer arithmetic ** sizeof() returns number of bytes, but pointer arithmetic multiplies by the sizeof the type.
int buf[SIZE] = { … }; int *buf_ptr = buf; while (!done() && buf_ptr < (buf + sizeof(buf))) { *buf_ptr++ = getnext(); // will overflow }
use the right units
while (!done() && buf_ptr < (buf + SIZE)) { *buf_ptr++ = getnext(); // stays in bounds }
Defend dangling pointers
Rule: Use NULL after free
int x = 5; int *p = malloc(sizeof(int)); free(p); p = NULL; //defend against bad deref int **q = malloc(sizeof(int*)); //reuses p’s space *q = &x; *p = 5; //(good) crash **q = 3;
**Rule: Use safe string library ** Libraries designed to ensure strings used safely
- Safety first, despite some performance loss
- Example: Very Secure FTP (vsftp) string library https://security.appspot.com/vsftpd.html
Rule: Favor safe libraries
Libraries encapsulate well-thought-out design. Take advantage!
- Smart pointers
- Pointers with only safe operations
- Lifetimes managed appropriately
- First in the Boost library, now a C++11 standard
Networking: Google protocol buffers, Apache Thrift
- For dealing with network-transmitted data
- Ensures input validation, parsing, etc.
- Efficient
Rule: Use a safe allocator
- ASLR challenges exploits by making the base address of libraries unpredictable
- Challenge heap-based overflows by making the addresses returned by malloc unpredictable
- Can have some negative performance impact
All rights reserved