Notice
Recent Posts
Recent Comments
Link
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Tags more
Archives
Today
Total
관리 메뉴

Piki's Play

NTFS의 개념 - 다른 속성 개념, 인덱스, 분석 본문

포렌식/파일시스템 (파일시스템 포렌식분석)

NTFS의 개념 - 다른 속성 개념, 인덱스, 분석

Pikigod 2020. 3. 3. 18:55

11.5 다른 속성 개념들

- 이전 절에서 모든 NTFS 속성들에 적용할 수 있는 기본적인 개념들을 확인해 보았다. 모든 속성이 기본적이지는 않기 때문에 이번 절에서는 깊이있는 개념들을 살펴보자. 특별한 파일이 아주 많은 속성을 가질 때 어떤 일이 일어나는지 알아보고 그 다음에는 속성들의 내용을 압축하고 암호화하는 방법들을 알아보자. 

 

 

기준 MFT엔트리

- 한 파일의 속성은 65,536개(16비트 식별자)가 있을 수 있고 속성 헤더를 모두 저장하기 위해 한 개 이상의 MFT엔트리가 필요할 수 있다. 추가적인 MFT엔트리들이 한 파일에 할당될 때, 그 원본은 기준 MFT엔트리가 된다. 비기준 엔트리는 그것들의 필드에 기준 주소를 가질것이다. 

- 기준 MFT엔드리에는 $ATTRIBUTE_LIST타입 속성이 있고 그 속성은 각 파일 속성과 MFT주소가 있는 목록을 포함한다. 비기준 MFT엔트리에는 $FILE_NAME과 $STANDARD_INFOMATION 속성이 없다. 

$ATTRIBUTE_LIST 속성은 12장 '메타데이터 범주'절에서 설명한다.

 

 

Sparse 속성

- NTFS는 비거주 $DATA 속성 값을 Sparse로 저장하여 한 파일에 필요한 공간을 줄일 수 있다. Sparse 속성은 모두 0인 클러스터들이 디스크에 써지지 않도록 하는 것이다. 대신 한 특별한 run이 0 클러스터를 위해 생성된다. 

- 일반 run은 시작위치와 크기를 표현하지만 Sparse run은 단지 크기만을 표현한다. 거기에는 속성이 Sparse인지 아닌지를 나타내는 플래그도 존재한다.

sparse run은 길이만 나타낸다.

 

 

▶ 압축된 속성

- 실제적인 알고리즘이 공개되지는 않았지만 NTFS는 속성들을 압축된 형태로 사용할 수 있다. 이것은 '파일시스템 수준' 압축으로 응용프로그램 수준이 아니다. 마이크로소프트는 $DATA 속성이 비거주일때만 압축할 수 있다고 전하고 있다.

NTFS는 필요한 저장공간을 줄이기위해, Sparse runs와 압축된 데이터 2개를 사용한다. 속성 헤더 플래그는 압축여부를 구분하고, $FILE_NAME과 $STANDARD_INFORMATION 플래그 또한 압축된 속성을 포함한 파일인지 보여준다.

- 속성 내용은 압축되기전에 그 데이터는 '압축유닛'(Compression Units)이라는 같은 크기의 데이터 묶음으로 나뉜다. 그 '압축유닛' 크기는 속성헤더에서 주어준다. 각 압축유닛이 발생할 수 있는 3가지 상황이 있다. 

 

1. Sparse 데이터 Run이 압축 유닛 크기로 만들어지는 경우, 모든 클러스터들은 0을 포함하고 디스크 공간에 할당하지 않는다. 

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

3. 압축 시 결과데이터는 적은 수의 클러스터를 사용한다. 이 경우 데이터를 먼저 run으로 압축하고 디스크에 저장한다. Sparse run은 전체 run길이와 압축 유닛에 클러스터 수를 같도록 만들기 위해 압축된 run 뒤에 따른다. 

 

 

각 시나리오를 확인하기 위해 예를 보자. 압축 유닛 크기는 16개 클러스터이고, $DATA 속성이 64개의 클러스터로 구성되어 있다고 하자. 

위에서 나온 3가지 상황이 다 있다.

-> 내용을 4개의 압축유닛으로 나눠보면 첫 유닛은 16개의 클러스터 그대로 압축되지 않았다. 두 번째 유닛은 모두 0이어서 16개 클러스터는 1개의 Sparse run으로 만들어져 할당되지 않는다. 세 번째 유닛은 10개의 클러스터를 압축해서 그 압축된 데이터는 10개의 클러스터가 한 개의 run으로 디스크에 쓰였다. 남은 6개는 Sparse run으로 압축된 데이터 설명을 위해 더해졌다. 마지막 유닛은 압축되지 않고 16개의 클러스터의 run을 생성했다.

 

- 운영체제나 포렌식 도구는 먼저 압축 플래그가 있는지 없는지 확인을 한다. 이후 압축유닛 크기의 데이터 묶음으로 구성한다. 

 

※ 더 복잡한 예는 다음과 같다. 

runs를 보고 원래의 내용을 만들어보자

-> 병합된 Runs를 보고 원래의 내용을 알아내기는 쉽지않다. 그래서 먼저 6개의 run을 보고 데이터를 구성하는 것이 필요하다. 그 후 16개 클러스터로 이루어진 압축 유닛의 레이아웃을 찾는다. 그 이후 Sparse공간과 일반공간을 결합해서 원래의 내용을 알아낸다.

 

 

암호화된 속성들

- NTFS 속성 내용을 암호화 할 수 있는 기능을 제공한다. 이 절에서는 암호화 방법과, 디스크에 존재하는 형식에 대한 개요를 기술한다. 속성이 암호화 될 때 속성 내용만 암호화되고 속성헤더는 암호화 되지 않는다. 

파일을 위해 $LOGGED_UTILITY_STREAM이 생성되고 그것은 데이터를 복호화하는데 필요한 키를 갖는다. 윈도우에서 사용자는 파일이나 디렉토리를 암호화할 수 있는 선택을 가진다. 이 때 $STANDARD_INFORMATION 속성에는 특별한 플래그를 갖는다. 또한 각 속성은 헤더에 특별한 플래그 설정이 있다.

 

▷ 암호화 기초

- 암호화는 평문데이터를 암호데이터로 변경하기 위해 암호 알고리즘과 키를 사용하는 과정이다. 복호화는 반대로 복호알고리즘과 키를 이용해 암호데이터를 평문데이터로 변경하는 과정이다. 암호알고리즘은 두 가지의 종류로 나타낼 수 있는데 이는 '대칭'과 '비대칭'이다.

대칭 알고리즘은 암호화와 복호화에 같은 키를 사용한다.

비대칭 알고리즘은 암호화키와 복호화 키가 다른 것을 의미한다.

보통 비대칭에서 공개키와 개인키의 개념이 있다. 공개키는 누구에게나 공개되어있는 키이고, 개인키는 본인만 가지고 있는 키다. 보통 이 키들은 전형적으로 1024비트의 길이를 갖는다.

 

▷ NTFS 구현

- NTFS는 $DATA 속성을 암호화할때 DESX라는 대칭 알고리즘을 이용해 암호화한다. 한개의 난수 키는 암호화된 데이터가 있는 각 MFT엔트리를 위해 생성되고, FEK(File Encryption Key)로 부른다. MFT엔트리에 다수의 $DATA가 있으면 그것들은 모두 같은 FEK로 암호화 된다.

- 이 FEK는 $LOGGED_UTILTY_STREAM 속성에 암호화 된 상태로 저장된다. 또한 이 $LOGGED_UTILTY_STREAM 속성은 DDF와 DRF의 목록을 포함한다.

DDF(Data Decryption Fields)는 그 파일에 접근하려는 모든 사용자를 위해 생성되고, 사용자의 SID(Security_ID), 암호화정보, 사용자의 공개키로 암호화된 FEK(즉, 데이터를 얻기 위해서는 사용자의 개인키와 이것을 이용)를 포함한다. 

DRF(Data Recovery Fields)는 데이터 복구를 위해 필요하다. 이것은 데이터 복구 공개키로 암호화된 FEK를 포함한다. 이 공개키는 관리자나 인증된 사용자가 데이터 접근을 하기 위해 필요하다. 

<파일내용과 공개키로 시작하고, 암호화된 내용과 암호화 키로 끝나는 암호화 과정>

 

- $DATA 속성을 복호화 하기 위해 $LOGGED_UTILITY_STREAM 속성을 해석해야 하고, 사용자의 DDF엔트리에서 확인할 수 있다. 사용자의 개인키는 FEK를 복호화 하는데 사용되고, 그 FEK는 $DATA 속성의 복호화를 위해 사용된다. 사용자가 접근을 취소할 때 키는 목록에서 삭제된다. 사용자의 개인키는 윈도우 레지스트리에 저장되고, 대칭알고리즘으로 암호화된다. 그래서 조사하는 동안 사용자의 패스워드와 레지스트리는 어떤 파일을 복호화하던지 필요하다. 

내용, 키, 사용자 패스워드로 시작하고 암호화된 내용으로 끝나는 복호화 과정

 

- 많은 보안 도구들이 패스워드 무작위 대입 공격을 할 수 있고, 이것은 데이터복호화에도 사용된다. 일부 파일들과 디렉토리들이 암호화되어 있다면 암호화 되어 있지 않은 복사본들이 비할당 공간에 있을 수 있다. NTFS의 MFT에 이런 평문이 있는 복사본이 있는데 이 부분이 재할당되어서 지워지지 않았다면 파일은 복구될 수 있다. 

 


 11.6 인덱스 (INDEX)

- NTFS는 많은 상황에서 인덱스 데이터 구조체를 사용한다. 이 절에서는 인덱스에 대해 언급하겠다. NTFS 인덱스는 정렬된 순서로 저장된 속성들의 모임이다. 특히 디렉토리에서 흔히 사용되는데 $FILE_NAME 속성을 포함하기 때문이다. NTFS 3.0 이상부터 $FILE_NAME 외에도 인덱스가 사용된다. 

 

 

▶ B - Trees

- NTFS는 트리, B-Tree로 속성을 정렬한다. 부모노드는 자식노드를 가지고있고 노드 당 최대 2개의 자식을 가지면 이는 이진트리이다. 

 

-> (B)는 (A)와 같은 트리이지만 각 노드에 값이 할당되어 있다. 부모노드보다 작은 값은 왼쪽에 있고 부모보다 큰 값은 오른쪽에 있다. 

 

- NTFS는 위와 비슷한 B-Tree를 사용하지만 노드 당 2개 이상의 자식이 있다. N개의 값을 저장하면 N+1개의 자식 노드가 있을 수 있다.

<B-Tree>

 

- 만약 파일 g.txt를 찾는다면 루트노드에서부터 찾고 e.txt와  L.txt 사이에서 운선 순위를 결정하고 C노드를 해석한다. 

 

3개의 자식노드가 적당하다.

-> i 다음 j이기 때문에 적절한 위치 C에 처음 할당이 된다. 이때 C의 노드가 3개보다 많은 4개로서 적절하지 않다. 그래서 C를 절반으로 나누고 g.txt를 위로 올린다. 그래서 C는 F, G로 분리가 된다. 이때 A가 4개가 되므로 또 반을 나누고 g를 위로 올린다. 이후 모습은 다음과 같다.

 

z.txt와 f.txt를 지운 다음 모습

- 다음 z.txt를 지우면 그대로 모습이고, 추가로 f.txt를 지우는 경우를 생각해 보자. 노드 F가 비워지게 되므로 그것이 채워져야 한다. 따라서 e.txt가 F노드로 이동하고 b.txt가 부모로 올라오면서 양 노드의 균형을 맞춘다. 분석을 할 때 b.txt가 삭제된 파일로 보여질 수 있다. 하지만 이는 삭제가 아니라 f.txt가 삭제되어서 이동된 것이다. 

디렉토리 이름목록을 사용하는 FAT와 같은 파일시스템은 지워진 이름이 존재하는지 아닌지 설명하기 쉽지만 트리의 마지막 결과는 예상하기 어렵다.

 

 

▶ NTFS 인덱스 속성

- 앞에서 B-Tree의 개념을 설명했고 이제 NTFS에서 어떻게 구현했는지 보자. 트리의 각 엔트리는 각 노드에 값들을 저장하기 위해 인덱스 엔트리라 부르는 데이터 구조체를 사용한다. (앞에서 A,B = 인덱스 노드, 그 안에 구조체 = 인덱스 엔트리)

이 인덱스 엔트리에 많은 타입들이 있지만 그것들 모두 같은 표준 헤더필드를 갖는다. 예를 들어 한개의 디렉토리 인덱스 엔트리가 일부 헤더와 $FILE_NAME 속성을 포함한다. 그 인덱스 엔트리들은 트리의 노드로 구성되고, 목록을 저장한다. 비어있는 엔트리는 목록의 마지막이라는 표시이다. 

 

<4개의 인덱스 엔트리가 있는 NTFS 디렉토리 인덱스 트리 내 한 노드>

- 인덱스 노드들은 MFT 엔트리 속성의 2가지 타입에 저장된다. $INDEX_ROOT 속성은 항상 거주이고, 한 개의 노드를 저장한다. 또한 그 노드는 적은 개수의 인덱스 엔트리를 포함 할 수 있다.

- 더 큰 인덱스들은 많은 노드들을 포함할 수 있는 비거주 $INDEX_ALLOCATION 속성을 할당한다. 이 속성의 내용은 한개 또는 그 이상의 인덱스 레코드들을 포함하는 큰 버퍼이다. 

- 1개의 인덱스 레코드는 4096바이트의 고정된 크기를 갖고 인덱스 엔트리들의 목록을 포함한다. 각 인덱스 레코드는 4096바이트의 고정된 크기를 갖고, 주소는 0부터 시작한다.

-> 위 그림은 인덱스 엔트리 3개를 갖는 $INDEX_ROOT속성과 클러스터 713에 할당한 비거주 $INDEX_ALLOCATION 속성이 3개의 인덱스 레코드를 사용하는 예이다. 

 

- $INDEX_ALLOCATION 속성은 인덱스 레코드에서 사용하지 않는 공간을 할당할 수 있다. $BITMAP 속성은 인텍스 레코드의 할당상태를 관리하는데 사용된다. 새로운 내용이 트리에 할당된다면, $BITMAP은 사용가능한 인텍스 레코드를 찾는데 사용한다. 인덱스에 이름이 주어지고 그 인덱스를 위한 $INDEX_ROOT, $INDEX_ALLOCATION, $BITMAP 속성은 모두 헤더에 동일한 이름으로 할당된다. 

 

 


11.7 분석도구들

- 1장에서 언급된 모든 도구들은 NTFS 이미지들을 지원한다. 하지만 자신의 윈도우 시스템을 보기 위해 마이크로소프트에서 제공하는 nfi.exe를 사용할 수 있다. 이 도구는 동적 시스템의 MFT내용, 속성, 이름, 클러스터를 보여준다. 그러나 정적 분석이 어울리는 포렌식에서는 유용한 도구는 아니다.

- MFT 엔트리 각 속성은 고유의 식별자를 할당하고, 1개의 타입 값을 갖는다. 이러한 2개의 값은 어떤 속성이던지 나타낼 수 있다. 

- icat에 그 주소와 속성 타입을 적자. 동일한 타입이 한개이상 존재하면 고유한 식별자를 주어서 구분한다. 예를들어 MFT엔트리 34를 조사한다고 하자. 

'34-48'을 지정해서 $FILE_NAME 속성(타입48)을 확인할 수 있고, 만일 $DATA 속성(타입128)을 확인하고 싶으면 '34-128'을 지정하자. 또한 $DATA 속성이 여러개면 고유 속성 식별자를 지정하자. 속성 ID가 3이면 '34-128-3'을 지정한다. 

 

- TSK istat을 이용해 아래의 속성들을 알 수 있다. 

 

 


p.s 개념적으로 어떤식으로 데이터들이 저장되는지 알것같다.