tmxklab
[Volatility] 프로세스 조사 본문
1. pslit 플러그인
- 프로세스 리스트 출력(리스트워킹-가상주소)
- Double Linked List 탐색에 의존
- DKOM 탐지 못함
vol_2.6.exe -f <메모리 이미지 파일> --profile=<프로파일 명> pslist
[ pslist 도움말 확인 ]
vol_2.6.exe -f "IE11 - Win7 (2)-462275e1.vmem" --profile=Win7SP0x86 pslist -h
[ 출력 결과 리다이렉션 ]
vol_2.6.exe -f "IE11 - Win7 (2)-462275e1.vmem" --profile=Win7SP0x86 pslist --output-file=result.txt
프로세스들은 Double Linked List구조로 되어있음, 다음 링크를 통해 참고하자
2. psscan 플러그인
- 프로세스 구조체 스캔 후 출력(패턴매칭-물리주소)
- _EPROCESS 객체의 Double Linked List를 탐색 x
- 프로세스 객체의 시그니쳐를 스캔
- 종료된 프로세스와 숨겨진 프로세스 탐지 가능 (DKOM, pool tag scanning)
vol_2.6.exe -f <메모리 이미지 파일> --profile=<프로파일 명> psscan
직접 커널 객체 조작 (DKOM : Direct Kernel Object Manipulation)
DKOM이란 윈도우 커널에 의해 관리되는 커널 객체(Kernel Object)를 건드려 프로세스를 은닉하는 기술이다.
다음 그림을 보면 이해하기 수월할 것이다.
중간에 있는 프로세스의 Flink와 Blink가 자기 자신을 가리키고 있는 상황이다. 위와 같은 상황이라면 pslist 플러그인과 같이 Double Linked List에 의존하는 포렌식 도구로 중간에 있는 프로세스(악의적인 프로세스)를 탐지하지 못할 것이다.
+) 다음 링크에서 DKOM을 사용하여 프로세스를 은닉하는 방법 및 코드가 잘 나와 있다.
index-of.co.uk/Reverse-Engineering/DKOM-%5Balonglog%5D.pdf
그럼 psscan은 어떻게 탐지할 수 있을까?
그 이유는 풀 태그 스캐닝(pool tag scanning)이라는 기술을 사용하기 때문이다.
풀 태그 스캐닝(pool tag scanning)
시스템 리소스들은 객체관리자(object manager)에서 객체로써 관리되며 앞서 살펴봤던 프로세스 객체는 _EPROCESS구조체로 구성되어 있고 다른 실행 객체들은 _EPROCESS구조체와 비슷한 구조체들로 구성되어 있다. 모든 실행 객체 구조체는 객체 유형과 일부 참조 카운터에 대한 정보를 포함하는 _OBJECT_HEADER구조체를 가지고 있다.
객체를 저장하기 위해 윈도우 메모리 관리자가 커널 풀에 메모리를 할당하게 된다. 윈도우 커널에서 memory pool방식으로 메모리를 관리하는데, 미리 물리적 메모리에 pool을 잡아놓고, 가상메모리에 있는 내용을 필요로 할 때 실제 메모리에 올리고 필요 없을 경우 다시 가상메모리로 내린다. 여기서 pool은 paged memory pool과 non paged memory pool로 나뉘게 된다.
- paged memory pool : 물리적 메모리와 가상 메모리를 오가며 처리되는 방식(하드디스크에 페이징되는 풀)
- non paged memory pool : 물리적 메모리에만 상주하는 방식(하드디스크에 페이징되지 않는 풀)
여기서 객체는 커널에서 non paged memory pool로 유지되며, 이는 물리 메모리에서 항상 상주함을 의미한다.
참고자료)
윈도우 커널은 객체를 생성하라는 요청을 받으면(예를 들면 프로세스를 생성하기 위해 API함수인 CreateProcess()를 호출)을 받으면 객체 유형에 따라 paged memory pool 또는 non paged memory pool에서 객체를 위한 할당을 한다. 이러한 할당을 통해서 객체에 _POOL_HEADER 구조체를 추가해 태깅하게 된다.
_POOL_HEADER구조체는 4바이트의 태그를 포함하는 Pool Tag라는 필드를 포함한다.
Pool Tag는 객체를 식별하는 데 사용할 수 있다. 프로세스 객체를 위한 태그는 Proc이고 파일 객체는 File이다.
다시 psscan으로 돌아와서 psscan은 프로세스 객체를 식별하기 위해 물리 메모리에서 Pool Tag가 Proc인 태그를 스캔하여 프로세스 객체와 연관된 풀 태그 할당을 식별하고, 더 강력한 시그니쳐와 휴리스틱을 사용해 탐지한다. psscan은 프로세스 객체를 찾으면 _EPROCESS 구조체에서 필요한 정보를 추출하고 이 과정을 모든 프로세스 객체를 찾을 때까지 반복한다. 이러한 풀 태그 스캐닝 기법은 psscan뿐만 아니라 volatility 플러그인 다수가 풀 태그 스캐닝에 의존해 메모리 이미지에서 정보를 식별하여 추출한다.
추가적으로 풀 태그 스캐닝을 사용하는 psscan은 숨겨진 프로세스뿐만 아니라 종료된 프로세스도 탐지할 수 있다. 예를 들어 프로세스 객체가 종료되면 해당 객체를 포함한 메모리 할당은 커널 풀로 해제되지만, 메모리에 있는 내용은 즉시 덮어쓰지 않는다. 즉, 메모리가 다른 목적으로 할당되지 않는 한 프로세스 객체는 여전히 메모리에 존재한다. 이를 통해 종료된 프로세스 객체를 포함하는 메모리가 덮어씌지지 않았다면 종료된 프로세스도 탐지할 수 있다. (마치 free된 청크를 관리하는 느낌???인 것 같다.)
3. pstree 플러그인
- pslist의 결과를 트리 뷰 형식으로 프로세스 관계 표시
- 프로세스 검사할 때 프로세스간 부모/자식 관계 파악하는 것은 매우 유용
- 악성코드와 연관된 다른 프로세스 파악하는데 유용
vol_2.6.exe -f <메모리 이미지 파일> --profile=<프로파일 명> pstree
하지만 앞서 말했듯이 pslist에 의존하기 때문에 은닉되었거나 종료된 프로세스를 탐지할 수 없다는 단점이 존재한다.
이럴때는 psscan을 사용하여 프로세스 관계를 시각화하는 방법을 사용하면 된다.
vol_2.6.exe -f <메모리 이미지 파일> --profile=<프로파일 명> psscan --output=dot --output-file=view.dot
위와 같이 명령어를 작성하여 실행하면은 view.dot파일이 생성되는데 dot포맷의 파일은 Graphviz와 XDot과 같은 시각화 툴을 사용하여 확인할 수 있다.
여기서 다음 링크에서 "Malware - Cridex"다운받아 해보자
psscan.dot파일이 생성되고 요걸로 시각화를 진행해보자
[ Graphviz Download ]
나는 wsl에서 진행하였으므로 "sudo apt install graphviz"입력해서 설치하자
여기서 fdp라는 힘-방향 그래프 랜더라라는 툴이 있는데 GraphViz 네트워크 시각화 도구 중 하나이다. 요거를 사용한다.
fdp <dotfile> -T png -o <outputfile.png>
요렇게 입력하면 psscan.png파일이 생성되고 확인해보면
요렇게 예쁘게(?) 나온다.
4. psxview 플러그인
- 7가지의 다른 기술을 사용하여 프로세스를 나열
- 풀 태그 수정을 통해 은닉한 프로세스 탐지
- _POOL_HEADER는 디버깅 목적으로만 사용되며 OS에 영향을 끼치지 않음
- 이를 통해 공격자가 커널 드라이버를 설치해 커널 공간에 실행하고 _POOL_HEADER의 풀 태그 또는 다른 필드를 수정할 수 있음 -> 풀 태그 스캐닝에 의존하는 플러그인들의 문제점(ex. psscan)
vol_2.6.exe -f <메모리 이미지 파일> --profile=<프로파일 명> psxview
위에서 pslist부터 deskthrd까지 7개 항목에 대해서 True, False 두 개로 나뉘는데 여기서 True는 프로세스를 찾았다는 의미이고 False는 프로세스를 찾지 못했다는 뜻이다. 예를 들어 DKOM이 적용되어 은닉하고 있는 프로세스가 존재하면 pslist에서는 False라고 뜨고 psscan에서는 True라고 뜰 것이다.(풀 태그 스캐닝때문에) 주의할 것은 pslist에서는 False라고 뜨고 psscan에는 True라고 떴지만 ExitTime에 종료된 시각이 포함된 프로세스는 은닉 프로세스가 아니다. 이는 종료된 프로세스이기 때문에 pslist에서는 탐지를 못 한것이기 때문이다.(psscan은 종료된 프로세스도 탐지 가능)
추가로 R옵션을 통해 프로세스 정보를 해당 플러그인이 프로세스 정보를 어디서 가져오는지 예상할 수 있다.
vol_2.6.exe -f <메모리 이미지 파일> --profile=<프로파일 명> psxview -R
위 그림과 같이 R옵션을 주게되면 아까 전에 봤던 False위치에 Okay로 바뀌는 것을 볼 수 있는데 여기서 Okay는 False를 의미하지만 예상한 동작임을 말한다. 여기서 말하는 예상한 동작이란 프로세스 정보를 어떻게 어디에서 가져오는지 예상이 됨을 말한다. 그럼에도 불구하고 R옵션을 주었는데 False라고 떴다면 프로세스가 은닉되어있음을 알려주는 지표가 될 수 있다.
5. handles 플러그인
- 프로세스 핸들 나열
// 모든 프로세스의 핸들 정보 표시
vol_2.6.exe -f <메모리 이미지 파일> --profile=<프로파일 명> handles
// -p옵션 : 특정 프로세스의 핸들 정보 표시
vol_2.6.exe -f <메모리 이미지 파일> --profile=<프로파일 명> handles -p <PID>
// -t옵션 : 특정 객체 유형으로 필터링하여 핸들 정보 표시
vol_2.6.exe -f <메모리 이미지 파일> --profile=<프로파일 명> handles -p <PID> -t <Type>
특정 프로세스에 대해 참조했던 핸들 조사(pid : 608)
특정 프로세스에 대해 Thread 타입만 조사
핸들을 조사함으로써 악의적인 프로세스가 어떤 객체를 참조하는지 알 수 있다. 해당 객체를 참조하기 위해서는 먼저 핸들을 가져와야 하기 때문이다. 핸들을 가져올 수 있다면 레지스트리나 프로세스, 파일 등 실행 객체들에 참조할 수 있다. (핸들:객체에 대한 간접 참조)
직접 객체에 접근하지 않고 핸들을 가져오는 이유는 객체는 커널 메모리에 상주하고 프로세스는 유저 공간에서 실행되기 때문이다. 각각의 프로세스는 커널 메모리에 존재하는 private handle table을 가지는데 이 테이블에는 파일, 프로세스, 네트워크 소켓 등과 같은 커널 객체를 포함한다. 프로세스가 커널에게 객체를 생성하려는 요청을 보내면 커널은 해당 객체를 커널 메모리에 생성되고 객체에 대한 포인터는 private handle table에 채워지게 된다.
6. procdump 플러그인
- 프로세스 실행 파일 덤프
- 악의적인 프로세스를 식별한 후 추가 조사를 위해 덤프를 진행
vol_2.6.exe -f <메모리 이미지 파일> --profile=<프로파일 명> procdump
-p 옵션 : 특정 프로세스만 덤프(ex. -p <pid>)
-D 옵션 : 덤프할 디렉터리 지정(ex. -D <directory path>)
-o 옵션 : 물리 오프셋으로 프로세스 덤프(ex. -o <offset>)
(여기서 -o옵션을 사용하면 메모리에서 숨겨진 프로세스를 덤프할 때 유용하다. 물리 오프셋은 psscan이나 psxview 플러그인에서 확인할 수 있다.)
'Security > Volatility' 카테고리의 다른 글
[Volatility] 명령어 히스토리 조사 (0) | 2021.04.28 |
---|---|
[Volatility] 서비스 조사 (0) | 2021.04.28 |
[Volatility] 레지스트리 조사 (0) | 2021.04.28 |
[Volatility] 네트워크 및 소켓 조사 (0) | 2021.04.28 |
[Volatility] DLL 조사 (0) | 2021.04.28 |