0% found this document useful (0 votes)
63 views15 pages

Buffer Overflow Attacks

The document discusses different types of software vulnerabilities including buffer overflows, code injections, cross-site scripting attacks, SQL injections, and heap overflows. It provides examples of each type of vulnerability and methods to prevent them.

Uploaded by

Menberu Munye
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
63 views15 pages

Buffer Overflow Attacks

The document discusses different types of software vulnerabilities including buffer overflows, code injections, cross-site scripting attacks, SQL injections, and heap overflows. It provides examples of each type of vulnerability and methods to prevent them.

Uploaded by

Menberu Munye
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 15

Buffer Overflow Attacks

What Are They?


Like a flooding river, a buffer overflow has the potential to cause
significant damage. To understand why, let’s begin at the source of
the problem. In low-level languages that access and write memory, a
part of this memory stays allocated for temporary data that needs to
be saved during run-time. This part of memory is called a buffer. A
buffer overflow happens when the data that needs to be saved
exceeds the allocated memory space in the buffer.

Examples of a Buffer Overflow


As you can see in the image to the right, memory is made of different
parts. Between the stack and the heap, there is a buffer area, which
allows both to grow during run time. If we look at a stack in detail,
we can see different sections:
• Function: The calling function written by the developer
• Parameters: The parameters needed by the function
• Return: Tells the program what to do after it has executed the
function
• Basepointer: Marks the start of a function stack frame
• Buffer: The allocated space for data
Types of Buffer Overflow

This involves overflowing a buffer on the call stack, as described


above.

Same as stack overflow, but it takes place in an open memory pool.

An arithmetic operation results in an integer too large for its integer


type.

Unicode characters are inserted into an input that expects ASCII


characters.
Preventing Buffer Overflow Attacks
Avoid C/C++, these programming languages prone to buffer
overflow.
Address space layout randomization.
Enhance the security of executable programs by detecting buffer
overflows on stack-allocated variables.
Mark memory regions as non-executable.
Avoid standard library functions that are not bounds checked, such
as gets, scanf and strcpy.
Scan your code for buffer overflow vulnerabilities.
Code Injection Attacks
What Are They?
Code injection is a general term for a type of software vulnerability
where unvalidated input is evaluated by an application. It is fairly
common on web applications that rely on user input through forms
that lack appropriate input/output data validation. This flaw can be
exploited by attackers by injecting malicious code in the language of
the application into it, which will then be executed by the server-
side interpreter for that language.
Consequences of code injection can be dire:
• Data loss • Lack of accountability
• Data corruption • Denial of access

Types of Code Injections

(file inclusion vulnerability)

(format string attack)


Preventing Code Injection Attacks
Validate and sanitize inputs — accept only a limited set of values.
Use a SAST solution.
Give the account the database calls run under only limited
privileges.
Avoid vulnerable evaluation constructs.
Cross-Site Scripting Attacks
What Is Cross-Site Scripting?
According to OWASP Top 10, XSS is the second-most prevalent
issue found in the majority of web applications. By using XSS,
attackers can bypass the Same Origin Policy (SOP) in a vulnerable
application by entering malicious code that is mistakenly
interpreted as user input. This can be done with technologies like
VBScript, ActiveX, Flash, and even CSS, but JavaScript attacks are the
most common.
XSS differs from SQL because it does not target the database of web
applications; it mostly limits itself to their front end.
These attacks can be non-persistent, persistent, and DOM-based.
The consequences of XSS attacks can be very damaging, especially
when combined with social engineering.
Websites or web interfaces can become corrupted and unsafe.
Cookies and authentication information can be stolen, leading to
identity theft. By hacking a vulnerable company website, attackers
can gain control of the company’s computer clients.
Examples of Cross-Site Scripting Attacks
Preventing Cross-Site Scripting Attacks
Specify which tags are designed as “safe” in the HTML documents
created by user inputs.
Encode the data on output.
Use Content Security Policy (CSP).
Use a Static Application Security Testing solution.
The Dangers of SQL Injection Attacks
What Are They?
From November 2017 to March 2019, 65% of web application
attacks worldwide used SQL injection (SQLi). So it’s no surprise that
injection attacks were named as the number one threat to web
applications by the Open Web Application Security Project
(OWASP).
If you’re wondering why SQLi attacks are so frequent, it’s because
web forms that use SQL queries to retrieve data are common. From
login pages to search queries, online order forms, and more, these
web forms are often connected to databases with potentially
valuable information such as personal data and financial records.
By targeting web forms, attackers can bypass other types of security,
such as firewalls and endpoint defenses. The knowledge needed to
conduct an injection attack is readily available online.
Attackers use SQLi to extract data, such as passwords and credit
card information. They can add, modify, or delete records in the
database, perform database operations such as changing credentials
or dropping entire tables, and more. Any database that uses
Structured Query Language (SQL) is vulnerable to SQLi, including
Microsoft SQL Server, Oracle, MySQL, PostgreSQL, and MongoDB.
Preventing SQL Injection Attacks
Avoid constructing dynamic queries.
Use stored procedures and call them using canonical syntax.
Sanitize user data by removing special characters and reserved
words.
Suppress database error messages to avoid revealing details.
Limit application user permissions.
Use a SAST solution.
Common software vulnerabilities, Part I: heap overflows
Introduction

One of the most widely taught software exploits is a stack buffer


overflow, and although they’re great for learning they aren’t very
applicable in the real world. Most modern security vulnerabilities
that make the headlines involve exploiting heap corruption or use
after frees. For more on vulnerability trends, see this presentation
from Microsoft.

The heap is potentially large and complex, and so there are different
types of vulnerabilities: there are heap overflows, use after free and
double free vulnerabilities. In these series of blogs I’ll cover all the
previously mentioned heap vulnerabilities, starting off with heap
overflows.

Heap vs. Stack


Before I dive into some code, let’s have a brief comparison between
the stack and the heap. When a program is run, both the heap and
stack are created and stored in RAM, but they have some important
differences. For starters, the stack is used for static memory
allocation, whereas the heap is used for dynamic memory allocation.
An important difference is the stack is normally used for lightweight
data for fast access, such as local variables. The heap normally holds
objects and data structures, these pieces of data may be slower to
access, however it’s useful if you do not know the exact size of the
piece of data you want to set. For a more in depth article discussing
their differences and what they are, I’d recommend
reading this article.

Example C Code

Let’s look at some example code:

#include <stdlib.h>

#include <unistd.h>

#include <string.h>

#include <stdio.h>

#include <sys/types.h>

struct data {

char name[64];

};
struct fp {

int (*fp)();

};

void winner()

printf("level passed\n");

void nowinner()

printf("level has not been passed\n");

int main(int argc, char **argv)

struct data *d;

struct fp *f;

d = malloc(sizeof(struct data));

f = malloc(sizeof(struct fp));
f->fp = nowinner;

printf("data is at %p, fp is at %p\n", d, f);

strcpy(d->name, argv[1]);

f->fp();

This code was taken from exploit-exercises. This challenge is


“protostar heap0”.

First, let’s start by walking through the code. I find it helps when you
first just read the code and understand it, without looking for
vulnerabilities. Right off the bat, we have two structs: data which
has a character array of 64 bytes, and fp which has a pointer to a
function.

Next we have two functions winner() and nowinner(), each of which


will print out different results. In the main() function, we allocate
memory to d and f on the heap, we then set fp of f to the
function nowinner. We print some information about the pointers,
and then copy the data from the first argument passed to the
program into the buffer of d. Lastly, we call the function that fp was
set to.

Now if you’ve got a keen eye, you might have already spotted the
developer’s mistake. If you didn’t, it’s explained in the next section.

An exploitation example
Now when exploiting a program, it almost goes without saying, but
the first thing to do is run it. We’ve seen the code, but let’s see the
program in action as it will help us in the next steps.

Running the program

If we first run the program without arguments, it throws a segfault.


If we run it with a single argument it outputs “level not passed”, and
if we give it a second argument it ignores it. So what’s happening on
the heap?
This is what the heap looks like in the different scenarios

This image provides us a look at the heap with these given inputs.
Since in the first run we don’t provide an input it is empty, so when
strcpy is called it points to nothing and thus a segmentation fault
occurs. In the second scenario, strcpy successfully copies the first
argument given to the program, which is argv[1]. argv[2] is never
used as the second argument is just ignored by the program.

Luckily we’ve read the code and know that the first argument is
being passed to an unchecked buffer of 64 bytes, so we start by
giving it 64 characters and see what happens:
Fuzzing the input of the program

I originally started inputting letters from A to N since I’m doing four


of each character (which will display as hex and is easy to identify
where in the string something is going wrong). I kept adding
characters from the alphabet until finally it threw a segfault at “T”,
making the inputted data a total of 80 characters, despite the buffer
only having a limit of 64. This normally happens due to protections
introduced by the compiler.

I added some “U”s to see what would happen and it seemed the
segfault address changed. That’s a bit strange. To double check, I
tried entering a single “U” and it still added a 55 to the segfault
address (0x55 in ASCII is “U”). Seeing as this is the point where it is
overwriting the addresses, we’ll mark it down as important.

Something else that we notice is the segfault is only raised after the
program has printed the data about the struct pointers. We also
notice that it stopped printing “level not passed”. Thus we can
conclude that the memory space that the “T”s and “U”s are taking up
are corrupting the address to which fp is pointing.

What the heap looks like now that the buffer is overflowed

As we can see in the image above, characters overflow from the


buffer of the first struct into the memory addresses of the second
struct. If we look at the memory image below we can see each chunk
contains some information at the beginning of the block of memory
before the actual data:
A malloc as it appears on the heap, from here

The reason the segfault occurs when we get to the “T”‘s is because
we are overwriting the information at the beginning of the block. We
can now mess around with the heap since we’re leaking the memory
and get it to output different results.

Seeing as the character “U” changes the segfault address, I’ll replace
those characters with our winner() address. Now if this was done in
the wild an attacker would place the address of their malicious code
here. Let’s see where the winner() function is located. By
doing disass winner gdb will disassemble the function and print the
address of the first instruction. Let’s go ahead and overwrite the “U”
with the hex address of the first instruction in the winner() function.
Exploiting the program

Now we can see that I ran the function for the address a little bit
differently. In order to pass the hex address we need to insert it
using echo -ne. To pass the command, we need to use backticks so
we open the string, enclose it in backticks, and pass the echo
command our custom string. We separate each hex byte with “” to
identify it as hex. Lastly, the reason we write the address back to
front is because it works in little endian notation. Knowing which
endianness to use is always important when exploiting a function, in
this case I tried little endian on my first time and it worked.

You might also like