Secure Programming in C/C++

With the rapid pace of technological advancement, daily life is now intimately connected to the Internet. Critical portions of business operations, financial systems, manufacturing supply chains and military systems are also networked. Indeed, while it was originally computers and their users that communicated over networks, we now have commonplace objects (such as thermostats, light bulbs and kitchen appliances) that communicate with each other and with us. This trend is accelerating, leading to what is called the “Internet of Things.” - from A report on the NSF-sponsored Cybersecurity Ideas Lab held in Arlington, Virginia on February 10-12, 2014
In one of the most serious cyber incidents to date against our military networks, several thousand computers were infected last year by malicious software – malware. And while no sensitive information was compromised, our troops and defense personnel had to give up those external memory devices – thumb drives – changing the way they used their computers every day.
And last year we had a glimpse of the future face of war. As Russian tanks rolled into Georgia, cyber attacks crippled Georgian government websites. The terrorists that sowed so much death and destruction in Mumbai relied not only on guns and grenades but also on GPS and phones using voice-over-the-Internet.
For all these reasons, it's now clear this cyber threat is one of the most serious economic and national security challenges we face as a nation.” - President Barack Obama, REMARKS BY THE PRESIDENT ON SECURING OUR NATION'S CYBER INFRASTRUCTURE, May 29, 2009

Introduction

It is every programmer's responsibility to write secure code. Thirty or forty years ago no one thought very seriously about this, because the world of programmers was small and filled mostly with trustworthy people, and there was no World Wide Web. This is no longer true. Hackers abound and people with malevolent intentions are out there trying to exploit vulnerabilities in code all of the time. As a programmer, you must ensure that your code cannot be used to help someone break into a system or gain access to data to which they have not been given access rights.
This small set of notes is intended to make you aware of the major problems and to give you suggestions on how to write code more securely.
The C/C++ programming languages have been the most important higher programming languages for years, mostly because of the very things that make them susceptible to attack –
These two features, when not used properly, make programs susceptible to a wide variety of attacks. There are other features that are susceptible to attacks as well. What are they? What can you do to reduce the risk of attacks? The purpose of these notes is to get you thinking about these issues, and to a limited extent, to

Common Vulnerabilities

Three of the most common types of software vulnerabilities are
The following exercise is a good place to start.
Exercise 1. Consider the following code:
#include <iostream>
using namespace std;
int main()
{
int length;
int volume;
int factorial[10] = {1,2,6,24,120,720,5040,40320,362880,3628800};
int index;
cout << “Enter the length of the cube as a whole number: “;
cin >> length;
volume = length * length * length;
cout << “The volume is “ << volume << endl;
cout << “Which factorial do you want? Enter its index: “ ;
cin >> index;
cout << “Factorial[“ << index << “] is “ << factorial[index] << endl;
return 0;
}
Which lines of code are safe? Which might be vulnerable? What changes must be made to make this code safe and secure? Can you identify sources of integer errors, input validation errors, and/or buffer overflows?

2.1 Integer Errors

In any operating system and on any machine, and integer is a fixed number of bytes. What happens when a number larger than that is stored into the memory allocated for it depends on the compiler, the operating system, and the hardware. It is pretty unpredictable. That is why the code has to make sure that this does not happen. It might cause a program crash, or it might not. It might just silently corrupt other data. Integer errors also include mistakes related to conversions between integer types, such as from unsigned to signed or vice versa.
The task of the programmer is to be aware of the various types of integer errors and to write code that prevents them from occurring. Did you know that you can always find the value of the largest positive integer on the machine, or the smallest negative one? Is there a way to use this to check if overflow will occur before performing the operations?
Activity: Visit the following site, read the material and answer the short questions there: Security Injection for CS2: Integer Errors

2.2 Input Validation

Input comes from various sources and is stored into variables of various types. In the exercise above, the user was asked to enter a number. What would this program do if the user entered something other than a whole number, such as a number with a fractional part, or something that was not even a number?
Exercise 2. Consider this example:
#include <iostream>
using namespace std;
int main()
{
int factorial[10] = {1,2,6,24,120,720,5040,40320,362880,3628800};
int index;
cout << "Enter the index of the factorial that you want to display: " ;
cin >> index;
cout << "Factorial[" << index << "] is " << factorial[index] << endl;
return 0;
}
What are the different ways in which the input can be “bad”? What can go “wrong”? How can you fix it?
Activity: Visit the following site, read the material, and answer the questions there: Security Injection for CS2: Input Validation

2.3 Buffer Overflows

A buffer overflow attack is one in which the perpetrator purposely writes more into a buffer than its size allows, designing the part that overflows in such a way that it can be used to run the perpetrator's malicious code, or to obtain information about the computer system that was supposed to be protected. There are many different types of buffer overflow attacks, and this small set of notes is not intended to describe how they work, but to provide guidance that will aid in your preventing them. Some buffer overflows are not malicious, but result from the program code's failing to prevent some storage from being overflowed.
Exercise 3. Consider this program:
#include <iostream>
using namespace std;
int main()
{
int mydata = 1;
int mydata2 = 2;
int buffer[10];
cout << "Before buffer assignment:" << endl;
cout << "mydata = " << mydata << " and mydata2 = " << mydata2 << endl;
for ( int i = 0; i < 15; i++ ) {
buffer[i] = 4;
}
cout << "After buffer assignment:" << endl;
cout << "mydata = " << mydata << " and mydata2 = " << mydata2 << endl;
return 0;
}
Predict the output. Do not run it until you can reason through what happens. Run it and try to figure out why the output is what you see. Make sure that you compile it with the g++ flag -fno-stack-protector just in case on your platform g++ has been installed to default to -fstack-protector.
Activity: Visit the following site, read the material, and answer the questions there: Security Injection for CS2: Buffer Overflows
Exercise 4. Figure out what this program does:
#pragma check_stack(off)
#include <string.h>
#include <stdio.h>
void foo(const char* input)
{
char buf[10];
printf("My stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n\n");
strcpy(buf, input);
printf("%s\n", buf);
printf("Now the stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n\n");
}
void bar(void)
{
printf("Augh! I've been hacked!\n");
}
int main(int argc, char* argv[])
{
//Blatant cheating to make life easier on myself
printf("Address of foo = %p\n", foo);
printf("Address of bar = %p\n", bar);
if (argc != 2)
{
printf("Please supply a string as an argument!\n");
return -1;
}
foo(argv[1]);
return 0;
}

2.4 Design Issues: Encapsulation

Activity: Encapsulation Exercise

2.5 Exception Handling

Activity: Exception Handling Exercise

Rules to Observe When Coding