Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
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

UFS1, UFS2 개념과 분석 - 파일 이름 범주, 큰 그림, 다른 주제 본문

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

UFS1, UFS2 개념과 분석 - 파일 이름 범주, 큰 그림, 다른 주제

Pikigod 2020. 4. 8. 17:46

16.5 파일 이름 범주

- 파일이름 범주는 inode와 다른 메타데이터에 사람이 읽기 가능한 이름들을 할당하는 데이터이다. 이 절에서는 UFS가 데이터를 어디에 저장하는지, 그리고 어떻게 분석하는지 설명하도록 하겠다. 

 

▶ 개요

- UFS1과 UFS2는 ExtX와 동일한 파일이름 데이터 구조체를 사용한다. 디렉토리 엔트리 데이터 구조체는 파일의 이름, inode 주소, 그리고 유형 값을 저장한다. 구조체의 길이는 최대 파일의 길이가 255개 문자인 이름 길이를 참조한다. 이름은 ASCII로 저장되고, Ext이름은 null로 끝나지 않았지만 UFS에서는 null로 끝난다. 

- 디렉토리 엔트리 구조체들은 디렉토리에 할당된 블록에 위치한다. 디렉토리들을 일반 파일과 다르게 타입이 모드필드에 디렉토리로 설정이 되어있다. 디렉토리의 첫 두 엔트리는 '.'과 '..' 디렉토리이다. 각 엔트리는 다음 엔트리를 가리키는 길이 값을 갖고, 마지막 엔트리의 길이는 블록의 마지막을 가리킨다. 삭제 시 이전 엔트리는 삭제된 엔트리가 가리키던 엔트리의 길이를 증가해서 가리킨다. 루트 디렉토리는 항상 inode2에 위치한다. 

 

아래는 예제 파일시스템 이미지를 fls로 분석한 결과이다. 

 

# fls -f openbsd -a openbsd.dd 1921

d/d 1921 :        .

d/d 2 :             ..

r/r 1932 :         file1.txt

r/r 1933 :         file8.txt

r/r 1934 :         file7.txt

r/- * 1935 :       file6.txt

[REMOVED]

-> '*'이 표시된 엔트리는 삭제된 파일이고, 첫 열은 디렉토리 엔트리와 inode에서 보고된 파일 타입이다. 삭제된 파일에 inode열은 타입을 갖지 못하는 것을 알 수 있고, UFS가 파일을 삭제할때 inode에서 타입을 제거한다는 것을 알려준다.

 

- UFS도 ExtX와 마찬가지로 파일이나 디렉토리에 다양한 이름을 제공하기 위해 하드링크와 소프트링크를 제공한다.

하드링크는 파일이나 디렉토리의 두 번째 이름으로 볼 수 있고, 원본파일의 inode를 가리킨다. 그래서 원본 inode에 링크카운트는 증가하게 된다. 

소프트링크는 심볼릭 링크를 이용해 생성된다. 심볼릭 링크는 목적지 파일 경로를 조각이나 블록 포인터에서 사용된 60바이트에 저장한다. UFS는 32비트 포인터 대신 64비트 포인터를 갖고, 그 경로를 저장하는데 120바이트를 갖는다. 

- 유닉스에서 디렉토리들파일명을 저장하고, 다른 파일시스템을 마운트하는 지점으로 사용한다. 많은 BSD 시스템들이 마운트 지점으로 사용중인 디렉토리에 파일들이 어디에 있는지 보여주는 유니온 마운트를 지원한다. 운영체제는 마운트 디렉토리에 파일들과 볼륨의 루트 디렉토리를 결합해 그것들을 하나로 보이게 한다. 

 

 

할당 알고리즘

- BSD와 솔라리스 시스템들의 디렉토리 엔트리는 '첫 번째 적용' 정책으로 할당된다. 운영체제는 각 디렉토리 엔트리들을 검사하고, 파일명 길이를 기초로 하는 실제 필요한 길이와 보고된 엔트리 길이를 비교한다. 만약 보고된 길이가 더 크고 새로운 파일이 그 공간에 적합하면 거기에 이름을 할당한다. 디렉토리 블록들은 그것들이 할당될 때 0으로 영구 삭제된다. 또한 디렉토리 엔트리 구조체은 블록경계를 넘지 못한다. 

- 파일이 삭제될 때 BSD 시스템들은 타입이나 inode 필드들을 영구 삭제하지 않는다. (포인터는 영구삭제함;;)

 

 

 분석기술

- 파일 이름 범주의 분석은 주어진 디렉토리의 하위 디렉토리 목록을 확인하고, 일부 패턴과 특정 이름을 찾는 것들을 포함한다. 이러한 작업을 위해 '루트 디렉토리'의 위치를 찾을 필요가 있다. 루트 디렉토리는 항상 inode 2에 위치하므로 찾기가 쉽다. 그 이후에 디렉토리 엔트리 목록을 처리할 필요가 있다. 

- 디렉토리 내용을 해석할 때 현재 엔트리의 포인터를 사용해서 다음에 할당된 엔트리를 찾을 수 있다. 삭제된 엔트리를 찾을 때 할당된 엔트리의 파일명 끝과, 다음에 할당된 엔트리의 시작 사이의 공간을 조사해야 한다. 만약 이 공간에 어떤 데이터가 디렉토리 엔트리 형식을 만족하면 이는 아마도 삭제된 파일일 것이다. 이제 특정 엔트리를 자세히 보기위해, inode주소를 식별하고, 처리하여 그 파일의 세부적인 정보를 얻을 수 있다.

- 디렉토리가 삭제될 때 inode와 블록 사이의 링크는 삭제될 수 있다. 삭제된 디렉토리 내용을 찾기 위해 '.'과 '..' 엔트리를 찾는 것도 다른 방법이다. 디렉토리 엔트리는 블록단위로 교차하지 않고 각 블록은 새로운 엔트리에서 시작해야 한다. 

 

 

분석 고려사항

- 거의 모든 BSD 시스템들은 삭제된 파일명을 쉽게 찾을 수 있고, inode 값이 제거되지않아 그 파일의 메타데이터를 쉽게 찾을 수 있다. 하지만 솔라리스는 이 inode 값을 영구 삭제해서 추가 데이터를 찾기 힘들다. 만약 삭제된 파일의 inode 값이 존재하면 재할당 여부를 확인해야 한다. 만약 inode 값이 재할당 되어 있으면 그 inode는 다른 파일에 재할당 되었거나 그 파일이 같은 파일시스템에서 다른 곳으로 이동되었을 수도 있다.

- 디렉토리 엔트리 구조체는 숨겨진 데이터가 있을 수 있다.

 


16.6 큰그림

- UFS 시스템 설명을 마무리하기 위해 크기가 25,000바이트인 /dir1/file1.dat 파일을 UFS2 파일시스템에서 할당하고 삭제하는 예를 단계별로 살펴보도록 하겠다.

 

파일 할당 예제

- /dir1/file1.dat 파일을 생성하기 위해서는 dir1 디렉토리를 찾고, 디렉토리 엔트리를 생성한 후 inode를 할당해서 파일 내용에 블록을 할당해야 한다. 여러 개의 데이터 구조체에 접근하는 순서가 운영체제마다 다르기 때문에 여기서는 언급하는 순서가 실제 시스템과는 다를 수 있음을 주의 하자. 이 예제를 간단하게 설명하기 위해 클러스터와 이용 가능한 조각 목록을 유지하는 많은 데이터 구조체들에 대한 과정은 생략했다.

 

1. 먼저 파일시스템 64KB에 위치하고, 크기가 2KB인 슈퍼 블록 데이터 구조체를 읽는다. 이것을 해석하면 블록크기는 16KB이고, 조각 크기는 2KB라는 것을 알 수 있다. 각 실린더 그룹은 32,776 조각과 8,256 inode를 갖는 것을 알 수 있다. 또한 그룹기술자는 각 실린더 그룹에서 40조각에 위치하고, inode 테이블은 56조각에 위치한다. 

2. 다음은 루트 디렉토리에서 dir1 디렉토리 위치를 확인하는 게 필요하기 때문에 inode2를 해석해야 한다. inode2는 실린더 그룹 0에 있고, inode2의 inode 테이블은 블록 56에서 시작한다. 

3. 블록 56의 inode 테이블을 읽고, 세 번째 엔트리(첫 엔트리는 inode 0임)를 처리한다. inode2의 데이터는 루트 디렉토리의 디렉토리 엔트리 구조체가 블록 1096에 위치하는 것을 보여준다.

4. 블록 1096의 루트 디렉토리 내용을 읽고, 디렉토리 엔트리의 목록 내용을 해석한다. 각 엔트리의 보고된 레코드 길이를 이용해서 다음 엔트리를 건너뛰고, 그 중 dir1 이름으로 된 엔트리를 찾을 수 있다. 그 디렉토리의 inode 값은 16,549이다. 루트 디렉토리의 A-time은 업데이트된다. 

5. 그룹 당 inode 수로 inode 16,549를 나눠 그 위치를 확인할 수 있고, 계산된 값은 실린더 그룹2 이다. 그룹2는 블록 65,552에서 시작하고, 블록 65,608에서 inode 테이블이 시작한다. 

6. 블록 65,608에 있는 inode 테이블을 읽어 inode 16,549의 엔트리의 상대적인 위치, 엔트리 37을 해석한다. inode를 분석해서 dir 내용이 블록 66,816에 위치한다는 것을 알 수 있다. 

7. 블록 66,816에서 dir1 내용을 읽고, 디렉토리 엔트리의 목록 내용을 처리한다. 디렉토리에 사용되지 않은 공간을 찾아야 한다. file1.dat 이름은 8문자 길이이므로, 디렉토리 엔트리는 16바이트를 필요로 한다. 2개의 할당된 이름 사이에 공간을 찾는데, 그 공간은 삭제된 파일이 사용하던 공간이다. 그 디렉토리의 M-, C-time은 업데이트 된다.

8. 파일에 inode를 할당해야 한다. 부모 디렉토리와 동일한 실린더 그룹, 그룹2에 할당한다. inode 비트맵을 찾기 위해 먼저 그룹의 시작에서 48조각만큼 떨어져 있는 그룹 기술자 위치를 찾아야 한다. 그룹 기술자는 블록 65,600에 있고, inode 비트맵은 그룹기술자 168바이트에 위치하고 있다는 것을 확인할 수 있다. 그룹 기술자는 또한 상태를 검사하고, 그것이 비할당되어 있는지를 확인한다. 비트맵에서 해당 비트를 설정하고, 그룹 기술자에서 마지막 할당된 inode값을 업데이트하고, 그룹 기술자와 실린더 그룹 요약 영역에 비할당 inode 값을 1 감소한다. inode 주소는 file1.dat 디렉토리 엔트리에 더해진다. 

9. inode 테이블에서 inode 16,651의 상대적 위치인 inode 139 위치를 확인하고, 값을 초기화한다. 시간 값들은 현재 시간으로 설정하고, 링크 값은 1로 설정한다. 또한 모든 필드 및 UID, GID를 설정한다. 

10. 그 파일의 크기는 25,000 바이트이므로, 한 개의 블록과 5개의 조각을 할당할 필요가 있다. 먼저 조각 비트맵의 오프셋을 확인하기 위해 그룹 기술자를 해석해야 하고, 비트맵은 바이트 오프셋 1200에 위치한다. 그룹 기술자는 마지막 할당된 블록으로 블록 67,896을 저장하고 있다. 비할당 조각 비트맵에서 블록 67,904를 조사하고, 그것은 할당되지 않았다는 것을 판단할 수 있다. 이 블록의 비트는 더 이상 비할당 상태가 아니라는 것을 나타내기 위해 0으로 설정하고, 이용 가능한 블록의 카운터는 1 감소한다. 마지막 할당된 포인터 또한 업데이트된다. 5개의 이용 가능한 조각들을 비트맵을 사용해서 찾아야 하고, 그것들은 74,242에서 74,246에 위치한다. 그것들의 비트맵 비트들도 0으로 설정되고, 그 외 조각 할당과 관련된 값들을 업데이트해야 한다. 블록 주소와 조각 시작은 inode에 더해진다.

11. File1.dat의 파일 내용은 할당된 블록과 조각에 써진다. 

 

파일시스템의 마지막 상태는 아래와 같다.

<'dir1/file1.dat' 파일이 추가된 후 파일시스템의 마지막 상태>

 

 

▶ 파일 삭제 예제

- 지금부터는 BSD 시스템에서 /dir1/file1.dat 파일이 어떻게 삭제되는지 알아본다. 

 

1. 먼저 파일시스템 64KB에 위치하고, 크기가 2KB인 슈퍼 블록 데이터 구조체를 읽는다. 이것을 해석하면 블록크기는 16KB이고, 조각 크기는 2KB라는 것을 알 수 있다. 각 실린더 그룹은 32,776 조각과 8,256 inode를 갖는 것을 알 수 있다. 또한 그룹기술자는 각 실린더 그룹에서 40조각에 위치하고, inode 테이블은 56조각에 위치한다. 

2. 다음은 루트 디렉토리에서 dir1 디렉토리 위치를 확인하는 게 필요하기 때문에 inode2를 해석해야 한다. inode2는 실린더 그룹 0에 있고, inode2의 inode 테이블은 블록 56에서 시작한다. 

3. 블록 56의 inode 테이블을 읽고, 세 번째 엔트리(첫 엔트리는 inode 0임)를 처리한다. inode2의 데이터는 루트 디렉토리의 디렉토리 엔트리 구조체가 블록 1096에 위치하는 것을 보여준다.

4. 블록 1096의 루트 디렉토리 내용을 읽고, 디렉토리 엔트리의 목록 내용을 해석한다. 각 엔트리의 보고된 레코드 길이를 이용해서 다음 엔트리를 건너뛰고, 그 중 dir1 이름으로 된 엔트리를 찾을 수 있다. 그 디렉토리의 inode 값은 16,549이다. 루트 디렉토리의 A-time은 업데이트된다. 

5. 그룹 당 inode 수로 inode 16,549를 나눠 그 위치를 확인할 수 있고, 계산된 값은 실린더 그룹2 이다. 그룹2는 블록 65,552에서 시작하고, 블록 65,608에서 inode 테이블이 시작한다. 

6. 블록 65,608에 있는 inode 테이블을 읽어 inode 16,549의 엔트리의 상대적인 위치, 엔트리 37을 해석한다. inode를 분석해서 dir 내용이 블록 66,816에 위치한다는 것을 알 수 있다. 

7. 블록 66,816에서 dir1 내용을 읽고, 디렉토리 엔트리의 목록 내용을 처리해서 File1.dat 파일의 엔트리를 찾는다. 그 파일의 엔트리를 찾고, 그 파일이 inode 엔트리 16,651에 할당되었다는 것을 할 수 있다. 디렉토리 엔트리는 이전 디렉토리 엔트리, 12.jpg 파일의 레코드 길이 필드에 그 레코드 길이를 더해서 비할당한다. 만약 시스템이 솔라리스 시스템이었다면 inode 포인터 또한 제거된다. Dir1 디렉토리의 M-, A-, C-time이 갱신된다. 

8. 그룹 2 inode 테이블에서 inode 16,651의 내용을 해석하고, 삭제되었다는 것을 표시하기 위해 링크 카운트 1을 감소시킨다. 결국 링크 카운트는 0이 되고, inode는 이제 할당이 해제되었다는 것을 의미한다. inode를 비할당하기 위해 inode 비트맵에 해당하는 비트를 0으로 설정하고, 그룹 기술자와 실린더 그룹 요약 영역에 비할당 inode 카운트를 업데이트한다. inode에서 모드 값은 제거된다. 

9. 할당된 한 개의 블록과 5개의 조각을 해제할 필요가 있다. 블록과 조각 비트맵에 해당하는 비트는 1로 설정되고, inode의 블록 포인터는 제거된다. 파일 크기는 블록이 할당이 해제될 때 마다 감소하고, 결국 0으로 된다. M-, C-time은 inode가 변경되는 시간을 반영해 갱신된다. 비할당 블록과 조각 카운트는 그룹 기술자와 실린더 그룹 요약 영역에서 업데이트된다.

 

※ 이 삭제 과정을 마친 후 파일시스템의 마지막 상태는 아래 그림과 같다.

<'dir1/file1.dat' 파일 삭제 이후의 마지막 상태>

 


16.7 다른 주제

- 여러 데이터 범주에 적용할 수 있는 파일 복구와 파일 시스템 일관성 검사 주제를 앞으로 언급하겠다.

 

파일 복구

- 삭제된 UFS 파일을 복구하는 작업은 그리 쉽지 않다. 이 복구작업의 어려움에 대한 내용은 ExtX에서 이미 설명했다. 솔라리스에는 삭제된 파일 복구가 더 어렵다. 이유는 디렉토리 엔트리와 inode연결이 완전히 삭제되어 있기 때문이다. 직접 블록 포인터는 BSD 시스템에서 영구 삭제되어있어 복구는 응용프로그램 수준의 데이터 수집 기술에 의존할 수 밖에 없다. 마지막 데이터는 조각들에 남아있을 가능성이 크다. 

- 많은 BSD 시스템들은 64KB나 128KB의 연속적인 블록에 파일을 할당한다. 그렇기 때문에 조사에 도움이 된다. 하지만 이것은 파일 전체를 연속적인 블록에 놓는 '자동 맟줌' 정책만큼 도움이 되지는 않는다. 특히 일부 파일시스템은 파일이 단일그룹에 할당할 수 있는 블록 수가 제한되어있기 때문에 큰 파일들은 파일이 연속적인 블록에 할당되더라도 단편화가 일어난다. 솔라리스는 첫 12블록을 할당 후 실린더 그룹을 변경하기 때문에 이러한 파일들의 데이터를 수집하는 것은 매우 어렵다. 간접 블록 포인터의 내용은 BSD나 솔라리스에서 영구 삭제하지 않기 때문에 그 포인터를 찾는다면 복구에 도움을 줄 수 있다.

 

 

일관성 검사

- 일관성 검사는 파일시스템 데이터 구조체에서 유효한 값을 찾아서 용의자가 숨긴 데이터를 찾는 목적으로 수행된다. 먼저 파일시스템 범주의 슈퍼블록을 조사한다. 슈퍼블록의 2048바이트 모두 사용하지는 않기 때문에 거기에 데이터를 숨길 수 있다. 도한 슈퍼블록 전에 사용하지 않는 섹터들은 부트코드와 디스크 레이블에서 사용될 수 있지만 쿠팅 파일시스템이 아닌 경우에는 사용되지 않는다. 슈퍼블록은 전체 블록에 할당되기 때문에 블록에서 사용하지 않는 조각들은 데이터를 숨기는데 사용될 수 있다. 

- 그룹기술자 또한 데이터를 숨기는데 사용될 수 있다. 데이터 구조체의 시작은 구조체를 갖지만, 그 나머지 부분이 큰 경우가 있어서 데이터를 숨기는데 사용될 수 있다. 이것을 위한 검사는 비트맵 구조체가 어디서 시작하는지, 실제 그것들이 필요한 공간은 얼마인지 비교해야 한다. 

- 할당된 inode 엔트리 모두를 검사해야한다. 또한 그 inode 엔트리가 가리키는 블록과 조각들이 할당되었는지를 검증해야한다. 모든 할당된 블록은 실린더 그룹 관리 데이터 구조체에서 사용되거나, inode가 가리키고 있어야 한다. inode 테이블 마지막 또한 사용하지 않는 바이트들이 있을 수 있다.

- 할당된 모든 디렉토리 엔트리는 할당된 inode 엔트리를 지정한다. inode 0~2는 예약된 inode로서 그 inode를 가리키는 파일명은 없지만 할당되어 있다.

- 디렉토리 끝에 공간에 데이터를 숨길 수는 있지만, 운영체제가 그 공간을 덮어쓸 수 있기 때문에 공격자가 숨기기는 쉽지않다. 

 

 

 요약

- 많은 서버 환경에서 UFS 파일시스템을 볼 수 있다. 블록과 조각들의 할당을 돕기위해 존재하는 많은 구조체들이 있지만 이 장에서는 설명하지 않았다. 또한 슈퍼블록에는 다른 값들을 계산하는데 필요한 값들을 가지고 있다. 이것은 슈퍼블록과 파일시스템 범주의 데이터 구조체를 이전에 본 것보다 더 크게 만든다. 

UFS 파일시스템 분석 중 가장 어려운 것 중 하나는 삭제된 파일을 복구하는 것이다. 그 이유는 블록 포인터가 영구 삭제되고, 솔라리스는 심지어 이름과 그 inode 사이의 포인터까지 영구삭제하기 때문이다. 그래서 응용프로그램 수준의 복구 기술이 필요하지만, 이는 블록 할당 루틴으로 인해 한개의 파일이 여러 실린더 그룹에 있을 수 있어 어려울 수도 있다. 구조체와 UFS 파일 시스템의 삭제 방법은 FAT나 NTFS와 상당히 다르지만 기본 분석 기술은 동일하다. 

 


p.s 학교 과제도 하느라 정신이 없네