Summary & Purpose

북한의 라자루스 그룹(Lazarus Group)이 기존에 있던 쉘코드가 아닌 쉘코드에 사용하지 않는 Windows API를 사용한 로더(Loader)가 2021년 1월 21일에 발견되었다.

또한 해당 로더(Loader)에 대해서 분석한 NCCGroup의 RIFT(Research and Intelligence Fusion Team)에 의하면 쉘코드 실행에 있어서 생소한 윈도우 API(HeapCreate, HeapAlloc, UUIDFromStringA, EnumSystemLocalesA)를 사용했다. 또한 필자는 쉘코드에 잘 쓰이지 않는 윈도우 API를 사용한 부분에서 흥미를 느꼈다.

UUID Shellcode Execution

Summary & Purpose에서 다룬것 처럼 라자루스 그룹은 기존에 쉘코드에서 사용하는 윈도우 API(NtQueueAPCThread, SetThreadContext, WriteProcessMemory, VirtualAllocExec, CreateRemoteThread)가 아닌 쉘코드에 생소한 윈도우 API(HeapCreate, HeapAlloc, UUIDFromStringA, EnumSystemLocalesA)를 사용하였다.

라자루스 그룹의 로더가 어떻게 UUID 문자열을 이용해서 쉘코드를 힙(Heap)에서 실행할 수 있는지 알아보자.

기본적으로 쉘코드를 실행할 때 아래와 같은 과정을 통해서 진행된다.

  1. 로컬, 혹은 원격 프로세스의 핸들을 얻는다.
  2. 핸들을 가지고 대상 프로세스에 새로운 메모리를 할당한다.
  3. 새롭게 할당된 메모리에 쉘코드를 로드 시킨다.
  4. 다양한 방법으로 로드된 쉘코드를 실행한다.

위의 과정과 완전히 다르지 않지만, 생소한 윈도우 API를 이용한 UUID 쉘코드는 다음과 같이 진행이 된다.

  1. 로컬 프로세스에 힙(Heap) 오브젝트를 생성한다.
  2. 힙(Heap) 오브젝트를 이용해서 특정 사이즈의 메모리를 할당한다.
  3. UUIDFromStringA 함수를 이용해 UUID 문자열 배열을 차례대로 바이너리(Binary) 형태로 바꿔서 힙(Heap)에 저장한다. 이때 이 바이너리 형태의 데이터가 쉘코드가 된다.
  4. 저장해 놓은 쉘코드를 가르키는 포인터를 콜백(Callback)함수로 지정하여 EnumSystemLocalesA 함수의 파라미터 중 하나로 넘기면서 쉘코드를 실행하게 된다.

UUID Shellcode를 실행하기 위해서 EnumSystemLocalesA 함수가 매우 중요한 함수이다. 그렇기 때문에 EnumSystemLocalesA 함수를 한번 확인해 보자.

BOOL EnumSystemLocalesA(
	LOCALE_ENUMPROCA lpLocaleEnumProc,
	DWORD            dwFlags
);

EnumSystemLocalesA 함수를 보면 2개의 인자값을 사용하는데, lpLocaleEnumProc에 원래 콜백 함수를 넣어서 로케일 정보에 관련된 처리를 하면된다. 이때 콜백 함수 대신 lpLocaleEnumProc 값에 쉘코드를 가르키는 포인터를 대신 넣어서 쉘코드를 실행하게 된다.