The document discusses secure coding techniques in C/C++ to mitigate software vulnerabilities, including buffer overflows, pointer misuse, and improper memory management. It emphasizes proactive development practices, such as proper allocation and checking of memory, using safe API functions, and the importance of understanding concurrency issues. The presentation aims to inform developers about common vulnerabilities and practical measures for secure coding to prevent exploitation.
McAfee Confidential—Internal UseOnly
Secure Coding in C/C++
A technical perspective
September 25, 2013
Dan-Claudiu Dragoș
Software Development Engineer
2.
What will wecover today:
• Software vulnerabilities: who and why?
• String and buffer overflows
• Pointer vulnerabilities
• Dynamic memory management
• Format strings (printf)
• Integer values
• Concurrency
• File I/O
3.
McAfee Confidential—Internal UseOnly
Software vulnerabilities: who and why?
3
• Script kiddies or illiterate cybercriminals do not find vulnerabilities:
• … they simply use them for profit or fame
• Vulnerabilities are found by security experts
• They may be working for McAfee or for the government of Elbonia
• … this is not a non profit activity!
• These experts can set up environments similar to yours
• They have a deep understanding of the system architecture
• They have access to the same tools as you do
» … including debuggers!
» … or even to the source code!
• They practice the attacks in controlled environments before going live.
4.
McAfee Confidential—Internal UseOnly
Software vulnerabilities: what to do?
4
• There is no magic recipe!
• The approach should be proactive, not reactive
» … it’s like pipe work when fixing leaks
• There are some good development practices
» … do’s and don’ts
• There is also some external help:
• Modern compilers may reorder parameters on stack or apply
optimizations
• Modern operating systems may use memory randomization
• Modern CPUs have “execute disable” flags
5.
McAfee Confidential—Internal UseOnly
Software vulnerabilities: Buffers
5
• Unbounded buffer operations are the recipe for disaster
– Never use:
• API functions that populate buffers without taking sizes
• C-String operations without allowing for buffer size!
• Array iterations without checking for bounds
• Unsafe functions marked as such in the documentation
– Do not rely on your own canary values, let the compiler do its job!
– During development:
• Build the source code with a debug library with strict bounds checking
• Use static analysis software (Coverity)
• Run the software through a dynamic analyser (Purify)
6.
McAfee Confidential—Internal UseOnly
Software vulnerabilities: Buffers
6
• Design patterns to keep in mind:
• Allocating memory for the use of (external) API functions is unsafe!
» On Linux the ELF dynamic linking table can be exploited
» Windows approach on using DLLs is safe
GNU libc (unsafe) GNU libc (safer) C++ STL (safest)
Caller allocates Calee allocates Callee allocates
Callee initializes
Caller uses
Caller frees Caller frees Callee frees
7.
McAfee Confidential—Internal UseOnly
Software vulnerabilities: Pointers
7
• Function pointers are dangerous!
– An attacker may modify the memory and use such pointer as a trampoline
to their own shell code
• C++ polymorphic approach is much safer
• Always initialize and set the pointers to NULL after use
– NULL pointers may point to valid memory on some architectures
• Linux platforms: running the program through valgrind may help
identify potential issues
– the attacker may very likely do this in search of vulnerabilities!
8.
McAfee Confidential—Internal UseOnly
Software vulnerabilities: Memory
8
• Never use buffer sizes based only on user input
» …argv[] elements can be empty strings!
» …including argv[0]
• Do not use malloc(0), the behaviour is undefined
• Always check the result of memory allocation (and handle the error)
• Always use the proper call pairs:
• new – delete
• malloc – free
• new[] – delete[]
• placement new – explicit destructor call
9.
McAfee Confidential—Internal UseOnly
Software vulnerabilities: Format strings
9
• Variadic functions such as printf are dangerous
• the C standard does not provide a reliable way to determine the call
argument count
• these functions must rely on the caller to provide the proper format, the
right number of arguments and the proper argument types
• If the format string contains unparsed user input, this is an exploit
invitation:
» the attacker can trigger reading arbitrary data from the stack
» the %n format specifier causes data to be written!
» specially crafted format strings can cause data to be written to
arbitrary memory locations!
• Localization code is a prime target for these attacks
McAfee Confidential—Internal UseOnly
Software vulnerabilities: Integers
11
• C language defines multiple integer types and default conversions
• Integer values are prone to overflow
• Don’t:
• design your code with a certain architecture in mind
• forget that the safe storage of the multiplication result requires twice
the size of the largest argument
• mix signed and unsigned types
• forget about LSB/MSB or the negative numbers
• Do:
• check for bounds on any integer value received from the user
• test the code thoroughly on all relevant architectures
12.
McAfee Confidential—Internal UseOnly
Software vulnerabilities: Concurrency
12
• The concurrency issues do not usually result in privilege escalation
» …they are mostly used for denial of service
• An attacker may only want to get your system to an undefined state
» …but this is also a job for the QA!
• Always be on the look for:
• scalability issues
• race conditions
• deadlocks
• starvation and live locks
13.
McAfee Confidential—Internal UseOnly
Software vulnerabilities: File I/O
13
• Referring files by names is unsafe by design
• on Linux the race window between stat() and open() cannot be
(cleanly) avoided
• an attacker may replace the file in this race window
• The prime target for these attacks are the setuid() programs
• Mitigation strategies:
• use canonical names / paths, do not trust the user input
• perform all the operations with the lowest required privileges / drop
super user privileges when they are no longer required
• check that the file operation is not performed on a symlinked file
• the admin must ensure that no hard links are possible between user
files and system files