Null dereference
The dangers of accessing null objects
C++
What is null dereference?
A null dereference is a general term that refers to the act of trying to access or dereference an object reference that has a null value. This can occur in various programming languages and it can cause the program to crash or behave unexpectedly, potentially leading to security issues.
A null pointer dereference, on the other hand, is a specific type of null dereference that occurs when you try to access an object reference that has a null value in a programming language that uses pointers. Pointers are variables that store the memory address of an object, and a null pointer dereference occurs when you try to access an object at a memory address that is null.
In languages that use pointers, such as C and C++, null pointer dereferences can lead to program crashes and other unpredictable behavior. In languages that do not use pointers, such as Java and Python, null dereferences may not cause the program to crash, but can still lead to runtime errors and other unexpected behavior.
Null dereference vulnerabilities are often the result of programming errors, such as using uninitialized pointers or failing to check for null values before accessing them. These vulnerabilities can be difficult to detect and prevent, but they can be addressed through careful programming practices and regular testing.
About this lesson
In this lesson, you will learn about vulnerabilities stemming from null dereferencing and how to protect your applications against them. We’ll look at how a vulnerable application can be attacked and brought down. After that, we’ll look under the hood at the code that made this possible. We will then update the code to fix the vulnerability.
Marc is curious and he is learning a lot of development and security. He recently read about null dereference and wants to see if he can find this vulnerability in the wild!
What just happened?
What you just witnessed is a classic example of a null pointer dereference vulnerability.
The extension back-end, specifically the review code, did not check the value of a pointer before dereferencing it.
Let’s take a look at the code:
Okay, that's a lot of code. Let's try to break this down further.
The endpoint expects a JSON field named stars
and assigns this value to the star's pointer that it created before parsing the JSON. Then after parsing the JSON, it returns a message with the review variable being dereferenced.
Seems right, doesn’t it?
Let's debug this code in the context of Marc’s scenario, where a POST request was sent without POST (JSON) data.
The stars
variable is only assigned a non-null value when there is a valid JSON structure, but it is dereferenced anyway. This makes the code susceptible to a null pointer dereference vulnerability, which Marc triggered by just poking around.
Preventing null pointer dereferences is often very simple. All that was missing in the review code was a check to see if the stars variable was still pointing to null
or not:
Note that this check should go right after the JSON parsing and extraction. No other interaction with the variable should go first that can result in a dereference.
Another way to mitigate this vulnerability in the extension review code is to have the requests.extract_json().then().get()
handle the JSON values instead of passing a pointer to that function. Even though this works, it is cleaner to work with early returns and validate the stars
variable after the JSON parsing.
This way, not too much code becomes nested inside if
, else
statements.
A general rule of thumb is to sanity-check all user-supplied values and to verify that all return values are non-null before acting on them.
At last, in the example of Marc and the extension review code, a pointer was not even needed. By using a non-pointer integer as stars
, the code would have never been exposed to null pointer dereferences.
This can be done in the following way:
Smart pointers
Smart pointers are a crucial feature in modern C++ that significantly enhance memory management and help prevent common issues like null pointer dereferences. These tools are essential for writing safer, more robust code and should be a key part of any C++ developer's toolkit.
At their core, smart pointers are objects that act like pointers but provide additional functionality. They wrap raw pointers and manage the lifetime of the objects they point to, automatically deallocating memory when it's no longer needed. This automatic memory management helps prevent memory leaks and makes code less prone to errors.
The C++ standard library provides several types of smart pointers, with the most commonly used being std::unique_ptr
and std::shared_ptr
.
Test your knowledge!
Keep learning
As mentioned, null dereference was one of the most popular vulnerabilities found by Snyk Open Source. Check out some of these links:
- OWASP page about null dereferences can be found here
- Snyk top 10 vulnerabilities