Process Reload시 DLL Injection을 유지하는 방법

박민(Park Min)·2022년 6월 15일

Misc

목록 보기
1/1

1. 고충

어느 날 DLL Injection 을 이용해 악성 행위를 구현할 일이 있었다. 주어진 시나리오에 의해 감염된 PC를 만들어 놓으면 Blue Team이 Artifact를 분석하여 실시간으로 악성코드를 제거해내는 훈련이었는데, Blue Team 의 대응 역량을 강화하기 위해 Live System을 필수적으로 분석해야 하는 Reflective DLL Injection 기법을 이용하기로 한 것이다.

처음에는 그냥 "Loader 하나 만들어서 적당한 Persistence 에다가 등록 해야겠다." 라고 생각했지만, 문제가 하나 생겼다.

해당 훈련의 특성상 낮은 Integrity Level 에서 TTP를 만들어야 했었는데, 그렇다보니 Injection할 Process가 explorer.exe 말고는 마땅히 없었다. Blue Team도 바보는 아니기 때문에 "만약 공격자가 DLL Injection을 수행했다면 explorer.exe에 Injection 확률이 높겠다." 라고 생각하고, 요행으로 그냥 프로세스를 종료시키면 해당 공격은 무력화되어 버린다.

나는 Blue Team이 치열한 분석 끝에 악성 행위 지속성(Persistence)의 근원지를 찾아내고 이를 제거하는 그림을 원한 것이지, 이렇게 요행으로 문제를 해결하길 바랬던건 아니기 때문에 무언가 대책이 필요했다.


2. 아이디어

그렇게 고민하던 중 이 문제를 해결해냈고, 꽤 오래전 일이지만 블로그에 기록을 남기고자 한다.

2.1. explorer.exe는 종료되어도 다시 실행된다

파일 탐색기 아이콘을 한 explorer.exe 는 윈도우 OS를 이용할 때 필수적인 프로세스이고, 그렇기 때문에 종료를 시키더라도 OS에서 재시동 시켜준다. 그렇기 때문에 아래와 같은 아이디어를 떠올릴 수 있다.

explorer.exe 가 재시동되었을 시점에 다시 Injection 하면 된다..!

Red Team이 프로세스 목록을 보고 있다가 explorer.exe 가 종료되었을 때 직접 Injection 해줄 수 있다면 좋겠지만, 그게 가능하다면 굳이 DLL Injection 까지 해가며 악성행위를 수행할 필요가 없다.

이 행위를 악성코드(Persistence)가 해줘야 하는데, 악성코드도 코드인지라 다시 Injection을 수행할 조건을 만들어주고 스스로 공격을 재개하도록 해줘야 한다.

2.2. 프로세스가 재실행되면 PID가 바뀐다

MS에서 공식적으로 PID를 할당하는 메커니즘을 공개한 적은 없지만 일반적으로 동일한 실행 파일을 두 번 실행한다면 PID가 겹치는 일은 없다.

2.3. (해결) 이전 프로세스의 PID를 기억해두자


최종적으로 내가 이 문제를 해결한 방법이다. 이전 프로세스의 PID를 기억하고, Persistence가 다음 Cycle에서 explorer.exe의 PID를 확인해 봤을 때 만약 이전 PID와 달라졌다면 프로세스가 재실행 된 것으로 간주하고 Injection을 수행하게 하면 된다.


3. 코드

코드는 전체 공개할 수 없어서 이 글에서 제시한 아이디어가 포함된 루틴만 공개함.

#include <windows.h>
#include <time.h>
#include <tchar.h>
#include <urlmon.h>
#include <sys/stat.h>
#include <string>
#include <tlhelp32.h>
#include <stdio.h>
#include <stdlib.h>

#define TARGET_PROC "explorer.exe"

// 중략

/* dll injection 여부를 판단하기 위한 PID 플래그 */
DWORD prevPID = -1; // 이전 PID
DWORD nowPID = -1; // 현재 PID


VOID Walk()
{
    while (1)
    {

        /* 자체 Agent 실행 루틴 */
		// code
        
        /* injector, dll 다운로드 */
		// code
        
        /* DLL Injection을 수행할 것인가? */

		nowPID = find_pid(TARGET_PROC);
        if (prevPID == -1) { // 최초 실행시 인젝션 수행
            prevPID = find_pid(TARGET_PROC);
            // 인젝션 루틴 수행
        }

        else if (prevPID != nowPID) { // 과거 pid, 현재 pid가 다른 경우 --> 프로세스가 제거되어 reload 되었음 --> 인젝션 수행
            prevPID = find_pid(TARGET_PROC);
            // 인젝션 루틴 수행
        }
        
        else {
            // 인젝션할 필요가 없음. ( 기존 프로세스 계속 살아있음 )
        }

        Sleep(600000);
    }
}

// 후략
profile
Security Researcher

0개의 댓글