본문 바로가기
Pwnable

Buffer Overflow

by ms-eo 2025. 11. 19.

Stack Buffer Overflow

Stack 영역

  • 함수의 호출에 필요한 지역 변수와 매개 변수 등이 저장되는 영역
  • 데이터의 교환이 Top에서만 이루어지며, 높은 주소에서 낮은 주소의 방향으로 메모리 영역 차지 (선입선출)

Stack Frame

  • 스택 영역에 저장되는 함수의 호출 정보로 함수마다 스택 영역을 구분하기 위해 생성되는 공간
  • RSP(Stack Pointer)가 아닌 RBP(Base Pointer)로 로컬 변수, 파라미터, 복귀 주소에 접근

Stack Buffer Overflow

  • 스택 할당 개체의 범위를 벗어난 버퍼 접근으로 발생하는 오류
  • 할당된 입력 크기보다 큰 입력 값으로 RET의 주소 영역을 침범해 악성코드로 덮는 공격 가능

Stack Buffer Overflow 취약 코드 예시

※ 취약 함수

  • scanf(), sscanf(), gets(), strcat(), strcpy(), sprintf() 등

※ 권장 함수

  • fscanf(), vfscanf(), fgets(), strncat(), strncpy() 등

OOB (Out Of Bounds)

  • 버퍼의 정상 범위 외의 인덱스에 잘못 접근 시에 발생하는 취약점
  • 사용자가 입력한 index 값에 대한 입력 값 검증 과정이 누락된 경우 주로 발생

메모리 보호 기법

  • 컴퓨터 메모리의 사용을 제어하는 방법
  • 자신에게 할당되지 않은 영역의 메모리의 접근으로 인한 영향을 사전에 방지

리눅스 메모리 보호 기법의 종류

메모리 보호 기법
설명
우회 공격 기법
ASLR
프로그램 실행마다 Stack, Heap 등이 메모리 적재 시, 주소 랜덤화
NOP Sled 등
RELRO
바이너리의 Data Segment에 쓰기 권한을 제거해 읽기 권한만 부여
GOT Overwrite, Hook Overwrite 등
SSP
Stack 정보들이 덮어 씌워져 의도치 않은 프로그램의 실행을 방지
stackchk_fail(), Array 활용 등
NX
메모리 영역에 실행 권한을 없애 Shellcode의 삽입과 실행을 방지
RTL, ROP 등
PIE
바이너리가 실행될 때마다 바이너리의 주소를 랜덤화
GOT Overwrite, Code Base 등

checksec

  • 바이너리에 설정된 보호 기법을 확인할 수 있는 명령어로 pwntools를 설치하면 사용 가능
  • 바이너리를 열어보기 전에 어떤 보호 기법이 있는지 확인하기 위해 주로 사용 (그걸 어떻게 우회할지 생각)

ASLR

ASLR 보호 기법

ASLR (Address Space Layout Randomization)

  • 공격자가 메모리 상의 주소를 추측하는 것을 어렵게 하기 위한 목적의 보호 기법
  • 프로그램 실행마다 Stack이나 Heap, 공유 라이브러리 등이 메모리를 적재할 때 주소 랜덤화 (데이터의 주소가 계속 바뀜. 단, main함수의 주소는 바뀌지 않음)

ASLR 설정 명령어

ASLR OFF

ASLR ON

ASLR 우회 공격 기법

라이브러리 주소가 계속 바뀌기 때문에 정적 주소를 이용한 공격은 사용할 수 없음

그러나, 바이너리 코드 영역의 주소는 변하지 않기 때문에 이를 이용하면 exploit 가능

NOP (No OPeration)

  • 어셈블리 명령어 중 하나. 1 byte 크기를 가짐
  • 프로그램의 실행에 아무런 영향을 주지 않는 명령어로 주로 주소 정렬에 쓰임
  • NOP 명령어를 만났을 시, 이 명령은 수행하지 않고 무시한 채 다음으로 넘어감
  • Linux에서 기계어로 표기하면 \x90

NOP Sled

  • NOP (명령어) + Sled (썰매)
  • ASLR로 인해 주소 값이 계속 변경되는 환경을 우회하기 위해 주로 사용
  • 의미있는 명령이 나올 떄까지 NOP 명령어를 사용해 프로그램의 실행 흐름을 흘려 보내는 공격

NOP Sled 공격 조건

  1. 메모리 상의 정확한 주소 위치를 모를 경우
  2. 버퍼의 크기가 충분히 클 경우

NOP Sled 공격 기법 실습

  1. 바이너리 파일 정보 수집

2-1. 바이너리 파일 실행

2-2. 바이너리 파일 실행 환경 확인 (ASLR 설정 여부)

3. 정적 분석

    1. 버퍼 사이즈 확인 가능
    2. 버퍼의 중간 위치 주소
    3. 입력 받는 부분

4. 동적 분석 (pwn디버거 사용)

-q : 버전정보 출력 안함

nop : 바이너리 파일명

프로그램 실행

메인함수 디스어셈블

read 함수 호출 부분

read 함수 부분 중단점 설정 후 실행 → r 로 실행된 중단점 부분으로 이동

5. Payload 작성

6. Exploit


RELRO

RELRO 보호 기법

RELRO (RELocation Read-Only)

  • 바이너리의 Data Segment에 쓰기 권한을 제거해 읽기 권한만 부여하는 것이 목적인 보호 기법
  • RELRO가 적용되면 Read Only 권한을 가진 RELRO 영역이 생성됨
  • 쓰기 권한을 제거해 읽기 권한만 부여하고 싶은 영역의 범위에 따라 설정 종류가 다름

RELRO 설정 명령어

RELRO의 종류

  1. No RELRO : ELF 기본 헤더, 코드 영역을 제외한 거의 모든 영역에 읽기와 쓰기 권한 존재
  2. Partial RELRO : .dynamic 영역에 쓰기 권한 존재하지 않음, GOT 영역 변조 가능
  3. Full RELRO : .bss 영역을 제외한 모든 영역에 쓰기 권한 존재하지 않음. GOT 영역 변조 불가능

※ GOT (Global Offset Table) : 함수의 실제적인 절대 주소가 기록되어 있는 테이블

Lazy Binding

  • Dynamic Link로 컴파일된 바이너리 파일이 함수를 호출할 때, 공유 라이브러리 함수의 주소가 기록되어 있는 GOT를 사용하는 방식

PLT (Procedure Linkage Table)

  • 동적 링크 파일이 타 라이브러리의 프로시저나 함수의 주소를 참조하기 위해 사용하는 테이블
  • 함수가 최초로 호출되었을 때, dl_resolve() 함수를 사용해 함수의 주소를 알아오는 과정

GOT(Global Offset Table)

  • 함수의 실제적인 절대 주소가 기록되어 있는 테이블
  • 최초 호출 이후에는 PLT에서 바로 GOT가 위치한 곳으로 점프

Lazy Binding 과정

함수 최초 호출 시

함수 최초 호출 이후

GOT Overwrite

  • PLT에서 GOT를 참조하여 RIP를 이동할 때, GOT의 값을 검증하지 않는 취약점을 이용한 공격
  • 저장된 GOT 주소를 공격자가 변조한다면, 변조된 이후의 호출부터는 공격자의 코드가 실행됨

GOT Overwrite 실습

Hooking

  • 코드 실행이나 이벤트를 중간에 가로채서 프로그램의 기능/동작을 변경하거나 확장하는 기술
  • 프로그램의 디버깅이나 모니터링에도 사용하는 등 다양한 목적으로 활용
  • 특정 함수의 코드를 낚아채어 원하는 악의적 코드(hook)를 실행시키는 공격으로도 사용

Hook Overwrite

  • 동적 할당/해제 함수의 hook 변수를 덮어씌워 함수가 호출될 때 공격자의 코드를 실행하는 공격
  • .bss 영역에 존재하는 malloc_hook, _realloc*_c*hook, _free_hook 변수를 덮어씌우는 방식
  • Full RELRO가 적용되어도 bss 영역은 쓰기가 가능하므로 이를 우회하기 위한 방법 중 하나

SSP

SSP 보호 기법

SSP (Stack Smashing Protector)

  • Stack의 정보들이 덮어 씌워져 의도치 않은 프로그램의 실행을 방지하기 위한 목적의 보호 기법
  • SSP 옵션이 커지면 Canary라는 임의의 값을 삽입해 변조 여부를 확인
  • Canary 값의 손상이 탐지되었을 경우 __stack_chk_fail 함수 호출

SSP 설정 명령어

Canary

  • 위혐을 탐지하는 새 라는 별명이 있는 카나리아 에서 이름이 유래됨
  • 컴파일 단계에서 Stack Buffer와 SFP 사이에 삽입되는 에측하기 어려운 패턴의 랜덤 값

Canary 동작 과정

  1. 프로세스 시작 시, TLS에 전역 변수로 저장
  2. 프롤로그 뒤에서 32bit는 DWORD PTR gs:0x14, 64bit는 QWORD PTR fs:0x28을 통해 값 읽음
  3. 읽어온 fs:0x28의 데이터를 rax에 저장하고, rbp-0x8로 옮겨 저장
  4. 에필로그 전에 rbp-0x8에 저장했던 값을 다시 rcx에 저장
  5. 호출된 함수가 종료되기 전에 rcx를 XOR 연산으로 Canary 값의 일치 여부를 확인

SSP 우회 공격 기법

Array 활용

  • 배열 버퍼에 BOF를 발생시켜 Canary 값을 유출시키는 공격 기법
  • 유출시킨 Canary 값을 받아와서 복원한 뒤, 공격 payload에 연결해 SSP를 우회

__stack_chk_fail() Overwrite

  • Canary가 변조되었을 때 호출되는 __stack_chk_fail() 함수를 덮어씌우는 공격 기법
  • GOT Overwrite 개념 기반

Canary Logic 취약점

  • 별도의 Canary Logic이 존재하는 함수에서 취약점을 찾아 공격하는 기법
  • 출제자가 사용자 함수로 Canary Logic을 구현해 프로그램에 삽입한 경우에 해당

Array 활용 공격 기법 실습

  1. 바이너리 파일 정보 수집

2. 바이너리 파일 실행

3. 정적 분석

4. 동적 분석

5. Payload 작성

6. Exploit


NX

NX 보호 기법

NX (No eXecute)

  • 메모리 영역에 실행 권한을 없애 Shellcode를 실행하지 못하도록 하는 것이 목적인 보호 기법
  • 읽기와 쓰기 권한만 부여해 해커가 작성한 어셈블리 코드를 실행시키는 공격을 방어
  • NX가 적용된 바이너리 파일은 코드 영역 외에 실행 권한이 존재하지 않음

NX 설정 명령어

Gadget

  • 해당 프로그램이 사용하는 메모리에 이미 존재하는 명령어 조작
  • 일반적으로 RET로 끝나는 연속된 명령어이기 때문에 Return Gadget이라고도 함

One-Gadget

  • 함수에 인자를 전달하기 힘들 때 한 번에 Shell을 획득할 수 있도록 만들어진 Gadget
  • /bin/sh 쉘이 라이브러리 파일 내에서 실행되고, 라이브러리 버전마다 다르게 존재함

One-Gadget 설치 명령어

One-Gadget 실습

  • gadget마다 제약 조건(constraints)이 다르므로 offset을 바꿔가며 적용해보는 것을 권장

One-Gadget 수동 탐색 실습

  • 몇몇 라이브러리에 따라 one-gadget 명령어가 적용되지 않는 경우가 존재
  • 이 때, 수동으로 one-gadget의 offset을 찾는 방법을 활용

NX 우회 공격 기법

RTL (Return To Libc/Library)

  • Dynamic Link 파일에 존재하는 공유 라이브러리의 함수 주소를 RET에 덮어씌우는 공격 기법
  • Stack이나 Heap 영역이 아닌 Library 영역에 있는 함수들로 리턴하므로 NX 우회 가능
  • 바이너리에 존재하지 않는 함수도 공유 라이브러리에서 찾아 사용 가능 (주로 system, execve)

ROP (Return Oriented Programming)

  • 대표적인 코드 재사용 공격 기법
  • BOF를 발생시켜 리턴 주소 이후를 덮을 수 있을 때 사용하는 기법
  • 바이너리 내에서 공격할 Return Gadget을 찾아 복잡한 실행 흐름의 공격 코드를 구성
  • ROP를 연쇄적으로 사용하는 공격 기법인 ROP Chain은 대부분 난이도 높은 문제들에 사용

32bit RTL/ROP

  • 32bit는 함수 호출 시 인자를 스택으로 전달하는 방식
  • RTL/ROP 시, 먼저 함수 호출 후 pop 명령어를 통해 인자 전달

64bit RTL/ROP

  • 64bit는 함수 호출 시 인자를 레지스터를 통해 전달하는 방식
  • 인자 전달 순서는 rdi, rsi, rdx, rcx, r8, r9로, 그 이상은 스택을 통해 전달
  • RTL/ROP 시, pop 명령어를 통해 레지스터에 인자를 먼저 전달한 후 함수 호출

ROPGadget

  • 공격자의 의도된 특정 행동들을 수행하기 때문에 포너블 기법 중 ROP에서 가장 많이 사용
  • ROPgadget을 이용하여 바이너리 내부에 존재하는 호출 함수 및 인자를 조작
  • 대표적으로 pop rdi; ret와 pop rsi; ret

※ RTC (Return To Csu)

  • __libc_csu_init 함수가 존재할 경우 이를 사용하는 공격 기법

ROPGadget 설치 명령어

POP 명령어

  • 스택의 최상위인 RSP가 가리키는 데이터를 제거하는 명령어
  • POP [operand1] : 현재 RSP가 가리키는 데이터를 [operand1]에 저장 후, RSP는 8byte 증가

PIE

PIE 보호 기법

PIE (Position Independent Executable)

  • 바이너리가 실행될 때마다 바이너리의 주소를 랜덤화하는 것이 목적인 보호 기법
  • 바이너리의 메모리 주소를 알아야 가능한 공격들을 방어
  • ASLR을 코드 영역에 적용하는 것과 같은 의미
  • 모든 PIE의 코드는 PIC(Position Independent Code)

PIE 설정 명령어

PIE 적용 파일 특징

  • 리눅스 ELF는 실행파일과 공유 오브젝트로 나뉨
  • file 명령어로 파일 정보 출력 시, ELF 64bit LSB shared object 문구 확인

Relative Addressing (상대 주소)

  • PIE 적용 시에 사용하며, RIP를 기준으로 Offset을 통해 다른 주소에 접근
  • 공격자가 프로그램 코드의 Offset을 활용해 상대 주소 값을 알아낸다면 ROP 사용이 가능해짐

Code Base (PIE Base)

  • PIE 적용 시에 함수의 모든 심볼 주소가 상대 주소라는 특징을 활용하는 방법
  • 코드 영역의 Base 주소와 Base 주소부터 사용할 함수의 심볼까지의 거리인 Offset 필요

 

'Pwnable' 카테고리의 다른 글

Integer Overflow  (0) 2025.11.19
Format String Bug  (0) 2025.11.19
Pwnable Tools  (0) 2025.11.19
Pwnable 방법론  (0) 2025.11.19
리눅스 & 어셈블리어  (0) 2025.11.19