출처: Process Hollowing - John Leitch
Process Hollowing
Suspended 상태의 프로세스를 생성한 후 해당 프로세스의 이미지를 언매핑하고 원하는 악성코드를 매핑하는 기술이다.
#suspended 상태: 프로세스가 메모리를 강제로 빼앗긴 상태, 즉 프로세스의 중지 상태를 의미함.
Technique: Process Injection
# 공격자가 목표에 대한 tactic을 달성하기 위한 방법
# Technique를 사용함으로써 발생하는 결과를 명시함
# Tactic에 따라 다양한 technique들이 존재 가능.
Tactics
MITRE ATT&CK 홈페이지에서 실제 공격 기술에 대해 분류한 카테고리 Techniques 내 Process Hollowing 항목에 따르면, 다음과 같다.
- 방어회피(Defense Evasion): 공격자가 침입한 시간 동안 탐지 당하는 것을 피하기 위한 행위
- 권한상승(Privilege Escalation): 공격자가 시스템이나 네트워크에서 높은 권한을 얻기 위한 행위
합법적으로 생성한 프로세스로부터 보안 컨텍스트를 상속받으며 생성된 프로세스 이기 때문에, (해당 기법으로 권한 상승의 목적을 달성하기는 어려움이 있지만) 합법적인 프로세스로부터 새로운 instance(process)를 생성하므로 보안 제품의 탐지로부터 회피하기 좋다.
+) 권한 상승 충분히 가능함.
Mitigations
# 관리자가 공격을 예방하고 탐지하기 위해 취할 수 있는 행동을 의미.
# 보안의 목적과 시스템 상황에 따라 심층적 mitigation이 가능.
Process Hollowing 과정
Creating The Process
대상 프로세스는 일시 중단된 상태로 생성해야 한다. 이를 수행하려면 dwCreationFlags 파라미터를 사용하여 CREATE_SUSPENDED 플래그를 CreateProcess 함수에 전달한다.
프로세스가 생성되면 PROCESS_INFORMATION 구조의 hProcess 멤버가 제공하는 핸들을 사용하여 메모리 공간을 변경할 수 있다.
Gathering Information
먼저 destination image 의 기본 주소를 찾아야 한다.
이를 수행하려면 NtQueryProcessInformation를 사용하여 프로세스를 쿼리하여 Process Environment Block(PEB; 프로세스 환경 블록)의 주소를 취득한다.
이 모든 기능은 ReadRemotePEB라는 이름의 편리한 헬퍼(helper) 함수에 캡슐화되어 있다.
프로세스에서 PEB를 읽으면 image base가 NT 헤더의 읽기에 사용된다.
다시 한번 Read Process Memory를 사용하여 편리한 헬퍼(helper) 함수를 제공한다.
Carving The Hole
헤더를 수중에 두면, destination image 를 메모리에 매핑 할 필요가 없어지기에, NtUnmapViewOfSection 함수를 사용하여 메모리에서 제거한다.
다음으로 Source image 에 새로운 메모리 블록을 할당한다. 블록 크기는 Source image 옵션 헤더(Optional Header)의 SizeOfImage 멤버에 의해 결정된다. 단순화를 위해 블록 전체가 PAGE_EXECUTE_READWRITE로 플래그가 지정되지만 섹션 헤더에 지정된 특성에 따라 각 포터블 실행 가능 섹션에 적절한 플래그를 할당함으로써 이를 개선할 수 있다.
Copying The Source Image
이제 메모리가 새 이미지에 할당되었으므로 프로세스 메모리에 복사해야 한다.
할로잉이 작동하려면 Source image 의 임의 헤더 내에 저장된 image base 가 destination image 의 base 주소로 설정되어야 한다.
✔ 설정하기 전에 두 기본 주소 간의 차이를 계산하여 재베이스화(rebase)에 사용해야 함.
옵션 헤더(Optional Header)가 고정되면 이미지는 WriteProcessMemory를 통해 휴대용 실행 파일 헤더부터 프로세스에 복사된다. 그 후 각 섹션의 데이터를 복사한다.
앞서 설명한 바와 같이 적절한 메모리 보호 옵션을 다른 섹션에 적용함으로써 이 단계를 조금 더 진행하면 할로잉을 감지하기가 어려워진다.
Rebasing The Source Image
이전 단계에서 계산된 델타가 0이 아닌 경우 Source image를 rebase 해야 한다.
이를 위해 부트스트랩 응용 프로그램은 .reloc 섹션에 저장되어 있는 재배치 테이블을 사용한다.
✔ IMAGE_Directory_ENTRY_BASERELOC 상수로 액세스되는 관련 IMAGE_DATA_Directory에는 테이블에 대한 포인터가 포함되어 있음
재배치 테이블 자체는 일련의 가변 길이 블록으로 분할되며, 각 블록에는 4KB 페이지의 일련의 엔트리가 포함된다.
각 재배치 블록의 선두에는 페이지 주소와 블록사이즈가 표시되고 그 다음에 재배치 엔트리가 표시된다.
각 재배치 엔트리는 SIGLE WORD. 하위 12비트는 재배치 오프셋, 상위 4비트는 재배치 유형이다.
C - Bit Fields를 사용하여 해당 값들에 쉽게 액세스할 수 있다.
블록 내의 엔트리 수를 계산하려면 BlockSize에서 BASE_RELOCATION_BLOCK 크기를 빼고 차이를 BASE_RELOCATION_ENTRY 크기로 나눠야 한다.
#define CountRelocationEntries(dwBlockSize)
(dwBlockSize - sizeof(BASE_RELOCATION_BLOCK)) / sizeof(BASE_RELOCATION_ENTRY)
이를 통해 각 블록과 해당 항목을 반복하여 이미지의 주소를 패치할 수 있다.
The Final Touches
Source image 를 대상 프로세스에 로드한 상태에서 프로세스 스레드를 변경해야 한다. 이를 위해,
① 스레드 CONTEXT를 취득.
EAX 레지스터만 업데이트하면 되기 때문에 CONTEXT 구조의 ContextFlags 멤버는 CONTEX_INTEGER 로 설정할 수 있다.
스레드 CONTEXT를 취득한 후, EAX는 원본 이미지의 base 주소와 Entry point 주소의 합으로 설정된다.
# entry point: 진입점
② 스레드 CONTEXT가 설정되고 변경 내용이 EAX 레지스터에 적용된다.
③ 마지막으로 스레드를 재개하여 Source image 의 엔트리 포인트 주소를 실행한다.
이제 할로잉 기능을 사용할 수 있다.
EX) svchost.exe(Windows 서비스 호스트)가 비워지고 메시지 상자를 표시하는 단순한 응용 프로그램으로 대체됨
'System > TTPs' 카테고리의 다른 글
DLL Hijacking 실습 (1) (0) | 2023.03.29 |
---|---|
2. DLL Hijacking (0) | 2023.03.29 |
UAC bypass 실습하다가 컴날림 (1) | 2022.07.15 |
AV 엔진 우회 2 (0) | 2022.06.11 |
VM 엔진 우회 실습 1 (0) | 2022.04.28 |