-
dreamhack stage 2 - Linux Memory Layout보안/SYSTEM HACKING 2024. 3. 15. 09:42
STAGE 2
Linux Memory Layout
Background: Linux Memory Layout
0. 서론
컴퓨터는 크게 CPU와 메모리로 구성되어 있다.
- CPU
- 실행할 명령어와 명령어 처리에 필요한 데이터를 메모리에서 읽고 Instruction Set Architecture (ISA)에
따라 이를 처리하고 연산의 결과를 다시 메모리에 적재한다.
- CPU의 동작과 메모리 사이에는 밀접한 연관이 있다
: 공격자가 메모리를 악의적으로 조작 가능하다면 이는 메모리가 오염됐다고 표현한다
--> 이를 유발하는 취약점 == 메모리 오염 (Memory Corruption) 취약점
많은 공격기법이 메모리 오염을 기반으로 한다.
- 커리큘럼에서 소개할 내용: Stack Buffer Overflow, Off by One, Format String Bug, Double Free Bug, Use After Free, 공격 활용
- 리눅스 메모리 구조에 대해 알아볼 예정이다.
1. 리눅스 프로세스의 메모리 구조
리눅스에서는 프로세스의 메모리를 크게 5가지의 세그먼트(Segment)로 구분한다.
- 세그먼트(Segment)
: 적재되는 데이터의 용도별로 메모리의 구획을 나눈 것
코드 세그먼트, 데이터 세그먼트, BSS 세그먼트, 힙 세그먼트, 스택 세그먼트로 구분한다.
장점: 운영체제가 메모리를 용도별로 나누면 각 용도에 맞게 적절한 권한(읽기, 쓰기, 실행)을 부여할 수 있다.
CPU는 메모리에 대해 권한이 부여된 행위만 할 수 있다.
- 코드 세그먼트(Code Segment)
: 실행 가능한 기계 코드가 위치하는 영역, 텍스트 세그먼트(Text Segment)라고도 한다.
- 읽기 권한과 실행 권한이 부여된다. (이유: 프로그램이 동작하려면 코드를 실행할 수 있어야 한다.)
쓰기 권한은 없다. 쓰기 권한이 있다면 악의적인 코드 삽입의 가능성이 있기 때문이다.
정수 31337을 반환하는 메인 함수가 컴파일 되면 기계 코드로 변환되는데 기계 코드가 코드 세그먼트에
위치한다.
- 데이터 세그먼트(Data Segment)
: 컴파일 시점에 값이 정해진 전역 변수 및 전역 상수들이 위치하는 영역
- 읽기 권한이 부여된다. (이유: CPU가 세그먼트의 데이터를 읽을 수 있어야 한다.
- 데이터 세그먼트는 쓰기가 가능한 세그먼트와 쓰기가 불가능한 세그먼트로 나뉜다.
- 쓰기가 가능한 세그먼트: 전역 변수와 같이 프로그램이 실행되면서 값이 변할 수 있는 데이터들이 위치
( data 세그먼트 라고 부른다.)
- 쓰기가 불가능한 세그먼트: 프로그램이 실행되면서 값이 변하면 안되는 데이터들이 위치, 전역으로
선언된 상수가 포함된다. ( rodata(read-only data) 세그먼트 라고 부른다.)
str_ptr 은 readonly 라는 문자열을 가리키는데 이 문자열은 상수 문자열로 취급되어 rodata에 위치하고 str_ptr은 전역 변수로서 data에 위치한다.
- BSS 세그먼트(BSS Segment, Block Started By Symbol Segment)
: 컴파일 시점에 값이 정해지지 않은 전역 변수가 위치하는 메모리 영역, 개발자가 선언만 하고 초기화하지 않은
전역 변수 등이 포함된다.
- 읽기 권한 및 쓰기 권한이 부여된다.
- 메모리 영역은 프로그램이 시작될 때 모두 0으로 초기화된다.
--> C코드 작성할 때 초기화되지 않은 전역변수의 값은 0이 된다.
초기화되지 않은 전역 변수인 bss_data가 BSS 세그먼트에 위치한다.
- 스택 세그먼트(Stack Segment)
: 프로세스의 스택이 위치하는 영역, 함수의 인자나 지역 변수 같은 임시 변수들이 실행 중에 저장된다.
- 스택 프레임 (Stack Frame) 이라는 단위로 사용된다. 함수가 호출될 때 생성되고 반환될 때 해제된다.
- 프로그램의 전체 실행 흐름은 사용자의 입력을 비롯한 여러 요인에 영향을 받는다.
- 읽기 권한과 쓰기 권한이 부여된다. (이유: CPU가 자유롭게 값을 읽고 쓸 수 있어야 한다.
choice 에 따라 call_true 혹은 call_false가 호출될 수 있다. 지역변수 choice는 스택에 저장되게 된다.
유저의 입력에 따라 호출되는 함수가 달라지므로 어떤 프로세스가 실행될 때 얼마만큼의 스택 프레임을 사용하게 될 지 미리 계산하는 것은 일반적으로 불가능하다.
---> 운영체제는 프로세스를 시작할 때 작은 크기의 스택 세그먼트를 먼저 할당해주고 부족해질 때마다 확장해준다.
스택에 대해서 '아래로 자란다' == 스택이 확장될 때 기존 주소보다 낮은 주소로 확장되기 때문이다.
- 힙 세그먼트(Heap Segment)
: 힙 데이터가 위치하는 세그먼트
- 스택처럼 실행 중에 동적으로 할당될 수 있으며 리눅스에서는 스택 세그먼트와 반대 방향으로 자란다.
이유: 만약 두 세그먼트가 동일한 방향으로 자라고 연속된 메모리 주소에 할당된다면 기존의 힙 세그먼트를 다
사용하면 확장 과정에서 스택 세그먼트와 충돌하기 때문이다. 리눅스는 스택을 메모리의 끝에 위치시키고
힙과 스택을 반대로 자라게 하면 힙과 스택은 메모리를 자유롭게 사용할 수 있고 충돌 문제로부터도
비교적 자유로워진다.
- C 언어에서 malloc(), calloc() 등을 호출해서 할당받는 메모리가 위치한다.
- 읽기 권한, 쓰기 권한이 부여된다.
heap_data_ptr에 malloc()으로 동적 할당한 영역의 주소를 대입하고, 이 영역에 값을 쓴다.
heap_data_ptr은 지역변수이므로 스택에 위치하며, malloc으로 할당받은 힙 세그먼트의 주소를 가리킨다.
2. 결론
STAGE 2
Quiz: Linux Memory Layout
'보안 > SYSTEM HACKING' 카테고리의 다른 글
dreamhack stage 3 - Tool:pwntools (0) 2024.03.15 dreamhack stage 3 - Tool:gdb (0) 2024.03.15 dreamhack stage 2 - x86 Assembly (0) 2024.03.15 dreamhack stage 2 - Computer Architecture (0) 2024.03.15 dreamhack stage 1 - System Hacking Introduction (0) 2024.03.13