시스템 해킹과 보안

PART 02 시스템 해킹

bumsoha 2024. 11. 4. 10:04

01. 80X86 시스템 CPU 구조과 레지스터

  • 80X86 시스템은 XT라고 칭했던 인텔  CPU의 IBM PC 중 아주 초기 보급형 모델이다.

1.1 연산 장지

구성요소 기능
내부 장치 가산기 뎃셈 연산 수행
보수기 뺄셈 연산 수행, 1의 보수나 2의 보수 방식 사용
시프터 비트를 오른쪽이나 왼쪽으로 이동하여 나눗셈과 곱셉 연산 수행
관련
레지스터
누산기 연사의 중간 결과 저장
데이터 레지스터 연산에 사용할 데이터 저장
상태 레지스터 연산 실행 결과로 나타나는 양수와 음수, 자리올림, 오버플로 상태 기억

1.2 제어 장치

구성 요소 기능
내부 장치 명령 해독기 명령 레지스터에 있는 명령을 해독하여 부호기로 전송한다.
부호기 명령 해독기가 전송한 명령을 신호로 만들어 각 장치로 전송한다
주속 해독기 명령 레지스터에 있는 주소를 해독하여 메모리의 실제 주소로 변환한 후, 이를 데이터 레지스터에 저장한다
관련 레지스터 프로그램 카운터 다으므에 실행할 명령의 주소를 저장한다
명령 레지스터 현재 실행 중인 명령을 저장한다
메모리 주소 레지스터 주기억 장치의 번지를 저장한다
메모리 버퍼 레지스터 메모리 주소 레지스터에 저장된 주소의 실제 내용을 저장한다

 

1.3 레지스터

  • 처리 중인 데이터나 처리 결과를 임시 보관하는 CPU 안의 기억 장치로, 대개 연산 장치나 제어 장치에 함께 포함되어 있다. 

0.2 레지스터의 종류와 기능

2.1 범용 레지스터

  • EAX 레지스터 : 누산기인 EAX 레지스터는 입출려과 대부분의 산술 연산에서 사용한다. 
  • EBX : DS 세그먼트의 포인터를 주로 저장하며, ESI나 EDI와 결합하여 인덱스에 사용한다. 
  • ECX : 루프가 반복되는 횟수를 제어하는 값, 왼쪽이나 오른쪽으로 이동되는 비트 수 등을 포함한다. 
  • EDX : 입출력 연산에 사용한다.

2.2 세그먼트 레지스터

  • 프로그램에 정의한 메모리상의 특정 영역으로 코드, 데이터, 스택 등을 포함한다.
  • CS : 코드 세그먼트는 실행될 기계 명령을 포함한다
  • DS : 데이터 세그먼트는 프로그램에 정의된 데이터, 상수, 작업 영역을 포함한다. 
  • SS : 스택 세그먼트는 프로그램을 실행할 때, 실행 과정에서 필요한 데이터나 연산 결과 등을 임시로 저장하거나 삭제하는 등의 목적으로 사용한다.
  • ES,FS,GS : ES는 사용된 데이터 세그먼트의 주소를 가리킨다. 

2.3 포인터 레지스터

  • EBP : 스택 세그먼트에서 현재 호출해서 사용하는 함수의 시작 주소 값을 저장한다. 
  • ESP : 현재 스택 영역에서 가장 하위 주소를 저장한다. 
  • EIP : 다음에 실행될 명령의 오프셋을 포함한다.

2.4 인데스 레지스터

  • 인덱스 레스터란? 데이터를 복사할 때 출발지와 목적지 주소를 각각 가리키는 레지스터로 사용
  • ESI & EDI : 메모리의 한 영역에서 다른 영역으로 데이터를 연속적으로 복사 할 때 사용한다.

2.5  플래그 레지스터 

  • 상태 플래그
    • CF(비트0) : 산술 연산 결과로 자리올림이나 자리내림이 발생할 때 세트된다.
    • ZF(비트6) : 산술 연산 결과가 0이면 세트되고, 0 이외에는 클리어 된다.
    • OP(비트11) : 부호가 있는 수의 오버플로가  발생하거나  MSB를 변경 했을 때 세트된다.
    • PF(비트2) : 산술 연산 결과가 짝수이면 세트된다. 
    • AF(비트4) : 8비트 피연산자를 사용한 산술 연산에서 비트 3을 비트4로 자리올림하면 세트된다.
    • SF(비트7) : 산술 및 논리 연산 결과가 음수이면 세트된다.
  • 제어 플래그
    • 제어 플래그 DF는 스트링 명령(MOVS, CMPS,SCAS,LODS,STOS)을 처리한다.
  • 시스템 플래그
    • TF(비트8) : 디버깅을 할 때 'Single Step Mode' 를 활성화하면 세트되고, 비활성화 하면 클리어 된다. 
    • IF(비트9) : 프로세서의 인터럽트 처리 여부를 제어한다. 
    • IOPL(비트 12,13) : 현재 실행하는 프로그램이나 태스크의 입출력 특권 레벨을 지시한다. 
    • NT(비트14) : 인터럽트하거나 호출된 태스크를 제어한다.
    • RF(비트16) : 프로세서의 디버그 예외 반응을 제어한다. 
    • VW(비트17) : V86 모드를 활성화하면 세트되고, 사용하지 않고 보호 모드로 리턴하면 클리어 된다.
    • AC(비트18) : 메모리를 참조할 때 정렬 기능을 활성화하면 세트된다.
    • VIF(비트19) , VIP(비트20) : 가상 모드 확장과 관련하여 사용한다.
    • ID(비트12) : CPUID명령의 지원 유무를 결정한다. 

 

02 80X86 시스템 메모리의 구조와 동작

1. 메모리의 기본 구조

1.1 스택

  • 후입 선출 방식에 의해 정보를 관리하는 데이터 구조, 스택에서는 TOP이라고 불리는 스택의 끝부분에서 데이터의 삽입과 삭제가 발생한다. 

1.2 힙

  • 프로그램을 실행 중 필요한 기억 장소를 할당하기 위해 운영체제에 예약되어 있는 기억 장소 영역

1.3 BSS 세그먼트

  • 초기화되지 않는 데이터 세그먼트라고도 하며, 프로그램을 싱행할 때 0이나 NULL 포인터로 초기화되는 영역이다. 

1.4 데이터 세그먼트

  • 초기화된 데이터 세그먼트라고도 하며, 다음 예 처럼 초기화된 외부 변수나 static 변수 등을 저장하는 영역이다.

1.5 텍스트 세그먼트

  • CPU로  실행되는 머신 코드가 있는 영역으로, EIP가 다음에 실행하는 명령을 가리킨다. 

02. 메모리 접근 모드와 동작
2.1 실제 모드

  • x86 계열로 처음 등장한 8086 CUP에서 사용하더 동작 모드이다.

2.2 보호 모드

  • 인터럽트나 예외 처리 등도 모두 보호 모드에서 지원하는 기능을 활용한다.
  • 03. 어셈브리어 기본 문법과 명령

01. 어셈블리어의 구조

  • 보통 윈도우에서는 Intel 문법을 사용하고, 리눅스에서는 AT&T 문법을 사용한다.
  • 이 둘의 가자 큰 차이점은 제1피연산자와 제2피연산자의 위치이다. 

02. 어셈블리어의 데이터 타입과 리틀 엔디안 방신

2.1 데이터 타입

  • 바이트 : 1바이트 (8비트) 데이터 항목
  • 위드 : 2바이트(16비트) 데이터 항목
  • 더블워드 : 4바이트(32비트) 데이터 항목

2.2 리틀 엔디안 

  • 데이터는 리틀 엔디안 방식에 따라 스택에 저장하고 참조한다.
  • 리틀 엔디안 방식에서는 번지 두 개로 나누어 저장해야 하는 16비트 데이터(워드)의 경우 하위 바이트는 하위 번지에 저장하고, 상위 바이트는 상위 번지에 저장한다.

03. 어셈블리어의 주소 지정 방식

  • 80X86 시스템에서는 메모리에 접근할 수 있도록 다양한 주소 지정 방식을 제공한다.
  • 이런 주소 지정 방식은 실제 어셈블리어로 프로그래밍할 때나 시스템을 해킹할 때 자주 접한다.

3.1 레지스터 주소 지정

  • 얼핏 일반적으로 생각하는 메모리에 접근하는 방식은 아니다. 레지스터의 주소 값을 직접 지정하여 복사하는  방식으로 처리 속도가 가장 빠르다. 

3.2 직접 메모리 주소 지정

  • 가장 일반적인 주소 지정 방식이다. 보통 피연산자 하나가 메모리 위치를 참조하고, 다른 하나는 레지스터 참조한다. 두 피연산자가 메모리를 직접 참조하는 것은 MOVS 와CMPS만 가능하다.

3.3 레지스터 간접 주소 지종

  • 직접 메모리 주소 방식처럼 '세그먼트 : 오프셋' 형식을 사용한다. 단지 세그머트를 명시적으로 적지 않다.

3.4 인덱스 주소 지정

  • 레지스터 간접 지정 방식에 변위가 더해진 메모리 주소 지정 방식이다.

3.5 베이스 인덱스 주소 지정

  • 실제 주소를 생성하려고 작동한다.

3.6 변위를 갖는 베이스 인덱스 주소 지정

  • 방식은 베이스-인덱스 변형으로 실제 주소를 생성하려고 베이스 레지스터, 인덱스 레지스터, 변위를 결합한다. 

04. 어셈블리어 기본 명령

4.1 산술 연산 명령

  • ADD : 제1피연산자와 제2피연산자 값을 더한 결과 값을 제1피연산자에 저장한다. 
  • SUB : 제1피연산자에서 제2피연산자 값을 뺀 결과 값을 제1피연산자에 저장한다. 
  • CMP : 데이터의 두 값을 비교할 때 사용한다.

4.2 데이터 전송 명령

  • 메모리, 범용 레지스터, 세그머트 레지스터로 참조되는 주소에 들어 있는 데이터를 전송한다.
  • 이들은 조건 이동, 스택 접근, 접근 데이터 변환 같은 특정 연산도 수행한다.
    • MOV : 데이터를 이동할 때만 사용한다. 
    • PUSH : 스택에 데이터를 삽입할 때 사용한다. 
    • POP : 스택에서 데이터를 삭제할 때 사용한다.
    • LEA : 데이터 값을 이동할 때 사용하며, MOV와 비슷하면서 조금 다르다.

4.3 논리 명령

  • AND : 대응되는 비트가 둘 다 1 일 때만 결과가 1이고,  그 외는 모두 0이 된다. 
  • OR : 대응되는 비트 중 하나만 1 이어도 결과가 1이고, 둘다 0 일 때만 0이 된다. 
  • XOR : 대응되는 비트 중에서 한 비트가 1이고 다른 비트가 0이면 결과가 1이 된다. 
  • NOT : 피연산자 1의 보수를 구하는 작동 코드로 각 비트를 반전시켜 준다. 
  • TEST : CMP명령처럼 데이터의 두 값을 비교할 때 사용한다. 

4.4 스트링 명령

  • 바이트로 구성된 데이터를 메모리에 가져오거나 메모리로 전송한다. 
    • REP : ADD나 MOVS 같은 동작 코드 앞에 위치하며, ,CX가  0이 될 때까지 뒤에 오는 스트링 명령을 반복한다.
    • MOVS: 바이트나 워드, 더블워드를 옮기는 명령어로 각각 MOVSB, MOVSW,MOVSD가 있다

4.5 제어 전송 명령

  • 점프, 조건 점프, 루프호출, 리턴 등으로 프로그램 흐름을 제어한다.
    • JMP : 대표적인 점프 명령으로 프로그램 실행 주소 또는 라벨로 이동한다.
    • CALL : JMP처럼 함수를 호출할 때 사용하고 제1피연산자에 라벨을 지정한다.
    • RET : 함수에서 호출한 곳으로 돌아갈 때 사용하는 명령이다. 
    • LOOP : 문장들의 블록을 지정된 횟수만큼 반복한다. 
    • INT :  인터럽트가 호출되면 CS:IP와 플래그를 스택에 저장하고, 그 인터럽트와 관련한 서브루틴을 실행한다.

4.6 프로세서 제어 명령

  • STC : 피연산자 없이 사용하며, EFLAGS 레지스터와 CF 값을 세트한다.
  • NOP :  아무 의미 없는 명령으로, 일종의 빈칸을 채우는 데 사용한다. 

PART01

01. 리눅스 / 유닉스의 계정과 권한 체계

  • 로그인은 계정ID와 패스워드로 자신이 누군지 밝히고, 그에 따른 권한을 부여 받아 시스템에 접근할 수 있도록 허가를 받는 과정이다.

02. 리눅스 / 유닉스의 권한 상승

  • 시스템에서 해킹을 하는 주요 목적은 권한 상승이다. 

03. 윈도우의 계정과 권한 체계

  • 윈도우 계정과 권한 체계도 리눅스처럼 기본으로 관리자와 일반 사용자로 나눈다.

04. 윈도우의 권한 상승

  • 윈도우에는 setUID같은 기능이 없어 궈한 상승 과정이 리눅스와는 달라 보이지만, 근본적으로는 다르지 않다.

PART 02 -  시스템 해킹

01. 패스워드 크래킹의 이해

 

1. 패스워드 관리

  • 보안 관리자의 첫 번째 방어책은 패스워드이다. 
  • 패스워드는 보안에서 가장 중요한 항목임이 분명하다.
  • 패스워드 설정 문제는 서버 관리자만의 문제가 아니다. 사용자도 크래킹 공격에 취약하다고 할 수 있다.
  • 패스워드를 자신의 이름이나 주민등록번호,  전화번호처럼 매우 간단한 것으로 설정해 놓는다면, 인터넷에서 개인 정보가 누출된 것에 전적으로 책임을 져야 할지 모른다.

2. 해시와 암호화

  • 운영체제는 어떤 형식으로든 패스워드 내용을 숨겨야 한다. 패스워드를 숨기는 방법에는 기본적으로 두 가지가 있다. 해시와 암호화 이다.
  • 해시 : 임의의 데이터에서 일종의 짧은 '전자 지문'을 만들어 내는 방법이다. 해시 함수는 데이터를 자르고 치환하거나 위치를 바꾸는 등의 방법으로 결과를 만들어 내며, 이 결과를 흔이 해시 값이라고 한다.
  • 암호화 : 특별한 지식을 소유한 사람을 제외하고 누구도 읽을 수 없도록 알고리즘을 이용하여 데이터를 전달하는 것이다. 이런 과정을 거쳐 암호화된 정보를 만들 수 있다. 그리고 암호화된 정보는 복호화 되어 다시 읽을 수 있다.
  • 차이점 : 암호화 알고리즘이 암호화하지 않은 평문을 암호화한 후 이를 다시 복호화할 수 있는 반면에 해시 알고리즘 결과물은 복호화가 불가능하다는 것이다.

3. Salt

  •  기본적으로  패스워드는 해시와 암호화 알고리즘으로 변경하여 저장한다. 
  • 똑같은 해시 값이나 함호문은 독같은 결과만으로도 패스워드를 노출시킨다는 약점이 있다.

4. 패스워드 크래킹 방법 이해

  • 패스워드 길이는 패스워드 강도를 결정하는 매우 중요한 요소이다. 그러므로 사용자가 설정한 패스워드에 해시나 암호화 알고리즘을 한자리씩 별도로 적용해서 어처구니없이 패스워드 강도를 약화시킬 필요가 없다. 

4.1 사전 대입 공격

  • 사용자가 설정하는 대부분의 패스워드에는 특정한 패턴이 있다는 것을 착안한다. 특정 패턴이 사전에 있는 단어일 수도 있다. 실제로 모의 해킹을 시도 해보면, 상당수 패스웓으가 추측에 기반을 둔 사전 대입 공격으로 밝혀졌다.

4.2 무작위 대입 공격

  • 사전 댕입 공겨기에서 실패했을 때 주로 사용한다. 이 공격은 패스워드가 그다지 복잡하지 않거나 짧을 때 단시간에 크래킹도니 패스워드를 알아 낼 수 있다.

4.3 레인보우 테이블을 이용한 공격

  • 2000년대에 들어 윈도우 LM 패스워드를 몇 분 만에 크래킹하면서 유명해지기 시작했다.

 

02. 윈도우 인증과 패스워드

 

01. 윈도우 인증과 구성 요소

  • SAM은 윈도우에서 패스워드를 암호화하여 보관하는 파일 이름과 같다.

2. 로컬 인증과 도메인 인증

2.1 로컬 인증 

  • Winlogon 화면에서 ID와 패스워드를 입력하면 LSA  서브시스템이 인증 정보를 받아 NTLM모듈에 ID와 패스웓를 넘겨준다. 이를 다시 SAM이 받아 확인하고, 로그인을 허용한다.

2.2 도메인 인증

  • LSA 서비스시스템에서 해당 인증 정보가 로컬 인증용인지, 도메인 인증용인지 확인하고 커버로스 프로토콜을 이용하여 도메인 컨트롤러에 인증을 요청한다. 
  • 도메인 인증에서는 기본적으로 풀 도메인 이름과 커버로스 프로토콜을 이용하지만, IP로 접근을 시도할 때는 NTLM을 사용한다.

 

3.인증 구조

3.1 Challenge & Response인증

  • 패스워드 값을 읹으 서버와 동일한 인증 주체에 전달하여 올바른 패스워드라고 증명하는 가장 직관적이고 쉬운 방법은 패스워드 값을 직접 전달하는 것이다.
  • Challenge & Response 방식의 인증 프로토콜은 기본적으로 구조가 같다.
    • 인증 요청 : 인증을 수행하고자 하는 주체가 인증 서버에 인증을 요청한다.
    • Challenge 값 생성, Challenge 값 전송 : 인증을 요청받은 인증 서버는 문자열 등 값을 특정 규칙에 따르거나 랜덤하게 생성하여 인증 요구자에게 전달한다.
    • Response 값 생성 : 인증 요구자는 서버에서 전달받은 Challenge 값과 자신이 입력한 패스워드 정보 등을 이용하여 서버에 보낼 Response값을 생성한다.
    • Reponse 값 전송 , Response 값 확인, 인증 성공 : 인증 요구자는 생성한 Reponse 값을 인증 서버에 전달하고, 인증 서버는 이 Response 값을 확인하여 인증 요구자가 적절한 패스워드를 소유하고 있는지 확인한다. 확인된 Response가 적절하면 인증 성공 여부를 인증 요구자에게 알린다.

3.2 LM & NTLM

  • LM 해시  
    • 대문자 변환 : 우선 LN 방식은 사용자가 패스워드를 입력하면 모두 대문자로 바꾼다. 
    • 패딩 : LN은 기본적으로 열네 글자를 패스워트 하나로 인식한다. 따라서 열네 글자가 되지 않는 패스워드는 뒤에 0을 붙여 14자리로 만든다.
    • 분리  : LN은 패스워드 길이에 관계없이 8바이트가 블록 하나를 형성한다. 이 중 1바이트는 패스워드 블록 정보를 담고 있어 실질적으로 패스워드 문자열 7바이트, 즉 문자 일곱 개다. 따라서 패스워드가 qwwe1234라면 여덟 글자이므로 패스워트 블록을 두 개 형성 한다.
    • DES 암호화  : 블록 두 개로 분리된 패스워드는 각각 "KGS!@#$%"문자열을 암호화 키로 사용하여 암호화 한다. 
    • 결합 : 키 두 개로 "KSG!@#$%"를 각각 암호화한 결과 값을 합하여 SAM파일에 저장한다.

3.3 NTLMv2해시

4. 자격 증명

  • 네트워크가 연결되지 않았을 때도 도메인에 등록된 PC에 로그인 할 때 도메인 계정으로 로그인하는데, 이는 자격 증명 때문에 가능하다. 
  • 패스워드 복잡도가 충분하다면 자격 증명에 대한 패스워드 크래킹은 사실상 거의 불가능 하다.

 

03. 리눅스/유닉스 인증과 패스워드

 

04. 서비스 데몬 패스워드

  • 여러 공격 대상 서버 중에서 비집고 들어갈 지점을 찾아서 하는 공격으로, 취약한 계정 하나를 찾으려고 광범위하게 특정 네트워크에 접근을 시도한다.

05. 운영체제별 패스워드 복구

 

CHAPTER05 리버스 엔지니어링

01. 리버스 엔지니어링의 이해

  • 리버스 엔지니어링을 역공학으로 번역하는데, 장치나 시스템 구조를 분석하여 원리를 발견하는 과정을 의미한다.

02. 리버스 엔지니어링 툴

1.이뮤니티 디버거

 

03. 리버스 엔지니어링 공격

 

04. 리버스 언제니어링 대응책

1. 패킹

2. 안티 디버깅

  • 리버스 엔지니어링을 수행하려면 이뮤니티 디버거를 사용하면서 브레이크 포인트를 설정하고, 한 단계씩 실행하여 분석하는 디버깅 과정을 거쳐야 한다. 안티 디버거는 이렇게 수행하는 디버거 활동을 여러 방법을로 탐자라여 프로그램을 강제로 종료한다.

3. 타이밍 체크

  • 프로세서가 디버깅 중일 때, CPU 연산 시간이 정상적으로 실행할 때 보다 많이 걸린다는 점에서 착안한 방법이다. RDTSC 명령을 이용하여 두 구간 사이의 타임스탬프 값을 비교하고, 시간이 많이 걸리는 특정 구간을 디버깅 중으로 판단하여 프로그램이나 디버거를 종료시킨다.

4. 쓰레기 코드 넣기와 코드 치환 

  • 코드 사이에 의미가 없은 쓰레기 코드를 넣고, 다단계 점프문을 섞어 코드를 치환하는 방법이다. 그렇게 함으로서 리버서가 해당 코드를 따라가서 지치게 만든다.

 

CHAPTER06  레이스 컨디션

01 레이스 컨디션 공격의 이해

1. 레이스 컨디션 공격의 기본 아이디어

  • 간단히 말해 일종의 끼워 넣기라고 할 수 있다.
  • 관리자 권환으로 실행되는 프로그램 중간에 끼어들어 자신이 원하는 작업을 하는 것이다. 

2 파일 링크

  • 링크를 쉽게 설명하면 파일을 잇는 끈의 일종이라고 할 수 있다. 링크에는 하드 링크와 심볼릭 링크가 있다. 

2.1 하드 링크

  • 똑같이 복사된 파일을 만드는 것이다.

2.2 심볼릭 링크

  • 하드 링크와 달리 실제 두 파일을 생성하여 링크하지 않는다. 데이터가 있는 파일은 처음부터 하나뿐이고, 심볼릭 링크는 단지 원본 파일 데이터를 가리키는 링크 정보만 가지고 있다.

3. 심볼릭 링크와 레이스 컨디션 공격

  • 임시 파일 존재 여부를 확인한다.
  • 임시 파일이 있다면 삭제하고 재생성 한다.
  • 임시 파일에 접근하고 처리한다.
  • 임시 파일이 존재하면 심볼릭 링크 파일인지 여부를 확인한다.
  • 심볼릭 링크가 아니면 임시 파일을 삭제한다
  • 임시 파일을 심볼릭 링크로 생성한다.

4. 다른 레이스 컨디션 공격 예

  • 어떤 프로그램이 중요한 데이터를 암호화하여 가지고 있다. 프로그램 실행 전에 이 암호환된 파일을 복호화한 후 메모리에 로드하고, 복호화된 임시 파일을 삭제한다고 하자. 다음과 같은 프로세스로 처리할 것이다.
  •  

02. 레이스 컨디션 공격 대응책

  • 프로그램 실행 과정에서 임시 파일의 레이스 컨디션 공격을 막으려면 다음 과정을 거쳐야 한다. 먼저 프로그램 로직 중에 임시 파일을 생성한 후, 생성한 임시 파일에 다시 접근하기 전에 임시 파일에 대한 심볼록 링크 설정 여부와 권한 검사 과정을 추가한다. 이런 내용을 포함한 함수의 사용 예를 보자.

 

CHAPTER07 버퍼 오버플로

01. 스택 버퍼 오버플로 공격

  • 버퍼 : 데이터를 한 곳에서 다른 곳으로 전송하는 동안 일시 보관하는 메모리 영역
  • 스택 버퍼 오버플로 공격은 모든 경우에 가능하지 않고, 프로그래머가 취약한 특정 함수를 사용해야 가능하다.

 

02. 힙 버퍼 오버플로 공격

  • 힙 영역에 대한 버퍼 오버플로 공격의 가장 기본은 관리자 권한을 이용한 데이터 변조이다. 
  • 셸을 얻어 내는 것도 가능하지만, 힙은 기본적으로 실행 영역이 아니기 때문에 스택 버퍼 오버플로처럼 셸을 바로 얻어 내기가 쉽지 않다. 

03. 버퍼 오버플로 공격 대응책과 발전된 공격

 

01. 안전한 함수 사용

  • 버퍼 오버플로 공격에 대응하는 가장 쉽고 효과적이면서 확실한 방법은 버퍼 오버플로에 취약한 함수를 사용하지 않는 것이다.
  • 기본적으로 버퍼 오버플로에 취약한 함수는 사용하지 않는 것이 좋다. 모두 사용하지 않고 프로그램을 작성하려면 무척 번거롭고 프로그램 효율이 떨이지기 때문에 실제로는 많이 쓴다. 따라서, 가능하면 사용자가 접근 가능한 입출력 여지를 줄여야 하며, 꼭 필요할 때는 입력 값의 길이를 검사할 수 있는 함수를 써야 한다.

02. 실행 가능 공간 보호

  • 프로그램은 메모리의 텍스트 세그먼트 부분에 오브젝트 파일 형태로 저장하고 실행한다. 이 부분은 보통 읽기만 가능하고 쓰기가 가능하지 않는데, 프로그램을 실행할 때 추가적으로 필요한 일종의 임시 코드 등을 저장하는 데이터 공간은 스택이나 힙에 저장 된다. 실행 가능 공간 보호는 스택이나 힙에 이렇게 저장된 데이터 공간에서 쓰기만 가능하게 하고, 실행은 할 수 없게 한 것이다. 

03. 스택 가드 

  • 스택 가드는 프로그램을 실행할 때 버퍼 오버플로 공격을 탐지하도록 gcc 컴파일러 확장으로 만들었다. 즉, 컴파일러가 프로그램의 함수를 호출할 때 ret 앞에 canart(카나리아) 값을 주입하고, 종료할 때 canary 값을 변조했는지 여부를 확인하여 버퍼 오버플로 공격을 탐지한다. 

*카나리아 : 카나리아가 위험을 탐지하는 신호 의미로 쓰이곤 한다.

 

04. 스택 실드

  • gcc 컴파일러 확장으로 개발했으며, ret 보호가 주목적이다. 스택 실드는 함수를 호출할 때는 ret를 Global RET Stack이라는 특수 스택에 저장한다. 함수를 종료할 때는 Global RET Stack에 저장된 ret값과 스택의 ret 값을 비교하여 일치하지 않으면 프로그램을 종료시킨다.

05. ASLR

  • 메모리 공격을 방어하려고 주소 공간 배치를 난수화하는 기법이다. 즉, 스택, 힙, 라이브러리 등 데이터 영역 주소 등을 난수화하여 프로세스의 주소 공간에 배치하는 것으로, 리눅스 커널 2.6.12 이후부터 적용했다. 

CHAPTER08 포맷 스트링

01. 포맷 스트링 공격

  • 포맷 스트링 공격은 버퍼 오버플로 공격과 매우 유사하다.

02. 포맷 스트링 공격 대응책

  • 간단하게 다음과 같이 printf 함수를 정상적으로 사용하면 문제가 발생하지 않는다.
  • 문제는 printf처럼 코드가 게으른 프로그래머나 시간이 촉박한 프로그래머가 일으킨다. 
  • 포맷 스트링 공격에 대응하는 데 사용하지 말아야 할 포맷 스트링 공격 취약점을 가진 함수는...
    • fprintf함수
    • sprintf함수
    • snprintf함수

CHAPTER 09  백도어

01. 백도어의 이해

  • 공격자가 이미 관리자 권한을 획득한 상황에서 백도어를 이용한 공격을 시도하는 것이 일반적이다. 
  • 상대방 시스템에 침투하여 권한을 획득하는 것을 해킹으로 한정한다면, 엄밀하게 말해 백도어는 해킹이 아니다.

1. 백도어와 트로이 목마

  • 백도어 종류는 매우 다양하여 시스템과 네트워크의 모든 것을 사용해서 만든다고 생각해도 된다.
  • 백도어는 트로이 목마와 조금 다르다. 백도어의 원래 의미는 운영체제나 프로그램을 만들 때 정상적인 인증 과정을 거치지 않고, 운영체제나 프로그램 등에 접근할 수 있도록 만든 일종의 통로이다.
  • 운영체제를 개발할 때는 정상적인 인증을 거치지 않는 상태에서 관리자 권한으로 어떤 작업을 수행해야 할 때가 있다. 트랩 도어는 이런 상황에서 사용하는 일종의 편법이라고 할 수 있다.

2. 백도어 종류

2.1 로컬 백도어

  • 서버의 셸을 얻어 내 관리자로 권한 상승할 때 사용하는 백도어이다. 
  • 시스템에 로그인한 후 관리자로 권한을 상승시키는 백도어이다. 공격자가 로컬 백도어를 이용하러면 일반 계정이 하나 더 필요하다.

2.2 원격 백도어

  • 로컬 백도어와 달리 시스템 계정이 필요 없다. 원격 백도어는 계정에 패스워드를 입력하고 로그인할 것처럼 원격으로 바로 관리자 권한을 획득하여 시스템에 접근할 수 있는 백도어이다.
  • 서비스를 제공하는 일종의 데몬처럼 동작하는 것이다.

2.3 패스워드 크래킹 백도어

  • 키 로거라도 하는데, 다른 백도어처럼 인증을 회피하지 않는다. 회피보다는 인증에 필요한 패스워드를 원격지의 공격자에게 보내주는 역할을 하는 백도어이다. 

2.4 시스템 설정 변경 백도어

  • 셸을 얻어 낸다기보다 시스템 설정을 해커가 원하는 대로 상화에 따라 변경하는 툴이다.

2.5 트로이 목마 형태의 프로그램

  • 처음부터 백도어를 목적으로 만든 것이 아니지만, 백도어로 동작한다. 
  • 원도우에서는 웹 브라우저나 명령창, 간단한 게임 등도 백도어와 섞을 수 있다. 이렇게 만든 백도어를 동작하면 원하는 프로그램을 실행하면서 동시에 백도어도 설치된다.

2.6 거짓 업그레이드

  • 시스템을 패치하거나 업그레이드할 때 잘못된 프로그램을 설치하는 것이다. 

 

02. 윈도우 백도어

03. 리눅스 백도어

  • 인터넷에서 웹 서비스를 제공하는 데몬은  80번 포트를 사용하는 http데몬이다. 
  • root권한으로 nobody 계정으로 웹에 접속하고 있을 때는 nobody 권한으로 시스템에 자료를 요청하는 것이다.

04. 백도어 탐지 순서와 대응책

1. 현재 동작 중인 프로세스 확인

  • 윈도우와 리눅스 시스템 등 정상 프로세스를 외위두면 좋다. 특히 윈도우 프로세스는 이름을 어느 정도 인지하고 있으면 윈도우 웜이나 바이러스, 백도어를 대응하는 데 큰 도움이 된다. 

2. 열린 포트 확인 

  • 백도어 상당수가 외부와 통신을 하려고 서비스 포트를 생성한다. 
  • 시스템에서는 netstat명령으로 열린 포트를 확인할 수 있는데, 일반 시스템에서 사용하는 포트는 그리 많지 않기 때문에 주의해서 살펴보면 백도어가 사용하는 포트를 쉽게 확인할 수 있다.

3. SetUID 파일 검사

  • 윈도우 시스템에는 해당되지 않지만 SetUID 파일은 리눅스 시스템에서 로컬 백도어로 강력항 기능을 가질 때가 많다.
  • SetUID 파일 중에 추가되거나 변경된 것은 없는지 주기적으로 살펴보아야 한다.

4. 바이러스와 백도어 탐지 툴 이용

  • 잘 알려진 백도어는 대부분 바이러스 일종으로 분류되는데, 백신 툴은 물론이고 다양한 탐지 툴에서 발견된다.
  • 툴을 사용하면 백도어를 쉽게 잡아낼 수 있다. 
  • 리눅스에서는 이런 툴이 많이 부족하므로 수동으로 찾아야 할 때가 많다.

5. 무결성 검사 

  • 시스템에 어떤 변화가 일어나는지 테스트하는 것이다.
  • 관리자가 변경하지 않았거나 시스템 운영상 변할 일이 없다면 변경된 파일을 조치하면 된다. 

6. 로그 분석

  • 방법은 무척 다양하며, 사이버 포렌식이라는 하나의 분야로 정착했다. 

 

 

'시스템 해킹과 보안' 카테고리의 다른 글

PART 03 운영체제 보안  (2) 2024.11.07
PART 01 운영체제 이해  (1) 2024.09.04