Low-level security or C and the infamous buffer overflow
Bài đăng này đã không được cập nhật trong 4 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