공부/정보보안기사 실기

[Section 01] 시스템 기본 학습 (104 ~ 115pg)

남쪽마을밤송이 2022. 4. 13. 04:32

 [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개 문자로 저장된다.
    • 실습
      • 책 참조
  • 스택 버퍼 오버플로우 공격 실습
    • 테스트 코드
      • 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]);