0% found this document useful (0 votes)
31 views20 pages

Buffer Overflow Lab Report

The document is a lab report on software security, focusing on buffer overflow vulnerabilities in C programs. It details experiments with various code examples, including 'overflow_example.c', 'notesearch.c', and 'auth_overflow.c', demonstrating how unchecked memory operations can lead to exploitation. The report concludes with key takeaways on secure coding practices and the importance of understanding vulnerabilities for cybersecurity.

Uploaded by

Liyat Tesfaye
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)
31 views20 pages

Buffer Overflow Lab Report

The document is a lab report on software security, focusing on buffer overflow vulnerabilities in C programs. It details experiments with various code examples, including 'overflow_example.c', 'notesearch.c', and 'auth_overflow.c', demonstrating how unchecked memory operations can lead to exploitation. The report concludes with key takeaways on secure coding practices and the importance of understanding vulnerabilities for cybersecurity.

Uploaded by

Liyat Tesfaye
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/ 20

Addis Ababa University

School of Information Technology and Engineering

Software Security
Lab-Report

Name :Liyat Tesfaye


ID:UGR-6140-12
Stream: Cyber

Date: Nov 7,2024


1. Buffer Overflow Exploration............................................................................................. 3
Overview of the Code.........................................................................................................3
Compiling and Running the Code...................................................................................... 4
Analysis of Output.............................................................................................................. 4
How the Stack is Impacted.................................................................................................5
Major Overflow: 38-Byte Input Example....................................................................... 5
Running the Code with a Long Input:
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"..................................5
Breakdown of the Overflow and Its Effects:............................................................6
Conclusion....................................................................................................................6
2. Exploitation Of Note Search..............................................................................................6
Overview...................................................................................................................... 7
Detailed Breakdown..................................................................................................... 7
Vulnerabilities Identified................................................................................................8
Understanding exploit_notesearch.c.................................................................................. 9
Overview.................................................................................................................... 10
Exploit Mechanics...................................................................................................... 10
How notesearch.c and exploit_notesearch.c Work Together........................................... 11
Step-by-Step Interaction............................................................................................. 11
3. Authentication overflow.................................................................................................. 12
Overview.................................................................................................................... 13
Function Purpose:................................................................................................ 13
Detailed Breakdown:............................................................................................ 14
Analysis of the result and sets taken when debugging with gdb:............................... 15
Security Vulnerability: Buffer Overflow....................................................................... 17
4. Authentication overflow2................................................................................................ 17
Security Improvements in auth_overflow2.c.....................................................................18
Analysis Summary......................................................................................................20
Key Takeaways................................................................................................................ 20
Conclusion..................................................................................................................20
1. Buffer Overflow Exploration

Code: overflow_example.c

Overview of the Code

This C program, overflow_example.c, demonstrates a buffer overflow vulnerability, which


occurs when data exceeds its allocated space, potentially overwriting adjacent memory
locations.

The program declares two 8-byte character arrays, buffer_one and buffer_two, and an
integer variable value initialised to 5. Here’s a breakdown of how it works:

1. Setting Initial Values:


○ buffer_one is initialised with the string "one", and buffer_two with
"two", using strcpy.
○ strcpy doesn’t check if the source string is too large, which is what makes it
possible to create a buffer overflow.
2. Printing Initial Values:
○ Before any modification, the code prints the memory addresses and current
contents of buffer_one, buffer_two, and value.
3. Buffer Overflow Attempt:
○ The program attempts to copy the command-line argument (argv[1]) into
buffer_two, without checking if it fits into 8 bytes. This sets up an overflow
if the argument is too long.
4. Printing After Modification:
○ After the copy operation, the program prints the updated values to show the
impact of the overflow on the memory layout.

Compiling and Running the Code

To compile and run the program, i used the following command:

gcc -fno-stack-protector -o overflow_example overflow_example.c


./overflow_example 1234567890

The -fno-stack-protector flag disables GCC's built-in stack protection, which would
otherwise prevent buffer overflows. By disabling this, we can clearly see how an overflow
might affect the program's execution.

Analysis of Output

The output from running ./overflow_example 1234567890 shows the following steps:

1. [BEFORE] Initial State:


○ buffer_two contains "two", buffer_one contains "one", and value is
set to 5.
2. [STRCPY] Copying into buffer_two:
○ The program attempts to copy "1234567890" (10 bytes) into buffer_two,
which only has an 8-byte space. This causes an overflow.
3. [AFTER] Post-Overflow State:
○ buffer_two now contains "1234567890", buffer_one is unexpectedly
altered to "90", and value remains 5.
○ The overflow caused "90" to spill into buffer_one, demonstrating how a
buffer overflow can modify nearby memory locations.

How the Stack is Impacted

In C, local variables are typically stored consecutively in memory on the stack. Here’s how
the memory layout of the stack looks in this example:

Address Variable Value

0x...dde4 buffer_one "90"

0x...dddc buffer_two "1234567890"

0x...ddec value 5

When buffer_two overflows, it overwrites part of buffer_one, changing its contents.


This example highlights the risk of unchecked copying in C and how it can lead to
unpredictable or dangerous behaviour.

Major Overflow: 38-Byte Input Example

Running the Code with a Long Input:


"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"

Next, we run the program with a longer input consisting of 38 "A" characters:
Breakdown of the Overflow and Its Effects:

When we pass a 38-byte input, the strcpy function blindly copies all 38 characters, causing
a much more significant overflow. This overflow overwrites not only buffer_two but also
buffer_one and the value variable. Here’s a detailed breakdown of the stack behaviour:

Initial Stack Layout: Before the overflow, buffer_two, buffer_one, and value are laid
out sequentially in memory, just like before:
[buffer_two] [buffer_one] [value]

|'two' | |'one' | |5 |

1. Overflow Effect on Stack Memory: After copying 38 bytes, the memory looks like
this:
[buffer_two] [buffer_one] [value]

| AAAAAAAAAAAAAAAA | | AAAAAAAAAAAAAAAA | | 0x41414141 |

2. Each "A" character is represented by 0x41 in hexadecimal. As strcpy copies the


characters, buffer_two fills up and then spills over into buffer_one and finally
into the memory location for value.
3. Impact on value: By the time the overflow reaches value, it overwrites its original
integer value 5 with 0x41414141. This value, in decimal form, is 1094795585,
which is why we see that specific number in the output.
4. Segmentation Fault: The excessive overflow leads to a segmentation fault. This error
occurs because the program tries to access memory it doesn’t have permission to
access. In our case, the overflow has corrupted parts of the stack, leading to an
illegal memory access that ultimately crashes the program.

Conclusion

Through these examples, I've observed how buffer overflows can have varying impacts,
from minor data corruption to program crashes. The 1234567890 input showed a subtle
effect with a minor overflow, while the long input "AAAAAAAA..." highlighted a more severe
overflow resulting in a segmentation fault.

2. Exploitation Of Note Search

Understanding notesearch.c => [it's good to start from here]


Code: notesearch.c
Overview

notesearch.c is a C program designed to manage and search user notes stored in a file
(/var/notes). It allows users to search through their notes based on specific keywords.
However, the program contains vulnerabilities that can be exploited, particularly a buffer
overflow vulnerability.

Detailed Breakdown

Function Prototypes:

○ print_notes: Handles printing notes based on user ID and search string.


○ find_user_note: Locates a note belonging to a specific user.
○ search_note: Searches for a keyword within a note.
○ fatal: Likely handles fatal errors by printing an error message and exiting.

main Function:

○ Argument Handling: If a command-line argument is provided, it copies it into


searchstring using strcpy. Vulnerability Point: strcpy does not
perform bounds checking, allowing for potential buffer overflow if argv[1]
exceeds 99 characters.
○ User ID and File Handling: Retrieves the user ID using getuid() and opens
the notes file in read-only mode. If opening the file fails, it calls fatal.
○ Printing Notes: Enters a loop to print notes relevant to the user and
containing the search string until no more notes match.
○ Cleanup: Prints an end-of-data marker and closes the file descriptor.

print_notes Function:

○ Finding Notes: Calls find_user_note to locate a note for the given user ID.
○ Reading Notes: Reads the note into note_buffer. Vulnerability Point: If
note_length is greater than 99, note_buffer can overflow.
○ Null-Termination: Adds a null terminator to ensure the string is properly
terminated.
○ Searching and Printing: If the note contains the search string, it prints the
note.

find_user_note Function:
Reading User ID: Continuously reads user IDs from the file until it finds a match.

○ Reading Note Length: After finding the matching user ID, it reads bytes until it
encounters a newline character, calculating the length of the note.
○ Seeking Back: Uses lseek to move the file pointer back by the length of the
note, preparing to read the actual note content.
○ Debugging Output: Prints a debug message indicating the size and user ID of
the found note.
○ Return Value: Returns the length of the found note or -1 if not found.

search_note Function:
Keyword Search: Iterates through the note to find if the keyword exists within it.

○ Matching Logic: Increments the match counter when characters match and
resets appropriately.
○ Return Value: Returns 1 if the keyword is found, otherwise 0.

Vulnerabilities Identified
1. Buffer Overflow in main: The use of strcpy(searchstring, argv[1]);
without bounds checking allows an attacker to input a string longer than 99
characters, potentially overwriting adjacent memory.
2. Potential Buffer Overflow in print_notes: Reading note_length bytes into
note_buffer[100] without verifying if note_length exceeds the buffer size can
lead to overflow.

These vulnerabilities can be exploited to manipulate the program's memory, potentially


allowing an attacker to execute arbitrary code.

When ran, this is what the compilation looks like:

Understanding exploit_notesearch.c
Code: exploit_notesearch.c
Overview

exploit_notesearch.c is an exploit program designed to take advantage of the buffer


overflow vulnerability in notesearch.c. The goal is to inject shellcode into the vulnerable
program's memory space and execute it, thereby gaining unauthorised shell access.

Shellcode Definition:

○ Purpose: This is a sequence of machine instructions (shellcode) intended to


spawn a shell (/bin/sh). It typically performs the following:
■ Setup Registers: Clears registers to set up for a system call.
■ Execve Call: Executes the execve system call to run /bin/sh.

main Function:

○ Memory Allocation and Initialization:


■ Allocates 200 bytes for command and zeroes it out using bzero.
■ Copies the initial part of the command string ./notesearch ' into
command.
○ Buffer Preparation:
■ Sets buffer to point to the end of the current command string.
■ Adjusts the offset if a command-line argument is provided,
defaulting to 270.
○ Calculating Return Address:
■ Calculates the return address (ret) by taking the address of variable i
and subtracting the offset. This is intended to point to the NOP sled
or shellcode within the buffer.
○ Filling the Buffer with Return Addresses:
■ Loops through the first 160 bytes of buffer, writing the calculated
return address (ret) every 4 bytes. This creates a "return address
overwrite" area in the buffer, increasing the likelihood that the
program's execution flow will jump to the shellcode.
○ Inserting NOP Sled and Shellcode:
■ NOP Sled: Fills the first 60 bytes of the buffer with 0x90 (NOP
instruction), creating a NOP sled that slides execution into the
shellcode.
■ Shellcode Insertion: Copies the shellcode into the buffer immediately
after the NOP sled.
○ Finalising the Command:
■ Appends a closing single quote to complete the command string.
■ Executes the constructed command using system(), which runs the
vulnerable notesearch program with the crafted input.
■ Frees the allocated memory for command.

Exploit Mechanics
1. Buffer Construction:
○ The exploit constructs an input string that starts with ./notesearch ',
followed by a buffer that contains:
■ A series of return addresses pointing back into the buffer where the
shellcode resides.
■ A NOP sled to provide a landing area for the execution flow.
■ The actual shellcode that spawns a shell.
2. Exploitation Process:
○ Buffer Overflow Trigger: When notesearch processes the input string, it
uses strcpy to copy the malicious input into a fixed-size buffer
(searchstring[100]), exceeding its capacity.
○ Overwriting Return Address: The overflow overwrites the return address on
the stack with the address pointing to the NOP sled within the buffer.
○ Shellcode Execution: When the function returns, it jumps to the overwritten
return address, slides through the NOP sled, and executes the shellcode,
spawning a shell.

How notesearch.c and exploit_notesearch.c Work Together

Step-by-Step Interaction

1. Launching the Vulnerable Program:


○ exploit_notesearch.c calls ./notesearch with the malicious input
string as an argument.
2. Buffer Overflow in notesearch.c:
○ Inside notesearch.c, strcpy(searchstring, argv[1]); copies the
malicious input into searchstring[100], exceeding its capacity.
3. Overwriting the Return Address:
○ The excess data from the malicious input overwrites the stack's return
address with the address pointing to the shellcode.
4. Redirecting Execution Flow:
○ When the vulnerable function in notesearch.c attempts to return, it uses
the corrupted return address, jumping to the shellcode instead of the intended
return location.
5. Executing Shellcode:
○ The shellcode executes, spawning a new shell (/bin/sh) with the privileges
of the notesearch process.
6. Gaining Unauthorised Access:
○ The attacker gains shell access (sh-3.2#), allowing them to execute
commands with the privileges of the compromised program.
When ran, this is what it looks like:

As seen from the picture ,

● The code did not execute the way it was supposed to. Disabled all detections, still did
not work, also checked using the gdb, but still the return address was 0x00,
technically not writing the shellcode we have inserted.
● Also , I tried with different shell code and also NOP ,but it still did not work.
● Tried it with gcc 3.3.6 , still did not work

Conclusion

The interaction between notesearch.c and exploit_notesearch.c serves as a


practical demonstration of how buffer overflow vulnerabilities can be exploited to execute
arbitrary code. While the exploit may not have succeeded in your case due to modern
security mechanisms or other factors, understanding the underlying principles is crucial for
both offensive and defensive cybersecurity practices.

Key Takeaways:

● Exploitation Techniques: Attackers can inject shellcode and manipulate return


addresses to redirect program execution, leading to unauthorised actions.
● Security Measures: Modern systems employ various protections (NX, ASLR, stack
canaries) to mitigate buffer overflow exploits, making such attacks more
challenging,which seems to be it in my case here.
● Secure Coding Practices: Always perform bounds checking when handling user input
and prefer safer functions (e.g., strncpy over strcpy) to prevent vulnerabilities.

3. Authentication overflow

Understanding Auth_overflow.c
Code: auth_overflow.c
Overview
The code auth_overflow.c provided implements a simple C program designed to check if a
password input matches one of two predefined passwords. Here’s a breakdown of what
each part of the code does:

Function: check_authentication

Function Purpose:

This function, check_authentication, takes a password (a pointer to a character array,


or string) as input and checks if it matches either of two specific passwords, "brillig" or
"outgrabe".
Detailed Breakdown:

● Variables:
○ int auth_flag = 0;: Initialises a variable named auth_flag to 0. This
variable will be used as a flag to indicate whether authentication was
successful (set to 1 if a password match is found).
○ char password_buffer[16];: Declares a buffer with a size of 16 bytes to
store the password input.
● Password Copying (Potential Buffer Overflow):
○ strcpy(password_buffer, password);: This function copies the
content of password into password_buffer.
○ Issue: strcpy does not check the length of password before copying it into
password_buffer. If the password is longer than 16 characters, this will
cause a buffer overflow, potentially overwriting adjacent memory, including
the auth_flag variable, and introducing a security vulnerability.
● Password Comparison:
○ if(strcmp(password_buffer, "brillig") == 0): Compares
password_buffer with the string "brillig". If they match, auth_flag is
set to 1.
○ if(strcmp(password_buffer, "outgrabe") == 0): Compares
password_buffer with the string "outgrabe". If they match, auth_flag
is also set to 1.
○ If either comparison is successful, auth_flag will be 1, indicating
successful authentication.
● Return Statement:
○ return auth_flag;: Returns the value of auth_flag to indicate the result
of the authentication check. A return value of 1 means authentication
succeeded, while 0 means it failed.

Main Function: main

Purpose of main:

The main function is the program’s entry point. It expects the user to provide a single
command-line argument (the password) when running the program. This argument is then
passed to the check_authentication function to determine if access should be granted.

Breakdown:

Argument Count Check:

if(argc < 2): Checks if there are fewer than 2 command-line arguments
(argc is less than 2).
i. If argc is less than 2, the program outputs the correct usage format
and exits with exit(0). This ensures the user provides a password
as an argument.

Authentication Check:

if(check_authentication(argv[1])): Calls the


check_authentication function with the provided password (argv[1])
and checks its return value.

ii. If check_authentication returns 1, indicating a successful


password match, the program prints an "Access Granted" message.
iii. If check_authentication returns 0, indicating a failed password
match, the program prints an "Access Denied" message.

After compilation this is the result:

Analysis of the result and sets taken when debugging with gdb:

1. Set Breakpoints:
○ break 9: Sets a breakpoint at line 9 of auth_overflow.c.
○ break 16: Sets another breakpoint at line 16 of auth_overflow.c.
2. Run Program with Input:
○ run AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: Starts the program with an
input of 30 'A' characters, likely to trigger a buffer overflow in the
password_buffer.
3. First Breakpoint (Line 9):
○ check_authentication (password=0x7fffffffe667 'A'
<repeats 30 times>): Indicates that the check_authentication
function is called with a password input that contains 30 'A' characters. Line
9 in the code contains a strcpy operation where password is copied into
password_buffer, setting up for a potential overflow if password_buffer
is not large enough.
4. Inspect Memory:
○ x/s password_buffer: Examines the password_buffer contents,
showing it holds no data initially.
○ x/w &auth_flag: Examines the auth_flag variable, showing it’s set to
0x00, indicating no access granted at this point.
○ print 0x7fffffffe27c - 0x7fffffffe260: Calculates the size of
password_buffer, showing 28 bytes, which may be smaller than the 30 'A's
passed, leading to overflow.
5. Memory View in Hex:
○ x/16xw password_buffer: Displays password_buffer in hex format
with 16 words (4 bytes each). Initially, password_buffer contains zeros,
and there's no visible overflow at this point.
6. Continue Execution:
○ cont: Continues the program until the next breakpoint.
7. Second Breakpoint (Line 16):
○ Execution halts at line 16 in auth_overflow.c, where it checks if
auth_flag is set, to grant or deny access.
○ x/s password_buffer: Shows password_buffer contains 30 'A'
characters, confirming overflow.
○ x/w &auth_flag: auth_flag is now set to 0x41 (ASCII 'A'), meaning the
buffer overflow has overwritten auth_flag.
8. Memory Dump of password_buffer:
○ x/16xw password_buffer: Memory of password_buffer now shows
0x41414141 values (hex for 'AAAA') and some additional overwritten values,
showing a clear overflow past the buffer’s bounds.
9. Display auth_flag:
○ x/4cb &auth_flag: Displays auth_flag in character format as 'A',
confirming that it has been altered from its initial state.
10. Access Granted:
○ The program continues, and the output message Access Granted.
confirms that the overflow exploit succeeded, setting auth_flag to a value
that granted access.
Conclusion

Security Vulnerability: Buffer Overflow

This code has a significant security vulnerability due to the use of strcpy to copy
password into password_buffer without checking its length. If a user provides a
password longer than 16 characters, it will overflow password_buffer and can overwrite
adjacent memory. Since auth_flag is located close to password_buffer in memory, it
could be overwritten by an attacker.

4. Authentication overflow2

Understanding Auth_overflow2.c
Code: auth_overflow2.c
You might wonder what the difference is between auth_overflow one and two. Well,
here’s the key: in version two, by putting auth_flag before password_buffer in memory,
we prevent the buffer overflow from corrupting the return address or other critical control
points. This small change limits the overflow’s impact—while it might still overwrite
auth_flag, it can’t reach the return address anymore, so the program flow is safer. It’s a
simple tweak, but it reduces the severity of the security risk by making it harder for an
overflow to hijack program execution.

Code Overview

Security Improvements in auth_overflow2.c

Compared to the previous version of the code, this version makes a subtle but important
change that improves security. Here’s why:

1. Reordering of Variables:
○ In this version, the auth_flag variable is declared after password_buffer
in the check_authentication function.
○ Since auth_flag is placed after password_buffer in memory, a buffer
overflow on password_buffer could overwrite only auth_flag but would
not reach the return address or other critical control points.
2. Prevention of Return Address Overwrite:
○ In the previous version, the auth_flag variable was declared first, placing it
before password_buffer in memory. This allowed an overflow in
password_buffer to potentially overwrite the function’s return address,
creating a vulnerability where an attacker could control program execution.
○ By moving auth_flag after password_buffer, this version of the code
reduces the risk of such an exploit. The overflow might still affect
auth_flag, but it won't impact the return address, making the program more
resistant to attacks.

When we ran the code , this is the result of the compilation and gdb:
In this updated GDB output, we can see that despite the buffer overflow attempt, the
auth_flag remains at 0x00, meaning it has not been overwritten by the overflowed data.
Here’s a summary explaining why this is happening:

Analysis Summary

1. Position of auth_flag:
○ In this code, auth_flag is located just after password_buffer in memory.
○ However, the overflowed data (repeating 0x41 or ASCII 'A') did not reach
auth_flag this time, leaving it untouched as 0x00.
2. Memory Layout and Overflow:
○ The previous attempt demonstrated that auth_flag was overwritten with
0x41414141 (repeating As) because the overflow reached into its memory
space.
○ The repeated 0x41 values stop before reaching auth_flag, preserving its
original value of 0x00.
3. Effect on Authentication:
○ Since auth_flag remains 0x00, the authentication check fails as intended,
and no unauthorised access is granted.
○ This demonstrates that while the buffer overflow is still present, it does not
corrupt the auth_flag as it did previously, thus failing to manipulate the
program’s behaviour.

Key Takeaways

● Variable Ordering Matters: Placing sensitive variables (like auth_flag) after buffers
can help prevent critical memory corruption, such as overwriting the return address.

Conclusion

The reason the overflow fails to modify auth_flag here is due to the memory layout. The
auth_flag variable is positioned at a memory address that the overflowed data does not
reach, leaving it at 0x00. This prevents the overflow from tricking the program into granting
access, unlike in the previous version where auth_flag was overwritten.

You might also like