[Digital Forensic] NTFS 파일 시스템 분석 (1)

 

NTFS 파일 시스템


(1) NTFS란 ?

  • Microsoft 사에서 설계한 파일 시스템 으로 윈도우 NT, 2000, XP, 2003, 2008, 7, 10 등 많은 버전에서 사용하는 파일 시스템

  • FAT는 이동형 디스크에 많이 사용되며 고정식 디스크에는 대부분 NTFS를 사용한다고 봐도 무리가 없음

  • 많은 특징들을 제공하는데, 많은 특징만큼 확장성도 뛰어남

  • 뛰어난 만큼의 복잡성을 가지고 있는 파일 시스템이기에 분석이 FAT처럼 쉽지만은 않음

  • 신뢰성, 보안, 대용량 장치를 지원하기 위해 설계

  • 특정 내용으로 데이터 구조체를 감싸는 포괄적 데이터 구조체(Wrapper)를 사용해서 확장성 제공

NTFS 명세는 MS에서 모두 공개하지 않아 부정확한 면도 없지 않아 있다.

 

NTFS는 많은 윈도우의 표준이며, 거의 모든 공개 유닉스에서도 지원할 만큼 범용적이다.

 

하지만 비 공식적 명세와 출시된 응용 프로그램들이 만나 파일 시스템을 생성하기 때문에 응용 프로그램 종속 속성과 파일 시스템의 일반적 속성을 구분하기가 힘들어졌다.

 

 

중요한 NTFS 기능은 다음과 같다.

  • b-tree 개념 (파일 클러스터 추적할 때 사용)

  • 클러스터의 대한 정보를 클러스터에 같이 저장

  • 대략 160억 바이트 용량 파일 지원

  • 접근 제어 (ACL 사용 가능)

  • 파일 압축

  • 유니코드 기반 파일 이름 지원, 긴 파일 이름 지원

  • 이동식 디스크, 고정식 디스크 모두 보안 기능 지원

 

NTFS의 레이아웃은 다음 그림과 같다.

 

[그림 1] NTFS 레이아웃

 

VBR

  • 도스 파티션의 MBR 영역과 비슷하게 부트 섹터와 부트 코드가 위치하고 있는 영역

  • 해당 영역 크기는 섹터 단위가 아닌 클러스터 크기에 따라 변동 됨

 

MFT

  • NTFS 시스템에서 가장 핵심적인 요소

 

Data

  • 여러 가지 데이터가 위치하는 영역

 

위와 같이 보면 레이아웃이 매우 간단해 보이지만 의외로 복잡하게 구성 되어 있어 분석이 까다로운 파일 시스템이다.

 

NTFS는 시스템 내에서 중요한 데이터가 파일로 취급된다.

 

다른 말로 하면 NTFS 시스템 내 관리 데이터 들이 파일로 취급 받는다.

 

이러한 이유로 관리 데이터들이 일반 파일처럼 파일 시스템 어떤 위치에도 위치할 수 있게 된다.

 

그래서 NTFS는 다른 파일 시스템들과 달리 특정 레이아웃을 갖고 있지 않다.

 

다만, NTFS 볼륨 첫 섹터에는 부트 섹터가 있고, 부트 섹터에는 부트 코드가 포함되어 있을 뿐이다.


(2) 클러스터

  • NTFS에서 파일은 속성의 집합이라고 할 수 있음

  • 일부 속성은 거주 속성으로 MFT 엔트리에 존재

  • 나머지 속성들은 비거주 속성으로 클러스터에 그 내용이 존재

 

NTFS에서 클러스터는 다른 파일 시스템과 마찬가지로 연속적인 섹터의 그룹을 의미한다.

 

클러스터 수는 2^2이어야 하며, FAT 파일 시스템과는 다르게 NTFS에서는 클러스터 주소가 0으로 시작한다.

 

클러스터 0은 파일 시스템의 첫 번째 섹터를 포함하며, 클러스터 주소를 섹터 주소로 변환하기 위해 다음과 같은 계산식을 적용한다.

 

클러스터 X 클러스터 별 섹터 수 = 섹터


(3) MFT

  • 파일 시스템의 모든 파일들과 디렉토리에 대한 정보를 포함하고 있는 것으로 NTFS의 핵심

  • 모든 파일과 디렉토리는 MFT에 꼭 하나의 엔트리를 가지고 있으며, 매우 간단

  • NTFS를 설계한 MS사에서는 MFT 엔트리를 파일 레코드(File Record)라고 부름

 

다음은 MFT 엔트리 구조이다.

 

[그림 2] MFT 엔트리 구조

 

엔트리 크기는 1KB이며, 헤더는 미리 정의된 목적을 갖는다.

 

속성 영역은 특정 목적을 갖는 작은 데이터로 이루어져 있다.

 

각 MFT 엔트리는 테이블 내 주소를 갖고, 해당 주소는 0부터 시작한다.

 

보통 엔트리 크기는 1KB이지만, 정확한 크기는 부트 섹터에서 정의한다.

 

MFT도 시스템 내에서는 하나의 파일로 취급되어 MFT를 설명하는 MFT 엔트리가 MFT 안에 포함되어 있다.

 

MFT를 설명하는 엔트리 이름은 $MFT이며, 해당 엔트리는 MFT의 디스크 위치를 설명한다.

 

MFT의 전반적인 레이아웃과 크기를 파악하려면 $MFT 엔트리를 참조해야 하며, MFT 시작 위치는 부트 섹터에서 정의한다.

 

$MFT 엔트리는 MFT 첫 번째 엔트리이므로 쉽게 $MFT 엔트리를 찾을 수 있다. 

 

MS는 MFT를 가능한 작게 시작하고, 필요할 때 크기를 확장할 수 있도록 NTFS를 설계하여 운영체제에 의해 파일 시스템이 생성될 때에는 MFT에 고정 엔트리 수의 엔트리를 생성한다.

 

볼륨 스패닝 등으로 저장 공간이 늘어날 시에는 MFT를 동적으로 늘려 파일 시스템을 크게 만들 수 있게 하였다.

 

그리고 한 번 생성된 MFT 엔트리는 지워지지 않는다.

 

엔트리 크기는 원래 부트 섹터에서 정의하지만, MS 모든 윈도우 버전들은 보통 1KB 크기를 갖는다.

 

MFT 헤더는 42바이트 크기이며, 12개 필드를 포함하고 있고, 나머지 982바이트는 비구조적으로 속성 값들을 포함하고 있다.

 

MFT 엔트리 첫 번째 필드는 시그니처인데, 보통 시그니처로는 'FILE' 문자열이 사용된다.

 

하지만, 엔트리 오류 등이 생길 시에 시그니처 필드는 'BAAD'라는 문자열을 갖도록 되어 있다.

 

또 MFT 엔트리는 엔트리 할당 상태, 타입 구분 필드 등이 있으며 파일이 하나의 엔트리만으로 설명되지 않을 경우 여러 엔트리를 사용할 수도 있다.

 

MFT 엔트리는 48bit 주소(파일 번호) 값을 가지며, 순차적으로 주소가 할당되고, 주소 시작은 0부터이다.

 

첫 번째 엔트리가 주소 0을 가지며, MFT 최대 주소는 MFT 크기가 증가할 때마다 변경된다.

 

또 MFT는 주소 외에 다른 순서 번호를 가지며, 해당 순서 번호는 16비트이고, 48bit의 주소와 조합되어 64bit의 파일 참조 번호를 생성하는데 사용된다.


(4) 메타데이터 파일

  • 볼륨의 모든 바이트가 파일로 할당되어 이를 관리하는 데이터를 저장할 파일이 필요

  • 위와 같은 다른 데이터의 관리 데이터를 저장한 파일을 메타데이터라 부름

  • MFT의 첫 16개 엔트리들로 예약되어 있으며, 사용하지 않는 엔트리들은 비할당 상태가 아닌 할당 상태

  • 오직 기본적이고 일반적인 정보만을 포함

  • 사용자에게는 보이지 않지만, 루트 디렉토리로 존재

  • 각 파일들은 '$'로 파일명이 시작되고, 첫 번째 문자는 대문자로 시작

 

다음은 MFT 메타데이터에 대한 목록이다.

엔트리 번호

파일 이름

설명

0

$MFT

MFT의 전반적인 레이아웃과 크기 설명

1

$MFTMirr

MFT 엔트리 복사본

2

$LogFile

메타데이터 트랜젝션 기록

3

$Volume

볼륨 레이블 / 식별자 / 버전 등 정보 저장

4

$AttrDef

식별자 값 / 이름 / 크기 등 속성 정보 저장

5

.

파일 시스템 루트 디렉토리 저장

6

$Bitmap

파일 시스템에 있는 각 클러스터 할당 상태 저장

7

$Boot

파일 시스템 부트 섹터와 부트 코드 저장

8

$BadClus

불량 섹터가 있는 클러스터 저장

9

$Secure

파일 보안과 접근 제어 정보 저장 

10

$Upcase

유니코드 문자의 대문자 저장

11

$Extend

파일 추가 정보 저장

12 ~ 15

이름 없음

만약을 위한 예약 파일

번호 없음

$ObjId

파일의 고유 ID 저장

번호 없음

$Quota

사용자별 할당량 정보 저장

번호 없음

$Reparse

Reparse point 정보 저장

번호 없음

$UsnJrnl

Usn 저널 정보 저장


(5) MFT 엔트리 속성

  • 속성은 많은 타입들이 있으며, 각각 속성들은 자신의 내부 구조체를 가짐

  • NTFS는 다른 파일 시스템과 달리 파일 내용에 대한 속성이 있음

  • 속성은 3개로 나누어져 있는데 한 개의 속성마다 헤더가 존재

[그림 3] MFT 엔트리 구조

 

속성 헤더는 속성 타입, 크기, 이름을 구분지으며, 해당 값들이 압축, 암호화가 되었는지를 식별하는 플래그 값도 포함하고 있다.

 

속성 내용은 형식과 크기가 정해져 있지 않다.

 

이로 인해 속성 내용의 크기가 엔트리 크기보다 커지는 경우가 발생하여 NTFS에서는 두 가지 속성을 통해 속성 내용의 저장 장소를 판단한다.

 

MFT 엔트리 속성은 대부분 거주 속성이지만, $DATA, $ATTRIBUTE_LIST와 같이 크기가 유동적인 것들은 비거주 속성이 될 수 있다.

 

  • 거주(Resident) 속성 : 속성 내용이 엔트리 크기보다 작은 경우 엔트리 내 속성 내용을 저장

  • 비거주(Non-Resident) 속성 : 속성 내용이 엔트리 크기보다 클 경우 외부에 별도 클러스터를 할당받아 해당 클러스터에 속성 내용 저장

 

두 속성의 결정은 속성 헤더에서 결정하며, 비거주 속성이 될 경우 MFT 엔트리 속성 헤더에는 할당 받은 클러스터 주소가 포함되게 된다.

 

[그림 4] 비거주 속성 

 

만약 속성이 비거주 속성으로 판명되어 클러스터를 할당 받아 속성 내용을 저장한다고 하더라도, 할당 받은 클러스터 크기를 초과하면 또 다른 클러스터를 할당 받아 저장하게 된다.

 

하지만 새롭게 할당 받은 클러스터는 연속된 클러스터일 수도 있지만, 대부분 비연속적 클러스터일 가능성이 더 높다.

 

이럴 때 NTFS에서는 클러스터 런(Cluster Runs)이라는 것을 활용하여 비연속적으로 할당된 클러스터를 효과적으로 관리한다.

 

그리고 Run이라고 하는 것을 이용하여 각 클러스터를 문서화한다.

 

이러한 run을 목록화 해둔 것을 runlist라고 하며, run의 구조는 run의 길이(클러스터 개수)와 클러스터 시작 오프셋(파일 시스템 처음 오프셋부터)으로 이루어져 있다.

 

속성에는 표준적인 유형들이 있는데 속성 타입들은 번호로 정의되어 있으며, MS에서는 해당 번호들은 식별자로 사용한다.

 

각 속성 타입은 이름을 가지고, 모두 대문자로 구성되어 있다.

 

그리고 MFT 메타데이터와 동일하게 '$'로 시작한다.

 

 

다음은 표준 속성에 대한 목록이다.

식별자

속성 이름

설명

16

$STANDARD_INFORMATION

플래그, 접근 / 수정 / 생성 시간, 소유자와 보안 ID 등 정보 저장

32

$ATTRIBUTE_LIST

다른 속성의 위치 정보 저장

48

$FILE_NAME

파일 이름(Unicode), 접근 / 수정 / 생성 시간 저장

64

$VOLUME_VERSION

볼륨 정보 저장(Windows NT만 존재)

80

$OBJECT_ID

파일 또는 디렉토리의 16비트 고유 식별자 저장(Windows 2000 이상 존재)

96

$VOLUME_NAME

볼륨 이름 저장

112

$VOLUME_INFORMATION

파일 시스템 버전과 다른 플래그들 정보 저장

128

$DATA

파일 내용 저장

144

$INDEX_ROOT

인덱스 트리의 루트 노드 저장

160

$INDEX_ALLOCATION

$INDEX_ROOT 속성에 연결되어 있는 인덱스 노드 정보 저장

176

$BITMAP

$MFT 비트맵 정보 저장

192

$SYMBOLIC_LINK

소프트 링크 정보(Windows NT만 존재)

208

$EA_INFORMATION

OS/2 응용 프로그램과의 호환성을 위해 사용(HPFS)

224

$EA

OS/2 응용 프로그램과의 호환성을 위해 사용(HPFS)

256

$LOGGED_UTILITY_STREAM

암호화된 속성에 대한 키와 정보 저장(Windows 2000 이상 존재)

 

위 표에서 목록화된 속성들이 모두 파일에 존재하는 것은 아니다.

 

대부분 기본 파일에 할당된 MFT 엔트리는 $STANDARD_INFORMATION, $FILE_NAME, $DATA 속성만 갖는다.

 

$STANDARD_INFORMATION 속성의 경우 보안, 임시 정보, 소유권 등을 나타내기 때문에 모든 파일과 디렉토리에 있어 강제적 속성이다.

 

$FILE_NAME 속성의 경우 파일 이름, 크기, 임시 정보 등을 나타내기 때문에 이 속성 또한 모든 파일과 디렉토리에 있어서 강제적 속성이다.

 

$DATA 속성은 파일 내용을 저장하는 속성으로 파일 내용이 엔트리 크기를 초과한다면 비거주 속성으로 판단되어 별도의 클러스터에 파일 내용을 저장하게 된다.

 

기본적인 $DATA 속성은 이름을 갖지 않지만, 비거주 속성으로 인해 추가적인 $DATA 속성이 생긴다면 해당 속성은 이름을 반드시 가져야 한다.

 

하지만, 해당 이름은 따로 정해진 것이 없으며, 디렉토리에 $DATA 속성에는 어떠한 내용도 저장될 수 있다.

 

모든 디렉토리는 $INDEX_ROOT 속성을 가지며, $INDEX_ROOT 속성은 해당 디렉토리 내에 위치한 파일들과 하위 디렉토리 정보를 포함한다. ($INDEX_ROOT, $INDEX_ALLOCATION 속성 이름은 일반적으로 $I30)

 

디렉토리가 커지면 $INDEX_ALLOCATION 속성과 $BITMAP 속성을 사용하게 된다.

 

또 디렉토리에도 $DATA 속성이 있을 수 있으며, 디렉토리에 있는 $DATA 속성에는 해당 디렉토리의 하위 디렉토리 목록과 파일 내용 등이 저장된다.

 

[그림 5] 기본 MFT 엔트리 속성

 

다른 여러 가지 속성들을 알아보기 전에 참고로 알아두어야 할 것이다.

 

바로 '기준 MFT 엔트리'와 '비기준 MFT 엔트리'라는 개념이다.

 

기준 MFT 엔트리는 MFT 엔트리에 속성이 65536개가 올 수 있는데 이 모든 속성의 헤더를 저장하려면 하나 이상의 MFT 엔트리가 필요하게 된다.

 

이런 경우 추가적인 MFT 엔트리가 필요한데 추가적으로 MFT 엔트리가 파일이나 디렉토리에 할당될 시 기존에 할당되어 있던 MFT 엔트리가 기준 MFT 엔트리가 된다.

 

쉽게 말하자면, 원본 MFT 엔트리가 아닌 추가적으로 할당된 MFT 엔트리가 비기준 MFT 엔트리가 되는 것이다.

 

기준 MFT 엔트리에는 하나의 $ATTRIBUTE_LIST 속성이 있고, 해당 속성은 파일 속성과 MFT 주소가 있는 목록을 포함한다.

 

그리고 비기준 MFT 엔트리에는 $FILE_NAME과 $STANDARD_INFORMATION 속성이 없다.


(6)스파스 속성(Sparse Attribute)

  • 압축 기능 중 하나이며, 파일에 0으로 채워진 클러스터를 제외하고 디스크에 기록하는 기능

  • NTFS에서도 이 기능을 속성으로 지원하는데 NTFS에서는 $DATA 속성 값을 이 속성으로 정의하여 하나의 파일을 압축

  • FAT 파일 시스템과는 다르게 제외된 0으로 채워진 클러스터를 위해 runlist에 0으로 채워진 클러스터에 대한 run을 하나 생성

 

기본적으로 run은 시작 클러스터 위치와 크기를 포함하지만, 0으로 채워진 클러스터를 위해 생성된 run은 데이터로 크기만 가질 뿐 시작 위치는 포함하지 않는다.

 

0으로 채워진 클러스터를 위한 run이라는 것을 표시하기 위한 플래그 값도 포함하며, 이러한 run은 'sparse run'이라고 한다.

 

[그림 6] Sparse run

 

 

RunList는 스파스 속성 클러스터의 RunList이다.

클러스터 번호

정보

종류

1

시작 위치 : 100, 길이 : 5

Run

2

시작 위치 : x, 길이 : 2

Sparse Run

3

시작 위치 : 160, 길이 : 5

Run

 

속성의 압축

  • NTFS에서 지원하는 속성 압축은 파일 시스템 수준의 압축으로 $DATA 속성이 비거주 속성일 때만 압축 가능

  • 속성이 압축되었는지 판단하는 것은 속성 헤더

  • $STANDARD_INFORMATION, $FILE_NAME 속성 플래그는 해당 파일이 압축된 속성을 포함하였는지 판단하도록 정보 제공

  • 속성 내용이 압축되기 전에 속성 내용은 유닛이라는 같은 크기의 단위로 나뉘게 됨 (압축 유닛 크기는 속성 헤더에서 결정)

 

압축 유닛이 생성될 때 발생할 수 있는 경우가 3가지 정도 있는데 이는 다음과 같다.

 

  • Sparse run이 압축 유닛 크기로 만들어지는 경우, 모든 클러스터는 0을 포함하게 되고 디스크 공간에 할당되지 않음

  • 압축될 때 압축 결과는 저장을 위한 같은 수의 클러스터가 필요한데, 이 경우 압축 유닛은 압축되지 않고 하나의 run이 원본 데이터로 만들어짐

  • 압축될 때 압축 결과는 적은 양의 클러스터를 사용하며, 이 경우 압축 결과를 디스크에 run으로 압축 후에 저장하고, sparse run은 전체 run 길이와 압축 유닛에 클러스터 수를 같도록 하기 위해 압축된 run 뒤에 위치하게 됨

 

속성의 암호화

  • NTFS는 속성을 압축하는 기능 뿐만 아니라 암호화하는 기능도 있음

  • OS별로 보았을 때 윈도우를 제외한 OS는 여러 가지의 속성을 암호화할 수 있고 윈도우는 $DATA의 속성만을 암호화

  • 암호화 시 속성 헤더를 제외한 속성 내용만 암호화

  • $LOGGED_UTILITY_STREAM 속성이 암호화 된 파일을 복호화하기 위해서 사용하는 복호화 키를 포함

  • NTFS에서는 암호화 알고리즘으로 3DES 알고리즘을 사용

  • 3DES 알고리즘은 대칭 알고리즘인 DES를 연속으로 3번 적용한 알고리즘

 

복호화할 때 사용되는 난수 키는 암호화 된 각 MFT 엔트리를 위해 생성되며, NTFS에서는 'FEK(File Encryption Key)'라고 한다.

 

만약 MFT 엔트리에 여러 개의 $DATA가 있다면, 그것들은 모두 같은 FEK로 암호화 되는 것을 뜻한다.

 

FEK는 $LOGGED_UTILITY_STREAM 속성에 암호화 된 상태로 저장되는데, 해당 속성은 DDF(Data Decryption Fields)와 DRF(Data Recovery Filelds)의 목록을 포함한다.

 

DDF는 해당 파일에 접근하려는 모든 사용자를 위해 생성되는 것이며, 포함하는 데이터로는 사용자 SID, 암호화 정보, 사용자 공개 키로 암호화 된 FEK를 포함한다.

 

DRF는 데이터 복구를 위해 생성되는 것이며, 데이터 복구 공개 키로 암호화 된 FEK를 포함한다.

 

[그림 7] 암호화 과정

 

사용자 공개 키는 레지스트리 저장되며, 해당 키는 로그인 패스워드를 키로 하는 대칭 알고리즘으로 암호화되어 있다.

 

암호화가 되었다면 해당 내용을 사용자에게 보여주기 위해서는 복호화가 이루어져야 한다.

 

복호화 과정은 암호화된 FEK가 포함되어 있는 $LOGGED_UTILITY_STREAM을 참조하고, 참조하여 얻은 FEK를 사용자 공개 키로 복호화하여, 복호화된 FEK를 $DATA 속성 내용 복호화하는 것이다.

 

[그림 8] 복호화 과정

 

대부분 보안 도구들이 이러한 암호화를 풀기 위해 무작위 대입 공격 등을 시도하는 기능들이 들어있다.

 

하지만 성공률은 시간에 따라 달라 오래 걸릴 수 있고 짧게 걸릴 수도 있어 무조건적인 신뢰는 하지 않는 것이 좋다.

 

일부 디렉토리들과 파일들이 암호화 되어 있다면 암호화 되지 않은 파일 내용이 복사본이 불특정 비할당 영역 어딘가에 존재할 수도 있다.

 

이는 NTFS 설계 상의 취약점이며, 이러한 문제로 인해 평문 파일 내용이 저장된 EFS0, TMP 임시 파일이란 것이 생성되고, 이 파일은 MFT 엔트리가 재할당되지 않았다면 충분히 복구가 가능하다.

 

또 Swap 공간이나 페이지 파일 또한 암호화 되지 않은 평문 내용의 복사본을 포함하기도 한다.

 

하지만 이런 수고를 할 필요 없이 관리자나 도메인 컨트롤러, 해당 사용자 계정을 알고 있다면 바로 접근하고자 하는 암호화 파일에 접근하여 내용 확인이 가능하다.

 


# Reference

 

http://www.yes24.com/Product/Goods/8511539

+ Recent posts