In order to tackle this problem, we'll need to know what a C string actually is. Luckily, I already know so I can tell you.
A C string is a sequence of characters that are not '\0'
, followed by a '\0'
character. It can be any length. When we pass strings around, we're (almost) always passing around a pointer to the first character of the string (that is, the position in memory where it's stored). When you work with strings, you carry on until you see '\0'
. This makes it really easy to accidentally introduce a security vulnerability, as you'll see.
Now, how do we use strings? The C Standard Library is here to save the day!
#include <string.h>
This magical line means you can now use functions like strcpy
!
#include <string.h>
#include <stdio.h>
char array[50];
int main(int argc, char *argv[]) {
if (argc < 2) return 1; // Exit early if we don't have an argument.
strcpy(array, argv[1]); // Copy first argument
for (size_t i = 0; i < 50; i += 1) {
printf("%c", array[i]);
}
}
Look, it works:
wizzwizz4@myLaptop:~$ ./a.out "Hello this is my string!"
Hello this is my string!^@k£"'l`¬.v'4ka36}'3.^D,2#xf
But... you probably will have spotted the error. What if the string is longer than the space?
wizzwizz4@myLaptop:~$ ./a.out "Hello this is my string that is too long padding... k'57M3'ck~^B345"
Hello this is my string that is too long padding..
I, THE MIGHTY ATTACKER, HAVE OVERWRITTEN PARTS OF MEMORY THAT I SHOULD NEVER HAVE HAD ACCESS TO AND NOW CONTROL YOUR COMPUTER!
Oops... The space in memory just after array
just happened to contain some code, and when the attacker told our program to overwrite that code with k'57M3'ck~^B345
, it let the attacker in! To fix this, let's use strncpy
instead:
#include <string.h>
#include <stdio.h>
char array[50];
int main(int argc, char *argv[]) {
if (argc < 2) return 1; // Exit early if we don't have an argument.
strncpy(array, argv[1], 49); // Copy first argument
for (size_t i = 0; i < 50; i += 1) {
printf("%c", array[i]);
}
}
Let's run it!
wizzwizz4@myLaptop:~$ ./a.out "Hello this is my string that is too long padding... k'57M3'ck~^B345"
Hello this is my string that is too long padding..f
Success! Except... this "string" doesn't end in a '\0'
– it's not really a string. That means that the program will crash if you try to treat the contents of array
as a string, because whatever's using the string will read and read other bits of memory until it finds a '\0'
or crashes, like so:
#include <string.h>
#include <stdio.h>
char array[50];
int main(int argc, char *argv[]) {
if (argc < 2) return 1; // Exit early if we don't have an argument.
strncpy(array, argv[1], 49); // Copy first argument
printf("%s", array); // Uh oh...
}
Running it...
wizzwizz4@myLaptop:~$ ./a.out "Hello this is my string that is too long padding... k'57M3'ck~^B345"
Hello this is my string that is too long padding..f^D^D^D^D'2mCln My Password is 358231
^F^JESegmentation fault (core dumped)
To work around this, we need to add a final '\0'
:
#include <string.h>
#include <stdio.h>
char array[50];
int main(int argc, char *argv[]) {
if (argc < 2) return 1; // Exit early if we don't have an argument.
strncpy(array, argv[1], 49); // Copy first argument
array[49] = '\0';
for (size_t i = 0; i < 50; i += 1) {
printf("%c", array[i]);
}
}
It's finally safe. Breathe a big sigh of relief!