Where do Vulnerabilities come from?

A Simple Look at Inherent Vulnerabilities By Michael Adjei (MSc.), Security Trainer & Senior Security Engineer at Nuvias Cyber Security. In recent times, not a day goes by without the sensational flashing news story of a big organisation suffering a data breach through a cyber-attack. Other times, it is a big vulnerability that has been found […]

A Simple Look at Inherent Vulnerabilities

By Michael Adjei (MSc.), Security Trainer & Senior Security Engineer at Nuvias Cyber Security.

In recent times, not a day goes by without the sensational flashing news story of a big organisation suffering a data breach through a cyber-attack. Other times, it is a big vulnerability that has been found in some widely-used software or protocol. From mobile phones to Internet of Things right through to server operating systems, nothing seems to escape the reach of cyber attackers.

So, why has it become so seemingly easy for these breaches to occur and for information that was supposed to be protected to fall into the hands of unauthorised attackers? Notice, I use the term “unauthorised attackers.” An organisation can hire authorised attackers to test their cyber defences.

The V word

Most of these breaches occur because the attackers utilise a vulnerability in the target system or network. Once a vulnerability is discovered and publicised, it will have a Common Vulnerability & Exposures (CVE) number with an accompanying Common Vulnerability Scoring System (CVSS) score. It now becomes a known vulnerability as opposed to zero-day vulnerabilities that an attacker knows about but not the vendors. So how do these vulnerabilities come about in the first place?

Generally, you can have two types of these vulnerabilities because of:

  1. Code: an inherent issue in the code or program (source: vendor)
  2. Configuration: a misconfiguration or not following best practice (source: end-user)

A Simple Analysis of Code-Based Vulnerability

Let us review a very basic example. Below we have a simple piece of code to examine. This small program basically expects an input from the user in the form of a number (integer) and then uses that input in a Python “while loop” to run the program that many times.

x = 1

num = int(input(“\nHow many times should the loop run? \nEnter a whole number: “))

while x <= num:

   print(“The while loop has now run “, x, ” times”)

   x += 1

iteration = str(x – 1)

input(“\n The while loop run a total of ” + iteration + ” times. Press enter to exit … \n”)

Assuming I provide an input of 5, the program should then run and display that it has run 5 times.

How many times should the loop run?

Enter a whole number: 5

So below we see the program has run 5 times because we supplied an input of 5. It then ends gracefully afterwards.

The while loop has now run 1 times

The while loop has now run 2 times

The while loop has now run 3 times

The while loop has now run 4 times

The while loop has now run 5 times

The while loop run a total of 5 times. Press enter to exit …

Our small program runs smoothly as long as we provide the expected input which is a whole number integer but what happens if we go out of line and do any of the following?

  • Input a letter
  • Input a decimal number

These two inputs described above will cause the program to crash. Let us try with a letter as the input:

How many times should the loop run?

Enter a whole number: a 

Traceback (most recent call last):

File “D:/while_loop_raw.py”, line 3, in <module>

   num = int(input(“\nHow many times should the loop run? \nEnter a whole number: “))

ValueError: invalid literal for int() with base 10: ‘a’

Process finished with exit code 1

How do we know this? Well, we can decipher this from the fact that the programmer has not included any checks (“try / except” for example) for such unexpected behaviour. We can see this from the source code. If we did not have this source code, then we could use a technique known as fuzzing (providing invalid or unexpected input) to try and discover this vulnerability or reverse engineering.

  • Input a very large number

What about supplying a very large number, say 10000000000? Well, this will cause the program to attempt to run that many times. This can consume so much CPU that it will possibly eventually crash the host computer on which it is running. The program output below shows this happening:

!Too much output to process

2819 times

The while loop has now run 13882820 times

The while loop has now run 13882821 times

The while loop has now run 13882822 times

The while loop has now run 13882823 times

The while loop has now run 13882824 times

The while loop has now run 13882825 times

When we examine the CPU performance of the computer on which the program runs, we can see a huge spike in the CPU usage.

As you can see, this can cause unexpected problems. In our example, the computer code is basic and not in any way security-focussed. In situations where the code is supposed to be for security, we can have serious consequences because of vulnerabilities.

Inherent or code-based vulnerabilities typically require some in-depth analysis of the source code to fix, depending on the complexity of course. In most cases, reverse engineering of binary files will be employed. After being discovered and published, typically a patch from the vendor will be provided.

For the average Security Administrator, the ability to self-assess their systems for known vulnerabilities must be a crucial step in their overall security strategy. So, by employing effective Vulnerability Assessment combined with Patch Management, security administrators and managers can stay on top of some of these vulnerabilities. When dealing with zero-day vulnerabilities however, heuristic analysis, CPU-level sandboxing and security intelligence and analytics systems will prove a more effective counter-measure. Then there is always the point about making sure all end-users are cyber security aware to prevent popular delivery mechanisms like phishing.