Introduction:
Un-bounded arrays in C can cause memory allocation issues, potentially leading to overwriting locations in memory with extra information. It is crucial for software developers to understand how these issues occur and how to prevent them. In this project, we were given a program called wargames.c that has multiple issues with un-bounded arrays. Our task was to analyze the flaws in the code and propose solutions to fix it. I extensively examined the wargames program and identified its vulnerabilities, which I will elaborate on in this report and provide solutions to fix them.
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
void launch_missiles(int n)
{
printf("Launching %d missiles\n", n);
}
void authenticate_and_launch(void)
{
int n_missiles = 2;
bool allowaccess = false;
char response[8];
printf("Secret: ");
fgets(response, sizeof(response), stdin);
if (strcmp(response, "Joshua\n") == 0)
allowaccess = true;
if (allowaccess)
{
puts("Access granted");
launch_missiles(n_missiles);
}
if (!allowaccess)
puts("Access Denied");
}
int main(int argc, char **argv)
{
puts("Wargames Missile Launcher v1.3");
authenticate_and_launch();
puts("Operation Complete");
}
Establishing the groundwork
As buffer overflows are usually exploited through reverse engineering, I utilized gdb, a command line-based debugger, to conduct most of my testing. Although I was given the source code, I compiled the wargames program with the -g flag using the gcc compiler to include useful debugging information in the executable. This approach enabled the program to be compiled with minimal optimization.
Additionally, I disabled ASLR and incorporated -no-pie and -fno-stack-protector options to enhance my testing environment.

Finding each error
I began my exploit analysis of the wargames program by running it in gdb and executing the "run" command. The program printed two strings, "Wargames Missile Launcher v1.3" and "Secret," before prompting for user input.

Unfortunately, the program did not specify what value was expected as input. So, I began manually entering and testing random values, starting with a single 'a' character. The program returned "access denied," which suggested that it was looking for a secret key, and the incorrect key led to an "Access Denied" message.

I continued to enter random characters, increasing the length each time until I noticed a change. When I entered a string with thirteen characters, the program responded with "access granted and launching missiles."
When I entered a string with sixteen characters, gdb returned a segmentation fault, indicating that memory addresses were being overwritten. This suggested that the program malfunctioned as the input value got longer, and a string of twelve or more characters granted user access.

I then examined the source code and identified two key issues.
The first was the implementation of the input response as a char array with a size of eight bytes, stored using the gets() method, which is prone to buffer overflow errors. The second issue was with the use of the strcmp() method, which lacked data validation, allowing users to input invalid strings that were not null-terminated, leading to comparison errors and accessing non-accessible parts of memory.

Validating my theory
To validate my theory, I created breakpoints in gdb for each function using my knowledge of the function names in the Wargames program. I ran and traversed through the program line by line, keeping track of variable values using the display command.

I discovered that the authenticate_and_launch function was where the local variables were in use, and the value of n_missiles was initially set as garbage value until a few more lines were executed and stored the correct value of two. The allowaccess variable was initially set as false and returned a value of zero, while the response variable had a general garbage value stored until the strcmp() method was called.

Upon inputting a string of thirteen 'A' characters, n_missiles displayed a value of 1094795585, allowaccess displayed a value of 65, and the response array had a value of 'AAAAAAA.' Using the (p &) command, I obtained the memory address of where each variable's value was stored and looked at the stack using the command x/1x $rsp. I discovered that all the values were stored within close memory ranges from each other, explaining why the remaining 'A' characters were stored in the neighboring memory address and why allowaccess had a decimal value of 65 (an ASCII value of A) and n_missiles returned a decimal value of 1094795585, which is equivalent to four capital 'A' characters.

Explaining why these errors exist
These errors exist because the programmer did not implement proper data validation. It is important to validate user input to ensure that only valid submissions are processed. This involves checking the input size and rejecting anything that exceeds the allocated buffer size, as well as accepting only compatible data submissions. For example, if a program requires an integer input, any submission that comes in as a string should be rejected.
When implementing the wargames program, the programmer used the gets() method but failed to define any data validation. It was crucial to implement a way to reject inputs that surpassed the buffer size, which was not done. As a result, the program stored any submission it was handed, even if it was larger than the buffer.
Similarly, no validation was conducted when using the strcmp method. When comparing a string to another string using strcmp(), the method will continue to compare the string values until reaching a null terminated value. However, if there is no null terminated value, the method will continue to compare the string values until reaching a non-accessible part of memory. Therefore, we need to set a limit on the size of the string we are comparing. In this case, as the user input is being compared to the string value of "Joshua," there is no reason to allow an input that surpasses seven characters, including the null terminator.
By failing to properly implement the gets() and strcmp() methods, the wargames program suffered from a buffer overflow. This was evident when I entered a large string text and was still able to gain access to the program without entering the correct secret key. To prevent such vulnerabilities, it is crucial to implement proper data validation when dealing with user input.
How I exploited the program

To exploit the wargames program, I fed the response array a value that was longer than eight bytes. The gets() method didn't check or validate my input, so it just tried to store the entire string in the array. However, the array could only hold eight characters, so the excess characters spilled over into a neighboring memory address when the strcmp command was executed. As a result, my input overwrote the value stored in the "allowaccess" variable, changing it from 0 to 65. This granted me access to the missile system.
Proposed Solution
To prevent a buffer overflow from occurring, I would recommend using the fgets() method instead of gets() method. This is because fgets() allows us to limit the size of the input, ensuring that the program does not process any data larger than the expected number of bytes. In this case, I recommend setting the limit to eight bytes since the correct password, "Joshua," is only six bytes long, plus two bytes for the newline character.
Once we have restricted the length of the input, we need to address the strcmp() method. While strcmp() compares two strings, it does not have any restrictions in terms of when it stops, which can lead to segmentation faults if the input string does not have an EOF character. To avoid this, we can replace strcmp() with strncmp(), which allows us to set a limit on the number of bytes to be compared. In this case, we want to limit the comparison to the first eight bytes of the input string.
By implementing these changes, the program will be much more secure, preventing any memory buffer overflows and denying access to anyone who tries to enter a long string.


Conclusion
When it comes to data manipulation in programming, it's vital to incorporate secure coding practices to prevent malicious attacks, such as buffer overflows. In the wargames program provided, I was able to gain unauthorized access by overwriting memory values with a long string since the program did not perform any form of data validation. As the response array became full, the extra bytes of data were stored in the neighboring memory addresses containing the values of the local variables used in the program, resulting in unauthorized access.
To prevent similar buffer overflow issues, I recommend limiting the values processed by the program using the fgets() method to ensure only appropriate-sized values are processed. Moreover, we can use the strncmp() method to provide additional safety measures by limiting the number of bytes of data compared between two strings. Unlike the initial program, which kept reading values until it found a null terminator, our updated method ensures that the program doesn't access a non-accessible part of memory.
Overall, the security of a program solely depends on how the developer designs it. It's essential to evaluate how inputs are processed and provide appropriate error handling to prevent any potential security risks.