10.1 Stack Overflows
Buffer Overflow Basics
- Definition
- A condition at an interface under which more input can be placed into a buffer or data holding area than the capacity allocated, overwriting other information 데이터를 저장하는 버퍼 또는 데이터 보관 영역에 할당된 용량보다 더 많은 입력이 들어갈 수 있는 상태
- Attackers exploit such a condition to crash a system or to insert specially crafted code that allows them to gain control of the system 이러한 상태는 공격자들이 활용하여 시스템을 충돌시키거나 특별히 제작된 코드를 삽입하여 시스템의 제어권을 획득
- Programming error when a process attempts to store data beyond the limits of a fixed-sized buffer 버퍼 오버플로우는 프로그램이 고정된 크기의 버퍼를 넘어서 데이터를 저장하려고 할 때 발생하는 프로그래밍 오류임
- Overwrites adjacent memory locations 이로 인해 인접한 메모리 위치가 덮여쓰여짐
- Locations could hold other program variables, or program control flow data 이 위치에는 다른 프로그램 변수, 매개변수 또는 프로그램 제어 흐름 데이터가 있을 수 있음
- Buffer could be located on the stack, in the heap, or in the data section of the process 버퍼는 스택, 힙, 또는 프로세스의 데이터 섹션에 위치할 수 있음
- 버퍼 오버플로우 결과
- Corruption of program data
- Unexpected transfer of control
- Memory access violations
- Execution of code chosen by attacker
Basic Buffer Overflow Example
buffer1.c 플로우: 사용자로부터 str2값을 입력받아 str1 값과 비교 후 같은지 반환
- To exploit a buffer overflow an attacker needs
- To indentify a buffer overflow vulnerability in programs that can be triggered using externally sourced data under the attacker’s control 공격자의 제어 아래에 있는 외부 소스 데이터 사용을 유발할 수 있는 프로그램에서 버퍼 오버플로우 취약점을 식별해야 함
- To understand how that buffer is stored in memory and determine potential for corruption 프로세스 메모리에 해당 버퍼가 어떻게 저장되는지, 인접한 메모리 위치를 손상시킬 수 있는 잠재력을 이해해야 함
Stack buffer overflow
스택 오버플로우는 타겟 버퍼가 함수 스택 프레임 내의 지역 변수로 스택 상에 위치할 때 발생
- Occur when the targeted buffer is located on the stack
- Usually as a local variable in a function’s stack frame
- Also referred to as stack smashing 스택 스매싱 공격으로도 알려져 있음
- Used by Morris Worm 스택 오버플로우 공격은 모리스웜에서 처음 발견된 이후로 활용되어 왔음
- Exploits included an unchecked buffer overflow
- Stack frame에 저장되는 데이터
- When one function calls another it needs somewhere to save the return address
- Also needs locations to save the parameters to be passed into the called function and to possibly save register values
(중요)The process of P’s calling Q

1) P → Pushes the parameters for the called function onto the stack
2) P → Executes the call instruction to call the target function, which pushes the return address onto the stack
3) Q → Pushes the current frame pointer value (which points to the calling routine’s frame) on to the stack
4) Q → Sets the frame pointer to be current stack pointer value, which now identifies the new stack frame location for the called function
5) Q → Allocates space for local variables by moving the stack pointer down to leave sufficient room for them 로컬변수에 충분한 공간을 남기기 위해 스택포인터를 아래로 이동시켜 공간을 확장
6) Q → Run the body of the called function
- Example Stack Frame with Functions P and Q

7) (함수 종료) Q → As it exists it first sets the stack pointer back to the value of the frame pointer (effectively discarding the space used by local variables)
8) Q → Pops the old frame pointer value (restoring the link to the calling routine’s stack frame) 이전 프레임 포인터의 값을 팝하여 호출루틴의 스텍 프레임에 대한 연결을 복원
9) Q → Executes the return instruction which pops the saved address off the stack and returns control to the calling function 반환 명령어를 실행하여 저장된 주소를 스택에서 팝하고 제어를 호출 함수로 반환
10) P → Pops the parameter for the called function off the stack 호출된 함수에 대한 매개변수를 스택에서 팝
11) P → Continues execution with the instruction following the function call 함수 호출 다음 명령어로 실행을 계속함

Stack Overflow Example
- Program Loading into Process Memory 프로그램이 프로세스 메모리에 로드될 때 무슨 일이 일어나는가?
- When a program is run, the operating system
- It typically creates a new process for it. The process is given its own virtual address space
- This consists of the contents of the executable program file
- Certain amount of memory for stack region and the heap regions are allocated for the process of the program
- Stack is increased/decreased depending on the depth of the function call
- Heap is increased/decreased depending on how many dynamic object is created

- Basic stack overflow C code
- hello()
- begins at 0x08048394
- get() → user can type as many characters as the user input so it can cause buffer overflow vulnerability



- 첫번째 case
- 두번째 case
- long string → this input violates content in a stack
- so it cause segmentation fault
- 3번째 case
- if this is excuted, hello function is executed again

- 왜? → Stack values를 살펴보자
- return addr의 값을 hello() function의 startding address로 덮어씌워 자기자신을 다시 호출하게 함

- Another Stack Overflow Example
- getinp 함수
- fgets: it defines maximum size of input → doesn’t incur buffer overflow attack
- display 함수
- sprintf: if the size of val is huge, the things to be copied to temp will be beyond the capacity of the tmp

- Buffer overflow에 취약한 unsafe C standard library
Shellcode
- 개념
- Code supplied by attacker
- Often saved in buffer being overflowed 종종 오버플로우되고 있는 버퍼에 저장됨
- Traditionally transferred control to a user command-line interpreter(shell)
- Attackers generate shellcode using machine code
- Machine code
- Specific to processor and operating system 특정 프로세서와 운영체제에 특화되어 있음
- Traditionally needed good assembly language skills to create 어셈블리 언어를 만들기 위한 이해 스킬이 필요
- More recently a number of sites and tools have been developed that automate this process 해당 과정을 자동화 하는 다양한 사이트, 도구들이 개발됨
- Example UNIX shellcode → 피피티 21페이지 보기
Stack Overflow Variants
- Target program can be:
- A trusted system utility
- Network service daemon
- Commonly used library code
- Shellcode functions
- Launch a remote shell when connected to
- Create a reverse shell that connects back to the hacker
- Use local exploits that establish a shell
- Flush firewall rules that currently block other attacks
- Break out of a chroot(restricted execution) environment, giving full access to the system
Buffer Overflow Defenses
Two broad defense approaches
- Compile-time
- Aim to harden programs to resist attacks in new programs 새 프로그램에서 공격에 저항하는 프로그램을 강화하는 것을 목표로함
- Run-time
- Aim to detect and abort attacks in existing programs 기존 프로그램에서 공격을 탐지하고, 중단하는 것을 목표로 함
Compile-Time Defenses
- Programming Language 현대 고급 프로그래밍 언어를 사용하여 프로그램을 작성하는 것
- Use a modern high-level language
- Not vulnerable to buffer overflow attacks
- Compiler enforces range checks and permissible operations on variables 컴파일러가 범위 검사, 허용되는 연산을 강제함
- Disadvantages
- Additional code must be executed at run time to impose checks
- Flexibility and safety comes at a cost in resource use
- Distance from the underlying machine language and architecture means that access to some instructions and hardware resources is lost 기계언어와 아키텍처로부터의 거리는 일부명령과 하드웨어 자원에 대한 접근을 상실하게 만듦
- Safe Coding Techniques
- C designers placed much more emphasis on space efficiency and performance considerations than on type safety → 그래서 c가 더 빠르지만, 버퍼 오버플로우 유발
- Programmers need to inspect the code and rewrite any unsafe coding
- 첫번째 케이스 버퍼오버플로우 발생할 수 있는 이유
- 길이 검증 부재:
to
배열의 크기를 확인하지 않고 from
배열에서 len
길이만큼 바이트를 복사합니다. 만약 pos + len
이 to
배열의 크기를 초과한다면, 이는 to
배열의 할당된 메모리 영역을 벗어나는 쓰기 작업을 시도하게 되며, 이는 버퍼 오버플로우로 이어짐
- 해결방법
to
배열의 크기를 파라미터로 전달받아, 함수 내에서 pos + len
이 to
배열의 크기를 초과하지 않는지 확인
- 두번째 케이스 문제점
fread
를 통해 읽은 길이(len
)에 대한 검증이 없습니다. len
이 to
배열의 크기보다 크다면, fread(to, 1, len, fil)
호출 시 to
배열의 경계를 넘어서 데이터를 쓰려고 시도할 것입니다. 이는 버퍼 오버플로우를 유발
- 해결방법
to
배열의 크기를 파라미터로 전달받아, 읽으려는 데이터의 길이가 이 배열의 크기를 초과하지 않는지 검증

- Language Extension/Safe Libraries
- Handling dynamically allocated memory is more problematic because the size information is not available at compile time
- Requires an extenstion and the use of library routines
- Programs and libraires need to be recompiled
- Likely to have problems with third-party applications
- Concerns with C is use of unsafe standard library routines
- One approach has been to replace these with safer variants
- Stack protection
- Add function entry and exit code to check stack for signs of corruption
- Use random canary(random value)
- Value needs to be unpredictable
- Should be different on different systems

- Stackshield and Return Address Defender(RAD)
- GCC extensions that include additional function entry and exit code 추가적인 함수 진입 및 종료 코드를 포함하는 GCC 확장
- Function entry writes a copy of the return address to a safe region of memory 함수 진입 시 반환 주소의 복사본을 안전한 별도의 메모리 영역에 씀.
- Funtion exit code checks the return address in the stack frame against the saved copy 함수 종료 시 종료 코드는 스택 프레임의 반환 주소와 그 복사본을 비교
- If change is found, aborts the program 변화가 발생했다면, 공격된 것임. 이때 프로그램을 즉시 중단 시킴
Run-Time Defenses
- Executable Address Space Protection 실행 가능한 주소 공간 보호
- Use virtual memory support to make some regions of memory non-executable 가상 메모리 지원을 이용하여 일부 메모리 영역을 실행 불가능하게 만듦
- Requires support from memory management unit(MMU) 이는 메모리 관리 유닛(MMU)의 지원이 필요
- Long existed on SPARC/Solaris systems
- Recent on x86 Linux/Unix/Windows systems SPARC/Solaris 시스템에서는 오래전부터 존재했으며, 최근에는 x86 Linux/Unix/Windows 시스템에서도 지원됨
- Issues
- Support for executable stack code 실행 가능한 스택 코드 지원
- In just-in-time compilers Just-in-time 컴파일러에서 필요
- Nested functions in C C언어의 중첩 함수에서 필요
- Special provisions are needed
- Address Space Randomization 주소 공간 무작위화
- Manipulate location of key data structures 주요 데이터 구조의 위치를 조작하여 공격을 어렵게 만듦
- Stack, heap, global data
- Using random shift for each process 각 프로세스마다 무작위 변위를 사용
- Large address range on modern systems means wasting some has negligible impact 현대 시스템의 넓은 주소 범위 덕분에 일부 메모리를 낭비하는 것이 큰 영향이 없음
- Randomize location of heap buffers
- Random location of standard library functions 표준 라이브러리 함수의 위치를 무작위화하여 보안성을 높임

- Guard pages 가드페이지
- Place guard between critical regions of memory 중요한 메모리 영역 사이에 가드 페이지를 배치
- Flagged in MMU as illegal addresses MMU에서 불법 주소로 표시
- Any attempted access aborts access 접근 시도 시 접근이 중단됨
- Further extension places guard pages between stack frames and heap buffers 스택 프레임과 힙 버퍼 사이에 가드 페이지를 배치하여 확장된 가드 페이지 사용
- Cost in execution time to support the large number of page mappings necessary 많은 페이지 매핑을 지원해야 하므로 실행 시간 비용이 발생

Replacement Stack Frame
- Variant that overwrites buffer and saved frame pointer address
- Saved frame pointer value is changed to refer to a dummy stack frame
- Current function returns to the replacement dummy frame
- Control is transferred to the shellcode in the overwritten buffer
- Off-by-one attacks
- Coding error that allows one more byte to be copied than there is space available
- Happens due to misuse of operators ≤, ≥ instead of <, >
- Defenses
- Any stack protection mechanisms to detect modifications to the stack frame or return address by function exit code
- Use non-executable stacks 실행 불가능한 스택 사용
- Randomization of the stack in memory and of system libraries 메모리 내 스택 및 시스템 라이브러리의 무작위화
Return to System call
- Replaces return address with standard library function 공격자가 반환 주소를 표준 라이브러리 함수로 교체
- Responses to non-executable stack defenses 비실행 스택 방어에 대응
- Attacker constructs suitable parameters on stack above return address 공격자가 반환 주소 위에 적절한 매개변수를 스택에 구성
- Function returns and library function executes 함수가 반환되면 라이브러리 함수가 실행됨
- Attacker may need exact buffer address 공격자는 정확한 버퍼 주소를 알아야 할 수도 있음
- Can even chain two library calls 두 개의 라이브러리 호출을 연결할 수도 있음
- Defenses
- Any stack protection mechanisms to detect modifications to the stack frame or return address 스택 프레임 또는 반환 주소의 변경을 감지하는 스택 보호 메커니즘 사용
- Randomization of the stack in memory and of system libraries 스택과 시스템 라이브러리의 메모리 레이아웃을 무작위화
Heap Overflow
- Attack buffer located in heap
- Typically located above program code
- Memory is requested by programs to use in dynamic data structures (such as linked lists of records)
- No return address
- Hence no easy transfer of control
- May have function pointers can exploit
- Or manipulate management data structures
- Defenses
- Making the heap non-executable
- Randomizing the allocation of memory on the heap