1. Uninitialized Access (초기화되지 않은 접근)
1.1 정의 및 원리
•
C/C++ 등 low-level 언어에서 변수, 포인터, 배열, 구조체 등이 선언만 되고 값이 대입되지 않은 상태(“uninitialized”)에서 접근할 때 발생.
•
컴파일러는 자동으로 메모리를 0으로 초기화하지 않는다(성능 이유).
→ 실제 값은 이전에 해당 메모리 영역에 존재하던 임의 데이터(“garbage value”)가 남아 있음.
•
공격자는 이 “쓰레기 값”의 내용을 예측하거나 조작할 수 있음.
1.2 공격 벡터
•
읽기(read):
◦
개인정보, 패스워드, 암호키 등 민감 데이터가 남아있는 메모리 영역 유출.
•
쓰기(write):
◦
예를 들어, 초기화되지 않은 포인터 사용 시, 해당 포인터가 가리키는 주소에 임의 데이터 덮어쓰기 가능.
◦
Use-after-free 취약점으로 연결되기 쉬움(해제된 메모리 영역의 내용이 재활용).
1.3 실제 사례
•
CVE-2015-2411:
Internet Explorer uninitialized memory disclosure.
공격자는 uninitialized memory에 남아있는 정보를 추출 가능.
•
CVE-2009-1721 (libpng):
부적절하게 초기화된 힙 메모리 노출, crafted 이미지 파일로 익스플로잇.
•
이미지/폰트 파서:
공격자가 설계한 파일(이미지, 폰트, etc.)을 읽게 하여 uninitialized pointer를 통한 크래시, 임의코드 실행 유발.
1.4 예시 코드
c
CopyEdit
typedef struct {
int isAdmin;
char password[32];
} User;
User u; // 선언만 하고 초기화 X
printf("%d %s", u.isAdmin, u.password);
// 이전 프로세스 또는 사용자의 데이터가 노출될 수 있음
C
복사
1.5 방어/예방
•
모든 변수, 포인터 선언 시 명시적 초기화.
•
C/C++에서는 memset, 생성자(constructor) 활용.
•
보안/정적분석 도구로 uninitialized 변수 탐지.
2. Return Oriented Programming (ROP) & Code Reuse Attack
2.1 기존 공격 우회 배경
•
Buffer Overflow/Stack-based Code Injection:
◦
전통적 공격은 악성 shellcode(머신코드)를 스택에 삽입, 함수 리턴주소 덮어써 실행.
◦
현대 시스템은 스택/힙에 NX/DEP(Non-Executable/데이터 영역 실행 금지) 적용, 단순 삽입 공격 차단.
2.2 Code Reuse: ret2libc 공격
•
원리:
◦
이미 존재하는 라이브러리 함수(system, execve 등)의 주소로 리턴 포인터 덮어써 코드 실행.
◦
악성 페이로드:
1.
오버플로우로 리턴주소 → system() 함수 주소
2.
스택에 파라미터(/bin/sh 등), 추가적으로 exit() 등 후속함수 주소 배치
•
메모리 구조 예시:
python-repl
CopyEdit
... | system() | return address | "/bin/sh" string | ...
Plain Text
복사
•
효과:
◦
스택 자체에 코드 삽입 없이 OS 명령 실행.
2.3 ROP(Return Oriented Programming)
•
원리:
◦
바이너리/라이브러리 내에 흩어져 있는 작은 명령어 조각(“gadget”)을 ret(0xC3)로 연결해 원하는 로직 구현.
◦
공격자는 스택을 조작해 gadget chain이 차례로 실행되도록 만듦.
◦
각 gadget은 일반적으로 pop, mov, add, syscall, ret 등의 단일/간단한 연산.
•
공격 단계:
1.
바이너리 또는 라이브러리 내 ret 명령어로 끝나는 gadget 수집(ROPgadget, gdb-peda 등 활용)
2.
원하는 기능(예: 레지스터 조작, 메모리 쓰기, 시스템 콜 실행)을 gadget 조합으로 설계
3.
Buffer overflow로 조작된 스택프레임 생성
4.
함수 리턴시 ret 명령어에 따라 gadget chain 실행
•
ROP의 위력:
◦
Turing-complete(이론적으로 임의 코드 실행 가능)
◦
shellcode, 스택 실행권한 불필요
◦
실제로 exploit 난이도는 높으나, 성공 시 강력한 권한 획득 가능
2.4 Gadget 예시 및 공격 예시
•
Gadget:
◦
pop rdi; ret (x86_64에서 인자 전달 레지스터 설정)
◦
mov [rdi], rax; ret (메모리 쓰기)
◦
syscall; ret (시스템콜 호출)
•
공격 페이로드 예시:
1.
pop rdi; ret → "/bin/sh" 주소
2.
pop rsi; ret → NULL
3.
pop rax; ret → 59 (execve syscall)
4.
syscall; ret
3. ROP Gadget 자동탐색 및 우회 기술
•
도구:
◦
ROPgadget, Ropper, gdb peda, pwntools 등
•
Gadget source:
◦
바이너리, libc 등 표준 라이브러리
◦
함수의 중간에서 시작하거나, 정상 코드가 아니어도 유효한 명령어 시퀀스가 될 수 있음
4. 방어 기술
4.1 ASLR (Address Space Layout Randomization)
•
동작 원리:
◦
프로그램/라이브러리/스택/힙의 시작주소 무작위화
◦
공격자가 정확한 gadget·함수 위치를 예측·활용하기 어렵게 만듦
•
한계 및 우회:
◦
정보 유출 취약점(leak)이 있으면 ASLR 무력화 가능
◦
32bit 시스템은 엔트로피(난수화 정도)가 낮음
◦
PIC 미지원 모듈, 정적 링크 등으로 무작위화가 적용 안 되는 경우 gadget 고정
4.2 Stack Canaries, NX/DEP
•
Stack Canaries:
◦
함수 리턴 직전 스택에 무작위값(canary) 확인, 손상 시 프로그램 종료
•
NX/DEP:
◦
스택, 힙 등 데이터를 코드로 실행 금지
4.3 Fine-grained Randomization & CFI
•
Fine-grained Randomization:
◦
함수, 블록, instruction-level 단위로 위치를 무작위화
•
Control Flow Integrity(CFI):
◦
정해진 제어흐름 이외의 실행을 차단
◦
간접 분기 제한, 불법적인 ret chain 실행 불가
4.4 Attack Surface Reduction
•
불필요한 코드, 라이브러리, 함수, 시스템콜 제거
◦
Gadget pool 자체를 줄임(공격 난이도 증가)
5. 실전 공격 시나리오 예
•
공격자: 원격 공격 대상 C 프로그램에 buffer overflow 취약점 존재 확인
•
도구로 libc, 바이너리 내 gadget 수집 → ROP chain 설계
•
ASLR, NX 우회법(메모리 leak, PIE/PIC 분석, 여러 번 시도)
•
스택포인터·리턴주소 덮어써 payload 투입 → shell 획득 또는 임의명령 실행
6. 용어 정리
•
Uninitialized Access: 초기화 안된 변수·포인터 사용, 메모리 leak, 임의 코드 실행
•
ret2libc: 기존 라이브러리 함수 주소·파라미터 조작 공격
•
ROP: 코드 조각(gadget) 체인을 통한 제어 흐름 장악, 임의 명령 실행
•
Gadget: ret 명령어로 끝나는 짧은 기계어 명령 조각
•
ASLR: 메모리 구조 무작위화로 gadget·함수 위치 예측 방지
•
CFI: 비허용적 제어흐름 변경 차단