Secure Software Design — Part 2

Srishti Mishra
Information Security 101
4 min readDec 20, 2018

--

This post focuses on software security and covers several vulnerabilities and flaws to keep in mind while designing secure software. A system with design flaws and implementation bugs provides an entry point to attackers looking to damage the company or steal from the user. This is where Software Security comes in — it focuses on secure design and implementation of software from the coding level. Bugs are an inevitable part of the software and for most users, just a minor inconvenience. However, malicious actors actively look for bugs and exploit them to cause harm. A secure system must prevent undesired behaviour by reducing bugs or make them harder to exploit and protect the Confidentiality, Integrity and Availability of the system.

The First “Computer Bug” Moth (https://commons.wikimedia.org/wiki/File:H96566k.jpg)

CWE and CVE

Common Weakness Enumeration (CWE) and Common Vulnerabilities and Exposures (CVE) are databases by MITRE which provide standards followed by the information security community. These help in eliminating the most common mistakes that developers, designers and architects make in software and lead to more secure software.
CVE provides a database of vulnerabilities found in specific versions of software and scores them by severity while CWE records the underlying weakness itself (which could lead to vulnerabilities), independent of any software versions.

This is part of a series covering topics in Information Security:

  1. Introduction to Information Security
  2. Security in the Cloud
  3. Challenges in Mobile Security
  4. Secure Software Design — Part 1
  5. Secure Software Design — Part 2 (this post)

Vulnerabilities in Software

Low-level vulnerabilities

These are mainly violations of memory-safety in programming languages such as C and C++, where memory can be directly accessed and modified. They include buffer overflows (on the stack and heap) vulnerabilities, integer overflows, format string mismatches, and dangling pointers. Here, a pointer is accessing memory that it’s not supposed to.

Read more about stack smashing and try it out with this awesome paper — Smashing The Stack for Fun and Profit.

Attacks
These exploit the vulnerabilities described above to crash the program or execute malicious arbitrary code.

  • Stack smashing —Attacker overflows a buffer with input to fill up all the local variable space in the stack and accesses forbidden memory regions to crash the program or execute malicious code.
  • Return-to-libc attack — If the stack is non-executable (see more in defences below), the return address in the stack can be changed to a location of a library function already present in the address space.
  • Format string attacks — If the input is not properly validated, carefully crafted malicious code could be inserted and can execute arbitrary commands on the stack.
  • Stale memory access — A dangling pointer points to memory which is freed. If the memory is now being used somewhere else, overwriting the memory location via the dangling pointer could cause the system to crash.
  • Return-oriented programming (ROP) — Carefully crafted code can be inserted into the stack by overflowing a buffer. The code generally contains a NOP sled (series of null operations executed by the CPU) until the return address of the stack frame is reached. The return address now points to a location provided by the attacker, the CPU jumps to that location and executes the malicious code.

Defence

  • Address space layout randomization (ASLR) — ASLR randomly arranges the address positions of the stack, heap and libraries, preventing the attacker from reliably jumping to an exploited function in memory.
  • Non-executable data — Makes the stack and heap data segments non-executable so that the attacker’s code in the stack cannot be executed.
  • Stack canaries — Prevent stack smashing and ROP by placing a special number in between the local variables and saved base pointer called a canary. The program then checks whether this number has changed before returning from the function. If an attacker overwrote the return address, the canary would be modified as well.
  • Memory-safety enforcement — A compile-time transformation for enforcing complete spatial safety of C.
    Read more about it here.
  • Using Memory-safe languages such as Java — do not allow direct access to memory and are not exposed by these vulnerabilities.

More about Buffer overflows

The buffer overflow vulnerability is one of the most widespread vulnerabilities and has been exploited by almost every worm on the Internet, starting with the Morris Internet Worm in 1988 to the recent WannaCry ransomware attack in May, 2017. A buffer overflow attack is basically when an attacker provides an oversized input to fill up the buffer and write into the memory space after it. Carefully crafted input can lead to the execution of malicious code or at least crash the program.

In order to launch a buffer overflow attack, the attacker needs 2 things:

  1. Identify a buffer overflow vulnerability in the application
    - Inspect source code of the program
    - Trace the execution of the program with oversized input (with a debugger such as gdb for C programs)
    - Tools such as Fuzzing
  2. The vulnerability needs to be triggered by external data or an input string
    - The program uses an unsafe routine such as gets, strcat, strcpy, sprintf etc, where it does not check the length of input it copies into the buffer. If the length was checked (eg. in strncpy, strncat) the input would be truncated and the buffer would not overflow.

To try it out yourself, follow this demo!

Note: This post has been made with reference to slides used in Information Security lectures by Mr Prasad Honnavalli and various online sources

--

--