Weaknesses Addressed by the CERT C++ Secure Coding Standard
Definition in a New Window
View ID: 868 (View: Graph)
Status: Incomplete
View Data
View Objective
CWE entries in this view (graph) are fully or partially eliminated by following the CERT C++ Secure Coding Standard. Since not all rules map to specific weaknesses, this view is incomplete.
View Metrics
CWEs in this view
Total CWEs
Total
111
out of
920
Views
0
out of
29
Categories
16
out of
177
Weaknesses
93
out of
705
Compound_Elements
2
out of
9
View Audience
Stakeholder
Description
Developers
By following the CERT C++ Secure Coding Standard, developers will be
able to fully or partially prevent the weaknesses that are identified in
this view. In addition, developers can use a CWE coverage graph to
determine which weaknesses are not directly addressed by the standard,
which will help identify and resolve remaining gaps in training, tool
acquisition, or other approaches for reducing weaknesses.
Software_Customers
If a software developer claims to be following the CERT C++ Secure
Coding Standard, then customers can search for the weaknesses in this
view in order to formulate independent evidence of that claim.
Educators
Educators can use this view in multiple ways. For example, if there is
a focus on teaching weaknesses, the educator could link them to the
relevant Secure Coding Standard.
Weaknesses Addressed by the CERT C++ Secure Coding Standard (primary)868
Relationship Notes
The relationships in this view were determined based on specific
statements within the rules from the standard. Not all rules have direct
relationships to individual weaknesses, although they likely have chaining
relationships in specific circumstances.
The accidental addition of a data-structure sentinel can cause serious programming logic problems.
Extended Description
Data-structure sentinels are often used to mark the structure of data. A common example of this is the null character at the end of strings or a special sentinel to mark the end of a linked list. It is dangerous to allow this type of control data to be easily accessible. Therefore, it is important to protect from the addition or modification of sentinels.
Time of Introduction
Architecture and Design
Implementation
Applicable Platforms
Languages
C
C++
Common Consequences
Scope
Effect
Integrity
Technical Impact: Modify application
data
Generally this error will cause the data structure to not work
properly by truncating the data.
Likelihood of Exploit
High to Very High
Demonstrative Examples
Example 1
The following example assigns some character values to a list of
characters and prints them each individually, and then as a string. The
third character value is intended to be an integer taken from user input and
converted to an int.
The first print statement will print each character separated by a
space. However, if a non-integer is read from stdin by getc, then atoi
will not make a conversion and return 0. When foo is printed as a
string, the 0 at character foo[2] will act as a NULL terminator and
foo[3] will never be printed.
Potential Mitigations
Phases: Implementation; Architecture and Design
Encapsulate the user from interacting with data sentinels. Validate
user input to verify that sentinels are not present.
Phase: Implementation
Proper error checking can reduce the risk of inadvertently introducing
sentinel values into data. For example, if a parsing function fails or
encounters an error, it might return a value that is the same as the
sentinel.
Phase: Architecture and Design
Use an abstraction library to abstract away risky APIs. This is not a
complete solution.
Phase: Operation
Use OS-level preventative functionality. This is not a complete
solution.
Allocation of Resources Without Limits or Throttling
Definition in a New Window
Weakness ID: 770 (Weakness Base)
Status: Incomplete
Description
Description Summary
The software allocates a reusable resource or group of resources on behalf of an actor without imposing any restrictions on how many resources can be allocated, in violation of the intended security policy for that actor.
When allocating resources without limits, an attacker could prevent
other systems, applications, or processes from accessing the same type
of resource.
Likelihood of Exploit
Medium to High
Detection Methods
Manual Static Analysis
Manual static analysis can be useful for finding this weakness, but it
might not achieve desired code coverage within limited time constraints.
If denial-of-service is not considered a significant risk, or if there
is strong emphasis on consequences such as code execution, then manual
analysis may not focus on this weakness at all.
Fuzzing
While fuzzing is typically geared toward finding low-level
implementation bugs, it can inadvertently find uncontrolled resource
allocation problems. This can occur when the fuzzer generates a large
number of test cases but does not restart the targeted software in
between test cases. If an individual test case produces a crash, but it
does not do so reliably, then an inability to limit resource allocation
may be the cause.
When the allocation is directly affected by numeric inputs, then
fuzzing may produce indications of this weakness.
Effectiveness: Opportunistic
Automated Dynamic Analysis
Certain automated dynamic analysis techniques may be effective in
producing side effects of uncontrolled resource allocation problems,
especially with resources such as processes, memory, and connections.
The technique may involve generating a large number of requests to the
software within a short time frame. Manual analysis is likely required
to interpret the results.
Automated Static Analysis
Specialized configuration or tuning may be required to train automated
tools to recognize this weakness.
Automated static analysis typically has limited utility in recognizing
unlimited allocation problems, except for the missing release of
program-independent system resources such as files, sockets, and
processes, or unchecked arguments to memory. For system resources,
automated static analysis may be able to detect circumstances in which
resources are not released after they have expired, or if too much of a
resource is requested at once, as can occur with memory. Automated
analysis of configuration files may be able to detect settings that do
not specify a maximum value.
Automated static analysis tools will not be appropriate for detecting
exhaustion of custom resources, such as an intended security policy in
which a bulletin board user is only allowed to make a limited number of
posts per day.
Demonstrative Examples
Example 1
This code allocates a socket and forks each time it receives a new
connection.
(Bad Code)
Example Languages: C and C++
sock=socket(AF_INET, SOCK_STREAM, 0);
while (1) {
newsock=accept(sock, ...);
printf("A connection has been accepted\n");
pid = fork();
}
The program does not track how many connections have been made, and it
does not limit the number of connections. Because forking is a
relatively expensive operation, an attacker would be able to cause the
system to run out of CPU, processes, or memory by making a large number
of connections. Alternatively, an attacker could consume all available
connections, preventing others from accessing the system
remotely.
Example 2
In the following example a server socket connection is used to
accept a request to store data on the local file system using a specified
filename. The method openSocketConnection establishes a server socket to
accept requests from a client. When a client establishes a connection to
this service the getNextMessage method is first used to retrieve from the
socket the name of the file to store the data, the openFileToWrite method
will validate the filename and open a file to write to on the local file
system. The getNextMessage is then used within a while loop to continuously
read data from the socket and output the data to the file until there is no
longer any data from the socket.
(Bad Code)
Example Languages: C and C++
int writeDataFromSocketToFile(char *host, int port)
{
char filename[FILENAME_SIZE];
char buffer[BUFFER_SIZE];
int socket = openSocketConnection(host, port);
if (socket < 0) {
printf("Unable to open socket connection");
return(FAIL);
}
if (getNextMessage(socket, filename, FILENAME_SIZE) >
0) {
if (openFileToWrite(filename) > 0) {
while (getNextMessage(socket, buffer, BUFFER_SIZE)
> 0){
if (!(writeToFile(buffer) > 0))
break;
}
}
closeFile();
}
closeSocket(socket);
}
This example creates a situation where data can be dumped to a file on
the local file system without any limits on the size of the file. This
could potentially exhaust file or disk resources and/or limit other
clients' ability to access the service.
Example 3
In the following example, the processMessage method receives a two
dimensional character array containing the message to be processed. The
two-dimensional character array contains the length of the message in the
first character array and the message body in the second character array.
The getMessageLength method retrieves the integer value of the length from
the first character array. After validating that the message length is
greater than zero, the body character array pointer points to the start of
the second character array of the two-dimensional character array and memory
is allocated for the new body character array.
(Bad Code)
Example Languages: C and C++
/* process message accepts a two-dimensional character array of
the form [length][body] containing the message to be processed
*/
int processMessage(char **message)
{
char *body;
int length = getMessageLength(message[0]);
if (length > 0) {
body = &message[1][0];
processMessageBody(body);
return(SUCCESS);
}
else {
printf("Unable to process message; invalid message
length");
return(FAIL);
}
}
This example creates a situation where the length of the body
character array can be very large and will consume excessive memory,
exhausting system resources. This can be avoided by restricting the
length of the second character array with a maximum length check
Also, consider changing the type from 'int' to 'unsigned int', so that you are always guaranteed that the number is positive. This might not be possible if the protocol specifically requires allowing negative values, or if you cannot control the return value from getMessageLength(), but it could simplify the check to ensure the input is positive, and eliminate other errors such as signed-to-unsigned conversion errors (CWE-195) that may occur elsewhere in the code.
(Good Code)
Example Languages: C and C++
unsigned int length = getMessageLength(message[0]);
if ((length > 0) && (length <
MAX_LENGTH)) {...}
Example 4
In the following example, a server object creates a server socket
and accepts client connections to the socket. For every client connection to
the socket a separate thread object is generated using the
ClientSocketThread class that handles request made by the client through the
socket.
(Bad Code)
Example
Language: Java
public void acceptConnections() {
try {
ServerSocket serverSocket = new
ServerSocket(SERVER_PORT);
int counter = 0;
boolean hasConnections = true;
while (hasConnections) {
Socket client = serverSocket.accept();
Thread t = new Thread(new
ClientSocketThread(client));
In this example there is no limit to the number of client connections
and client threads that are created. Allowing an unlimited number of
client connections and threads could potentially overwhelm the system
and system resources.
The server should limit the number of client connections and the
client threads that are created. This can be easily done by creating a
thread pool object that limits the number of threads that are
generated.
(Good Code)
Example
Language: Java
public static final int SERVER_PORT = 4444;
public static final int MAX_CONNECTIONS = 10;
...
public void acceptConnections() {
try {
ServerSocket serverSocket = new
ServerSocket(SERVER_PORT);
int counter = 0;
boolean hasConnections = true;
while (hasConnections) {
hasConnections = checkForMoreConnections();
Socket client = serverSocket.accept();
Thread t = new Thread(new
ClientSocketThread(client));
ExecutorService pool =
Executors.newFixedThreadPool(MAX_CONNECTIONS);
pool.execute(t);
}
serverSocket.close();
} catch (IOException ex) {...}
}
Example 5
An unnamed web site allowed a user to purchase tickets for an event.
A menu option allowed the user to purchase up to 10 tickets, but the back
end did not restrict the actual number of tickets that could be
purchased.
CMS does not restrict the number of searches that
can occur simultaneously, leading to resource
exhaustion.
Potential Mitigations
Phase: Requirements
Clearly specify the minimum and maximum expectations for capabilities,
and dictate which behaviors are acceptable when resource allocation
reaches limits.
Phase: Architecture and Design
Limit the amount of resources that are accessible to unprivileged users. Set per-user limits for resources. Allow the system administrator to define these limits. Be careful to avoid CWE-410.
Phase: Architecture and Design
Design throttling mechanisms into the system architecture. The best
protection is to limit the amount of resources that an unauthorized user
can cause to be expended. A strong authentication and access control
model will help prevent such attacks from occurring in the first place,
and it will help the administrator to identify who is committing the
abuse. The login application should be protected against DoS attacks as
much as possible. Limiting the database access, perhaps by caching
result sets, can help minimize the resources expended. To further limit
the potential for a DoS attack, consider tracking the rate of requests
received from users and blocking requests that exceed a defined rate
threshold.
Phase: Implementation
Strategy: Input Validation
Assume all input is malicious. Use an "accept known good" input
validation strategy, i.e., use a whitelist of acceptable inputs that
strictly conform to specifications. Reject any input that does not
strictly conform to specifications, or transform it into something that
does.
When performing input validation, consider all potentially relevant
properties, including length, type of input, the full range of
acceptable values, missing or extra inputs, syntax, consistency across
related fields, and conformance to business rules. As an example of
business rule logic, "boat" may be syntactically valid because it only
contains alphanumeric characters, but it is not valid if the input is
only expected to contain colors such as "red" or "blue."
Do not rely exclusively on looking for malicious or malformed inputs
(i.e., do not rely on a blacklist). A blacklist is likely to miss at
least one undesirable input, especially if the code's environment
changes. This can give attackers enough room to bypass the intended
validation. However, blacklists can be useful for detecting potential
attacks or determining which inputs are so malformed that they should be
rejected outright.
This will only be applicable to cases where user input can influence
the size or frequency of resource allocations.
Phase: Architecture and Design
For any security checks that are performed on the client side, ensure that these checks are duplicated on the server side, in order to avoid CWE-602. Attackers can bypass the client-side checks by modifying values after the checks have been performed, or by changing the client to remove the client-side checks entirely. Then, these modified values would be submitted to the server.
Phase: Architecture and Design
Mitigation of resource exhaustion attacks requires that the target
system either:
recognizes the attack and denies that user further access for a
given amount of time, typically by using increasing time
delays
uniformly throttles all requests in order to make it more
difficult to consume resources more quickly than they can again be
freed.
The first of these solutions is an issue in itself though, since it
may allow attackers to prevent the use of the system by a particular
valid user. If the attacker impersonates the valid user, he may be able
to prevent the user from accessing the server in question.
The second solution can be difficult to effectively institute -- and
even when properly done, it does not provide a full solution. It simply
requires more resources on the part of the attacker.
Phase: Architecture and Design
Ensure that protocols have specific limits of scale placed on
them.
Phases: Architecture and Design; Implementation
If the program must fail, ensure that it fails gracefully (fails
closed). There may be a temptation to simply let the program fail poorly
in cases such as low memory conditions, but an attacker may be able to
assert control before the software has fully exited. Alternately, an
uncontrolled failure could cause cascading problems with other
downstream components; for example, the program could send a signal to a
downstream process so the process immediately knows that a problem has
occurred and has a better chance of recovery.
Ensure that all failures in resource allocation place the system into
a safe posture.
Phases: Operation; Architecture and Design
Strategy: Limit Resource Consumption
Use resource-limiting settings provided by the operating system or
environment. For example, when managing system resources in POSIX,
setrlimit() can be used to set limits for certain types of resources,
and getrlimit() can determine how many resources are available. However,
these functions are not available on all operating systems.
When the current levels get close to the maximum that is defined for the application (see CWE-770), then limit the allocation of further resources to privileged users; alternately, begin releasing resources for less-privileged users. While this mitigation may protect the system from attack, it will not necessarily stop attackers from adversely impacting other users.
Ensure that the application performs the appropriate error checks and error handling in case resources become unavailable (CWE-703).
Vulnerability theory is largely about how behaviors and resources
interact. "Resource exhaustion" can be regarded as either a consequence or
an attack, depending on the perspective. This entry is an attempt to reflect
one of the underlying weaknesses that enable these attacks (or consequences)
to take place.
Taxonomy Mappings
Mapped Taxonomy Name
Node ID
Fit
Mapped Node Name
CERT Java Secure Coding
FIO04-J
Close resources when they are no longer
needed
CERT Java Secure Coding
SER12-J
Avoid memory and resource leaks during
serialization
CERT Java Secure Coding
MSC05-J
Do not exhaust heap space
CERT C++ Secure Coding
MEM12-CPP
Do not assume infinite heap space
CERT C++ Secure Coding
FIO42-CPP
Ensure files are properly closed when they are no longer
needed
Joao Antunes, Nuno Ferreira Neves
and Paulo Verissimo. "Detection and Prediction of Resource-Exhaustion
Vulnerabilities". Proceedings of the IEEE International Symposium on
Software Reliability Engineering (ISSRE). November 2008. <http://homepages.di.fc.ul.pt/~nuno/PAPERS/ISSRE08.pdf>.
[REF-11] M. Howard and
D. LeBlanc. "Writing Secure Code". Chapter 17, "Protecting Against Denial of Service Attacks"
Page 517. 2nd Edition. Microsoft. 2002.
[REF-7] Mark Dowd, John McDonald
and Justin Schuh. "The Art of Software Security Assessment". Chapter 10, "Resource Limits", Page 574.. 1st Edition. Addison Wesley. 2006.
Maintenance Notes
"Resource exhaustion" (CWE-400) is currently treated as a weakness, although it is more like a category of weaknesses that all have the same type of consequence. While this entry treats CWE-400 as a parent in view 1000, the relationship is probably more appropriately described as a chain.
The software does not sufficiently delimit the arguments being passed to a component in another control sphere, allowing alternate arguments to be provided, leading to potentially security-relevant changes.
Time of Introduction
Architecture and Design
Implementation
Applicable Platforms
Languages
All
Common Consequences
Scope
Effect
Confidentiality
Integrity
Availability
Other
Technical Impact: Execute unauthorized code or
commands; Alter execution
logic; Read application
data; Modify application
data
An attacker could include arguments that allow unintended commands or
code to be executed, allow sensitive data to be read or modified or
could cause other unintended behavior.
Demonstrative Examples
Example 1
The following simple program accepts a filename as a command line
argument and displays the contents of the file back to the user. The program
is installed setuid root because it is intended for use as a learning tool
to allow system administrators in-training to inspect privileged system
files without giving them the ability to modify them or damage the
system.
(Bad Code)
Example
Language: C
int main(char* argc, char** argv) {
char cmd[CMD_MAX] = "/usr/bin/cat ";
strcat(cmd, argv[1]);
system(cmd);
}
Because the program runs with root privileges, the call to system()
also executes with root privileges. If a user specifies a standard
filename, the call works as expected. However, if an attacker passes a
string of the form ";rm -rf /", then the call to system() fails to
execute cat due to a lack of arguments and then plows on to recursively
delete the contents of the root partition.
Web browser executes Telnet sessions using
command line arguments that are specified by the web site, which could allow
remote attackers to execute arbitrary commands.
Web browser allows remote attackers to execute
commands by spawning Telnet with a log file option on the command line and
writing arbitrary code into an executable file which is later executed.
Argument injection vulnerability in the mail
function for PHP may allow attackers to bypass safe mode restrictions and
modify command line arguments to the MTA (e.g. sendmail) possibly executing
commands.
Help and Support center in windows does not
properly validate HCP URLs, which allows remote attackers to execute
arbitrary code via quotation marks in an "hcp://" URL.
Mail client does not sufficiently filter
parameters of mailto: URLs when using them as arguments to mail executable,
which allows remote attackers to execute arbitrary programs.
Mail client allows remote attackers to execute
arbitrary code via a URI that uses a UNC network share pathname to provide
an alternate configuration file.
Argument injection vulnerability in TellMe 1.2 and
earlier allows remote attackers to modify command line arguments for the
Whois program and obtain sensitive information via "--" style options in the
q_Host parameter.
Beagle before 0.2.5 can produce certain insecure
command lines to launch external helper applications while indexing, which
allows attackers to execute arbitrary commands. NOTE: it is not immediately
clear whether this issue involves argument injection, shell metacharacters,
or other issues.
Argument injection vulnerability in Internet
Explorer 6 for Windows XP SP2 allows user-assisted remote attackers to
modify command line arguments to an invoked mail client via " (double quote)
characters in a mailto: scheme handler, as demonstrated by launching
Microsoft Outlook with an arbitrary filename as an attachment. NOTE: it is
not clear whether this issue is implementation-specific or a problem in the
Microsoft API.
Argument injection vulnerability in Mozilla
Firefox 1.0.6 allows user-assisted remote attackers to modify command line
arguments to an invoked mail client via " (double quote) characters in a
mailto: scheme handler, as demonstrated by launching Microsoft Outlook with
an arbitrary filename as an attachment. NOTE: it is not clear whether this
issue is implementation-specific or a problem in the Microsoft
API.
Argument injection vulnerability in Avant Browser
10.1 Build 17 allows user-assisted remote attackers to modify command line
arguments to an invoked mail client via " (double quote) characters in a
mailto: scheme handler, as demonstrated by launching Microsoft Outlook with
an arbitrary filename as an attachment. NOTE: it is not clear whether this
issue is implementation-specific or a problem in the Microsoft
API.
Argument injection vulnerability in the URI
handler in Skype 2.0.*.104 and 2.5.*.0 through 2.5.*.78 for Windows allows
remote authorized attackers to download arbitrary files via a URL that
contains certain command-line switches.
Argument injection vulnerability in WinSCP 3.8.1
build 328 allows remote attackers to upload or download arbitrary files via
encoded spaces and double-quote characters in a scp or sftp
URI.
Argument injection vulnerability in the Windows
Object Packager (packager.exe) in Microsoft Windows XP SP1 and SP2 and
Server 2003 SP1 and earlier allows remote user-assisted attackers to execute
arbitrary commands via a crafted file with a "/" (slash) character in the
filename of the Command Line property, followed by a valid file extension,
which causes the command before the slash to be executed, aka "Object
Packager Dialogue Spoofing Vulnerability."
Argument injection vulnerability in HyperAccess
8.4 allows user-assisted remote attackers to execute arbitrary vbscript and
commands via the /r option in a telnet:// URI, which is configured to use
hawin32.exe.
Argument injection vulnerability in the telnet
daemon (in.telnetd) in Solaris 10 and 11 (SunOS 5.10 and 5.11) misinterprets
certain client "-f" sequences as valid requests for the login program to
skip authentication, which allows remote attackers to log into certain
accounts, as demonstrated by the bin account.
Language interpreter's mail function accepts another argument that is concatenated to a string used in a dangerous popen() call. Since there is no neutralization of this argument, both OS Command Injection (CWE-78) and Argument Injection (CWE-88) are possible.
Potential Mitigations
Phase: Architecture and Design
Strategy: Input Validation
Understand all the potential areas where untrusted inputs can enter
your software: parameters or arguments, cookies, anything read from the
network, environment variables, request headers as well as content, URL
components, e-mail, files, databases, and any external systems that
provide data to the application. Perform input validation at
well-defined interfaces.
Phase: Implementation
Strategy: Input Validation
Assume all input is malicious. Use an "accept known good" input
validation strategy, i.e., use a whitelist of acceptable inputs that
strictly conform to specifications. Reject any input that does not
strictly conform to specifications, or transform it into something that
does.
When performing input validation, consider all potentially relevant
properties, including length, type of input, the full range of
acceptable values, missing or extra inputs, syntax, consistency across
related fields, and conformance to business rules. As an example of
business rule logic, "boat" may be syntactically valid because it only
contains alphanumeric characters, but it is not valid if the input is
only expected to contain colors such as "red" or "blue."
Do not rely exclusively on looking for malicious or malformed inputs
(i.e., do not rely on a blacklist). A blacklist is likely to miss at
least one undesirable input, especially if the code's environment
changes. This can give attackers enough room to bypass the intended
validation. However, blacklists can be useful for detecting potential
attacks or determining which inputs are so malformed that they should be
rejected outright.
Phase: Implementation
Directly convert your input type into the expected data type, such as
using a conversion function that translates a string into a number.
After converting to the expected data type, ensure that the input's
values fall within the expected range of allowable values and that
multi-field consistencies are maintained.
Phase: Implementation
Inputs should be decoded and canonicalized to the application's current internal representation before being validated (CWE-180, CWE-181). Make sure that your application does not inadvertently decode the same input twice (CWE-174). Such errors could be used to bypass whitelist schemes by introducing dangerous inputs after they have been checked. Use libraries such as the OWASP ESAPI Canonicalization control.
Consider performing repeated canonicalization until your input does
not change any more. This will avoid double-decoding and similar
scenarios, but it might inadvertently modify inputs that are allowed to
contain properly-encoded dangerous content.
Phase: Implementation
When exchanging data between components, ensure that both components
are using the same character encoding. Ensure that the proper encoding
is applied at each interface. Explicitly set the encoding you are using
whenever the protocol allows you to do so.
Phase: Implementation
When your application combines data from multiple sources, perform the
validation after the sources have been combined. The individual data
elements may pass the validation step but violate the intended
restrictions after they have been combined.
Phase: Testing
Use automated static analysis tools that target this type of weakness.
Many modern techniques use data flow analysis to minimize the number of
false positives. This is not a perfect solution, since 100% accuracy and
coverage are not feasible.
Phase: Testing
Use dynamic tools and techniques that interact with the software using
large test suites with many diverse inputs, such as fuzz testing
(fuzzing), robustness testing, and fault injection. The software's
operation may slow down, but it should not become unstable, crash, or
generate incorrect results.
Weakness Ordinalities
Ordinality
Description
Primary
(where
the weakness exists independent of other weaknesses)
At one layer of abstraction, this can overlap other weaknesses that have
whitespace problems, e.g. injection of javascript into attributes of HTML
tags.
Affected Resources
System Process
Causal Nature
Explicit
Taxonomy Mappings
Mapped Taxonomy Name
Node ID
Fit
Mapped Node Name
PLOVER
Argument Injection or Modification
CERT C Secure Coding
ENV03-C
Sanitize the environment when invoking external
programs
CERT C Secure Coding
ENV04-C
Do not call system() if you do not need a command
processor
CERT C Secure Coding
STR02-C
Sanitize data passed to complex subsystems
WASC
30
Mail Command Injection
CERT C++ Secure Coding
STR02-CPP
Sanitize data passed to complex subsystems
CERT C++ Secure Coding
ENV03-CPP
Sanitize the environment when invoking external
programs
CERT C++ Secure Coding
ENV04-CPP
Do not call system() if you do not need a command
processor
[REF-7] Mark Dowd, John McDonald
and Justin Schuh. "The Art of Software Security Assessment". Chapter 10, "The Argument Array", Page
567.. 1st Edition. Addison Wesley. 2006.
The software sets a pointer to a specific address other than NULL or 0.
Extended Description
Using a fixed address is not portable because that address will probably not be valid in all environments or platforms.
Time of Introduction
Architecture and Design
Implementation
Applicable Platforms
Languages
C
C++
C#
Assembly
Common Consequences
Scope
Effect
Integrity
Confidentiality
Availability
Technical Impact: Execute unauthorized code or
commands
If one executes code at a known location, an attacker might be able to
inject code there beforehand.
Availability
Technical Impact: DoS: crash / exit /
restart
If the code is ported to another platform or environment, the pointer
is likely to be invalid and cause a crash.
Confidentiality
Integrity
Technical Impact: Read memory; Modify memory
The data at a known pointer location can be easily read or influenced
by an attacker.
Demonstrative Examples
Example 1
This code assumes a particular function will always be found at a
particular address. It assigns a pointer to that address and calls the
function.
(Bad Code)
Example
Language: C
int (*pt2Function) (float, char, char)=0x08040000;
int result2 = (*pt2Function) (12, 'a', 'b');
// Here we can inject code to execute.
The same function may not always be found at the same memory address.
This could lead to a crash, or an attacker may alter the memory at the
expected address, leading to arbitrary code execution.
Potential Mitigations
Phase: Implementation
Never set a pointer to a fixed address.
Weakness Ordinalities
Ordinality
Description
Primary
(where
the weakness exists independent of other weaknesses)
The software uses a sequential operation to read or write a buffer, but it uses an incorrect length value that causes it to access memory that is outside of the bounds of the buffer.
Extended Description
When the length value exceeds the size of the destination, a buffer overflow could occur.
Time of Introduction
Implementation
Applicable Platforms
Languages
C: (Often)
C++: (Often)
Assembly
Common Consequences
Scope
Effect
Integrity
Confidentiality
Availability
Technical Impact: Execute unauthorized code or
commands
Buffer overflows often can be used to execute arbitrary code, which is
usually outside the scope of a program's implicit security policy. This
can often be used to subvert any other security service.
Buffer overflows generally lead to crashes. Other attacks leading to
lack of availability are possible, including putting the program into an
infinite loop.
Likelihood of Exploit
Medium to High
Detection Methods
Automated Static Analysis
This weakness can often be detected using automated static analysis
tools. Many modern tools use data flow analysis or constraint-based
techniques to minimize the number of false positives.
Automated static analysis generally does not account for environmental
considerations when reporting out-of-bounds memory operations. This can
make it difficult for users to determine which warnings should be
investigated first. For example, an analysis tool might report buffer
overflows that originate from command line arguments in a program that
is not expected to run with setuid or other special privileges.
Effectiveness: High
Detection techniques for buffer-related errors are more mature than
for most other weakness types.
Automated Dynamic Analysis
This weakness can be detected using dynamic tools and techniques that
interact with the software using large test suites with many diverse
inputs, such as fuzz testing (fuzzing), robustness testing, and fault
injection. The software's operation may slow down, but it should not
become unstable, crash, or generate incorrect results.
Effectiveness: Moderate
Without visibility into the code, black box methods may not be able to
sufficiently distinguish this weakness from others, requiring manual
methods to diagnose the underlying problem.
Manual Analysis
Manual analysis can be useful for finding this weakness, but it might
not achieve desired code coverage within limited time constraints. This
becomes difficult for weaknesses that must be considered for all inputs,
since the attack surface can be too large.
Demonstrative Examples
Example 1
This example takes an IP address from a user, verifies that it is
well formed and then looks up the hostname and copies it into a
buffer.
(Bad Code)
Example
Language: C
void host_lookup(char *user_supplied_addr){
struct hostent *hp;
in_addr_t *addr;
char hostname[64];
in_addr_t inet_addr(const char *cp);
/*routine that ensures user_supplied_addr is in the right
format for conversion */
validate_addr_form(user_supplied_addr);
addr = inet_addr(user_supplied_addr);
hp = gethostbyaddr( addr, sizeof(struct in_addr),
AF_INET);
strcpy(hostname, hp->h_name);
}
This function allocates a buffer of 64 bytes to store the hostname
under the assumption that the maximum length value of hostname is 64
bytes, however there is no guarantee that the hostname will not be
larger than 64 bytes. If an attacker specifies an address which resolves
to a very large hostname, then we may overwrite sensitive data or even
relinquish control flow to the attacker.
Note that this example also contains an unchecked return value (CWE-252) that can lead to a NULL pointer dereference (CWE-476).
Example 2
In the following example, the source character string is copied to
the dest character string using the method strncpy.
(Bad Code)
Example Languages: C and C++
...
char source[21] = "the character string";
char dest[12];
strncpy(dest, source, sizeof(source)-1);
...
However, in the call to strncpy the source character string is used
within the sizeof call to determine the number of characters to copy.
This will create a buffer overflow as the size of the source character
string is greater than the dest character string. The dest character
string should be used within the sizeof call to ensure that the correct
number of characters are copied, as shown below.
(Good Code)
Example Languages: C and C++
...
char source[21] = "the character string";
char dest[12];
strncpy(dest, source, sizeof(dest)-1);
...
Example 3
In this example, the method outputFilenameToLog outputs a filename
to a log file. The method arguments include a pointer to a character string
containing the file name and an integer for the number of characters in the
string. The filename is copied to a buffer where the buffer size is set to a
maximum size for inputs to the log file. The method then calls another
method to save the contents of the buffer to the log file.
(Bad Code)
Example Languages: C and C++
#define LOG_INPUT_SIZE 40
// saves the file name to a log file
int outputFilenameToLog(char *filename, int length) {
int success;
// buffer with size set to maximum size for input to log
file
char buf[LOG_INPUT_SIZE];
// copy filename to buffer
strncpy(buf, filename, length);
// save to log file
success = saveToLogFile(buf);
return success;
}
However, in this case the string copy method, strncpy, mistakenly uses
the length method argument to determine the number of characters to copy
rather than using the size of the local character string, buf. This can
lead to a buffer overflow if the number of characters contained in
character string pointed to by filename is larger then the number of
characters allowed for the local character string. The string copy
method should use the buf character string within a sizeof call to
ensure that only characters up to the size of the buf array are copied
to avoid a buffer overflow, as shown below.
Language interpreter API function doesn't validate
length argument, leading to information
exposure
Potential Mitigations
Phase: Requirements
Strategy: Language Selection
Use a language that does not allow this weakness to occur or provides
constructs that make this weakness easier to avoid.
For example, many languages that perform their own memory management,
such as Java and Perl, are not subject to buffer overflows. Other
languages, such as Ada and C#, typically provide overflow protection,
but the protection can be disabled by the programmer.
Be wary that a language's interface to native code may still be
subject to overflows, even if the language itself is theoretically safe.
Phase: Architecture and Design
Strategy: Libraries or Frameworks
Use a vetted library or framework that does not allow this weakness to
occur or provides constructs that make this weakness easier to
avoid.
Examples include the Safe C String Library (SafeStr) by Messier and Viega [R.805.6], and the Strsafe.h library from Microsoft [R.805.7]. These libraries provide safer versions of overflow-prone string-handling functions.
This is not a complete solution, since many buffer overflows are not
related to strings.
Phase: Build and Compilation
Strategy: Compilation or Build Hardening
Run or compile the software using features or extensions that
automatically provide a protection mechanism that mitigates or
eliminates buffer overflows.
For example, certain compilers and extensions provide automatic buffer
overflow detection mechanisms that are built into the compiled code.
Examples include the Microsoft Visual Studio /GS flag, Fedora/Red Hat
FORTIFY_SOURCE GCC flag, StackGuard, and ProPolice.
Effectiveness: Defense in Depth
This is not necessarily a complete solution, since these mechanisms
can only detect certain types of overflows. In addition, an attack could
still cause a denial of service, since the typical response is to exit
the application.
Phase: Implementation
Consider adhering to the following rules when allocating and managing
an application's memory:
Double check that your buffer is as large as you specify.
When using functions that accept a number of bytes to copy, such
as strncpy(), be aware that if the destination buffer size is equal
to the source buffer size, it may not NULL-terminate the
string.
Check buffer boundaries if accessing the buffer in a loop and make
sure you are not in danger of writing past the allocated
space.
If necessary, truncate all input strings to a reasonable length
before passing them to the copy and concatenation functions.
Phase: Architecture and Design
For any security checks that are performed on the client side, ensure that these checks are duplicated on the server side, in order to avoid CWE-602. Attackers can bypass the client-side checks by modifying values after the checks have been performed, or by changing the client to remove the client-side checks entirely. Then, these modified values would be submitted to the server.
Phase: Operation
Strategy: Environment Hardening
Use a feature like Address Space Layout Randomization (ASLR) [R.805.2] [R.805.4].
Effectiveness: Defense in Depth
This is not a complete solution. However, it forces the attacker to
guess an unknown value that changes every program execution. In
addition, an attack could still cause a denial of service, since the
typical response is to exit the application.
Phase: Operation
Strategy: Environment Hardening
Use a CPU and operating system that offers Data Execution Protection (NX) or its equivalent [R.805.3] [R.805.6].
Effectiveness: Defense in Depth
This is not a complete solution, since buffer overflows could be used
to overwrite nearby variables to modify the software's state in
dangerous ways. In addition, it cannot be used in cases in which
self-modifying code is required. Finally, an attack could still cause a
denial of service, since the typical response is to exit the
application.
Phases: Architecture and Design; Operation
Strategy: Environment Hardening
Run your code using the lowest privileges that are required to accomplish the necessary tasks [R.805.9]. If possible, create isolated accounts with limited privileges that are only used for a single task. That way, a successful attack will not immediately give the attacker access to the rest of the software or its environment. For example, database applications rarely need to run as the database administrator, especially in day-to-day operations.
Phases: Architecture and Design; Operation
Strategy: Sandbox or Jail
Run the code in a "jail" or similar sandbox environment that enforces
strict boundaries between the process and the operating system. This may
effectively restrict which files can be accessed in a particular
directory or which commands can be executed by the software.
OS-level examples include the Unix chroot jail, AppArmor, and SELinux.
In general, managed code may provide some protection. For example,
java.io.FilePermission in the Java SecurityManager allows the software
to specify restrictions on file operations.
This may not be a feasible solution, and it only limits the impact to
the operating system; the rest of the application may still be subject
to compromise.
Be careful to avoid CWE-243 and other weaknesses related to jails.
Effectiveness: Limited
The effectiveness of this mitigation depends on the prevention
capabilities of the specific sandbox or jail being used and might only
help to reduce the scope of an attack, such as restricting the attacker
to certain system calls or limiting the portion of the file system that
can be accessed.
Weakness Ordinalities
Ordinality
Description
Resultant
(where
the weakness is typically related to the presence of some other
weaknesses)
Primary
(where
the weakness exists independent of other weaknesses)
Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')
Definition in a New Window
Weakness ID: 120 (Weakness Base)
Status: Incomplete
Description
Description Summary
The program copies an input buffer to an output buffer without verifying that the size of the input buffer is less than the size of the output buffer, leading to a buffer overflow.
Extended Description
A buffer overflow condition exists when a program attempts to put more data in a buffer than it can hold, or when a program attempts to put data in a memory area outside of the boundaries of a buffer. The simplest type of error, and the most common cause of buffer overflows, is the "classic" case in which the program copies the buffer without restricting how much is copied. Other variants exist, but the existence of a classic overflow strongly suggests that the programmer is not considering even the most basic of security protections.
Alternate Terms
buffer overrun:
Some prominent vendors and researchers use the term "buffer overrun,"
but most people use "buffer overflow."
Unbounded Transfer
Terminology Notes
Many issues that are now called "buffer overflows" are substantively
different than the "classic" overflow, including entirely different bug
types that rely on overflow exploit techniques, such as integer signedness
errors, integer overflows, and format string bugs. This imprecise
terminology can make it difficult to determine which variant is being
reported.
Time of Introduction
Implementation
Applicable Platforms
Languages
C
C++
Assembly
Common Consequences
Scope
Effect
Integrity
Confidentiality
Availability
Technical Impact: Execute unauthorized code or
commands
Buffer overflows often can be used to execute arbitrary code, which is
usually outside the scope of a program's implicit security policy. This
can often be used to subvert any other security service.
Buffer overflows generally lead to crashes. Other attacks leading to
lack of availability are possible, including putting the program into an
infinite loop.
Likelihood of Exploit
High to Very High
Detection Methods
Automated Static Analysis
This weakness can often be detected using automated static analysis
tools. Many modern tools use data flow analysis or constraint-based
techniques to minimize the number of false positives.
Automated static analysis generally does not account for environmental
considerations when reporting out-of-bounds memory operations. This can
make it difficult for users to determine which warnings should be
investigated first. For example, an analysis tool might report buffer
overflows that originate from command line arguments in a program that
is not expected to run with setuid or other special privileges.
Effectiveness: High
Detection techniques for buffer-related errors are more mature than
for most other weakness types.
Automated Dynamic Analysis
This weakness can be detected using dynamic tools and techniques that
interact with the software using large test suites with many diverse
inputs, such as fuzz testing (fuzzing), robustness testing, and fault
injection. The software's operation may slow down, but it should not
become unstable, crash, or generate incorrect results.
Manual Analysis
Manual analysis can be useful for finding this weakness, but it might
not achieve desired code coverage within limited time constraints. This
becomes difficult for weaknesses that must be considered for all inputs,
since the attack surface can be too large.
Demonstrative Examples
Example 1
The following code asks the user to enter their last name and then
attempts to store the value entered in the last_name array.
(Bad Code)
Example
Language: C
char last_name[20];
printf ("Enter your last name: ");
scanf ("%s", last_name);
The problem with the code above is that it does not restrict or limit
the size of the name entered by the user. If the user enters
"Very_very_long_last_name" which is 24 characters long, then a buffer
overflow will occur since the array can only hold 20 characters total.
Example 2
The following code attempts to create a local copy of a buffer to
perform some manipulations to the data.
(Bad Code)
Example
Language: C
void manipulate_string(char* string){
char buf[24];
strcpy(buf, string);
...
}
However, the programmer does not ensure that the size of the data
pointed to by string will fit in the local buffer and blindly copies the
data with the potentially dangerous strcpy() function. This may result
in a buffer overflow condition if an attacker can influence the contents
of the string parameter.
Example 3
The excerpt below calls the gets() function in C, which is
inherently unsafe.
(Bad Code)
Example
Language: C
char buf[24];
printf("Please enter your name and press
<Enter>\n");
gets(buf);
...
}
However, the programmer uses the function gets() which is inherently
unsafe because it blindly copies all input from STDIN to the buffer
without restricting how much is copied. This allows the user to provide
a string that is larger than the buffer size, resulting in an overflow
condition.
Example 4
In the following example, a server accepts connections from a client
and processes the client request. After accepting a client connection, the
program will obtain client information using the gethostbyaddr method, copy
the hostname of the client that connected to a local variable and output the
hostname of the client to a log file.
(Bad Code)
Example Languages: C and C++
...
struct hostent *clienthp;
char hostname[MAX_LEN];
// create server socket, bind to server address and listen on
socket
...
// accept client connections and process requests
int count = 0;
for (count = 0; count < MAX_CONNECTIONS; count++)
{
int clientlen = sizeof(struct sockaddr_in);
int clientsocket = accept(serversocket, (struct sockaddr
*)&clientaddr, &clientlen);
logOutput("Accepted client connection from host ",
hostname);
// process client request
...
close(clientsocket);
}
}
close(serversocket);
...
However, the hostname of the client that connected may be longer than
the allocated size for the local hostname variable. This will result in
a buffer overflow when copying the client hostname to the local variable
using the strcpy method.
By replacing a valid cookie value with an
extremely long string of characters, an attacker may overflow the
application's buffers.
Potential Mitigations
Phase: Requirements
Strategy: Language Selection
Use a language that does not allow this weakness to occur or provides
constructs that make this weakness easier to avoid.
For example, many languages that perform their own memory management,
such as Java and Perl, are not subject to buffer overflows. Other
languages, such as Ada and C#, typically provide overflow protection,
but the protection can be disabled by the programmer.
Be wary that a language's interface to native code may still be
subject to overflows, even if the language itself is theoretically safe.
Phase: Architecture and Design
Strategy: Libraries or Frameworks
Use a vetted library or framework that does not allow this weakness to
occur or provides constructs that make this weakness easier to
avoid.
Examples include the Safe C String Library (SafeStr) by Messier and Viega [R.120.4], and the Strsafe.h library from Microsoft [R.120.3]. These libraries provide safer versions of overflow-prone string-handling functions.
This is not a complete solution, since many buffer overflows are not
related to strings.
Phase: Build and Compilation
Strategy: Compilation or Build Hardening
Run or compile the software using features or extensions that
automatically provide a protection mechanism that mitigates or
eliminates buffer overflows.
For example, certain compilers and extensions provide automatic buffer
overflow detection mechanisms that are built into the compiled code.
Examples include the Microsoft Visual Studio /GS flag, Fedora/Red Hat
FORTIFY_SOURCE GCC flag, StackGuard, and ProPolice.
Effectiveness: Defense in Depth
This is not necessarily a complete solution, since these mechanisms
can only detect certain types of overflows. In addition, an attack could
still cause a denial of service, since the typical response is to exit
the application.
Phase: Implementation
Consider adhering to the following rules when allocating and managing
an application's memory:
Double check that your buffer is as large as you specify.
When using functions that accept a number of bytes to copy, such
as strncpy(), be aware that if the destination buffer size is equal
to the source buffer size, it may not NULL-terminate the
string.
Check buffer boundaries if accessing the buffer in a loop and make
sure you are not in danger of writing past the allocated
space.
If necessary, truncate all input strings to a reasonable length
before passing them to the copy and concatenation functions.
Phase: Implementation
Strategy: Input Validation
Assume all input is malicious. Use an "accept known good" input
validation strategy, i.e., use a whitelist of acceptable inputs that
strictly conform to specifications. Reject any input that does not
strictly conform to specifications, or transform it into something that
does.
When performing input validation, consider all potentially relevant
properties, including length, type of input, the full range of
acceptable values, missing or extra inputs, syntax, consistency across
related fields, and conformance to business rules. As an example of
business rule logic, "boat" may be syntactically valid because it only
contains alphanumeric characters, but it is not valid if the input is
only expected to contain colors such as "red" or "blue."
Do not rely exclusively on looking for malicious or malformed inputs
(i.e., do not rely on a blacklist). A blacklist is likely to miss at
least one undesirable input, especially if the code's environment
changes. This can give attackers enough room to bypass the intended
validation. However, blacklists can be useful for detecting potential
attacks or determining which inputs are so malformed that they should be
rejected outright.
Phase: Architecture and Design
For any security checks that are performed on the client side, ensure that these checks are duplicated on the server side, in order to avoid CWE-602. Attackers can bypass the client-side checks by modifying values after the checks have been performed, or by changing the client to remove the client-side checks entirely. Then, these modified values would be submitted to the server.
Phase: Operation
Strategy: Environment Hardening
Use a feature like Address Space Layout Randomization (ASLR) [R.120.5] [R.120.7].
Effectiveness: Defense in Depth
This is not a complete solution. However, it forces the attacker to
guess an unknown value that changes every program execution. In
addition, an attack could still cause a denial of service, since the
typical response is to exit the application.
Phase: Operation
Strategy: Environment Hardening
Use a CPU and operating system that offers Data Execution Protection (NX) or its equivalent [R.120.7] [R.120.9].
Effectiveness: Defense in Depth
This is not a complete solution, since buffer overflows could be used
to overwrite nearby variables to modify the software's state in
dangerous ways. In addition, it cannot be used in cases in which
self-modifying code is required. Finally, an attack could still cause a
denial of service, since the typical response is to exit the
application.
Phases: Build and Compilation; Operation
Most mitigating technologies at the compiler or OS level to date
address only a subset of buffer overflow problems and rarely provide
complete protection against even that subset. It is good practice to
implement strategies to increase the workload of an attacker, such as
leaving the attacker to guess an unknown value that changes every
program execution.
Phase: Implementation
Replace unbounded copy functions with analogous functions that support
length arguments, such as strcpy with strncpy. Create these if they are
not available.
Effectiveness: Moderate
This approach is still susceptible to calculation errors, including issues such as off-by-one errors (CWE-193) and incorrectly calculating buffer lengths (CWE-131).
Phase: Architecture and Design
Strategy: Enforcement by Conversion
When the set of acceptable objects, such as filenames or URLs, is
limited or known, create a mapping from a set of fixed input values
(such as numeric IDs) to the actual filenames or URLs, and reject all
other inputs.
Phases: Architecture and Design; Operation
Strategy: Environment Hardening
Run your code using the lowest privileges that are required to accomplish the necessary tasks [R.120.10]. If possible, create isolated accounts with limited privileges that are only used for a single task. That way, a successful attack will not immediately give the attacker access to the rest of the software or its environment. For example, database applications rarely need to run as the database administrator, especially in day-to-day operations.
Phases: Architecture and Design; Operation
Strategy: Sandbox or Jail
Run the code in a "jail" or similar sandbox environment that enforces
strict boundaries between the process and the operating system. This may
effectively restrict which files can be accessed in a particular
directory or which commands can be executed by the software.
OS-level examples include the Unix chroot jail, AppArmor, and SELinux.
In general, managed code may provide some protection. For example,
java.io.FilePermission in the Java SecurityManager allows the software
to specify restrictions on file operations.
This may not be a feasible solution, and it only limits the impact to
the operating system; the rest of the application may still be subject
to compromise.
Be careful to avoid CWE-243 and other weaknesses related to jails.
Effectiveness: Limited
The effectiveness of this mitigation depends on the prevention
capabilities of the specific sandbox or jail being used and might only
help to reduce the scope of an attack, such as restricting the attacker
to certain system calls or limiting the portion of the file system that
can be accessed.
Weakness Ordinalities
Ordinality
Description
Resultant
(where
the weakness is typically related to the presence of some other
weaknesses)
Primary
(where
the weakness exists independent of other weaknesses)
At the code level, stack-based and heap-based overflows do not differ
significantly, so there usually is not a need to distinguish them. From the
attacker perspective, they can be quite different, since different
techniques are required to exploit them.
Affected Resources
Memory
Functional Areas
Memory Management
Causal Nature
Explicit
Taxonomy Mappings
Mapped Taxonomy Name
Node ID
Fit
Mapped Node Name
PLOVER
Unbounded Transfer ('classic overflow')
7 Pernicious Kingdoms
Buffer Overflow
CLASP
Buffer overflow
OWASP Top Ten 2004
A1
CWE_More_Specific
Unvalidated Input
OWASP Top Ten 2004
A5
CWE_More_Specific
Buffer Overflows
CERT C Secure Coding
STR35-C
Do not copy data from an unbounded source to a fixed-length
array
WASC
7
Buffer Overflow
CERT C++ Secure Coding
STR35-CPP
Do not copy data from an unbounded source to a fixed-length
array
A weakness where the code path includes a Buffer Write Operation such
that:
1. the expected size of the buffer is greater than the actual size of
the buffer where expected size is equal to the sum of the size of the
data item and the position in the buffer
Where Buffer Write Operation is a statement that writes a data item of a
certain size into a buffer at a certain position and at a certain
index
References
[R.120.1] [REF-11] M. Howard and
D. LeBlanc. "Writing Secure Code". Chapter 5, "Public Enemy #1: The Buffer Overrun" Page
127. 2nd Edition. Microsoft. 2002.
[R.120.2] [REF-17] Michael Howard, David LeBlanc
and John Viega. "24 Deadly Sins of Software Security". "Sin 5: Buffer Overruns." Page 89. McGraw-Hill. 2010.
[R.120.11] [REF-7] Mark Dowd, John McDonald
and Justin Schuh. "The Art of Software Security Assessment". Chapter 3, "Nonexecutable Stack", Page
76.. 1st Edition. Addison Wesley. 2006.
[R.120.12] [REF-7] Mark Dowd, John McDonald
and Justin Schuh. "The Art of Software Security Assessment". Chapter 5, "Protection Mechanisms", Page
189.. 1st Edition. Addison Wesley. 2006.
[R.120.13] [REF-7] Mark Dowd, John McDonald
and Justin Schuh. "The Art of Software Security Assessment". Chapter 8, "C String Handling", Page 388.. 1st Edition. Addison Wesley. 2006.
CERT C++ Secure Coding Section 01 - Preprocessor (PRE)
Definition in a New Window
Category ID: 869 (Category)
Status: Incomplete
Description
Description Summary
Weaknesses in this category are related to rules in the Preprocessor (PRE) section of the CERT C++ Secure Coding Standard. Since not all rules map to specific weaknesses, this category may be incomplete.
CERT C++ Secure Coding Section 02 - Declarations and Initialization (DCL)
Definition in a New Window
Category ID: 870 (Category)
Status: Incomplete
Description
Description Summary
Weaknesses in this category are related to rules in the Declarations and Initialization (DCL) section of the CERT C++ Secure Coding Standard. Since not all rules map to specific weaknesses, this category may be incomplete.
CERT C++ Secure Coding Section 03 - Expressions (EXP)
Definition in a New Window
Category ID: 871 (Category)
Status: Incomplete
Description
Description Summary
Weaknesses in this category are related to rules in the Expressions (EXP) section of the CERT C++ Secure Coding Standard. Since not all rules map to specific weaknesses, this category may be incomplete.
CERT C++ Secure Coding Section 04 - Integers (INT)
Definition in a New Window
Category ID: 872 (Category)
Status: Incomplete
Description
Description Summary
Weaknesses in this category are related to rules in the Integers (INT) section of the CERT C++ Secure Coding Standard. Since not all rules map to specific weaknesses, this category may be incomplete.
CERT C++ Secure Coding Section 05 - Floating Point Arithmetic (FLP)
Definition in a New Window
Category ID: 873 (Category)
Status: Incomplete
Description
Description Summary
Weaknesses in this category are related to rules in the Floating Point Arithmetic (FLP) section of the CERT C++ Secure Coding Standard. Since not all rules map to specific weaknesses, this category may be incomplete.
CERT C++ Secure Coding Section 06 - Arrays and the STL (ARR)
Definition in a New Window
Category ID: 874 (Category)
Status: Incomplete
Description
Description Summary
Weaknesses in this category are related to rules in the Arrays and the STL (ARR) section of the CERT C++ Secure Coding Standard. Since not all rules map to specific weaknesses, this category may be incomplete.
CERT C++ Secure Coding Section 07 - Characters and Strings (STR)
Definition in a New Window
Category ID: 875 (Category)
Status: Incomplete
Description
Description Summary
Weaknesses in this category are related to rules in the Characters and Strings (STR) section of the CERT C++ Secure Coding Standard. Since not all rules map to specific weaknesses, this category may be incomplete.
CERT C++ Secure Coding Section 08 - Memory Management (MEM)
Definition in a New Window
Category ID: 876 (Category)
Status: Incomplete
Description
Description Summary
Weaknesses in this category are related to rules in the Memory Management (MEM) section of the CERT C++ Secure Coding Standard. Since not all rules map to specific weaknesses, this category may be incomplete.
CERT C++ Secure Coding Section 09 - Input Output (FIO)
Definition in a New Window
Category ID: 877 (Category)
Status: Incomplete
Description
Description Summary
Weaknesses in this category are related to rules in the Input Output (FIO) section of the CERT C++ Secure Coding Standard. Since not all rules map to specific weaknesses, this category may be incomplete.
CERT C++ Secure Coding Section 10 - Environment (ENV)
Definition in a New Window
Category ID: 878 (Category)
Status: Incomplete
Description
Description Summary
Weaknesses in this category are related to rules in the Environment (ENV) section of the CERT C++ Secure Coding Standard. Since not all rules map to specific weaknesses, this category may be incomplete.
Weaknesses in this category are related to rules in the Signals (SIG) section of the CERT C++ Secure Coding Standard. Since not all rules map to specific weaknesses, this category may be incomplete.
CERT C++ Secure Coding Section 12 - Exceptions and Error Handling (ERR)
Definition in a New Window
Category ID: 880 (Category)
Status: Incomplete
Description
Description Summary
Weaknesses in this category are related to rules in the Exceptions and Error Handling (ERR) section of the CERT C++ Secure Coding Standard. Since not all rules map to specific weaknesses, this category may be incomplete.
Weaknesses in this category are related to rules in the Object Oriented Programming (OOP) section of the CERT C++ Secure Coding Standard. Since not all rules map to specific weaknesses, this category may be incomplete.
CERT C++ Secure Coding Section 14 - Concurrency (CON)
Definition in a New Window
Category ID: 882 (Category)
Status: Incomplete
Description
Description Summary
Weaknesses in this category are related to rules in the Concurrency (CON) section of the CERT C++ Secure Coding Standard. Since not all rules map to specific weaknesses, this category may be incomplete.
CERT C++ Secure Coding Section 49 - Miscellaneous (MSC)
Definition in a New Window
Category ID: 883 (Category)
Status: Incomplete
Description
Description Summary
Weaknesses in this category are related to rules in the Miscellaneous (MSC) section of the CERT C++ Secure Coding Standard. Since not all rules map to specific weaknesses, this category may be incomplete.
The code uses an operator for comparison when the intention was to perform an assignment.
Extended Description
In many languages, the compare statement is very close in appearance to the assignment statement; they are often confused.
Time of Introduction
Implementation
Applicable Platforms
Languages
C
C++
Modes of Introduction
This bug primarily originates from a typo.
Common Consequences
Scope
Effect
Availability
Integrity
Technical Impact: Unexpected state
The assignment will not take place, which should cause obvious program
execution problems.
Likelihood of Exploit
Low
Demonstrative Examples
Example 1
(Bad Code)
Example Languages: C and C++ and Java
void called(int foo) {
foo==1;
if (foo==1) printf("foo\n");
}
int main() {
called(2);
return 0;
}
Example 2
The following C/C++ example shows a simple implementation of a stack
that includes methods for adding and removing integer values from the stack.
The example uses pointers to add and remove integer values to the stack
array variable.
(Bad Code)
Example Languages: C and C++
#define SIZE 50
int *tos, *p1, stack[SIZE];
void push(int i) {
p1++;
if(p1==(tos+SIZE)) {
// Print stack overflow error message and
exit
}
*p1 == i;
}
int pop(void) {
if(p1==tos) {
// Print stack underflow error message and
exit
}
p1--;
return *(p1+1);
}
int main(int argc, char *argv[]) {
// initialize tos and p1 to point to the top of
stack
tos = stack;
p1 = stack;
// code to add and remove items from stack
...
return 0;
}
The push method includes an expression to assign the integer value to
the location in the stack pointed to by the pointer variable.
However, this expression uses the comparison operator "==" rather than
the assignment operator "=". The result of using the comparison operator
instead of the assignment operator causes erroneous values to be entered
into the stack and can cause unexpected results.
Potential Mitigations
Phase: Testing
Many IDEs and static analysis products will detect this
problem.
[REF-7] Mark Dowd, John McDonald
and Justin Schuh. "The Art of Software Security Assessment". Chapter 6, "Typos", Page 289.. 1st Edition. Addison Wesley. 2006.
Sensitive memory is cleared according to the source code, but compiler optimizations leave the memory untouched when it is not read from again, aka "dead store removal."
Extended Description
This compiler optimization error occurs when:
1. Secret data are stored in memory.
2. The secret data are scrubbed from memory by overwriting its contents.
3. The source code is compiled using an optimizing compiler, which identifies and removes the function that overwrites the contents as a dead store because the memory is not used subsequently.
This weakness will allow data that has not been cleared from memory to
be read. If this data contains sensitive password information, then an
attacker can read the password and use the information to bypass
protection mechanisms.
Detection Methods
Black Box
This specific weakness is impossible to detect using black box
methods. While an analyst could examine memory to see that it has not
been scrubbed, an analysis of the executable would not be successful.
This is because the compiler has already removed the relevant code. Only
the source code shows whether the programmer intended to clear the
memory or not, so this weakness is indistinguishable from others.
White Box
This weakness is only detectable using white box methods (see black
box detection factor). Careful analysis is required to determine if the
code is likely to be removed by the compiler.
Demonstrative Examples
Example 1
The following code reads a password from the user, uses the password
to connect to a back-end mainframe and then attempts to scrub the password
from memory using memset().
(Bad Code)
Example
Language: C
void GetData(char *MFAddr) {
char pwd[64];
if (GetPasswordFromUser(pwd, sizeof(pwd))) {
if (ConnectToMainframe(MFAddr, pwd)) {
// Interaction with mainframe
}
}
memset(pwd, 0, sizeof(pwd));
}
The code in the example will behave correctly if it is executed
verbatim, but if the code is compiled using an optimizing compiler, such
as Microsoft Visual C++ .NET or GCC 3.x, then the call to memset() will
be removed as a dead store because the buffer pwd is not used after its
value is overwritten [18]. Because the buffer pwd contains a sensitive
value, the application may be vulnerable to attack if the data are left
memory resident. If attackers are able to access the correct region of
memory, they may use the recovered password to gain control of the
system.
It is common practice to overwrite sensitive data manipulated in
memory, such as passwords or cryptographic keys, in order to prevent
attackers from learning system secrets. However, with the advent of
optimizing compilers, programs do not always behave as their source code
alone would suggest. In the example, the compiler interprets the call to
memset() as dead code because the memory being written to is not
subsequently used, despite the fact that there is clearly a security
motivation for the operation to occur. The problem here is that many
compilers, and in fact many programming languages, do not take this and
other security concerns into consideration in their efforts to improve
efficiency.
Attackers typically exploit this type of vulnerability by using a
core dump or runtime mechanism to access the memory used by a particular
application and recover the secret information. Once an attacker has
access to the secret information, it is relatively straightforward to
further exploit the system and possibly compromise other resources with
which the application interacts.
Potential Mitigations
Phase: Implementation
Store the sensitive data in a "volatile" memory location if
available.
Phase: Build and Compilation
If possible, configure your compiler so that it does not remove dead
stores.
Phase: Architecture and Design
Where possible, encrypt sensitive data that are used by a software
system.
Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')
Definition in a New Window
Weakness ID: 362 (Weakness Class)
Status: Draft
Description
Description Summary
The program contains a code sequence that can run concurrently with other code, and the code sequence requires temporary, exclusive access to a shared resource, but a timing window exists in which the shared resource can be modified by another code sequence that is operating concurrently.
Extended Description
This can have security implications when the expected synchronization is in security-critical code, such as recording whether a user is authenticated or modifying important state information that should not be influenced by an outsider.
A race condition occurs within concurrent environments, and is effectively a property of a code sequence. Depending on the context, a code sequence may be in the form of a function call, a small number of instructions, a series of program invocations, etc.
A race condition violates these properties, which are closely related:
Exclusivity - the code sequence is given exclusive access to the shared resource, i.e., no other code sequence can modify properties of the shared resource before the original sequence has completed execution.
Atomicity - the code sequence is behaviorally atomic, i.e., no other thread or process can concurrently execute the same sequence of instructions (or a subset) against the same resource.
A race condition exists when an "interfering code sequence" can still access the shared resource, violating exclusivity. Programmers may assume that certain code sequences execute too quickly to be affected by an interfering code sequence; when they are not, this violates atomicity. For example, the single "x++" statement may appear atomic at the code layer, but it is actually non-atomic at the instruction layer, since it involves a read (the original value of x), followed by a computation (x+1), followed by a write (save the result to x).
The interfering code sequence could be "trusted" or "untrusted." A trusted interfering code sequence occurs within the program; it cannot be modified by the attacker, and it can only be invoked indirectly. An untrusted interfering code sequence can be authored directly by the attacker, and typically it is external to the vulnerable program.
Time of Introduction
Architecture and Design
Implementation
Applicable Platforms
Languages
C: (Sometimes)
C++: (Sometimes)
Java: (Sometimes)
Language-independent
Architectural Paradigms
Concurrent Systems Operating on Shared Resources: (Often)
When a race condition makes it possible to bypass a resource cleanup routine or trigger multiple initialization routines, it may lead to resource exhaustion (CWE-400).
When a race condition allows multiple control flows to access a
resource simultaneously, it might lead the program(s) into unexpected
states, possibly resulting in a crash.
Confidentiality
Integrity
Technical Impact: Read files or
directories; Read application
data
When a race condition is combined with predictable resource names and loose permissions, it may be possible for an attacker to overwrite or access confidential data (CWE-59).
Likelihood of Exploit
Medium
Detection Methods
Black Box
Black box methods may be able to identify evidence of race conditions
via methods such as multiple simultaneous connections, which may cause
the software to become instable or crash. However, race conditions with
very narrow timing windows would not be detectable.
White Box
Common idioms are detectable in white box analysis, such as time-of-check-time-of-use (TOCTOU) file operations (CWE-367), or double-checked locking (CWE-609).
Automated Dynamic Analysis
This weakness can be detected using dynamic tools and techniques that
interact with the software using large test suites with many diverse
inputs, such as fuzz testing (fuzzing), robustness testing, and fault
injection. The software's operation may slow down, but it should not
become unstable, crash, or generate incorrect results.
Race conditions may be detected with a stress-test by calling the
software simultaneously from a large number of threads or processes, and
look for evidence of any unexpected behavior.
Insert breakpoints or delays in between relevant code statements to
artificially expand the race window so that it will be easier to
detect.
Effectiveness: Moderate
Demonstrative Examples
Example 1
This code could be used in an e-commerce application that supports
transfers between accounts. It takes the total amount of the transfer, sends
it to the new account, and deducts the amount from the original
account.
(Bad Code)
Example
Language: Perl
$transfer_amount = GetTransferAmount();
$balance = GetBalanceFromDatabase();
if ($transfer_amount < 0) {
FatalError("Bad Transfer Amount");
}
$newbalance = $balance - $transfer_amount;
if (($balance - $transfer_amount) < 0) {
FatalError("Insufficient Funds");
}
SendNewBalanceToDatabase($newbalance);
NotifyUser("Transfer of $transfer_amount succeeded.");
NotifyUser("New balance: $newbalance");
A race condition could occur between the calls to
GetBalanceFromDatabase() and SendNewBalanceToDatabase().
Suppose the balance is initially 100.00. An attack could be
constructed as follows:
(Attack)
Example
Language: PseudoCode
The attacker makes two simultaneous calls of the program, CALLER-1
and CALLER-2. Both callers are for the same user account.
CALLER-1 (the attacker) is associated with PROGRAM-1 (the instance
that handles CALLER-1). CALLER-2 is associated with
PROGRAM-2.
CALLER-1 makes a transfer request of 80.00.
PROGRAM-1 calls GetBalanceFromDatabase and sets $balance to
100.00
PROGRAM-1 calculates $newbalance as 20.00, then calls
SendNewBalanceToDatabase().
Due to high server load, the PROGRAM-1 call to
SendNewBalanceToDatabase() encounters a delay.
CALLER-2 makes a transfer request of 1.00.
PROGRAM-2 calls GetBalanceFromDatabase() and sets $balance to
100.00. This happens because the previous PROGRAM-1 request was not
processed yet.
PROGRAM-2 determines the new balance as 99.00.
After the initial delay, PROGRAM-1 commits its balance to the
database, setting it to 20.00.
PROGRAM-2 sends a request to update the database, setting the
balance to 99.00
At this stage, the attacker should have a balance of 19.00 (due to
81.00 worth of transfers), but the balance is 99.00, as recorded in the
database.
To prevent this weakness, the programmer has several options,
including using a lock to prevent multiple simultaneous requests to the
web application, or using a synchronization mechanism that includes all
the code between GetBalanceFromDatabase() and
SendNewBalanceToDatabase().
Example 2
The following function attempts to acquire a lock in order to
perform operations on a shared resource.
(Bad Code)
Example
Language: C
void f(pthread_mutex_t *mutex) {
pthread_mutex_lock(mutex);
/* access shared resource */
pthread_mutex_unlock(mutex);
}
However, the code does not check the value returned by
pthread_mutex_lock() for errors. If pthread_mutex_lock() cannot acquire
the mutex for any reason, the function may introduce a race condition
into the program and result in undefined behavior.
In order to avoid data races, correctly written programs must check
the result of thread synchronization functions and appropriately handle
all errors, either by attempting to recover from them or reporting it to
higher levels.
chain: time-of-check time-of-use (TOCTOU) race
condition in program allows bypass of protection mechanism that was designed
to prevent symlink attacks.
chain: time-of-check time-of-use (TOCTOU) race
condition in program allows bypass of protection mechanism that was designed
to prevent symlink attacks.
chain: race condition might allow resource to be
released before operating on it, leading to NULL dereference
Potential Mitigations
Phase: Architecture and Design
In languages that support it, use synchronization primitives. Only
wrap these around critical code to minimize the impact on
performance.
Phase: Architecture and Design
Use thread-safe capabilities such as the data access abstraction in
Spring.
Phase: Architecture and Design
Minimize the usage of shared resources in order to remove as much
complexity as possible from the control flow and to reduce the
likelihood of unexpected conditions occurring.
Additionally, this will minimize the amount of synchronization necessary and may even help to reduce the likelihood of a denial of service where an attacker may be able to repeatedly trigger a critical section (CWE-400).
Phase: Implementation
When using multithreading and operating on shared variables, only use
thread-safe functions.
Phase: Implementation
Use atomic operations on shared variables. Be wary of innocent-looking
constructs such as "x++". This may appear atomic at the code layer, but
it is actually non-atomic at the instruction layer, since it involves a
read, followed by a computation, followed by a write.
Phase: Implementation
Use a mutex if available, but be sure to avoid related weaknesses such as CWE-412.
Phase: Implementation
Avoid double-checked locking (CWE-609) and other implementation errors that arise when trying to avoid the overhead of synchronization.
Phase: Implementation
Disable interrupts or signals over critical parts of the code, but
also make sure that the code does not go into a large or infinite
loop.
Phase: Implementation
Use the volatile type modifier for critical variables to avoid
unexpected compiler optimization or reordering. This does not
necessarily solve the synchronization problem, but it can help.
Phases: Architecture and Design; Operation
Strategy: Environment Hardening
Run your code using the lowest privileges that are required to accomplish the necessary tasks [R.362.11]. If possible, create isolated accounts with limited privileges that are only used for a single task. That way, a successful attack will not immediately give the attacker access to the rest of the software or its environment. For example, database applications rarely need to run as the database administrator, especially in day-to-day operations.
Race conditions in web applications are under-studied and probably
under-reported. However, in 2008 there has been growing interest in this
area.
Much of the focus of race condition research has been in Time-of-check Time-of-use (TOCTOU) variants (CWE-367), but many race conditions are related to synchronization problems that do not necessarily require a time-of-check.
Taxonomy Mappings
Mapped Taxonomy Name
Node ID
Fit
Mapped Node Name
PLOVER
Race Conditions
CERT C Secure Coding
FIO31-C
Do not simultaneously open the same file multiple
times
CERT Java Secure Coding
VNA03-J
Do not assume that a group of calls to independently atomic
methods is atomic
CERT C++ Secure Coding
FIO31-CPP
Do not simultaneously open the same file multiple
times
Leveraging Time-of-Check and Time-of-Use (TOCTOU) Race Conditions
References
[R.362.1] [REF-17] Michael Howard, David LeBlanc
and John Viega. "24 Deadly Sins of Software Security". "Sin 13: Race Conditions." Page 205. McGraw-Hill. 2010.
[R.362.2] Andrei Alexandrescu. "volatile - Multithreaded Programmer's Best
Friend". Dr. Dobb's. 2008-02-01. <http://www.ddj.com/cpp/184403766>.
The relationship between race conditions and synchronization problems (CWE-662) needs to be further developed. They are not necessarily two perspectives of the same core concept, since synchronization is only one technique for avoiding race conditions, and synchronization can be used for other purposes besides race condition prevention.
Creation of Temporary File in Directory with Incorrect Permissions
Definition in a New Window
Weakness ID: 379 (Weakness Base)
Status: Incomplete
Description
Description Summary
The software creates a temporary file in a directory whose permissions allow unintended actors to determine the file's existence or otherwise access that file.
Extended Description
On some operating systems, the fact that the temporary file exists may be apparent to any user with sufficient privileges to access that directory. Since the file is visible, the application that is using the temporary file could be known. If one has access to list the processes on the system, the attacker has gained information about what the user is doing at that time. By correlating this with the applications the user is running, an attacker could potentially discover what a user's actions are. From this, higher levels of security could be breached.
Time of Introduction
Architecture and Design
Implementation
Applicable Platforms
Languages
All
Common Consequences
Scope
Effect
Confidentiality
Technical Impact: Read application
data
Since the file is visible and the application which is using the temp
file could be known, the attacker has gained information about what the
user is doing at that time.
Likelihood of Exploit
Low
Demonstrative Examples
Example 1
In the following code examples a temporary file is created and
written to and after using the temporary file the file is closed and deleted
from the file system.
(Bad Code)
Example Languages: C and C++
FILE *stream;
if( (stream = tmpfile()) == NULL ) {
perror("Could not open new temporary file\n");
return (-1);
}
// write data to tmp file
...
// remove tmp file
rmtmp();
However, within this C/C++ code the method tmpfile() is used to create
and open the temp file. The tmpfile() method works the same way as the
fopen() method would with read/write permission, allowing attackers to
read potentially sensitive information contained in the temp file or
modify the contents of the file.
BufferedWriter out = new BufferedWriter(new
FileWriter(temp));
out.write("aString");
out.close();
}
catch (IOException e) {
}
Similarly, the createTempFile() method used in the Java code creates a
temp file that may be readable and writable to all users.
Additionally both methods used above place the file into a default
directory. On UNIX systems the default directory is usually "/tmp" or
"/var/tmp" and on Windows systems the default directory is usually
"C:\\Windows\\Temp", which may be easily accessible to attackers,
possibly enabling them to read and modify the contents of the temp
file.
Potential Mitigations
Phase: Requirements
Many contemporary languages have functions which properly handle this
condition. Older C temp file functions are especially
susceptible.
Phase: Implementation
Try to store sensitive tempfiles in a directory which is not world
readable -- i.e., per-user directories.
Ensure that file operations are performed in a secure
directory
CERT C Secure Coding
FIO43-C
Do not create temporary files in shared
directories
CERT C++ Secure Coding
FIO15-CPP
Ensure that file operations are performed in a secure
directory
CERT C++ Secure Coding
FIO43-CPP
Do not create temporary files in shared
directories
References
[REF-7] Mark Dowd, John McDonald
and Justin Schuh. "The Art of Software Security Assessment". Chapter 9, "Temporary Files", Page 538.. 1st Edition. Addison Wesley. 2006.
The software contains dead code, which can never be executed.
Extended Description
Dead code is source code that can never be executed in a running program. The surrounding code makes it impossible for a section of code to ever be executed.
Time of Introduction
Implementation
Common Consequences
Scope
Effect
Other
Technical Impact: Quality degradation
Dead code that results from code that can never be executed is an
indication of problems with the source code that needs to be fixed and
is an indication of poor quality.
Demonstrative Examples
Example 1
The condition for the second if statement is impossible to satisfy.
It requires that the variables be non-null, while on the only path where s
can be assigned a non-null value there is a return statement.
(Bad Code)
Example
Language: C++
String s = null;
if (b) {
s = "Yes";
return;
}
if (s != null) {
Dead();
}
Example 2
In the following class, two private methods call each other, but
since neither one is ever invoked from anywhere else, they are both dead
code.
(Bad Code)
Example
Language: Java
public class DoubleDead {
private void doTweedledee() {
doTweedledumb();
}
private void doTweedledumb() {
doTweedledee();
}
public static void main(String[] args) {
System.out.println("running DoubleDead");
}
}
(In this case it is a good thing that the methods are dead: invoking
either one would cause an infinite loop.)
Example 3
The field named glue is not used in the following class. The author
of the class has accidentally put quotes around the field name, transforming
it into a string constant.
(Bad Code)
Example
Language: Java
public class Dead {
String glue;
public String getGlue() {
return "glue";
}
}
Potential Mitigations
Phase: Implementation
Remove dead code before deploying the application.
The software detects a specific error, but takes no actions to handle the error.
Time of Introduction
Architecture and Design
Implementation
Applicable Platforms
Languages
All
Common Consequences
Scope
Effect
Integrity
Other
Technical Impact: Varies by context; Unexpected state; Alter execution
logic
An attacker could utilize an ignored error condition to place the
system in an unexpected state that could lead to the execution of
unintended logic and could cause other unintended behavior.
Likelihood of Exploit
Medium
Demonstrative Examples
Example 1
The following example attempts to allocate memory for a character.
After the call to malloc, an if statement is used to check whether the
malloc function failed.
(Bad Code)
Example
Language: C
foo=malloc(sizeof(char)); //the next line checks to see if malloc
failed
if (foo==NULL) {
//We do nothing so we just ignore the error.
}
The conditional successfully detects a NULL return value from malloc
indicating a failure, however it does not do anything to handle the
problem. Unhandled errors may have unexpected results and may cause the
program to crash or terminate.
Instead, the if block should contain statements that either attempt to
fix the problem or notify the user that an error has occurred and
continue processing or perform some cleanup and gracefully terminate the
program. The following example notifies the user that the malloc
function did not allocate the required memory resources and returns an
error code.
(Good Code)
Example
Language: C
foo=malloc(sizeof(char)); //the next line checks to see if malloc
failed
if (foo==NULL) {
printf("Malloc failed to allocate memory resources");
return -1;
}
Example 2
In the following C++ example the method readFile() will read the
file whose name is provided in the input parameter and will return the
contents of the file in char string. The method calls open() and read() may
result in errors if the file does not exist or does not contain any data to
read. These errors will be thrown when the is_open() method and good()
method indicate errors opening or reading the file. However, these errors
are not handled within the catch statement. Catch statements that do not
perform any processing will have unexpected results. In this case an empty
char string will be returned, and the file will not be properly
closed.
(Bad Code)
Example
Language: C++
char* readfile (char *filename) {
try {
// open input file
ifstream infile;
infile.open(filename);
if (!infile.is_open()) {
throw "Unable to open file " + filename;
}
// get length of file
infile.seekg (0, ios::end);
int length = infile.tellg();
infile.seekg (0, ios::beg);
// allocate memory
char *buffer = new char [length];
// read data from file
infile.read (buffer,length);
if (!infile.good()) {
throw "Unable to read from file " + filename;
}
infile.close();
return buffer;
}
catch (...) {
/* bug: insert code to handle this later */
}
}
The catch statement should contain statements that either attempt to
fix the problem or notify the user that an error has occurred and
continue processing or perform some cleanup and gracefully terminate the
program. The following C++ example contains two catch statements. The
first of these will catch a specific error thrown within the try block,
and the second catch statement will catch all other errors from within
the catch block. Both catch statements will notify the user that an
error has occurred, close the file, and rethrow to the block that called
the readFile() method for further handling or possible termination of
the program.
(Good Code)
Example
Language: C++
char* readFile (char *filename) {
try {
// open input file
ifstream infile;
infile.open(filename);
if (!infile.is_open()) {
throw "Unable to open file " + filename;
}
// get length of file
infile.seekg (0, ios::end);
int length = infile.tellg();
infile.seekg (0, ios::beg);
// allocate memory
char *buffer = new char [length];
// read data from file
infile.read (buffer,length);
if (!infile.good()) {
throw "Unable to read from file " + filename;
}
infile.close();
return buffer;
}
catch (char *str) {
printf("Error: %s \n", str);
infile.close();
throw str;
}
catch (...) {
printf("Error occurred trying to read from file
\n");
infile.close();
throw;
}
}
Example 3
In the following Java example the method readFile will read the file
whose name is provided in the input parameter and will return the contents
of the file in a String object. The constructor of the FileReader object and
the read method call may throw exceptions and therefore must be within a
try/catch block. While the catch statement in this example will catch thrown
exceptions in order for the method to compile, no processing is performed to
handle the thrown exceptions. Catch statements that do not perform any
processing will have unexpected results. In this case, this will result in
the return of a null String.
(Bad Code)
Example
Language: Java
public String readFile(String filename) {
String retString = null;
try {
// initialize File and FileReader objects
File file = new File(filename);
FileReader fr = new FileReader(file);
// initialize character buffer
long fLen = file.length();
char[] cBuf = new char[(int) fLen];
// read data from file
int iRead = fr.read(cBuf, 0, (int) fLen);
// close file
fr.close();
retString = new String(cBuf);
} catch (Exception ex) {
/* do nothing, but catch so it'll compile... */
}
return retString;
}
The catch statement should contain statements that either attempt to
fix the problem, notify the user that an exception has been raised and
continue processing, or perform some cleanup and gracefully terminate
the program. The following Java example contains three catch statements.
The first of these will catch the FileNotFoundException that may be
thrown by the FileReader constructor called within the try/catch block.
The second catch statement will catch the IOException that may be thrown
by the read method called within the try/catch block. The third catch
statement will catch all other exceptions thrown within the try block.
For all catch statements the user is notified that the exception has
been thrown and the exception is rethrown to the block that called the
readFile() method for further processing or possible termination of the
program. Note that with Java it is usually good practice to use the
getMessage() method of the exception class to provide more information
to the user about the exception raised.
(Good Code)
Example
Language: Java
public String readFile(String filename) throws
FileNotFoundException, IOException, Exception {
System.err.println("Error: IOException reading the input
file.\n" + ex.getMessage() );
throw new IOException(ex);
} catch (Exception ex) {
System.err.println("Error: Exception reading the input
file.\n" + ex.getMessage() );
throw new Exception(ex);
}
return retString;
}
Potential Mitigations
Phase: Implementation
Properly handle each exception. This is the recommended solution.
Ensure that all exceptions are handled in such a way that you can be
sure of the state of your system at any given moment.
Phase: Implementation
If a function returns an error, it is important to either fix the
problem and try again, alert the user that an error has happened and let
the program continue, or alert the user and close and cleanup the
program.
Phase: Testing
Subject the software to extensive testing to discover some of the
possible instances of where/how errors or return values are not handled.
Consider testing techniques such as ad hoc, equivalence partitioning,
robustness and fault tolerance, mutation, and fuzzing.
[REF-17] Michael Howard, David LeBlanc
and John Viega. "24 Deadly Sins of Software Security". "Sin 11: Failure to Handle Errors Correctly." Page
183. McGraw-Hill. 2010.
This weakness typically occurs when an unexpected value is provided to the product, or if an error occurs that is not properly detected. It frequently occurs in calculations involving physical dimensions such as size, length, width, and height.
Time of Introduction
Implementation
Common Consequences
Scope
Effect
Availability
Technical Impact: DoS: crash / exit /
restart
A Divide by Zero results in a crash.
Likelihood of Exploit
Medium
Demonstrative Examples
Example 1
The following Java example contains a function to compute an average
but does not validate that the input value used as the denominator is not
zero. This will create an exception for attempting to divide by zero. If
this error is not handled by Java exception handling, unexpected results can
occur.
(Bad Code)
Example
Language: Java
public int computeAverageResponseTime (int totalTime, int
numRequests) {
return totalTime / numRequests;
}
By validating the input value used as the denominator the following
code will ensure that a divide by zero error will not cause unexpected
results. The following Java code example will validate the input value,
output an error message, and throw an exception.
(Good Code)
public int computeAverageResponseTime (int totalTime, int
numRequests) throws ArithmeticException {
if (numRequests == 0) {
System.out.println("Division by zero attempted!");
throw ArithmeticException;
}
return totalTime / numRequests;
}
Example 2
The following C/C++ example contains a function that divides two
numeric values without verifying that the input value used as the
denominator is not zero. This will create an error for attempting to divide
by zero, if this error is not caught by the error handling capabilities of
the language, unexpected results can occur.
(Bad Code)
Example Languages: C and C++
double divide(double x, double y){
return x/y;
}
By validating the input value used as the denominator the following
code will ensure that a divide by zero error will not cause unexpected
results. If the method is called and a zero is passed as the second
argument a DivideByZero error will be thrown and should be caught by the
calling block with an output message indicating the error.
The following C# example contains a function that divides two
numeric values without verifying that the input value used as the
denominator is not zero. This will create an error for attempting to divide
by zero, if this error is not caught by the error handling capabilities of
the language, unexpected results can occur.
(Bad Code)
Example
Language: C#
int Division(int x, int y){
return (x / y);
}
The method can be modified to raise, catch and handle the
DivideByZeroException if the input value used as the denominator is
zero.
(Good Code)
int SafeDivision(int x, int y){
try{
return (x / y);
}
catch (System.DivideByZeroException dbz){
System.Console.WriteLine("Division by zero
attempted!");
The product calls free() twice on the same memory address, potentially leading to modification of unexpected memory locations.
Extended Description
When a program calls free() twice with the same argument, the program's memory management data structures become corrupted. This corruption can cause the program to crash or, in some circumstances, cause two later calls to malloc() to return the same pointer. If malloc() returns the same value twice and the program later gives the attacker control over the data that is written into this doubly-allocated memory, the program becomes vulnerable to a buffer overflow attack.
Alternate Terms
Double-free
Time of Introduction
Architecture and Design
Implementation
Applicable Platforms
Languages
C
C++
Common Consequences
Scope
Effect
Integrity
Confidentiality
Availability
Technical Impact: Execute unauthorized code or
commands
Doubly freeing memory may result in a write-what-where condition,
allowing an attacker to execute arbitrary code.
Likelihood of Exploit
Low to Medium
Demonstrative Examples
Example 1
The following code shows a simple example of a double free
vulnerability.
(Bad Code)
Example
Language: C
char* ptr = (char*)malloc (SIZE);
...
if (abrt) {
free(ptr);
}
...
free(ptr);
Double free vulnerabilities have two common (and sometimes
overlapping) causes:
Error conditions and other exceptional circumstances
Confusion over which part of the program is responsible for
freeing the memory
Although some double free vulnerabilities are not much more
complicated than the previous example, most are spread out across
hundreds of lines of code or even different files. Programmers seem
particularly susceptible to freeing global variables more than
once.
Example 2
While contrived, this code should be exploitable on Linux
distributions which do not ship with heap-chunk check summing turned
on.
Choose a language that provides automatic memory management.
Phase: Implementation
Ensure that each allocation is freed only once. After freeing a chunk,
set the pointer to NULL to ensure the pointer cannot be freed again. In
complicated error conditions, be sure that clean-up routines respect the
state of allocation properly. If the language is object oriented, ensure
that object destructors delete each chunk of memory only once.
Phase: Implementation
Use a static analysis tool to find double free instances.
This is usually resultant from another weakness, such as an unhandled
error or race condition between threads. It could also be primary to
weaknesses such as buffer overflows.
Affected Resources
Memory
Taxonomy Mappings
Mapped Taxonomy Name
Node ID
Fit
Mapped Node Name
PLOVER
DFREE - Double-Free Vulnerability
7 Pernicious Kingdoms
Double Free
CLASP
Doubly freeing memory
CERT C Secure Coding
MEM00-C
Allocate and free memory in the same module, at the same level
of abstraction
CERT C Secure Coding
MEM01-C
Store a new value in pointers immediately after
free()
CERT C Secure Coding
MEM31-C
Free dynamically allocated memory exactly
once
CERT C++ Secure Coding
MEM01-CPP
Store a valid value in pointers immediately after
deallocation
CERT C++ Secure Coding
MEM31-CPP
Free dynamically allocated memory exactly
once
White Box Definitions
A weakness where code path has:
1. start statement that relinquishes a dynamically allocated memory
resource
2. end statement that relinquishes the dynamically allocated memory
resource
References
[REF-17] Michael Howard, David LeBlanc
and John Viega. "24 Deadly Sins of Software Security". "Sin 8: C++ Catastrophes." Page 143. McGraw-Hill. 2010.
[REF-7] Mark Dowd, John McDonald
and Justin Schuh. "The Art of Software Security Assessment". Chapter 7, "Double Frees", Page 379.. 1st Edition. Addison Wesley. 2006.
Maintenance Notes
It could be argued that Double Free would be most appropriately located as
a child of "Use after Free", but "Use" and "Release" are considered to be
distinct operations within vulnerability theory, therefore this is more
accurately "Release of a Resource after Expiration or Release", which
doesn't exist yet.
Duplicate keys in associative lists can lead to non-unique keys being mistaken for an error.
Extended Description
A duplicate key entry -- if the alist is designed properly -- could be used as a constant time replace function. However, duplicate key entries could be inserted by mistake. Because of this ambiguity, duplicate key entries in an association list are not recommended and should not be allowed.
Time of Introduction
Architecture and Design
Implementation
Applicable Platforms
Languages
C
C++
Java
.NET
Common Consequences
Scope
Effect
Other
Technical Impact: Quality degradation; Varies by context
Likelihood of Exploit
Low
Demonstrative Examples
Example 1
The following code adds data to a list and then attempts to sort the
data.
(Bad Code)
alist = []
while (foo()): #now assume there is a string data with a key
basename
queue.append(basename,data)
queue.sort()
Since basename is not necessarily unique, this may not sort how one
would like it to be.
Potential Mitigations
Phase: Architecture and Design
Use a hash table instead of an alist.
Phase: Architecture and Design
Use an alist which checks the uniqueness of hash keys with each entry
before inserting the entry.
This weakness is probably closely associated with other issues related to doubling, such as CWE-462 (duplicate key in alist) or CWE-102 (Struts duplicate validation forms). It's usually a case of an API contract violation (CWE-227).
Relevant Properties
Uniqueness
Taxonomy Mappings
Mapped Taxonomy Name
Node ID
Fit
Mapped Node Name
CERT C Secure Coding
FIO31-C
Do not simultaneously open the same file multiple
times
CERT C++ Secure Coding
FIO31-CPP
Do not simultaneously open the same file multiple
times
The product does not sufficiently enforce boundaries between the states of different sessions, causing data to be provided to, or used by, the wrong session.
Extended Description
Data can "bleed" from one session to another through member variables of singleton objects, such as Servlets, and objects from a shared pool.
In the case of Servlets, developers sometimes do not understand that, unless a Servlet implements the SingleThreadModel interface, the Servlet is a singleton; there is only one instance of the Servlet, and that single instance is used and re-used to handle multiple requests that are processed simultaneously by different threads. A common result is that developers use Servlet member fields in such a way that one user may inadvertently see another user's data. In other words, storing user data in Servlet member fields introduces a data access race condition.
Time of Introduction
Implementation
Applicable Platforms
Languages
All
Common Consequences
Scope
Effect
Confidentiality
Technical Impact: Read application
data
Demonstrative Examples
Example 1
The following Servlet stores the value of a request parameter in a
member field and then later echoes the parameter value to the response
output stream.
While this code will work perfectly in a single-user environment, if
two users access the Servlet at approximately the same time, it is
possible for the two request handler threads to interleave in the
following way: Thread 1: assign "Dick" to name Thread 2: assign "Jane"
to name Thread 1: print "Jane, thanks for visiting!" Thread 2: print
"Jane, thanks for visiting!" Thereby showing the first user the second
user's name.
Potential Mitigations
Phase: Architecture and Design
Protect the application's sessions from information leakage. Make sure
that a session's data is not used or visible by other sessions.
Phase: Testing
Use a static analysis tool to scan the code for information leakage
vulnerabilities (e.g. Singleton Member Field).
Phase: Architecture and Design
In a multithreading environment, storing user data in Servlet member
fields introduces a data access race condition. Do not use member fields
to store information in the Servlet.
Exposure of File Descriptor to Unintended Control Sphere ('File Descriptor Leak')
Definition in a New Window
Weakness ID: 403 (Weakness Base)
Status: Draft
Description
Description Summary
A process does not close sensitive file descriptors before invoking a child process, which allows the child to perform unauthorized I/O operations using those descriptors.
Extended Description
When a new process is forked or executed, the child process inherits any open file descriptors. When the child process has fewer privileges than the parent process, this might introduce a vulnerability if the child process can access the file descriptor but does not have the privileges to access the associated file.
Alternate Terms
File descriptor leak:
While this issue is frequently called a file descriptor leak, the
"leak" term is often used in two different ways - exposure of a
resource, or consumption of a resource. Use of this term could cause
confusion.
Time of Introduction
Architecture and Design
Implementation
Applicable Platforms
Languages
All
Operating Systems
UNIX
Common Consequences
Scope
Effect
Confidentiality
Integrity
Technical Impact: Read application
data; Modify application
data
Exposure of System Data to an Unauthorized Control Sphere
Definition in a New Window
Weakness ID: 497 (Weakness Variant)
Status: Incomplete
Description
Description Summary
Exposing system data or debugging information helps an adversary learn about the system and form an attack plan.
Extended Description
An information exposure occurs when system data or debugging information leaves the program through an output stream or logging function that makes it accessible to unauthorized parties. An attacker can also cause errors to occur by submitting unusual requests to the web application. The response to these errors can reveal detailed system information, deny service, cause security mechanisms to fail, and crash the server. An attacker can use error messages that reveal technologies, operating systems, and product versions to tune the attack against known vulnerabilities in these technologies. An application may use diagnostic methods that provide significant implementation details such as stack traces as part of its error handling mechanism.
Time of Introduction
Implementation
Applicable Platforms
Languages
All
Common Consequences
Scope
Effect
Confidentiality
Technical Impact: Read application
data
Demonstrative Examples
Example 1
The following code prints the path environment variable to the
standard error stream:
(Bad Code)
Example
Language: C
char* path = getenv("PATH");
...
sprintf(stderr, "cannot find exe on path %s\n", path);
Example 2
The following code prints an exception to the standard error
stream:
(Bad Code)
Example
Language: Java
try {
...
} catch (Exception e) {
e.printStackTrace();
}
(Bad Code)
try {
...
} catch (Exception e) {
Console.Writeline(e);
}
Depending upon the system configuration, this information can be
dumped to a console, written to a log file, or exposed to a remote user.
In some cases the error message tells the attacker precisely what sort
of an attack the system will be vulnerable to. For example, a database
error message can reveal that the application is vulnerable to a SQL
injection attack. Other error messages can reveal more oblique clues
about the system. In the example above, the search path could imply
information about the type of operating system, the applications
installed on the system, and the amount of care that the administrators
have put into configuring the program.
Example 3
The following code constructs a database connection string, uses it
to create a new connection to the database, and prints it to the
console.
Depending on the system configuration, this information can be dumped
to a console, written to a log file, or exposed to a remote user. In
some cases the error message tells the attacker precisely what sort of
an attack the system is vulnerable to. For example, a database error
message can reveal that the application is vulnerable to a SQL injection
attack. Other error messages can reveal more oblique clues about the
system. In the example above, the search path could imply information
about the type of operating system, the applications installed on the
system, and the amount of care that the administrators have put into
configuring the program.
Potential Mitigations
Phases: Architecture and Design; Implementation
Production applications should never use methods that generate
internal details such as stack traces and error messages unless that
information is directly committed to a log that is not viewable by the
end user. All error message text should be HTML entity encoded before
being written to the log file to protect against potential cross-site
scripting attacks against the viewer of the logs
The software contains an expression that will always evaluate to false.
Time of Introduction
Implementation
Applicable Platforms
Languages
All
Common Consequences
Scope
Effect
Other
Technical Impact: Quality degradation; Varies by context
Demonstrative Examples
Example 1
In the following Java example the updateUserAccountOrder() method
used within an e-business product ordering/inventory application will
validate the product number that was ordered and the user account number. If
they are valid, the method will update the product inventory, the user
account, and the user order appropriately.
(Bad Code)
Example
Language: Java
public void updateUserAccountOrder(String productNumber, String
accountNumber) {
boolean isValidProduct = false;
boolean isValidAccount = false;
if (validProductNumber(productNumber)) {
isValidProduct = true;
updateInventory(productNumber);
}
else {
return;
}
if (validAccountNumber(accountNumber)) {
isValidProduct = true;
updateAccount(accountNumber, productNumber);
}
if (isValidProduct && isValidAccount) {
updateAccountOrder(accountNumber, productNumber);
}
}
However, the method never sets the isValidAccount variable after
initializing it to false so the isValidProduct is mistakenly used twice.
The result is that the expression "isValidProduct &&
isValidAccount" will always evaluate to false, so the
updateAccountOrder() method will never be invoked. This will create
serious problems with the product ordering application since the user
account and inventory databases will be updated but the order will not
be updated.
This can be easily corrected by updating the appropriate
variable.
(Good Code)
...
if (validAccountNumber(accountNumber)) {
isValidAccount = true;
updateAccount(accountNumber, productNumber);
}
...
Example 2
In the following example, the hasReadWriteAccess method uses bit
masks and bit operators to determine if a user has read and write privileges
for a particular process. The variable mask is defined as a bit mask from
the BIT_READ and BIT_WRITE constants that have been defined. The variable
mask is used within the predicate of the hasReadWriteAccess method to
determine if the userMask input parameter has the read and write bits set.
(Bad Code)
#define BIT_READ 0x0001 // 00000001
#define BIT_WRITE 0x0010 // 00010000
unsigned int mask = BIT_READ & BIT_WRITE; /* intended to
use "|" */
// using "&", mask = 00000000
// using "|", mask = 00010001
// determine if user has read and write access
int hasReadWriteAccess(unsigned int userMask) {
// if the userMask has read and write bits set
// then return 1 (true)
if (userMask & mask) {
return 1;
}
// otherwise return 0 (false)
return 0;
}
However the bit operator used to initialize the mask variable is the AND operator rather than the intended OR operator (CWE-480), this resulted in the variable mask being set to 0. As a result, the if statement will always evaluate to false and never get executed.
The use of bit masks, bit operators and bitwise operations on
variables can be difficult. If possible, try to use frameworks or
libraries that provide appropriate functionality and abstract the
implementation.
Example 3
In the following example, the updateInventory method used within an
e-business inventory application will update the inventory for a particular
product. This method includes an if statement with an expression that will
always evaluate to false. This is a common practice in C/C++ to introduce
debugging statements quickly by simply changing the expression to evaluate
to true and then removing those debugging statements by changing expression
to evaluate to false. This is also a common practice for disabling features
no longer needed.
(Bad Code)
int updateInventory(char* productNumber, int numberOfItems)
{
int initCount = getProductCount(productNumber);
int updatedCount = initCount + numberOfItems;
int updated = updateProductCount(updatedCount);
// if statement for debugging purposes only
if (1 == 0) {
char productName[128];
productName = getProductName(productNumber);
printf("product %s initially has %d items in inventory
\n", productName, initCount);
printf("adding %d items to inventory for %s \n",
numberOfItems, productName);
if (updated == 0) {
printf("Inventory updated for product %s to %d items
\n", productName, updatedCount);
}
else {
printf("Inventory not updated for product: %s \n",
productName);
}
}
return updated;
}
Using this practice for introducing debugging statements or disabling
features creates dead code that can cause problems during code
maintenance and potentially introduce vulnerabilities. To avoid using
expressions that evaluate to false for debugging purposes a logging API
or debugging API should be used for the output of debugging
messages.
Potential Mitigations
Phase: Testing
Use Static Analysis tools to spot such conditions.
The software contains an expression that will always evaluate to true.
Time of Introduction
Implementation
Applicable Platforms
Languages
All
Common Consequences
Scope
Effect
Other
Technical Impact: Quality degradation; Varies by context
Demonstrative Examples
Example 1
In the following Java example the updateInventory() method used
within an e-business product ordering/inventory application will check if
the input product number is in the store or in the warehouse. If the product
is found, the method will update the store or warehouse database as well as
the aggregate product database. If the product is not found, the method
intends to do some special processing without updating any database.
(Bad Code)
Example
Language: Java
public void updateInventory(String productNumber) {
boolean isProductAvailable = false;
boolean isDelayed = false;
if (productInStore(productNumber)) {
isProductAvailable = true;
updateInStoreDatabase(productNumber);
}
else if (productInWarehouse(productNumber)) {
isProductAvailable = true;
updateInWarehouseDatabase(productNumber);
}
else {
isProductAvailable = true;
}
if ( isProductAvailable ) {
updateProductDatabase(productNumber);
}
else if ( isDelayed ) {
/* Warn customer about delay before order processing
*/
...
}
}
However, the method never sets the isDelayed variable and instead will
always update the isProductAvailable variable to true. The result is
that the predicate testing the isProductAvailable boolean will always
evaluate to true and therefore always update the product database.
Further, since the isDelayed variable is initialized to false and never
changed, the expression always evaluates to false and the customer will
never be warned of a delay on their product.
Potential Mitigations
Phase: Testing
Use Static Analysis tools to spot such conditions.
The software allows user input to control or influence paths or file names that are used in filesystem operations.
Extended Description
This could allow an attacker to access or modify system files or other files that are critical to the application.
Path manipulation errors occur when the following two conditions are met:
1. An attacker can specify a path used in an operation on the filesystem.
2. By specifying the resource, the attacker gains a capability that would not otherwise be permitted.
For example, the program may give the attacker the ability to overwrite the specified file or run with a configuration controlled by the attacker.
Time of Introduction
Architecture and Design
Implementation
Operation
Applicable Platforms
Languages
All
Operating Systems
UNIX: (Often)
Windows: (Often)
Mac OS: (Often)
Common Consequences
Scope
Effect
Integrity
Confidentiality
Technical Impact: Read files or
directories; Modify files or
directories
The application can operate on unexpected files. Confidentiality is
violated when the targeted filename is not directly readable by the
attacker.
Integrity
Confidentiality
Availability
Technical Impact: Modify files or
directories; Execute unauthorized code or
commands
The application can operate on unexpected files. This may violate
integrity if the filename is written to, or if the filename is for a
program or other form of executable code.
The application can operate on unexpected files. Availability can be
violated if the attacker specifies an unexpected file that the
application modifies. Availability can also be affected if the attacker
specifies a filename for a large file, or points to a special device or
a file that does not have the format that the application
expects.
Likelihood of Exploit
High to Very High
Detection Methods
Automated Static Analysis
The external control or influence of filenames can often be detected
using automated static analysis that models data flow within the
software.
Automated static analysis might not be able to recognize when proper
input validation is being performed, leading to false positives - i.e.,
warnings that do not have any security consequences or require any code
changes.
Demonstrative Examples
Example 1
The following code uses input from an HTTP request to create a file name. The programmer has not considered the possibility that an attacker could provide a file name such as "../../tomcat/conf/server.xml", which causes the application to delete one of its own configuration files (CWE-22).
File rFile = new File("/usr/local/apfr/reports/" + rName);
...
rFile.delete();
Example 2
The following code uses input from a configuration file to determine
which file to open and echo back to the user. If the program runs with
privileges and malicious users can change the configuration file, they can
use the program to read any file on the system that ends with the extension
.txt.
(Bad Code)
Example
Language: Java
fis = new FileInputStream(cfg.getProperty("sub")+".txt");
Chain: external control of user's target language
enables remote file inclusion.
Potential Mitigations
Phase: Architecture and Design
When the set of filenames is limited or known, create a mapping from a
set of fixed input values (such as numeric IDs) to the actual filenames,
and reject all other inputs. For example, ID 1 could map to "inbox.txt"
and ID 2 could map to "profile.txt". Features such as the ESAPI
AccessReferenceMap provide this capability.
Phases: Architecture and Design; Operation
Run your code in a "jail" or similar sandbox environment that enforces
strict boundaries between the process and the operating system. This may
effectively restrict all access to files within a particular
directory.
Examples include the Unix chroot jail and AppArmor. In general,
managed code may provide some protection.
This may not be a feasible solution, and it only limits the impact to
the operating system; the rest of your application may still be subject
to compromise.
Be careful to avoid CWE-243 and other weaknesses related to jails.
Phase: Architecture and Design
For any security checks that are performed on the client side, ensure that these checks are duplicated on the server side, in order to avoid CWE-602. Attackers can bypass the client-side checks by modifying values after the checks have been performed, or by changing the client to remove the client-side checks entirely. Then, these modified values would be submitted to the server.
Phase: Implementation
Strategy: Input Validation
Assume all input is malicious. Use an "accept known good" input
validation strategy, i.e., use a whitelist of acceptable inputs that
strictly conform to specifications. Reject any input that does not
strictly conform to specifications, or transform it into something that
does.
When performing input validation, consider all potentially relevant
properties, including length, type of input, the full range of
acceptable values, missing or extra inputs, syntax, consistency across
related fields, and conformance to business rules. As an example of
business rule logic, "boat" may be syntactically valid because it only
contains alphanumeric characters, but it is not valid if the input is
only expected to contain colors such as "red" or "blue."
Do not rely exclusively on looking for malicious or malformed inputs
(i.e., do not rely on a blacklist). A blacklist is likely to miss at
least one undesirable input, especially if the code's environment
changes. This can give attackers enough room to bypass the intended
validation. However, blacklists can be useful for detecting potential
attacks or determining which inputs are so malformed that they should be
rejected outright.
When validating filenames, use stringent whitelists that limit the character set to be used. If feasible, only allow a single "." character in the filename to avoid weaknesses such as CWE-23, and exclude directory separators such as "/" to avoid CWE-36. Use a whitelist of allowable file extensions, which will help to avoid CWE-434.
Do not rely exclusively on a filtering mechanism that removes potentially dangerous characters. This is equivalent to a blacklist, which may be incomplete (CWE-184). For example, filtering "/" is insufficient protection if the filesystem also supports the use of "\" as a directory separator. Another possible error could occur when the filtering is applied in a way that still produces dangerous data (CWE-182). For example, if "../" sequences are removed from the ".../...//" string in a sequential fashion, two instances of "../" would be removed from the original string, but the remaining characters would still form the "../" string.
Phase: Implementation
Use a built-in path canonicalization function (such as realpath() in C) that produces the canonical version of the pathname, which effectively removes ".." sequences and symbolic links (CWE-23, CWE-59).
Phases: Installation; Operation
Use OS-level permissions and run as a low-privileged user to limit the
scope of any successful attack.
Phases: Operation; Implementation
If you are using PHP, configure your application so that it does not use register_globals. During implementation, develop your application so that it does not rely on this feature, but be wary of implementing a register_globals emulation that is subject to weaknesses such as CWE-95, CWE-621, and similar issues.
Phase: Testing
Use automated static analysis tools that target this type of weakness.
Many modern techniques use data flow analysis to minimize the number of
false positives. This is not a perfect solution, since 100% accuracy and
coverage are not feasible.
Phase: Testing
Use dynamic tools and techniques that interact with the software using
large test suites with many diverse inputs, such as fuzz testing
(fuzzing), robustness testing, and fault injection. The software's
operation may slow down, but it should not become unstable, crash, or
generate incorrect results.
Phase: Testing
Use tools and techniques that require manual (human) analysis, such as
penetration testing, threat modeling, and interactive tools that allow
the tester to record and modify an active session. These may be more
effective than strictly automated techniques. This is especially the
case with weaknesses that are related to design and business
rules.
Weakness Ordinalities
Ordinality
Description
Primary
(where
the weakness exists independent of other weaknesses)
The external control of filenames can be the primary link in chains with
other file-related weaknesses, as seen in the CanPrecede relationships. This
is because software systems use files for many different purposes: to
execute programs, load code libraries, to store application data, to store
configuration settings, record temporary data, act as signals or semaphores
to other processes, etc.
However, those weaknesses do not always require external control. For example, link-following weaknesses (CWE-59) often involve pathnames that are not controllable by the attacker at all.
The external control can be resultant from other issues. For example, in PHP applications, the register_globals setting can allow an attacker to modify variables that the programmer thought were immutable, enabling file inclusion (CWE-98) and path traversal (CWE-22). Operating with excessive privileges (CWE-250) might allow an attacker to specify an input filename that is not directly readable by the attacker, but is accessible to the privileged program. A buffer overflow (CWE-119) might give an attacker control over nearby memory locations that are related to pathnames, but were not directly modifiable by the attacker.
Taxonomy Mappings
Mapped Taxonomy Name
Node ID
Fit
Mapped Node Name
7 Pernicious Kingdoms
Path Manipulation
CERT C++ Secure Coding
FIO01-CPP
Be careful using functions that use file names for
identification
CERT C++ Secure Coding
FIO02-CPP
Canonicalize path names originating from untrusted
sources
The application calls free() on a pointer to memory that was not allocated using associated heap allocation functions such as malloc(), calloc(), or realloc().
Extended Description
When free() is called on an invalid pointer, the program's memory management data structures may become corrupted. This corruption can cause the program to crash or, in some circumstances, an attacker may be able to cause free() to operate on controllable memory locations to modify critical program variables or execute code.
Time of Introduction
Implementation
Common Consequences
Scope
Effect
Integrity
Confidentiality
Availability
Technical Impact: Execute unauthorized code or
commands; Modify memory
There is the potential for arbitrary code execution with privileges of
the vulnerable program via a "write, what where" primitive.
If pointers to memory which hold user information are freed, a
malicious user will be able to write 4 bytes anywhere in memory.
Demonstrative Examples
Example 1
In this example, an array of record_t structs, bar, is allocated
automatically on the stack as a local variable and the programmer attempts
to call free() on the array. The consequences will vary based on the
implementation of free(), but it will not succeed in deallocating the
memory.
(Bad Code)
Example
Language: C
void foo(){
record_t bar[MAX_SIZE];
/* do something interesting with bar */
...
free(bar);
}
This example shows the array allocated globally, as part of the data
segment of memory and the programmer attempts to call free() on the
array.
(Bad Code)
Example
Language: C
record_t bar[MAX_SIZE]; //Global var
void foo(){
/* do something interesting with bar */
...
free(bar);
}
Instead, if the programmer wanted to dynamically manage the memory,
malloc() or calloc() should have been used.
Additionally, you can pass global variables to free() when they are
pointers to dynamically allocated memory.
(Good Code)
record_t *bar; //Global var
void foo(){
bar = (record_t*)malloc(MAX_SIZE*sizeof(record_t));
/* do something interesting with bar */
...
free(bar);
}
Potential Mitigations
Phase: Implementation
Only free pointers that you have called malloc on previously. This is
the recommended solution. Keep track of which pointers point at the
beginning of valid chunks and free them only once.
Phase: Implementation
Before freeing a pointer, the programmer should make sure that the
pointer was previously allocated on the heap and that the memory belongs
to the programmer. Freeing an unallocated pointer will cause undefined
behavior in the program.
Phases: Architecture and Design; Implementation; Operation
Strategy: Libraries or Frameworks
Use a vetted library or framework that does not allow this weakness to
occur or provides constructs that make this weakness easier to
avoid.
For example, glibc in Linux provides protection against free of
invalid pointers.
Phase: Architecture and Design
Use a language that provides abstractions for memory allocation and
deallocation.
Phase: Testing
Use a tool that dynamically detects memory management problems, such
as valgrind.
In C++, if the new operator was used to allocate the memory, it may be allocated with the malloc(), calloc() or realloc() family of functions in the implementation. Someone aware of this behavior might choose to map this problem to CWE-590 or to its parent, CWE-762, depending on their perspective.
The software calls a function, procedure, or routine, but the caller specifies an argument that is the wrong data type, which may lead to resultant weaknesses.
Extended Description
This weakness is most likely to occur in loosely typed languages, or in strongly typed languages in which the types of variable arguments cannot be enforced at compilation time, or where there is implicit casting.
Time of Introduction
Implementation
Common Consequences
Scope
Effect
Other
Technical Impact: Quality degradation
Potential Mitigations
Phase: Testing
Because this function call often produces incorrect behavior it will
usually be detected during testing or normal operation of the software.
During testing exercise all possible control paths will typically expose
this weakness except in rare cases when the incorrect function call
accidentally produces the correct results or if the provided argument
type is very similar to the expected argument type.
Weakness Ordinalities
Ordinality
Description
Primary
(where
the weakness exists independent of other weaknesses)
Function Call With Incorrectly Specified Argument Value
Definition in a New Window
Weakness ID: 687 (Weakness Variant)
Status: Draft
Description
Description Summary
The software calls a function, procedure, or routine, but the caller specifies an argument that contains the wrong value, which may lead to resultant weaknesses.
Time of Introduction
Implementation
Common Consequences
Scope
Effect
Other
Technical Impact: Quality degradation
Detection Methods
Manual Static Analysis
This might require an understanding of intended program behavior or
design to determine whether the value is incorrect.
Demonstrative Examples
Example 1
This Perl code intends to record whether a user authenticated
successfully or not, and to exit if the user fails to authenticate. However,
when it calls ReportAuth(), the third argument is specified as 0 instead of
1, so it does not exit.
When primary, this weakness is most likely to occur in rarely-tested code,
since the wrong value can change the semantic meaning of the program's
execution and lead to obviously-incorrect behavior. It can also be resultant
from issues in which the program assigns the wrong value to a variable, and
that variable is later used in a function call. In that sense, this issue
could be argued as having chaining relationships with many implementation
errors in CWE.
Improper Check for Unusual or Exceptional Conditions
Definition in a New Window
Weakness ID: 754 (Weakness Class)
Status: Incomplete
Description
Description Summary
The software does not check or improperly checks for unusual or exceptional conditions that are not expected to occur frequently during day to day operation of the software.
Extended Description
The programmer may assume that certain events or conditions will never occur or do not need to be worried about, such as low memory conditions, lack of access to resources due to restrictive permissions, or misbehaving clients or components. However, attackers may intentionally trigger these unusual conditions, thus violating the programmer's assumptions, possibly introducing instability, incorrectbehavior, or a vulnerability.
Note that this entry is not exclusively about the use of exceptions and exception handling, which are mechanisms for both checking and handling unusual or unexpected conditions.
Time of Introduction
Implementation
Applicable Platforms
Languages
Language-independent
Common Consequences
Scope
Effect
Integrity
Availability
Technical Impact: DoS: crash / exit /
restart; Unexpected state
The data which were produced as a result of a function call could be
in a bad state upon return. If the return value is not checked, then
this bad data may be used in operations, possibly leading to a crash or
other unintended behaviors.
Likelihood of Exploit
Medium
Detection Methods
Automated Static Analysis
Automated static analysis may be useful for detecting unusual
conditions involving system resources or common programming idioms, but
not for violations of business rules.
Effectiveness: Moderate
Manual Dynamic Analysis
Identify error conditions that are not likely to occur during normal
usage and trigger them. For example, run the program under low memory
conditions, run with insufficient privileges or permissions, interrupt a
transaction before it is completed, or disable connectivity to basic
network services such as DNS. Monitor the software for any unexpected
behavior. If you trigger an unhandled exception or similar error that
was discovered and handled by the application's environment, it may
still indicate unexpected conditions that were not handled by the
application itself.
Demonstrative Examples
Example 1
Consider the following code segment:
(Bad Code)
Example
Language: C
char buf[10], cp_buf[10];
fgets(buf, 10, stdin);
strcpy(cp_buf, buf);
The programmer expects that when fgets() returns, buf will contain a
null-terminated string of length 9 or less. But if an I/O error occurs,
fgets() will not null-terminate buf. Furthermore, if the end of the file
is reached before any characters are read, fgets() returns without
writing anything to buf. In both of these situations, fgets() signals
that something unusual has happened by returning NULL, but in this code,
the warning will not be noticed. The lack of a null terminator in buf
can result in a buffer overflow in the subsequent call to strcpy().
Example 2
The following code does not check to see if memory allocation
succeeded before attempting to use the pointer returned by
malloc().
(Bad Code)
Example
Language: C
buf = (char*) malloc(req_size);
strncpy(buf, xfer, req_size);
The traditional defense of this coding error is: "If my program runs
out of memory, it will fail. It doesn't matter whether I handle the
error or simply allow the program to die with a segmentation fault when
it tries to dereference the null pointer." This argument ignores three
important considerations:
Depending upon the type and size of the application, it may be
possible to free memory that is being used elsewhere so that
execution can continue.
It is impossible for the program to perform a graceful exit if
required. If the program is performing an atomic operation, it can
leave the system in an inconsistent state.
The programmer has lost the opportunity to record diagnostic
information. Did the call to malloc() fail because req_size was too
large or because there were too many requests being handled at the
same time? Or was it caused by a memory leak that has built up over
time? Without handling the error, there is no way to know.
Example 3
The following code loops through a set of users, reading a private
data file for each user. The programmer assumes that the files are always 1
kilobyte in size and therefore ignores the return value from Read(). If an
attacker can create a smaller file, the program will recycle the remainder
of the data from the previous user and handle it as though it belongs to the
attacker.
(Bad Code)
Example
Language: Java
char[] byteArray = new char[1024];
for (IEnumerator i=users.GetEnumerator(); i.MoveNext()
;i.Current()) {
String userName = (String) i.Current();
String pFileName = PFILE_ROOT + "/" + userName;
StreamReader sr = new StreamReader(pFileName);
sr.Read(byteArray,0,1024);//the file is always 1k bytes
sr.Close();
processPFile(userName, byteArray);
}
(Bad Code)
Example
Language: Java
FileInputStream fis;
byte[] byteArray = new byte[1024];
for (Iterator i=users.iterator(); i.hasNext();) {
String userName = (String) i.next();
String pFileName = PFILE_ROOT + "/" + userName;
FileInputStream fis = new FileInputStream(pFileName);
fis.read(byteArray); // the file is always 1k bytes
fis.close();
processPFile(userName, byteArray);
}
Example 4
The following code does not check to see if the string returned by
getParameter() is null before calling the member function compareTo(),
potentially causing a NULL dereference.
The following code does not check to see if the string returned by the
Item property is null before calling the member function Equals(),
potentially causing a NULL dereference.
(Bad Code)
Example
Language: Java
String itemName = request.Item(ITEM_NAME);
if (itemName.Equals(IMPORTANT_ITEM)) {
...
}
...
The traditional defense of this coding error is: "I know the requested
value will always exist because.... If it does not exist, the program
cannot perform the desired behavior so it doesn't matter whether I
handle the error or simply allow the program to die dereferencing a null
value." But attackers are skilled at finding unexpected paths through
programs, particularly when exceptions are involved.
Example 5
The following code shows a system property that is set to null and
later dereferenced by a programmer who mistakenly assumes it will always be
defined.
(Bad Code)
Example
Language: Java
System.clearProperty("os.name");
...
String os = System.getProperty("os.name");
if (os.equalsIgnoreCase("Windows 95")) System.out.println("Not
supported");
The traditional defense of this coding error is: "I know the requested
value will always exist because.... If it does not exist, the program
cannot perform the desired behavior so it doesn't matter whether I
handle the error or simply allow the program to die dereferencing a null
value." But attackers are skilled at finding unexpected paths through
programs, particularly when exceptions are involved.
Example 6
The following VB.NET code does not check to make sure that it has
read 50 bytes from myfile.txt. This can cause DoDangerousOperation() to
operate on an unexpected value.
(Bad Code)
Example
Language: .NET
Dim MyFile As New FileStream("myfile.txt", FileMode.Open,
FileAccess.Read, FileShare.Read)
Dim MyArray(50) As Byte
MyFile.Read(MyArray, 0, 50)
DoDangerousOperation(MyArray(20))
In .NET, it is not uncommon for programmers to misunderstand Read()
and related methods that are part of many System.IO classes. The stream
and reader classes do not consider it to be unusual or exceptional if
only a small amount of data becomes available. These classes simply add
the small amount of data to the return buffer, and set the return value
to the number of bytes or characters read. There is no guarantee that
the amount of data returned is equal to the amount of data requested.
Example 7
This example takes an IP address from a user, verifies that it is
well formed and then looks up the hostname and copies it into a
buffer.
(Bad Code)
Example
Language: C
void host_lookup(char *user_supplied_addr){
struct hostent *hp;
in_addr_t *addr;
char hostname[64];
in_addr_t inet_addr(const char *cp);
/*routine that ensures user_supplied_addr is in the right
format for conversion */
validate_addr_form(user_supplied_addr);
addr = inet_addr(user_supplied_addr);
hp = gethostbyaddr( addr, sizeof(struct in_addr),
AF_INET);
strcpy(hostname, hp->h_name);
}
If an attacker provides an address that appears to be well-formed, but the address does not resolve to a hostname, then the call to gethostbyaddr() will return NULL. When this occurs, a NULL pointer dereference (CWE-476) will occur in the call to strcpy().
Note that this example is also vulnerable to a buffer overflow (see CWE-119).
Example 8
In the following C/C++ example the method outputStringToFile opens
a file in the local filesystem and outputs a string to the file. The input
parameters output and filename contain the string to output to the file and
the name of the file respectively.
(Bad Code)
Example
Language: C++
int outputStringToFile(char *output, char *filename) {
openFileToWrite(filename);
writeToFile(output);
closeFile(filename);
}
However, this code does not check the return values of the methods
openFileToWrite, writeToFile, closeFile to verify that the file was
properly opened and closed and that the string was successfully written
to the file. The return values for these methods should be checked to
determine if the method was successful and allow for detection of errors
or unexpected conditions as in the following example.
(Good Code)
Example
Language: C++
int outputStringToFile(char *output, char *filename) {
int isOutput = SUCCESS;
int isOpen = openFileToWrite(filename);
if (isOpen == FAIL) {
printf("Unable to open file %s", filename);
isOutput = FAIL;
}
else {
int isWrite = writeToFile(output);
if (isWrite == FAIL) {
printf("Unable to write to file %s", filename);
isOutput = FAIL;
}
int isClose = closeFile(filename);
if (isClose == FAIL)
isOutput = FAIL;
}
return isOutput;
}
Example 9
In the following Java example the method readFromFile uses a
FileReader object to read the contents of a file. The FileReader object is
created using the File object readFile, the readFile object is initialized
using the setInputFile method. The setInputFile method should be called
before calling the readFromFile method.
(Bad Code)
Example
Language: Java
private File readFile = null;
public void setInputFile(String inputFile) {
// create readFile File object from string containing name
of file
}
public void readFromFile() {
try {
reader = new FileReader(readFile);
// read input file
} catch (FileNotFoundException ex) {...}
}
However, the readFromFile method does not check to see if the
readFile object is null, i.e. has not been initialized, before creating
the FileReader object and reading from the input file. The readFromFile
method should verify whether the readFile object is null and output an
error message and raise an exception if the readFile object is null, as
in the following code.
(Good Code)
Example
Language: Java
private File readFile = null;
public void setInputFile(String inputFile) {
// create readFile File object from string containing name
of file
}
public void readFromFile() {
try {
if (readFile == null) {
System.err.println("Input file has not been set, call
setInputFile method before calling
openInputFile");
Program does not check return value when invoking
functions to drop privileges, which could leave users with higher privileges
than expected by forcing those functions to
fail.
Program does not check return value when invoking
functions to drop privileges, which could leave users with higher privileges
than expected by forcing those functions to
fail.
Potential Mitigations
Phase: Requirements
Strategy: Language Selection
Use a language that does not allow this weakness to occur or provides
constructs that make this weakness easier to avoid.
Choose languages with features such as exception handling that force the programmer to anticipate unusual conditions that may generate exceptions. Custom exceptions may need to be developed to handle unusual business-logic conditions. Be careful not to pass sensitive exceptions back to the user (CWE-209, CWE-248).
Phase: Implementation
Check the results of all functions that return a value and verify that
the value is expected.
Effectiveness: High
Checking the return value of the function will typically be sufficient, however beware of race conditions (CWE-362) in a concurrent environment.
Phase: Implementation
If using exception handling, catch and throw specific exceptions instead of overly-general exceptions (CWE-396, CWE-397). Catch and handle exceptions as locally as possible so that exceptions do not propagate too far up the call stack (CWE-705). Avoid unchecked or uncaught exceptions where feasible (CWE-248).
Effectiveness: High
Using specific exceptions, and ensuring that exceptions are checked,
helps programmers to anticipate and appropriately handle many unusual
events that could occur.
Phase: Implementation
Ensure that error messages only contain minimal details that are
useful to the intended audience, and nobody else. The messages need to
strike the balance between being too cryptic and not being cryptic
enough. They should not necessarily reveal the methods that were used to
determine the error. Such detailed information can be used to refine the
original attack to increase the chances of success.
If errors must be tracked in some detail, capture them in log messages
- but consider what could occur if the log messages can be viewed by
attackers. Avoid recording highly sensitive information such as
passwords in any form. Avoid inconsistent messaging that might
accidentally tip off an attacker about internal state, such as whether a
username is valid or not.
Exposing additional information to a potential attacker in the context
of an exceptional condition can help the attacker determine what attack
vectors are most likely to succeed beyond DoS.
Phase: Implementation
Strategy: Input Validation
Assume all input is malicious. Use an "accept known good" input
validation strategy, i.e., use a whitelist of acceptable inputs that
strictly conform to specifications. Reject any input that does not
strictly conform to specifications, or transform it into something that
does.
When performing input validation, consider all potentially relevant
properties, including length, type of input, the full range of
acceptable values, missing or extra inputs, syntax, consistency across
related fields, and conformance to business rules. As an example of
business rule logic, "boat" may be syntactically valid because it only
contains alphanumeric characters, but it is not valid if the input is
only expected to contain colors such as "red" or "blue."
Do not rely exclusively on looking for malicious or malformed inputs
(i.e., do not rely on a blacklist). A blacklist is likely to miss at
least one undesirable input, especially if the code's environment
changes. This can give attackers enough room to bypass the intended
validation. However, blacklists can be useful for detecting potential
attacks or determining which inputs are so malformed that they should be
rejected outright.
Performing extensive input validation does not help with handling
unusual conditions, but it will minimize their occurrences and will make
it more difficult for attackers to trigger them.
Phases: Architecture and Design; Implementation
If the program must fail, ensure that it fails gracefully (fails
closed). There may be a temptation to simply let the program fail poorly
in cases such as low memory conditions, but an attacker may be able to
assert control before the software has fully exited. Alternately, an
uncontrolled failure could cause cascading problems with other
downstream components; for example, the program could send a signal to a
downstream process so the process immediately knows that a problem has
occurred and has a better chance of recovery.
Phase: Architecture and Design
Use system limits, which should help to prevent resource exhaustion.
However, the software should still handle low resource conditions since
they may still occur.
Background Details
Many functions will return some value about the success of their actions.
This will alert the program whether or not to handle any errors caused by
that function.
Sometimes, when a return value can be used to indicate an error, an
unchecked return value is a code-layer instance of a missing
application-layer check for exceptional conditions. However, return values
are not always needed to communicate exceptional conditions. For example,
expiration of resources, values passed by reference, asynchronously modified
data, sockets, etc. may indicate exceptional conditions without the use of a
return value.
Taxonomy Mappings
Mapped Taxonomy Name
Node ID
Fit
Mapped Node Name
CERT C++ Secure Coding
MEM32-CPP
Detect and handle memory allocation errors
CERT C++ Secure Coding
ERR39-CPP
Guarantee exception safety
CERT C Secure Coding
MEM32-C
Detect and handle memory allocation errors
References
[REF-7] Mark Dowd, John McDonald
and Justin Schuh. "The Art of Software Security Assessment". Chapter 7, "Program Building Blocks" Page
341. 1st Edition. Addison Wesley. 2006.
[REF-7] Mark Dowd, John McDonald
and Justin Schuh. "The Art of Software Security Assessment". Chapter 1, "Exceptional Conditions," Page
22. 1st Edition. Addison Wesley. 2006.
[REF-17] Michael Howard, David LeBlanc
and John Viega. "24 Deadly Sins of Software Security". "Sin 11: Failure to Handle Errors Correctly." Page
183. McGraw-Hill. 2010.
This is a high-level class that might have some overlap with other classes. It could be argued that even "normal" weaknesses such as buffer overflows involve unusual or exceptional conditions. In that sense, this might be an inherent aspect of most other weaknesses within CWE, similar to API Abuse (CWE-227) and Indicator of Poor Code Quality (CWE-398). However, this entry is currently intended to unify disparate concepts that do not have other places within the Research Concepts view (CWE-1000).
The product does not clean up its state or incorrectly cleans up its state when an exception is thrown, leading to unexpected state or control flow.
Time of Introduction
Implementation
Applicable Platforms
Languages
C
C++
Java
.NET
Common Consequences
Scope
Effect
Other
Technical Impact: Varies by context
The code could be left in a bad state.
Likelihood of Exploit
Medium
Demonstrative Examples
Example 1
(Bad Code)
Example Languages: C++ and Java
public class foo {
public static final void main( String args[] ) {
boolean returnValue;
returnValue=doStuff();
}
public static final boolean doStuff( ) {
boolean threadLock;
boolean truthvalue=true;
try {
while(
//check some condition
) {
threadLock=true; //do some stuff to
truthvalue
threadLock=false;
}
}
catch (Exception e){
System.err.println("You did something bad");
if (something) return truthvalue;
}
return truthvalue;
}
}
In this case, you may leave a thread locked accidentally.
Potential Mitigations
Phase: Implementation
If one breaks from a loop or function by throwing an exception, make
sure that cleanup happens or that you should exit the program. Use
throwing exceptions sparsely.
Other Notes
Often, when functions or loops become complicated, some level of cleanup
in the beginning to the end is needed. Often, since exceptions can disturb
the flow of the code, one can leave a code block in a bad state.
Improper Clearing of Heap Memory Before Release ('Heap Inspection')
Definition in a New Window
Weakness ID: 244 (Weakness Variant)
Status: Draft
Description
Description Summary
Using realloc() to resize buffers that store sensitive information can leave the sensitive information exposed to attack, because it is not removed from memory.
Extended Description
When sensitive data such as a password or an encryption key is not removed from memory, it could be exposed to an attacker using a "heap inspection" attack that reads the sensitive data using memory dumps or other methods. The realloc() function is commonly used to increase the size of a block of allocated memory. This operation often requires copying the contents of the old memory block into a new and larger block. This operation leaves the contents of the original block intact but inaccessible to the program, preventing the program from being able to scrub sensitive data from memory. If an attacker can later examine the contents of a memory dump, the sensitive data could be exposed.
Time of Introduction
Implementation
Applicable Platforms
Languages
C
C++
Common Consequences
Scope
Effect
Confidentiality
Other
Technical Impact: Read memory; Other
Be careful using vfork() and fork() in security sensitive code. The
process state will not be cleaned up and will contain traces of data
from past use.
Demonstrative Examples
Example 1
The following code calls realloc() on a buffer containing sensitive
data:
There is an attempt to scrub the sensitive data from memory, but
realloc() is used, so a copy of the data can still be exposed in the
memory originally allocated for cleartext_buffer.