System Security and Buffer Overflow
Page 3
Recap: Injection of Malicious Code
Generates
compiler-hacking.o, uses to createlogin-hacked.ofromlogin.c.Understanding code verification processes.
Page 4
Buffer Overflow
Overview of system security thoughts:
Goals, threat model, mechanisms, policies.
Majority of mechanisms are software-based, which may have bugs.
Security bugs lead to vulnerabilities; buffer overflow is a prominent one.
Page 5
Buffer Overflow Context
Common in C/C++ due to being unsafe languages.
First exploit was the Morris Worm in 1988.
Continues to be relevant today.
Avoiding unsafe languages is suggested but not comprehensive; numerous changes in compilers and hardware architectures derive from it.
Page 6
Web Server Example
Threat Model: Any individual who can send messages to the server.
Attacker's Goals:
Crash server, inject code, leak, or modify data.
Page 7
Important Notes
Focus on Intel 32-bit architecture in Linux:
Little Endian, 4-byte addresses, 4GB virtual memory.
Use
-m32for 32-bit binaries on 64-bit machines.
Page 8
Stack Mechanism
Defines the process in memory with virtual memory management.
Each process has own stack, heap, and code/data segments.
Stack is managed by the OS/compiler and are not freely accessed by applications.
Registers:
$esp: Top of the stack address.$ebp: Bottom of the stack address.$eip: Current instruction address.

Page 9
Stack Mechanism
The stack consists of frames for each function:
Top stack frame holds function info, return address, previous frame pointer.
Stack grows to decreasing memory indices.
Page 10
Function Return in Stack
New stack pointer set to previous base pointer.
Pop saved base pointer and return address to new base pointer and instruction pointer.
Page 11
Invoking Function Example
int func(int a, int b)uses a stack frame for local variables and return addresses.Understand position within accounts and variables in call stack.
Page 12
Returning from Function
See stack frames evolve as function returns and local variables are popped from the stack.
Page 13
Buffer Overflow Example
void vul(char *str):Implements a vulnerable buffer with a limited size; using
strcpy()inserts data beyond the intended limit.
Function Return in Stack
New stack pointer set to previous base pointer. This process involves:
Popping the saved base pointer into the new base pointer to restore the previous stack frame.
Popping the return address into the instruction pointer that directs the flow of execution back to the caller function.
Invoking Function Example
The function declaration int func(int a, int b) is a demonstration of how local variables and return addresses are managed. Within the call stack, every invocation of a function creates a new stack frame that holds:
Local variables.
Return addresses allowing the program to know where to return after the function execution.
Returning from Function
As functions return:
The stack frames evolve; local variables are removed, and the stack pointer adjusts to previous frames.
This popping mechanism is crucial for maintaining the integrity of the program's execution flow.
Buffer Overflow Example
The code snippet:
void vul(char *str) {
char buffer[16];
strcpy(buffer, str);
}
illustrates a vulnerability where buffer can overflow. The function uses strcpy, which does not check the length of the input string. If str exceeds 16 characters, it will overwrite adjacent memory, potentially influencing return addresses and thereby may grant control over the program flow, leading to application crashes or unauthorized behavior.
Page 14
What Happens on Buffer Overflow?
When
strexceeds 16 characters, vulnerability can lead to control over program flow or application crash.
Page 15
Buffer Overflow Concepts
Classification: Writing exceeds buffer size, leading to crashes or overriding return addresses.
Page 16
Basic Exploit Mechanism
Return address point to a location on the stack which contains executable code, with buffer containing junk and injected code. When function return, jump to the injected code. Overflow buffer will have new return address, junk and injected code where injected code will start a shell. execute(‘/bin/sh’)
Page 17
Injected Code Execution
When returning from function, control jumps to shell initial code (
execute('/bin/sh')).
Page 18
Crafting Buffer Overflow
Change the return address through memory manipulation, specifying the position of injected code.
Knowledge of addresses and offsets is essential.
Page 19
Example of Injected Shell Code
Code represented in hex for executing shell operations with
int $0x80and specific registers manipulation as detailed.
Page 20
Retrieving Object Code
Use of
objdumpfor disassembly and verification of injected shell code structure.
Page 21
Crafting Exploit Methodology
Strategies involving setting the right return address and positioning of shellcode effectively in the buffer.
Page 22
Other Attack Vectors
Include return-oriented programming, heap overflow, string overflow, integer overflow.
Page 23
Return Oriented Programming (ROP)
Techniques involving stack buffer overflows without the need to inject code directly, using already loaded code to execute actions.
Stack buffer overflow
Change return address
Inject code to stack
Execute stack
Does not work when stack is not executable
Traditional Stack Buffer Overflow vs. ROP
Traditional stack buffer overflows worked by:
Overflowing a buffer on the stack
Injecting malicious code into the stack
Overwriting the return address to point to this injected code
When the function returns, the malicious code executes
This approach was mitigated by non-executable stack protections (NX/DEP), which prevent code on the stack from executing.
ROP Technique
Since code injection no longer works with these protections, ROP takes a different approach:
Instead of injecting new code, ROP reuses existing code already loaded in memory
It identifies small code sequences in existing libraries that end with a return instruction (called "gadgets")
It chains these gadgets together by carefully constructing a fake stack
Each gadget performs a small operation and then "returns" to the next gadget in the sequence, enabling the attacker to execute arbitrary code while bypassing the security mechanisms designed to prevent such attacks.
Page 24
Finding Code to Exploit
Using functions or code snippets already present in the memory to direct control to desired execution paths through manipulations.
Page 25
Executing Shell from libc

Manipulating return address to redirect flow to
system()function from libc with arguments properly set in the stack.Basic ROP with libc
The first image shows a straightforward ROP attack targeting the libc library:
Find the memory address of the
system()function in libcChange the return address in the stack to point to this
system()functionAdd the string "/bin/bash" to the top of the stack as an argument
When the vulnerable function returns, it will execute
system("/bin/bash"), spawning a shell
The diagram shows a vulnerable function
process_msg()with a buffer that can be overflowed, and how the stack is manipulated to execute code already present in memory.
Page 26
Constructing Arbitrary Programs with ROP
If no libc() - C standard library or system()
Construct arbitrary program, with innocent pieces of codes
If no system(), ROP will generate it.
Page 27
Return-Oriented Programming Basics
Identification of useful instruction sequences ('gadgets') that already exist in the code, allowing complex operations to be performed.
Page 28
ROP Example and Stitching Gadgets
illustrating how gadgets are placed sequentially in the payload for execution.
Page 29
Constructing the Stack for ROP
Mapping addresses of gadgets and setup needed stack alignment for correct ROP operation flow.
Page 30
Further Addressing and Stack Construction
Completing the stack setup to ensure gadgets fall within correct sequence for execution during exploitation.
Page 31
Final Layout of Stack in ROP
Explanation of finalized stack set up post-gadget injection.
Page 32
Additional Attack Vectors Recap
Return Oriented Programming, Heap Overflow, String Overflow, Integer Overflow reiterated as key focuses.
Page 33
Heap Overview in Memory
Details on how heap memory grows and inspection through tools like GDB.
Heap Memory Growth: The heap memory typically grows dynamically as requested by applications, allowing for flexible memory allocation.
Inspection Tools: Tools like GDB (GNU Debugger) can be utilized to examine the heap's state, monitor allocations, and detect potential vulnerabilities.

Page 34
Heap Operations
Memory management calls to allocate (
malloc used to allocate memory) and deallocate (free) with discussing overwriting potential memory addresses.char *buf = malloc(4) allocates 4 bytes of memory. 4 bytes x 8 bits = 32 bits
free() = Deallocate memory. free(buf) deallocated the above
Page 35
Heap Data Layout

Memory structure of allocated chunks, with focus on pointers and metadata relating to memory management.
Heap Data Layout (Chunks in use)
This image shows the structure of allocated memory chunks currently in use:
Each chunk begins with metadata including:
Information about the previous chunk (size if free, or user data)
The current chunk's size
Flag bits (N, M, P) for memory management
Page 36
Heap Data Layout for Unused Chunks

Description of free chunk pointers and their configurations within heap management.
Heap Data Layout (Chunks not in use)
When a chunk is freed, its user data area is repurposed:
Forward and backward pointers are stored where user data used to be
These pointers maintain a circular doubly-linked list of free chunks
The area marked with an X shows that user data no longer exists in this space
Page 37
State Before Free Operation

Memory structure representation before calling
free().Three buffers have been allocated and filled:
buf1with 'A' characters (0x41414141)buf2with 'B' characters (0x42424242)buf3with 'C' characters (0x43434343)
The memory headers for each buffer include:
Size information for the previous chunk
Size of the current chunk (highlighted as "Size of buf1 chunk")
The actual user data (highlighted as "Start of buf1 user data")
Page 38
After Free Operation

Show dynamic changes in chunk structures after freeing a chunk.
When buf2 is freed, its memory is repurposed:
Forward and backward pointers (marked as "Fwd Bwd pointers") are inserted into the space that previously held user data
These pointers (0xf7f727f8) connect this chunk to the free list data structure
The metadata is also updated:
"Previous Size updated since buf2 is free now" highlights how size flags get updated in adjacent chunks (buf3 in this case)
When a buffer is freed, the memory isn't actually cleared - instead, it's repurposed. This allows for potential buffer overflow vulnerabilities, as malicious actors can overwrite the data in these repurposed memory areas, exploiting the system's trust in previously allocated memory.
When you call
free(buf), the memory allocator takes that chunk of memory and adds it to its "free list" (a list of available memory chunks).To maintain this list, the allocator overwrites the user data area of the freed buffer with forward and backward pointers. These pointers connect this chunk to other free chunks in a doubly-linked list structure.
An attacker can manipulate these pointers, they may be able to redirect execution flow or corrupt memory, leading to unauthorized access of program or crashes.
Page 39
Example with GDB
Practical context of inspecting memory addresses using debugger; aids in understanding overflow implications.
Page 40
Free Operation Exploit
Tie into attack possibilities if memory address structures are corrupted.
Page 41
Heap Overflow Exploit Details
Heap overflow happens when you write more data into a heap-allocated buffer (memory from
malloc()) than it can hold.When you overflow into the metadata (the management data the system uses for heap chunks), you can corrupt it.
Representing how overflowed chunks can be manipulated to enable black-box approach within memory.
Page 42
Heap Chunk Overflow Mechanics
Carefully overwriting size fields to create links between arbitrary memory addresses, manipulating execution.
Before Overflow: Memory Layout
| Metadata for p | Data for p (1024 bytes) || Metadata for q | Data for q (1024 bytes) |pandqare two separate chunks.Each chunk has hidden metadata (like size, pointers) managed by the allocator.
When
strcpy(p, input)Happens with Large Input, there is a risk of overwriting the memory allocated for chunk q, which can lead to a buffer overflow. This vulnerability allows an attacker to manipulate the allocator's metadata, potentially redirecting execution flow or corrupting data.Normal input:
Fits inside
q→ no issue.
Malicious large input (more than 1024 bytes):
Writes into
q's data.Keeps writing past the end of
q, into p’s metadata!
Page 43
Manipulation of Free Procedure
Exploiting memory's management to create undesired functionality or behavior through overflow.
Page 44
Other Attack Vectors Recap
Return Oriented Programming, Heap Overflow, String Overflow, Integer Overflow included.
Page 45
String Overflow Explanation
Discussing various parameter types and format specifics during function calls in C, illustrating common fail points.
Page 46
String Overflow Parameters
Detailed value outputs for common formats like
%sand their implications in context.
Page 47
Reading Memory and Format Strings
Understanding how stack changes affect function inputs during string manipulation.
Page 48
Effects of Insufficient Arguments
Directed note towards observing how variances in input affect outputs in
printfoperations.
Page 49
Memory Writing via Formatting
Theoretical construct allowing output of byte counting to a variable using
%nformat inprintf.
Page 50
Testing
%nFormattingQuestions raised about reliability and typical behavior of
%nplaceholder in various contexts.printf(“100%nuke”); Does not always work!
When does
%nwork?You must pass a real address for
%nto store the result.
printf("100%nuke", &count);Now
%nwill safely write3(the number of characters printed so far) intocount
Page 51
Final Recap of Attack Vectors
Reiteration engaged with possible exploits including return-oriented programming to integer overflows.
Page 52
Integer Overflow Mechanics
Examination of valid ranges and overflow points in typical operations leading to unexpected behavior.
Page 53
Integer Ranges Overview
Detailed characterizations of types and their ranges within signed and unsigned contexts in C programming.

Page 54
Integer Representation Nuances
Binary representations discussed; how unsigned and signed types deviate markedly in behavior.
Page 55
Overflow Mechanics in Addition/Subtraction
Illustrate behaviors crossing signed bounds under arithmetic operations.

Page 56
Integer Division Behavior
Explain behaviors in division loops and the logic behind counting iterations directly.
Operation
Result
Why
(2³¹-1) × 2
Negative
Overflow into negative due to 32-bit limits
7 / 3
2
2 times 3 fits into 7
-7 / 3
-2
2 times 3 fits into -7 in negative direction
Page 57
Critical Integer Overflow Cases
Significant computation leading to overflow and unexpected outcomes for max-min ranges.
Page 58
Real-World Example of Integer Overflow
Discuss an actual case study in political vote counting misreporting due to overflow errors.
Page 59
Character Overflows Defined
Describe high likelihood scenarios and how reliance on inadequate types can lead to errors.
Page 60
Unsigned Type Iteration on Overflow
Explain behavior of unsigned integer loops and the infinite iteration effect.

When an unsigned integer underflows (goes below zero), it wraps around to its maximum possible value due to how unsigned integers are represented in binary. Unsigned integer CANNOT GO BELOW 0/negative so it goes back to maximum value which is 2^n - 1. This creates an infinite loop.
Unsigned integers can only represent non-negative values from 0 up to (2^n - 1), where n is the number of bits in the integer type. For example:
An 8-bit unsigned integer can represent values from 0 to 255 (2^8 - 1)
A 32-bit
size_tcan represent values from 0 to 4,294,967,295 (2^32 - 1)
Page 61
Security Principles
Emphasize designing with memory safety, optimizing TCB, least privilege, and various other fundamentals.
Page 62
Further Security Principles
Defense and detection mechanisms, along with fail-safes and ensuring robust threat modeling.
Page 63
Minimizing TCB for Security
TCB gives insight into how to create secure environments with emphasis on simplicity and effectiveness.
Page 64
Closing Questions?
Summary and closure to the lecture with a prompt for clarity or uncertainties.
Topic: Buffer Overflow and Security Principles
Instructor: Daisuke Mashima
Course: SUTD ISTD 50.044 System Security
Announcements
Tuesday sessions will be held in LEET Lab.
Today's TA discussion will focus on lab setup starting at 2 PM.
Students are encouraged to form groups for Capture the Flag (CTF) activities, consisting of 3-4 members each.
Recap: Injection of Malicious Code
Review of the process to generate the
compiler-hacking.o, which is pivotal for creatinglogin-hacked.ofromlogin.c.Emphasis on understanding the critical code verification processes necessary to safeguard against such injections.
Buffer Overflow
Overview of System Security Thoughts
Goals: Establish robust security measures that can anticipate and mitigate anticipated threats.
Threat Model: An applicative outlook on potential attacks targeting the system, focusing on vulnerabilities and weaknesses in the architecture.
Mechanisms: The various strategies employed to secure systems, mostly software-based, are examined—acknowledging that most can contain imperfections.
Policies: Implementation of organizational policies guiding security practices and incident response plans.
A significant concern is that security bugs may lead to serious vulnerabilities, with buffer overflow being a prominent example.
Buffer Overflow Context
Buffer overflow vulnerabilities are particularly prevalent in C/C++ languages due to their lack of inherent safety checks regarding memory bounds.
Historical context: The first documented exploit was the Morris Worm in 1988, marking a significant moment in cybersecurity awareness.
Current relevance: Buffer overflow attacks continue to pose a threat due to persistent coding practices and insufficient compiler protections within both legacy and new systems.
Recommendations include avoiding unsafe languages and updating compilers and hardware architectures to address such vulnerabilities.
Web Server Example
Threat Model
The model posits that any user capable of sending messages to a server can potentially exploit vulnerabilities directly.
Attacker's Goals:
Crash server: Aiming to use the overflow to cause denial of service, stopping legitimate access.
Inject code: Altering program behavior through unauthorized code execution.
Leak data: Extracting sensitive information improperly.
Modify data: Tampering with the data integrity of the server’s database or files.
Important Notes
Primarily focus on Intel's 32-bit architecture when working with Linux, characterized by:
Little Endian format, which indicates how byte values are stored.
4-byte addresses capable of addressing up to 4GB of virtual memory.
Use the
-m32flag for generating 32-bit binaries when compiling on 64-bit architectures, ensuring compatibility with certain systems during execution.
Stack Mechanism
Memory Management in Processes
Each process is allocated its own stack, alongside heap and code/data segments, organizing memory efficiently for operations.
The stack is managed strictly by the OS/compiler, preventing direct access by applications, to ensure stability and security.
Key registers associated with stack management include:
$esp: Points to the top of the stack, marking the most recent point in use.$ebp: Represents the base pointer, delineating the current stack frame.$eip: Contains the current instruction address indicating which code is being executed next.
Buffer Overflow Example
Function declaration:
void vul(char *str) {
char buffer[16];
strcpy(buffer, str);
}
The implementation of the vulnerable buffer demonstrated here is susceptible to overflowing; if the input
strexceeds 16 characters, it compromises adjacent memory, leading to potential control over program flow or even crashing the application, showcasing the dire consequences of insufficient validation.
Crafting Buffer Overflow
Memory Manipulation
Techniques for changing the return address through crafted inputs emphasize the necessity of understanding memory layout and address offset calculations.
Knowledge regarding immediate addresses and their offsets is critical when developing effective exploits for buffer overflows, as the correct manipulation of these leads to successful control over program execution flow.
What are the attacks?
Return oriented programming
Heap Overflow
String overflow
Integer overflow