[05 시스템 해킹]
버퍼 오버플로우 공격
- 개요
- 버퍼 오버플로우는 연속된 메모리 공간을 사용하는 프로그램에서 할당된 메모리의 범위를 넘어선 위치에 자료를 읽거나 쓰려고 할 때 발생한다. 버퍼 오버플로우가 발생하게 되면 프로그램의 오작동을 유발시키거나, 악의적인 코드를 실행시킴으로써 공격자 프로그램을 통제할 수 있는 권한을 획득하게 된다.
- 버퍼 오버플로운에는 스택 버퍼 오버플로우와 힙 버퍼 오버플로우가 있다.
- 스택 버퍼 오버플로우 : 스택은 함수 처리를 위해 지역변수 및 매개변수가 위치하는 메로리 영역을 말한다. 스택에 할당된 버퍼들이 문자열 계산등에 의해 정의된 버퍼의 한계치를 넘는 경우 버퍼 오버플로우가 발생하여 복귀 주소를 변경하고 공격자가 원하는 임의의 코드를 실행한다.
- 힙 버퍼 오버플로우 : 힙은 사용자가 동적으로 할당하는 메모리 영역(malloc())이다. 힙에 할당된 버퍼들에 문자열 등이 저장되어 질 때, 최초 정의된 힙의 메모리 사이즈를 초과하여 문자열 등이 저장되는 경우 버퍼 오버플로우가 발생하여 데이터와 함수 주소 등을 변경하여 공격자가 원하는 임의 코드를 실행한다.
- 버퍼 오버플로우 이해를 위한 C언어 함수
- 주요 C언어 함수
- strcpy : src 문자열을 dest 버퍼에 저장한다. src 문자열의 길이를 체크하지 않으므로 dst 버퍼를 초과하는 오버플로우가 발생할 수 있다.
- strncpy : src 문자열의 len 만큼을 dst 버퍼에 저장한다. src 문자열의 길이를 제한하기 때문에 버퍼 오버플로우에 안전하다.
- size_t strlen : 문자열의 null 문자를 제외한 바이트수를 반환한다.
- C언어에서 문자열 처리 방식
- C언어에서 문자열은 null문자(0x00)로 문자열의 끝을 표현한다.
- 가령 'ABCD'라는 4개의 문자로 구성된 문자열을 정의한다면, 실제로는 'ABCD\0'의 5개 문자로 저장된다.
- 실습
- 책 참조
- 주요 C언어 함수
- 스택 버퍼 오버플로우 공격 실습
- 테스트 코드
- strcpy 함수가 가지고 있는 취약점을 이용하여 스택 버퍼 오버플로우를 발생시켜 쉘코드 함수를 실행, root 권한의 쉘을 획득할 수 있다.
- strcpy(dst, src) 함수는 src 문자열을 dst 버퍼로 복사해주는 함수로 입력받은 문자열에 대한 크기를 점검하지 않아 dst 버퍼를 초과하는 문제가 발생할 수 있다.
- 쉘코드 함수는 악의적인 코드의 메모리 업로드를 가정한다. 실제 버퍼 오버플로우 공격은 공격자가 악의적인 코드(명령을 수행하기 위한 실행 바이너리 코드)를 만들어 이를 다양한 방법으로 메모리에 업로드 시킨 후 버퍼 오버플로우에 취약한 프로그램을 이용해 이를 실행시킨다.
- 스택 오버플로우 발생 시 스택 구조
- 모든 함수는 호출이 되면 자신만의 스택 공간이 할당되며 이를 스택 프레임이라 한다. 스택 프레임 공간 내에서 스택 프레임 포인터를 기준점으로 하여 스택 포인터에 상대주소를 저장하여 메모리 접근을 하게 된다.
- 현재 실행중인 함수의 스택 프레임 포인터는 EBP 레지스터에 저장되고, 스택 포인터는 ESP 레지스터에 저장되며, 다음 실행할 명령어의 주소는 EIP 레지스터에 저장된다.
- 함수가 호출되면 이전 함수의 다음 실행할 명령어의 주소정보와 스택 프레임 포인터를 먼저 스택에 저장한다. 이는 현재 호출된 함수가 종료하고 실행이 이전 호출한 함수로 돌아갔을 때 EIP, EBP 레지스터의 값을 이전 함수로 되돌리기 위한 일종의 백업이다.
- 위 그림에서 RET 영역이 이전 함수의 다음 실행 명령어의 주소를 저장하는 영역이고, SFP 영역이 이전 함수의 스택 프레임 포인터를 저장하는 영역이다. 만약 RET 영역이 악성코드가 위치한 주소로 변조가 된다면 함수가 종료된 후 악성코드가 실행될 수 있다.
- 공격자는 RET 영역을 변조하기 위해 버퍼 오버플로우를 이용하여 SFP 영역까지 A값으로 덮어쓴 후 악성코드가 위치한 주소값으로 RET 영역을 덮어쓴다. 결과적으로 main 함수가 종료하게 되면 RET 주소값을 참조하여 악성코드(shell_code)가 실행된다.
- gdb 툴을 통해 shell_code함수의 메모리 주소 확인
- gdb는 실행 파일을 디버깅 하기 위한 툴로 shell_code 함수의 메모리 주소를 확인할 수 있다.
- 확인된 shell_code 함수의 메모리 주소를 이용하여 Return Address를 해당 주소로 변경하게 되면 main 함수 호출 완료 후 shell_cde 함수를 수행하게 된다.
- 스택 오버플로우를 통한 root 권한의 쉘 획득
- perl 스크립트의 A*16은 A문자 16개를 출력한다느 ㄴ의미이다. 이를 통해 SPF 영역까지 A문자로 채울 수 있으며 shell_code 함수의 메모리 주소를 출력하여 RET 영역에 해당 주소를 덮어쓴다.
- 결과적으로 main 함수 호출이 끝나면 RET 영역의 주소를 참조하여 shell_code 함수가 수행되며 이를 통해 root 권한의 쉘을 획득하게 된다.
- 스택 버퍼 오버플로우 대응방안
- 안전한 함수를 사용하여 버퍼 오버플로우 방지
- 입력값 사전 검증을 통한 버프 오버플로우 방지
- 스택 버퍼 오버플로우 대응기술
- 스택 가드
- 스택 쉴드
- ASLR
- 테스트 코드
레이스 컨디션 공격
- 개요
- 레이스 컨디션은 두 이상의 프로세스나 스레드가 공유자원에 동시에 접근할 때 접근하는 순서에 따라 비정상적인 결과가 발생하는 조건/상황을 말한다.
- 실행되는 프로세스가 임시파일을 만드는 경우 악의적인 프로그램을 통해 그 프로세스의 실행 중에 끼어들어 임시파일을 목적파일로 연결(심볼릭 링크)하여 악의적인 행위를 할 수 있는데 이를 레이스 컨디션 공격이라고 한다.
- 만약 프로세스가 setuid 설정이 되어 root권한으로 실행된다면 권한 상승을 통한 중요 자원(파일)에 접근하는 심각한 문제가 발생할 수 있다.
- 실습
- 공격자는 /etc/shadow 파일을 조작하기 위해 임시파일 tmp.dat에 심볼릭 링크를 생성한다.
- 임시파일은 프로그램 수행 중 일시적인 목적으로 생성하는 파일로 프로그램에서 임시파일로 출력하면 실제로는 심볼릭 링크를 통해 /etc/shadow 파일에 출력된다.
- /etc/shadow 파일에 root 패스워드가 암호화되어 저장되어 있다.
- 프로그램을 통해 tmp.dat 에 조작된 패스워드를 출력하고 있으며 심볼릭 링크를 통해 실제로는 /etc/shadow 파일이 변경된다.
- 레이스 컨디션 대응방안
- 가능하면 임시파일을 생성하지 않는다.
- 파일 생성 시 이미 동일한 파일이 존재하는 경우 파일 생성 또는 쓰기를 금지한다.
- 사용하고자 하는 파일에 링크가 걸려있으면 실행을 중단한다.
- umask를 최하 022 정도로 유지하여 임시로 생성한 파일이 공격자에 의해 악의적으로 삭제되지 않도록 한다.
포맷 스트링 공격
- 개요
- 포맷 스트링은 C언어의 printf()등의 함수에서 사용되는 문자열의 입/출력 형태를 정의하는 문자열로 서식 문자열이라 표현한다.
- 포맷 스트링을 인자로 하는 함수의 취약점을 이용한 공격으로 외부로부터 입력된 값을 검증하지 않고 입출력 함수의 포맷 스트링을 그대로 사용하는 경우 발생할 수 있는 취약점이다.
- 공격자는 포맷 스트링을 이용하여 취약한 프로세스를 공격하거나 메모리 내용을 읽거나 쓸 수 있다. 그 결과, 공격자는 취약한 프로세스의 권한을 획득하여 임의의 코드를 실행할 수 있다.
- 테스트 코드
- 소스코드의 printf 함수를 보면 포맷 스트링을 외부 입력으로부터 받도록 되어 있다. %x 식별자를 통해 현재 수행되는 스택의 메모리 정보를 읽어올 수 있다.
- var1 변수에 저장된 10, var2 변수에 저장된 11 등이 출력되는 것을 볼 수 있다.
- 포맷 스트링의 취약점
- 포맷 스트링을 인자로 하는 함수 사용 시 포맷 스트링을 지정하지 않고 사용자 입력을 통해서 포맷 스트링이 결정된다면 공격자는 이를 조작하여 메모리 내용을 참조하고 특정 영역의 값을 변경할 수 있다.
- 가령, 공격자는 스택 프레임 구조를 고려하면서 '%x'를 통해 메모리 내용 참조 및 원하는 위치로 이동한 후 %n을 통해 return address를 악성코드가 위치한 주소로 변조하여 악성코드를 실행할 수 있다.
- 포맷 스트링 대응방안
- 포맷 스트링을 함수의 입력 파라미터로 직접 사용하지 않는다.
- 안전한 코드의 예처럼 함수 사용시 포맷스트링을 지정하여 간접적으로 참조가 되도록 한다.
- ex) print("%s", argv[1]);
'공부 > 정보보안기사 실기' 카테고리의 다른 글
[Section 03] 윈도우 서버 취약점 (126 ~ 140pg) (0) | 2022.04.15 |
---|---|
[Section 02] UNIX/Linux 서버 취약점 (116 ~ 125pg) (0) | 2022.04.14 |
[Section 01] 시스템 기본 학습 (86 ~ 103pg) (0) | 2022.04.12 |
[Section 01] 시스템 기본 학습 (62 ~ 85pg) (0) | 2022.04.11 |
[Section 01] 시스템 기본 학습 (53 ~ 61pg) (0) | 2022.04.10 |