Skip to main content

Secure Programming

The first step to secure our binaries is to program in a secure way. Security vulnerabilities come initially from bad security practices during the development of an application, because developers are unaware of the existing vulnerabilities (lack of knowledge), or just prioritize features over security (lack of time).

The latter may not be under your control, but we can improve our knowledge to avoid the first case.

For more recommendations on secure programming in C, refer to the SEI CERT C Coding Standard.

Stack-based buffers

Use secure functions

In many of the exercises, the vulnerability was caused by the call to gets().

The gets(buffer) takes user input, reads until a newline or end-of-file is found, and writes all of it inside the argument buffer, without checking the size of the buffer.

So a user could overwrite the buffer, but also overflow it to overwrite other elements on the stack.

So NEVER use the function gets().

Use fgets() instead, which allows to set a number of bytes to read from user input.

char *fgets(char *restrict s, int size, FILE *restrict stream);

From the manual :

fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s.  Read‐
ing stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A terminating null byte ('\0')
is stored after the last character in the buffer.

So the buffer will never overflow, even if the user input is way larger than the allocated size.

Instead of :

unsafe code
char buffer[30];
gets(buffer);

Use:

safe code
char buffer[30];
fgets(buffer, sizeof(buffer), stdin);
caution

A buffer overflow is still possible if size (2nd argument) is larger than the actual size of the buffer.

You can also use gets_s().

Format strings

User input as format string

Many printing functions use a format string (i.e: printf, fprintf, sprintf, etc...). Allowing a user to control the format string can result in leaking sensitive information from the stack, or even worse execution of arbitrary code.

Never pass user input / tainted strings directly into the format string argument. Pass it as one of the variadic arguments.

Tainted string : a string that has been modified by a user, or contains elements from user input.

If you want to print a string obtained from user input, instead of :

unsafe code
char buffer[30];
fgets(buffer, sizeof(buffer), stdin);
printf(buffer);

Use :

safe code
char buffer[30];
fgets(buffer, sizeof(buffer), stdin);
printf("%s\n", buffer);