The document discusses the importance of source code auditing to discover vulnerabilities and outlines various tools and methodologies for effective auditing. It highlights common types of vulnerabilities, such as buffer overflows, format string vulnerabilities, and use-after-free errors, while providing examples and explanations for each type. Additionally, it emphasizes the necessity of understanding code structure and employing a selective approach to audit specific, vulnerable sections of the code efficiently.
Introduction to source code auditing, its importance in discovering vulnerabilities, and tools like Cscope and Ctags for code indexing and browsing.
Discussion on automated tools for source code analysis, including Splint and Flawfinder to find vulnerabilities, and their usability.
Different methods for auditing: top-down, bottom-up, and selective approaches to code auditing, emphasizing their effectiveness and focus.
Overview of vulnerability classes such as logic errors, format strings, and incorrect bounds-checking, highlighting specific examples and implications.
Detailed examples of vulnerabilities including off-by-one errors, signed comparison issues, use-after-free vulnerabilities, and multithreading problems, showcasing real-world cases.
Why Audit SourceCode?
• Best way to discover vulnerabilities
• Can be done with just source code and
grep
• Specialized tools make it much easier
3.
Cscope
• A sourcecode browsing tool
• Useful for large code trees,
such as the whole Linux
kernel
• Many useful search
functions
• Cbrowser: GUI front-end
• Links Ch 18a, 18b
4.
Ctags
• Indexes sourcecode
• Creates a tag file with
locations for language
tags in files scanned
• Works in many
languages, including C
and C++
– Link Ch 18c
5.
Text Editor
• Vimand Emacs have features that make
writing and searching though large
amounts of code easy
• Bracket-matching: find matching ([{
Top-Down (Specific) Approach
•Search for specific lines of vulnerable
code, such as format string errors
• Auditor doesn't have to understand
application in depth
• Misses vulnerabilities that span more than
one part of the code
16.
Bottom-Up Approach
• Auditorreads large portion of code
• Starting at main()
• Time-consuming but can reveal subtle
bugs
17.
Selective Approach
• Mostauditors use this approach
• Locate code that can be reached with
attacker-defined input
• Focus energy on that code
• Learn the purpose of that code thoroughly
Generic Logic Errors
•Requires good understanding of an
application
– And internal structures and classes
• Example: wildcard certificates
– Pascal-based CA will sell a certificate for *
0.evil.com
– C-based browser will see it as *, a wildcard
• Link Ch 18g
Format Strings
• Easyto find with a code audit
– Although cppcheck failed
• Often found in logging code
• Vulnerable only if attacker controls the
format string
24.
Generic Incorrect Bounds-Checking
•Coder attempts to check limits, but does
it incorrectly
• Example: Snort RCP Processor (2003)
– Processes a series of RPC fragments
– Checks each fragment to make sure it's not
larger than the buffer
– But it should check the total size of all
combined fragments
Loop Constructs
• Codersoften use intricate loops, and loops
within loops
• Complex interactions can lead to insecurities
• Led to a buffer overflow in Sendmail
• Link Ch 18h
Off-by-One Vulnerabilities
• Oftencaused by improper null-
termination of strings
• Frequently found in loops or introduced
by common string functions
• Can lead to arbitrary code execution
29.
Example from Apache
•When both if statements are true
– Space allocated is one byte too small
– memcpy will write one null out of bounds
30.
OpenBSD ftp Daemon
•If last character is a quote, it can be
written past the bounds of the input
buffer
31.
strncat()
• Strncat alwaysnull-terminates its output
string
• Will write a null byte out of bounds unless
the third argument is equal to the
remaining space in the buffer minus one
byte
32.
Non-Null Termination Issues
•If a string is not terminated with a null
– Memory after the string is interpreted as part
of the string
– May increase length of string
– String writes may corrupt memory outside the
string buffer
– Can lead to arbitrary code execution
33.
strncpy()
• If there'snot enough space in the
destination buffer
– strncpy() won't null-terminate the string it
writes
34.
strncpy() Example
– Firststrncpy won't null-terminate not_term_buf
– Second strcpy is unsafe, even though both
buffers are the same size
– Fix it by adding this line of code after the first
strcpy
35.
Skipping Past Null-Termination
•String-processing loops that process more
than one character at a time
– Or where assumptions about string length are
made
• Can make it possible to write past end of
a buffer
– Possible arbitrary code execution
But Not AllSchemes End in ://
• If the URI is ldap:a
– The null byte is skipped
38.
Signed Comparison Vulnerabilities
•Coder attempts to check input length
• But uses a signed integer variable
• Or two different integer types or sizes
– C sometimes converts them both to signed
integers before comparing them
• Following example from Apache
– Led to code execution on Windows and BSD
Unix
39.
Example from Apache
•bufsize is a signed integer
– Remaining space in the buffer
• r->remaining is signed
– Chunk size from the request
• len_to_read should be the smaller of the two
– Negative chunk size tricks the code into performing a
large memcpy later, because it's cast to
unsigned
• A hashedpassword can begin with 0e and
contain only digits (very rare)
– Like 0e12353589661821035685
• PHP reads that as scientific notation
– 0^123…
– Always zero (link Ch 18j)
43.
Double Free Vulnerabilities
•Freeing the same memory chunk twice
• Can lead to memory corruption and arbitrary
code execution
• Most common when heap buffers are stored
in pointers with global scope
• Good practice: when a global pointer is
freed, set it to Null to prevent it being re-
used
• Prevents dangling pointers
Uninitialized Variable Usage
•Static memory in the .data or .bss
sections of an executable are initialized
to null on program startup
• But memory on the stack or heap is not
• Uninitializes variables will contain data
from previous function calls
• Argument data, saved registers, or local
variables from previous function calls
46.
Uninitialized Variable Usage
•Rare, because they can lead to immediate
program crashes
• So they get fixed
• Look for them in code that is rarely used
• Such as handlers for uncommon errors
• Compilers attempt to prevent these errors
47.
Example
• If datais null
– test is never assigned any value
– But test is still freed
48.
Exploitation
• The "uninitialized"data in test is not
random
• It comes from previous variables and
function calls
• It may be controlled by the attacker
• So the free() leads to a controllable
memory write
– Arbitrary code execution
49.
Use After FreeVulnerabilities
• Heap buffers are temporary
– Released with free()
• But a program may use a pointer after
free()
– If more than one variable points to the same
object
• Allows an attacker to write to RAM
– Possible arbitrary code execution
50.
Multithreaded Issues and
Re-Entrant Safe Code
• A global variable is used by more than one
thread, without proper locking
– A variable might be changed unexpectedly by
another thread
• Such issues won't appear until the server
is under heavy load
– May remain as intermittent software bugs
that are never verified