정보보안기사

[정보보안기사] SECTION 17 각종 시스템 보안 위협 및 대응책

tnvori 2026. 1. 16. 15:11

 

알프스의 카레 파스타. 카레 파스타는 처음이라 걱정했는데 생각보다 괜찮았다. 당근이랑 고기도 맛있음

  1. 버퍼 오버플로우 공격
    1. 버퍼 오버프로우 공격 개요
      1. 프로세스 메모리 구조와 스택 프레임 구조
        • 프로세스 메모리 구조
          • 텍스트 — 프로그램 코드와 상수 정의, 읽기만 가능
          • 데이터 — 전역 변수와 정적 변수 저장
          • 힙: 동적 메모리 호출에 의해 할당
          • 스택: 함수 인자 값, 함수 내 지역 변수, 함수의 반환 주소 등 저장. 상위에서 하위로 저장
      2. 버퍼 오버플로우 공격 기본 개념
        • 버퍼에 할당된 용량보다 더 많은 입력이 위치하면 다른 정보 변경 → 코드 삽입
      3. 공격 원리
    2. 스택 버퍼 오버플로우
      1. 개요
        • SetUID가 설정된 루트 권한의 프로그램을 공격 대상으로 함
        • 1988년 모리스 인터넷 웜에서 처음 발견 — fingerd 데몬에서 사용한 gets() 함수의 검사되지 않은 버퍼 오버플로우 이용
      2. 셸코드
        • 오버플로우가 발생하는 버퍼에 저장되는 공격자의 코드로 실행 제어를 이동시키는 것
        • 셸로 제어를 넘기고 공격당한 프로그램의 권한으로 다른 프로그램에 접근
      3. 스택 버퍼 오버플로우 공격 절차
        1. 공격 셸코드를 버퍼에 저장
        2. 루트 권한으로 실행되는 프로그램의 특정 함수의 스택 반환 주소 버퍼를 오버플로우시켜서 공격 셸코드가 저장되어 있는 버퍼의 주소로 덮어씌움
        3. 특정 함수가 호출되면 조작된 반환 주소로 셸 코드의 주소가 반환되어 셸 코드가 실행되고, 루트 권한 획득
    3. 힙 오버플로우
      1. 개요
        • 힙에 요청되는 메모리는 레코드의 연결 리스트와 같은 동적 데이터 구조를 위해 사용
        • 레코드가 오버플로우에 취약한 버퍼를 가진다면 연속된 메모리가 손상될 수 있음
        • 실행 제어를 쉽게 이동시킬 수 있는 반환 주소 없음
        • 할당된 공간이 함수에 대한 포인터를 포함하고 있다면 공격자는 이 주소를 변경하여 겹쳐 쓴 버퍼에 있는 셸코드를 가리키도록 할 수 있음
    4. 버퍼 오버플로우 공격 대응책
      1. 개요
      2. 컴파일 시간 방어
        • 기본 개념
          • 프로그램을 컴파일할 때 검사하여 버퍼 오버플로우를 방지하거나 발견하는 것을 목표로 함
          • 버퍼 오버플로우를 허용하지 않는 Java, ADA, Python과 같은 언어 사용
          • 메모리 접근에 자유도를 가진 언어를 사용하는 경우, 데이터 크기가 할당된 버퍼의 크기를 초과하지 않도록 반드시 확인하는 로직을 포함해야 함
        • 프로그래밍 언어의 선택
          • 현대 언어 — 컴파일러가 범위 검사를 강제로 수행하는 코드를 자동으로 추가
        • 안전한 코딩 기법들
          • 사용 자제 함수 — strcat(), strncat(), strcpy(), gets(), scanf(), sscanf(), vscanf(), vsscanf(), sprinf(), vsprinf(), gethostbyname(), realpath()
          • 사용 권장 함수
            • strcat() → stract_s() — 2개의 문자열을 연결시키는 함수
            • strncat() → strncat_s() — 2개의 문자열을 지정한 개수만큼 연결시키는 함수
            • strcpy() → strcpy_s() — 문자열을 복사해주는 함수
            • strncpy() → strncpy_s()
            • sprintf() → sprintf_s() — 서식에 따른 문자열을 문자 배열(버퍼)에 출력하는 함수
            • gets() → gets_s() 또는 fgets() — 표준 입력에서 문자열을 입력받는 함수
        • 언어 확장과 안전한 라이브러리 사용
          • Libsaft — 표준 의미를 구현하면서 복사 연산이 스택 프레임 내부의 지역 변수 공간을 넘지 않도록 검사하는 기능 구현
        • 스택 보호 메커니즘(Stack Guard)
          • 함수의 진입(entry)과 종료(exit) 코드를 조사하고 함수의 스택 프레임에 대해 손상이 있는지 검사 → 변경 발견 시 프로그램 종료
          • Stack Guard
            • GCC 컴파일러 확장 버전. 추가적인 함수 진입과 종료 코드 삽입
            • 컴파일러가 프로그램 함수 호출(프롤로그) 시에 ret 앞에 canary(밀고자) 값을 주입하고, 종료(return, 에필로그) 시에 canary 값이 변조되었는지 여부 확인
          • 스택 쉴드 — 함수 시작 시 복귀 주소를 Global RET이라는 특수 스택에 저장해두었다가 함수 종료 시 저장된 값과 스택의 RET 값을 비교
      3. 실행 시간 방어
        • 기본 개념
          • 컴파일 시간 기법 — 기존의 프로그램을 다시 컴파일해야 함
          • → 취약한 프로그램에 보호를 제공하기 위해 운영체제의 업데이트로 배포할 수 있는 실행 시간 방어법
          • 실행 시점 대응책 — 실행 가능 주소 공간 보호(Executable Address Space Protection) 기법과 주소 공간 임의화(Address Space Randomization) 기법 포함
          • 실행 가능 주소 공간 보호 기법 — 실행 코드가 프로세스 메모리상의 특정 위치에서만 실행될 수 있도록 함
          • 주소 공간 임의화 기법 — 스택 버퍼가 위치하는 주소 공간을 메모리 내에 임의적으로 배치
        • ASLR과 NOP
          • 주소 공간의 임의 추출(ASLR, Address Space Layout Randomization)
            • /proc/sys/kernel/randomize_va_space 설정
              • 0 — ASLR 해제
              • 1 — 랜덤 스택, 라이브러리 활성화
              • 2 — 랜덤 스택, 라이브러리, 힙 활성화
          • NOP sled(NOP 썰매) — 공격 기법인데 왜 방어에 박아둔 거임?
            • 버퍼의 맨 끝 부분에 셸코드를 위치시키고 버퍼의 앞 부분에 의도적으로 채워진 NOP 기계어의 연속 → 셸코드 시작 주소 지정의 정확성을 높임
            • NOP(No Operation)
              • 아무 기능도 수행하지 않는 명령어. 인텔 x86의 0x90
              • 빈 공간을 채우기 위한 명령어. 해당 명령어를 만나면 다음 명령어로 넘어감
        • 실행 가능 주소 공간의 보호
          • 스택과 힙을 실행 불가능하게 하여 방어 → 최신 운영체제
          • DEP(Data Execution Prevention) — MS 윈도우 운영체제에 포함된 보안 기능. 실행 방지 메모리 영역의 실행 코드에서 응용 프로그램이나 서비스가 실행되지 못하도록
          • NX-bit(No eXecute BIt) — 프로세스 명령어나 코드 또는 데이터 저장을 위한 메모리 영역을 따로 분리하는 CPU 기술. 프로세스 명령어가 지정된 구역을 상주하지 않아 실행되지 않도록 함
          • DEP/NX 설정 — /proc/sys/kernerl/exec-shield
            • 0 — 비활성화
            • 1 — 활성화
          • Solaris 2.7 이상의 버전 — /etc/system 파일에 다음을 추가
            • set noexec_user_stack = 1
            • set noexec_user_stack_log =1
          • rtl(return to libc) 공격
            • ret 주소를 실행 가능한 임의의 주소(libc 영역의 주소)로 돌려 원하는 함수 수행
            • 메모리에 적재된 공유 라이브러리는 스택에 존재하지 않아 Non-Executable Stack 우회 가능
  2. 포맷 스트링 공격(Format String Attack)
    1. 개요
      • printf(), fprintf(), sprintf()와 같이 포맷 스트링을 사용하는 함수를 사용하는 경우, 외부로부터 입력된 값을 검증하지 않고 입출력 함수의 포맷 문자열로 그대로 사용할 때 발생 가능한 취약점
      • 메모리 내용을 읽거나 쓸 수 있음 → 취약한 프로세스의 권한을 취득하여 임의의 코드 실행
    2. 공격 원리
      • 데이터 형태에 대한 불명확한 정의
      • %s, 등으로 명시해야 함
      • 함수 사용 시 포맷 스트링을 지정하지 않아 사용자에 의해 결정된다면, 이를 조작하여 메모리 내용을 참조하고 특정 영역의 값을 변경할 수 있음
      • %x를 통해 메모리 내용 참조 및 원하는 위치(RET 영역)로 이동 후%n을 통해 Return Address를 악성코드가 위치한 주소로 변조
    3. 포맷 스트링 취약점의 위협 요소
      • 프로그램 파괴
        • core를 덤프하는 데몬 kill
        • DNS 스푸핑 시 특정 서비스가 반응하지 않도록
      • 프로세스 메모리 보기
        • 포맷 함수의 응답(출력 스트링)을 볼 수 있다면 정보 수집 가능
        • 포맷 스트링이 무엇을 하며, 프로세스 배치가 어떤지에 대한 개략적인 내용 획득
      • 임의의 메모리 덮어쓰기
    4. 보안 대책
      • 포맷 문자열 사용 하수 사용 시 사용자 입력값을 직접적으로 포맷 문자열로 사용하지 않고, 포맷 문자열 생성에 포함하지 시키지 않도록 함
      • 사용자가 포맷 스트링을 변경할 수 있는 구조로 작성하지 않도록 함
        • %n, %hn — 공격자가 특정 메모리 위치에 특정 값을 변경할 수 있음 → 사용 x
      • 사용자 입력값을 포맷 문자열을 사용하는 함수 사용 시 %s 권장
      • 점검 툴 — gdb, ltrace, strace, Objdump
        • gdb — 텍스트 기반 디버그. 소스 차원과 머신 코드 디버깅에 적절
        • ltrace, strace — 프로그램 호출 시, 인자와 리턴값을 로깅하면서 라이브러리와 시스템 호출을 hook. 프로그램을 블랙 박스로 간주하여 어떻게 프로그램이 시스템과 상호작용하는지 확인 가능
        • Objdump — 실행 가능한 바이너리나 오브젝트 파일에 대한 정보를 알아내는 데 사용
  3. 레이스 컨디션 공격
    1. 기본 개념
      • 레이스 컨디션 — 둘 이상의 프로세스나 스레드가 공유 자원에 동시에 접근 할 때 접근 순서에 따라 비정상적인 결과가 발생하는 조건/상황
      • 실행되는 프로세스가 임시 파일을 만드는 경우, 악의적인 프로그램을 통해 그 프로세스 실행에 끼어들어 임시 파일을 목적 파일로 연결(심볼릭 링크)하여 악의적인 행위를 하는 것
      • 프로세스가 setuid 설정이 되어 root 권한으로 실행된다면 권한 상승 가능
    2. 파일 링크
      • 하드 링크
        • 똑같이 복사된 파일을 만드는 것
        • 하드 링크된 파일 수정 시 원본 파일 또한 수정됨 → 서로 동기화
        • 링크하고자 하는 파일이 다른 파티션에 존재하면 안 됨
      • 심볼릭 링크
        • 원본 파일 데이터를 가리키는 링크 정보만을 가짐
        • 원본 파일이 삭제되더라도 원본 파일의 이름과 위치 기억
        • 삭제 후 같은 경로에 같은 파일 생성 시, 해당 파일에 대해 링크 정보 보유
    3. 심볼릭 링크와 레이스 컨디션 공격
      • 공격 대상 — 소유자가 root고, SetUID 비트를 가지며, 임시 파일을 생성하는 파일, 생성되는 임시 파일의 이름을 알아야 함
      • lsof — 특정 파일에 접근하는 프로세스 목록 확인. 특정 프로세스가 사용하는 파일 목록 확인
      • 생성된 임시 파일 확인 → 임시 파일로 프로그램이 실행되기 전 심볼릭 링크 파일 생성 → 심볼링 링크 파일이 관리자 권한으로 접근 가능한 파일을 가리켜 접근하도록
    4. 레이스 컨디션 공격에 대한 대응책
      • 임시 파일에 접근하기 전 임시 파일에 대한 심볼릭 링크 설정 여부와 권한에 대한 검사 과정 추가
      • 가능하면 임시 파일을 생성하지 않도록
      • umask를 최하 022 정도로 유지하여 임시로 생성한 파일이 공격자에 의해 악의적으로 삭제되지 않도록 함
  4. 백도어
    1. 개요
      • 설계자가 고의적으로 만든 통로
      • 백 오피리스 — 악의적 목적. PC에 내장되어 사용자 정보를 저장 및 유출하기 위한 프로그램
    2. 리눅스/유닉스 백도어
      • root 권한으로 운영되는 경우 — http 데몬이 시작 프로그램으로 자동 실행, 또는 관리자가 보안에 관심없는 경우
    3. 백도어 탐지와 대응책
      • 현재 동작 중인 프로세스 확인
      • Csrss, Svchost — 웜/바이러스 백도어가 애용하는 프로세스
        • Csrss.exe — 윈도우 콘솔을 관장하고, 스레드를 생성/삭제하며, 32비트 가상 MS-DOS 모드를 지원하는 프로세스
        • Explorer.exe — 작업 표시줄, 바탕 화면같은 사용자 셸을 지원하는 프로세스
        • Lsass.exe
          • 윈도우 서비스에 필요한 인증 프로세스 담당
          • 인증 성공 시 초기 셸 실행
          • 사용자별 액세스 토큰을 생성하여 다른 프로세스들이 해당 토큰을 상속받도록 함
        • Mstask.exe — 시스템에 대한 백업이나 업데이트 등에 관련된 작업의 스케줄러 프로세스
        • Smss.exe
          • 사용자 세션 시작 기능을 담당하는 프로세스
          • Winlogon, Win32(Csrss.exe)를 구동하고 시스템 변수 설정
          • Winlogon이나 Csrss가 끝나기를 기다려 정상적인 Winlogon, Csrss 종료 시 시스템 종료
        • Spoolsv.exe — 프린터와 팩스의 스풀링 기능 담당
        • Svchost.exe
          • DLL에 의해 실행되는 프로세스의 기본 프로세스
          • 한 시스템에서 svhost 프로세스를 여러 개 볼 수 있음
        • Services.exe — 시스템 서비스를 시작/정지하여 그들 간의 상호작용하는 기능 수행
        • Taskmgr.exe — 윈도우 작업 관리자 자신
        • Winlogon — 사용자 로그인/로그오프를 담당
      • H-IDS 사용
        • 의심스러운 실행 파일에 대해 변경 발생 여부를 확인하기 위해 checksum 수행
        • 안티바이러스, IDS 소프트웨어를 통해 자동 수행
  5. 시스템 자원 고갈 공격(시스템 서비스 거부 공격(DoS) 공격 중 하나?)
    1. 개요
    2. 시스템 자원 고갈 공격의 종류
      • 가용 디스크 자원 고갈 공격 — 파일을 생성하고 1000바이트씩 계속 작성하는 프로그램
      • 가용 메모리 자원 고갈 공격 — malloc() 함수를 통해 메모리 할당만 계속 수행하는 프로그램. 디스크 고갈 공격보다 시스템 자원을 더 많이 차지
      • 가용 프로세스 자원 고갈 공격 — 프로세스 할당 함수 fork()를 계속해서 사용
      • 프로레스 죽이기 공격 — 루트 권한을 획득한 상태에서 사용 중인 프로세스 kill
  6. 리버스 엔지니어링
    1. 기본 개념 — 장치나 시스템의 구조를 분석하여 원리를 발견하는 과정
      • 도구
        • OllyDbg
          • 바이너리 코드 분석을 위한 x86 디버거
          • 소스코드가 없을 때 유용
          • 프로그램의 리버스 엔지니어링 사용
        • Procexp(Process Explorer)
          • MS 윈도우용 프리웨어 작업 관리자, 시스템 모니터
          • 실행 중인 프로세스에 관한 정보를 수집하기 위한 기능, 작업 관리자 기능 제공
        • FileMonitor — 파일 생성, 삭제, 파일명 변경 등 실시간 확인
    2. 리버스 엔지니어링 공격
    3. 리버스 엔지니어링에 대한 대응책
      • 프로그램 코드를 읽기 어렵게
      • 소스코드 난독화
      • 바이너리 난독화 — 컴파일 후 생성된 바이너리 변조
  7. 기타 시스템 보안 위협 및 대응책
    1. 루트킷
      • 개요 — 시스템에 설치되어 그 존재의 흔적을 숨기면서 공격자가 관리자 권한으로 접근할 수 있도록 유지하는 프로그램 집합
      • 루트킷의 확인
        • 공격자는 행동을 숨기기 위해 정상적인 프로그램을 대신하도록 바이너리 파일을 변조시킴
          • ls, ps, netstat, login, top, dir, du, ifconfig, find, tcpd 등을 변조하여 공격자 파일 은닉
        • 시스템 프로그램의 파일 크기, 생성 시간, 변경 시간 등을 확인해야 함
          • /bin 또는 /usr/bin에서 #ls -alct|more로 확인
        • ls, ps, netstat 등의 파일은 똑같은 OS 버전의 다른 시스템 파일 사이즈를 비교하여 변조 여부 확인
      • 윈도우용 — FU-Rootkit, Hxdef100, NTRootkit
      • 리눅스용 — Suckit, lrk4, lrk5, adore
    2. 논리 폭탄(logic bomb)
      • 특정한 사건 발생 시 프로그램이나 코드 실행
      • 포렌식 활동 실행 시 논리 폭탄이 시작되어 디지털 증거를 삭제하도록