Skip to content

GemAppSec/vulnerable-c-and-cpp

 
 

Repository files navigation

Program 1

The program1.c file contains an example of Dynamic Memory Allocation Vulnerability (MISRA Dir 4.12, MISRA Rule 21.3).

The function allocateMemory uses malloc to allocate memory but does not free it, leading to a memory leak. This can be prevented by following MISRA guidelines that restrict dynamic memory allocation.

Run the program by compiling first and then executing it:

$ gcc program1.c -o program1.app
$ ./program1.app

Is there a memory leak in the program? How can you fix it?

Find the vulnerability with Valgrind

Valgrind is a powerful tool that can help you find memory leaks in your program. We can run the program with Valgrind to see if there are any memory leaks.

Install Valgrind on your system. If you use a Linux-based system, you can install it using the package manager. Here's Debian-based example:

sudo apt-get install valgrind

Note: If you're on macOS and using ARM-based chips, support for Valgrind is not available so we'll skip it and run Valgrind from within a Docker container:

docker build -t "valgrind" . -f Dockerfile

Then run the container and map our current directory to the container's /tmp directory:

docker run -it -v $PWD:/tmp -w /tmp valgrind

Then compile the program1.c program within the container:

gcc program1.c -o program1.app

We can then run the program with Valgrind to check for memory leaks:

valgrind --leak-check=full ./program1.app

Then you should see the output from Valgrind that shows the memory leak:

/tmp # valgrind --leak-check=full ./program1.app
==29== Memcheck, a memory error detector
==29== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==29== Using Valgrind-3.23.0 and LibVEX; rerun with -h for copyright info
==29== Command: ./program1
==29==
==29==
==29== HEAP SUMMARY:
==29==     in use at exit: 40 bytes in 1 blocks
==29==   total heap usage: 1 allocs, 0 frees, 40 bytes allocated
==29==
==29== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==29==    at 0x48E978C: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-arm64-linux.so)
==29==    by 0x108823: allocateMemory (in /tmp/program1)
==29==    by 0x108857: main (in /tmp/program1)
==29==
==29== LEAK SUMMARY:
==29==    definitely lost: 40 bytes in 1 blocks
==29==    indirectly lost: 0 bytes in 0 blocks
==29==      possibly lost: 0 bytes in 0 blocks
==29==    still reachable: 0 bytes in 0 blocks
==29==         suppressed: 0 bytes in 0 blocks
==29==
==29== For lists of detected and suppressed errors, rerun with: -s
==29== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Find the vulnerability with Snyk Code

Snyk Code will help you identify this vulnerability in your codebase, without even going through the compilation process. Just installing the extension and opening the file will show you the vulnerability because Snyk Code is a static code analysis tool that applies machine learning techniques to identify static code that doesn't require a build and compilation step and this approach enables reliable, low false-positive and fast feedback loop when Snyk scans your code for security vulnerabilities.

Vulnerable C program code for memory leaks

Program 2

The program2.c file contains an example of Undesired Behavior (MISRA Rule 1.3)

Here's the program code:

#include <stdio.h>

void undefinedBehavior() {
    int x = 5 / 0;
    printf("Value of x: %d\n", x);
}

int main() {
    undefinedBehavior();
    return 0;
}

Division by zero is an undefined behavior in C, which can lead to unpredictable results and MISRA guidelines, rightfully so, prohibit such operations to ensure code safety and security in critical software.

Run the program by compiling first and then executing it:

$ gcc program2.c -o program2.app
$ ./program2.app

You'll notice that the GCC compiler will throw a warning about division by zero:

program2.c:5:15: warning: division by zero is undefined [-Wdivision-by-zero]
    int x = 5 / 0;
              ^ ~
1 warning generated.

However, this is a simple and small program code. In real-world scenarios, such issues can be hard to find across a large codebase and many compiler warnings piped to standard output.

Find the vulnerability with Snyk Code

Seeing the undefined behavior error message from a compiler warning about division by zero and other issues can be hard to spot and late in the development cycle. Snyk Code can help you identify such issues early in the development cycle by scanning your codebase for such vulnerabilities before you even compile the code.

The reason for that is that Snyk employed machine learning techniques in its static code application security engine that can understand program call flows and connect sink-to-source code path flows to unearth insecure code and potential vulnerabilities in your codebase without even compiling the code.

Vulnerable C program code showing undefined behavior

Program 3

The program3.c file contains several example, let's exploit them to demonstrate the different issues.

Once the program is compiled, you can run it:

$ ./program3.app "text.txt"

Given that you have a file in the same directory named text.txt and it is not empty, the program will read the file and print its contents.

For example:

Size of the file: 44
Contents of the file: FROM alpine:latest
RUN apk add g++ valgrind

Looks ok. What happens if you pass a file that traverses the directory structure?

$ ./program3.app "../../../../../etc/passwd"

A path traversal vulnerability is present in the program, allowing an attacker to read sensitive files on the system.

To test other vulnerabilities, try to:

  • Pass a file that does not exist
  • Pass a file that is empty
  • Pass a file name or full path that is too large (more than 50 characters)

About

A reference Git repository to demonstrate vulnerable C and C++ patterns in code

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C 99.3%
  • Dockerfile 0.7%